|
1 | 1 | import {
|
2 | 2 | ContentKitBlock,
|
3 |
| - UIRenderEvent, |
4 |
| - ContentKitRenderOutput, |
5 | 3 | ContentKitContext,
|
6 | 4 | ContentKitDefaultAction,
|
| 5 | + ContentKitRenderOutput, |
| 6 | + UIRenderEvent, |
7 | 7 | } from '@gitbook/api';
|
8 | 8 |
|
9 | 9 | import { RuntimeCallback, RuntimeContext } from './context';
|
@@ -67,15 +67,19 @@ export function createComponent<
|
67 | 67 | * Initial state of the component.
|
68 | 68 | */
|
69 | 69 | initialState?:
|
70 |
| - | State |
71 |
| - | ((props: Props, renderContext: ContentKitContext, context: Context) => State); |
| 70 | + | State |
| 71 | + | ((props: Props, renderContext: ContentKitContext, context: Context) => State); |
72 | 72 |
|
73 | 73 | /**
|
74 | 74 | * Callback to handle a dispatched action.
|
75 | 75 | */
|
76 | 76 | action?: RuntimeCallback<
|
77 | 77 | [ComponentInstance<Props, State>, ComponentAction<Action>],
|
78 |
| - Promise<{ props?: Props; state?: State } | undefined>, |
| 78 | + Promise< |
| 79 | + | { type?: 'element'; props?: Props; state?: State } |
| 80 | + | { type: 'complete'; returnValue?: PlainObject } |
| 81 | + | undefined |
| 82 | + >, |
79 | 83 | Context
|
80 | 84 | >;
|
81 | 85 |
|
@@ -112,29 +116,42 @@ export function createComponent<
|
112 | 116 | dynamicState: (key) => ({ $state: key }),
|
113 | 117 | };
|
114 | 118 |
|
| 119 | + const wrapResponse = (output: ContentKitRenderOutput) => { |
| 120 | + return new Response(JSON.stringify(output), { |
| 121 | + headers: { |
| 122 | + 'Content-Type': 'application/json', |
| 123 | + ...(cache |
| 124 | + ? { |
| 125 | + // @ts-ignore - I'm not sure how to fix this one with TS |
| 126 | + 'Cache-Control': `max-age=${cache.maxAge}`, |
| 127 | + } |
| 128 | + : {}), |
| 129 | + }, |
| 130 | + }); |
| 131 | + }; |
| 132 | + |
115 | 133 | if (action && component.action) {
|
116 |
| - instance = { ...instance, ...(await component.action(instance, action, context)) }; |
| 134 | + const actionResult = await component.action(instance, action, context); |
| 135 | + |
| 136 | + // If the action is complete, return the result directly. No need to render the component. |
| 137 | + if (actionResult?.type === 'complete') { |
| 138 | + return wrapResponse(actionResult); |
| 139 | + } |
| 140 | + |
| 141 | + instance = { ...instance, ...actionResult }; |
117 | 142 | }
|
118 | 143 |
|
119 | 144 | const element = await component.render(instance, context);
|
120 | 145 |
|
121 | 146 | const output: ContentKitRenderOutput = {
|
| 147 | + // for backward compatibility always default to 'element' |
| 148 | + type: 'element', |
122 | 149 | state: instance.state,
|
123 | 150 | props: instance.props,
|
124 | 151 | element,
|
125 | 152 | };
|
126 | 153 |
|
127 |
| - return new Response(JSON.stringify(output), { |
128 |
| - headers: { |
129 |
| - 'Content-Type': 'application/json', |
130 |
| - ...(cache |
131 |
| - ? { |
132 |
| - // @ts-ignore - I'm not sure how to fix this one with TS |
133 |
| - 'Cache-Control': `max-age=${cache.maxAge}`, |
134 |
| - } |
135 |
| - : {}), |
136 |
| - }, |
137 |
| - }); |
| 154 | + return wrapResponse(output); |
138 | 155 | },
|
139 | 156 | };
|
140 | 157 | }
|
0 commit comments