@tailorkit/react 0.1.0-beta.4 → 0.1.0-beta.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +74 -0
- package/README.md +35 -0
- package/dist/components/context.d.ts +7 -9
- package/dist/components/index.d.ts +1 -1
- package/dist/components/render-slot.d.ts +9 -0
- package/dist/hooks/use-apps.d.ts +6 -12
- package/dist/hooks/use-query-result.d.ts +9 -0
- package/dist/hooks/use-view-context.d.ts +6 -0
- package/dist/hooks/use-views.d.ts +7 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +451 -840
- package/dist/primitives.d.ts +15 -20
- package/dist/remote-view.d.ts +11 -5
- package/dist/tailorkit.d.ts +45 -0
- package/package.json +43 -13
- package/LICENSE +0 -674
- package/dist/components/render.d.ts +0 -19
- package/dist/components/root.d.ts +0 -10
- package/dist/hooks/use-current-screen.d.ts +0 -23
- package/dist/node-store.d.ts +0 -16
- package/dist/remote-context.d.ts +0 -8
- package/dist/tailor-kit.d.ts +0 -116
package/dist/index.js
CHANGED
|
@@ -1,342 +1,16 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { useMemo as useMemo2 } from "react";
|
|
6
|
-
|
|
7
|
-
// src/components/render.tsx
|
|
8
|
-
import { cloneElement, createElement, isValidElement, useMemo } from "react";
|
|
9
|
-
function useRender({
|
|
10
|
-
defaultTagName,
|
|
11
|
-
props,
|
|
12
|
-
render
|
|
13
|
-
}) {
|
|
14
|
-
return useMemo(() => {
|
|
15
|
-
if (render) {
|
|
16
|
-
if (!isValidElement(render)) {
|
|
17
|
-
throw new Error("The render prop must be a valid React element.");
|
|
18
|
-
}
|
|
19
|
-
return cloneElement(render, mergeProps(render.props, props));
|
|
20
|
-
}
|
|
21
|
-
return createElement(defaultTagName, props);
|
|
22
|
-
}, [defaultTagName, props, render]);
|
|
23
|
-
}
|
|
24
|
-
function mergeProps(...propSets) {
|
|
25
|
-
const merged = {};
|
|
26
|
-
for (const props of propSets) {
|
|
27
|
-
if (!props) {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
for (const [key, value] of Object.entries(props)) {
|
|
31
|
-
if (value === void 0) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
const existing = merged[key];
|
|
35
|
-
if (key === "className" && existing && value) {
|
|
36
|
-
merged[key] = `${existing} ${value}`;
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (key === "style" && existing && value) {
|
|
40
|
-
merged[key] = {
|
|
41
|
-
...existing,
|
|
42
|
-
...value
|
|
43
|
-
};
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (key === "ref" && existing && value) {
|
|
47
|
-
merged[key] = composeRefs(existing, value);
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (isEventHandler(key) && typeof existing === "function" && typeof value === "function") {
|
|
51
|
-
merged[key] = (...args) => {
|
|
52
|
-
existing(...args);
|
|
53
|
-
const event = args[0];
|
|
54
|
-
if (!event?.defaultPrevented) {
|
|
55
|
-
value(...args);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
merged[key] = value;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return merged;
|
|
64
|
-
}
|
|
65
|
-
function composeRefs(...refs) {
|
|
66
|
-
return (node) => {
|
|
67
|
-
for (const ref of refs) {
|
|
68
|
-
if (typeof ref === "function") {
|
|
69
|
-
ref(node);
|
|
70
|
-
} else if (ref) {
|
|
71
|
-
ref.current = node;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function isEventHandler(key) {
|
|
77
|
-
return /^on[A-Z]/u.test(key);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/components/context.ts
|
|
81
|
-
import { createContext, useContext } from "react";
|
|
82
|
-
var TailorRootContext = createContext(null);
|
|
83
|
-
function useTailorRootContext(component) {
|
|
84
|
-
const context = useContext(TailorRootContext);
|
|
85
|
-
if (!context) {
|
|
86
|
-
throw new Error(`${component} must be rendered inside tailor.Root.`);
|
|
87
|
-
}
|
|
88
|
-
return context;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// src/components/root.tsx
|
|
92
|
-
import { jsx } from "react/jsx-runtime";
|
|
93
|
-
var EMPTY_APPS = [];
|
|
94
|
-
function Root({ apps: appsProp, children, render, tailor, ...props }) {
|
|
95
|
-
const appsResult = tailor.useApps();
|
|
96
|
-
const apps = appsProp ?? appsResult.data ?? EMPTY_APPS;
|
|
97
|
-
const context = useMemo2(
|
|
98
|
-
() => ({
|
|
99
|
-
apps
|
|
100
|
-
}),
|
|
101
|
-
[apps]
|
|
102
|
-
);
|
|
103
|
-
const element = render ? useRender({
|
|
104
|
-
defaultTagName: "div",
|
|
105
|
-
props: mergeProps({ children }, props),
|
|
106
|
-
render
|
|
107
|
-
}) : children;
|
|
108
|
-
return /* @__PURE__ */ jsx(TailorRootContext.Provider, { value: context, children: element });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// src/hooks/use-apps.ts
|
|
112
|
-
import { useCallback, useEffect, useSyncExternalStore } from "react";
|
|
113
|
-
function createUseApps(store) {
|
|
114
|
-
return function useApps() {
|
|
115
|
-
const snapshot = useSyncExternalStore(
|
|
116
|
-
store.subscribe,
|
|
117
|
-
store.getAppsSnapshot,
|
|
118
|
-
store.getAppsSnapshot
|
|
119
|
-
);
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
void store.fetchApps();
|
|
122
|
-
}, []);
|
|
123
|
-
const refetch = useCallback(() => store.fetchApps({ force: true }), []);
|
|
124
|
-
return toUseAppsResult(snapshot, refetch);
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
function toUseAppsResult(snapshot, refetch) {
|
|
128
|
-
return {
|
|
129
|
-
data: snapshot.status === "ready" ? snapshot.apps : void 0,
|
|
130
|
-
error: snapshot.error,
|
|
131
|
-
isError: snapshot.status === "error",
|
|
132
|
-
isLoading: snapshot.status === "loading",
|
|
133
|
-
isPending: snapshot.status === "idle" || snapshot.status === "loading",
|
|
134
|
-
isSuccess: snapshot.status === "ready",
|
|
135
|
-
refetch,
|
|
136
|
-
status: snapshot.status
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// src/hooks/use-current-screen.ts
|
|
141
|
-
import { useEffect as useEffect2, useMemo as useMemo3, useRef } from "react";
|
|
142
|
-
function createUseCurrentScreen(store) {
|
|
143
|
-
return function useCurrentScreen(options) {
|
|
144
|
-
useTailorRootContext("tailor.useCurrentScreen");
|
|
145
|
-
const id = useMemo3(() => /* @__PURE__ */ Symbol("tailorkit-current-screen"), []);
|
|
146
|
-
const status = options.status ?? "ready";
|
|
147
|
-
const context = "context" in options ? options.context : void 0;
|
|
148
|
-
const contextKey = JSON.stringify(context);
|
|
149
|
-
const contextRef = useRef({ key: contextKey, value: context });
|
|
150
|
-
if (contextRef.current.key !== contextKey) {
|
|
151
|
-
contextRef.current = { key: contextKey, value: context };
|
|
152
|
-
}
|
|
153
|
-
const contextSnapshot = contextRef.current.value;
|
|
154
|
-
useEffect2(
|
|
155
|
-
() => () => {
|
|
156
|
-
store.unregisterScreen(id);
|
|
157
|
-
},
|
|
158
|
-
[id]
|
|
159
|
-
);
|
|
160
|
-
useEffect2(() => {
|
|
161
|
-
store.registerScreen({
|
|
162
|
-
context: contextSnapshot,
|
|
163
|
-
id,
|
|
164
|
-
screen: options.screen,
|
|
165
|
-
status
|
|
166
|
-
});
|
|
167
|
-
}, [contextSnapshot, id, options.screen, status]);
|
|
168
|
-
};
|
|
169
|
-
}
|
|
1
|
+
// src/components/render-slot.tsx
|
|
2
|
+
import { useStore as useStore2 } from "@nanostores/react";
|
|
3
|
+
import { createSlotRuntime, buildThemeCss } from "@tailorkit/client-core";
|
|
4
|
+
import { useEffect as useEffect2, useId as useId2, useMemo as useMemo3, useState as useState3 } from "react";
|
|
170
5
|
|
|
171
6
|
// src/primitives.tsx
|
|
172
|
-
import {
|
|
173
|
-
import {
|
|
174
|
-
import { jsx
|
|
175
|
-
var PrimitiveThemeContext =
|
|
176
|
-
var tokenGroups = [
|
|
177
|
-
"space",
|
|
178
|
-
"radius",
|
|
179
|
-
"background",
|
|
180
|
-
"border",
|
|
181
|
-
"borderColor",
|
|
182
|
-
"textColor"
|
|
183
|
-
];
|
|
184
|
-
var cssEscape = (value) => {
|
|
185
|
-
const css = globalThis.CSS;
|
|
186
|
-
if (typeof css?.escape === "function") {
|
|
187
|
-
return css.escape(value);
|
|
188
|
-
}
|
|
189
|
-
return value.replaceAll(/[^A-Za-z0-9_-]/gu, "\\$&");
|
|
190
|
-
};
|
|
191
|
-
var toCssValue = (group, value) => {
|
|
192
|
-
if (typeof value === "number") {
|
|
193
|
-
return `${value}px`;
|
|
194
|
-
}
|
|
195
|
-
if (group === "size" || group === "raw") {
|
|
196
|
-
return value;
|
|
197
|
-
}
|
|
198
|
-
return `var(--tailorkit-${group}-${cssEscape(value)})`;
|
|
199
|
-
};
|
|
200
|
-
var toResponsiveEntries = (value) => {
|
|
201
|
-
if (value === void 0) {
|
|
202
|
-
return [];
|
|
203
|
-
}
|
|
204
|
-
if (!(value && typeof value === "object") || Array.isArray(value)) {
|
|
205
|
-
return [["base", value]];
|
|
206
|
-
}
|
|
207
|
-
return Object.entries(value).filter(
|
|
208
|
-
(entry) => entry[1] !== void 0
|
|
209
|
-
);
|
|
210
|
-
};
|
|
211
|
-
var declarationsForProp = (prop, value) => {
|
|
212
|
-
if (prop === "columns") {
|
|
213
|
-
return [`grid-template-columns: repeat(${String(value)}, minmax(0, 1fr));`];
|
|
214
|
-
}
|
|
215
|
-
const tokenDeclarations = {
|
|
216
|
-
background: ["background", "background"],
|
|
217
|
-
border: ["border", "border"],
|
|
218
|
-
borderColor: ["borderColor", "border-color"],
|
|
219
|
-
textColor: ["textColor", "color"]
|
|
220
|
-
};
|
|
221
|
-
const tokenDeclaration = tokenDeclarations[prop];
|
|
222
|
-
if (tokenDeclaration) {
|
|
223
|
-
const [group, property] = tokenDeclaration;
|
|
224
|
-
if (prop === "border") {
|
|
225
|
-
return [`border-style: ${toCssValue(group, value)};`, "border-width: 1px;"];
|
|
226
|
-
}
|
|
227
|
-
return [`${property}: ${toCssValue(group, value)};`];
|
|
228
|
-
}
|
|
229
|
-
if (prop === "gap" || prop === "margin" || prop === "padding") {
|
|
230
|
-
return [`${prop}: ${toCssValue("space", value)};`];
|
|
231
|
-
}
|
|
232
|
-
if (prop === "height" || prop === "width") {
|
|
233
|
-
return [`${prop}: ${toCssValue("size", value)};`];
|
|
234
|
-
}
|
|
235
|
-
if (prop === "radius") {
|
|
236
|
-
return [`border-radius: ${toCssValue("radius", value)};`];
|
|
237
|
-
}
|
|
238
|
-
if (prop === "align") {
|
|
239
|
-
return [`align-items: ${toFlexAlignment(value)};`];
|
|
240
|
-
}
|
|
241
|
-
if (prop === "justify") {
|
|
242
|
-
return [`justify-content: ${toFlexJustification(value)};`];
|
|
243
|
-
}
|
|
244
|
-
if (prop === "direction") {
|
|
245
|
-
return [`flex-direction: ${toCssValue("raw", value)};`];
|
|
246
|
-
}
|
|
247
|
-
if (prop === "overflow") {
|
|
248
|
-
return [`overflow: ${toCssValue("raw", value)};`];
|
|
249
|
-
}
|
|
250
|
-
if (prop === "grow") {
|
|
251
|
-
return [`flex-grow: ${String(value)};`];
|
|
252
|
-
}
|
|
253
|
-
if (prop === "shrink") {
|
|
254
|
-
return [`flex-shrink: ${String(value)};`];
|
|
255
|
-
}
|
|
256
|
-
if (prop === "minHeight") {
|
|
257
|
-
return [`min-height: ${toCssValue("size", value)};`];
|
|
258
|
-
}
|
|
259
|
-
if (prop === "minWidth") {
|
|
260
|
-
return [`min-width: ${toCssValue("size", value)};`];
|
|
261
|
-
}
|
|
262
|
-
if (prop === "basis") {
|
|
263
|
-
return [`flex-basis: ${toCssValue("size", value)};`];
|
|
264
|
-
}
|
|
265
|
-
if (prop === "wrap") {
|
|
266
|
-
return [`flex-wrap: ${toCssValue("raw", value)};`];
|
|
267
|
-
}
|
|
268
|
-
return [];
|
|
269
|
-
};
|
|
270
|
-
var toFlexAlignment = (value) => {
|
|
271
|
-
if (value === "start") {
|
|
272
|
-
return "flex-start";
|
|
273
|
-
}
|
|
274
|
-
if (value === "end") {
|
|
275
|
-
return "flex-end";
|
|
276
|
-
}
|
|
277
|
-
return String(value);
|
|
278
|
-
};
|
|
279
|
-
var toFlexJustification = (value) => {
|
|
280
|
-
if (value === "start") {
|
|
281
|
-
return "flex-start";
|
|
282
|
-
}
|
|
283
|
-
if (value === "end") {
|
|
284
|
-
return "flex-end";
|
|
285
|
-
}
|
|
286
|
-
if (value === "between") {
|
|
287
|
-
return "space-between";
|
|
288
|
-
}
|
|
289
|
-
return String(value);
|
|
290
|
-
};
|
|
291
|
-
var buildPrimitiveCss = ({
|
|
292
|
-
display,
|
|
293
|
-
nodeId,
|
|
294
|
-
props,
|
|
295
|
-
screenId,
|
|
296
|
-
theme
|
|
297
|
-
}) => {
|
|
298
|
-
const selector = `[data-tailorkit-screen="${cssEscape(screenId)}"] [data-tailorkit-node="${cssEscape(
|
|
299
|
-
nodeId
|
|
300
|
-
)}"]`;
|
|
301
|
-
const base = [`display: ${display};`];
|
|
302
|
-
const byBreakpoint = /* @__PURE__ */ new Map();
|
|
303
|
-
for (const [prop, rawValue] of Object.entries(props)) {
|
|
304
|
-
for (const [breakpoint, value] of toResponsiveEntries(rawValue)) {
|
|
305
|
-
const declarations = declarationsForProp(prop, value);
|
|
306
|
-
if (declarations.length === 0) {
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
const target = breakpoint === "base" ? base : byBreakpoint.get(breakpoint) ?? [];
|
|
310
|
-
target.push(...declarations);
|
|
311
|
-
if (breakpoint !== "base") {
|
|
312
|
-
byBreakpoint.set(breakpoint, target);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
const rules = [`${selector} { ${base.join(" ")} }`];
|
|
317
|
-
for (const [breakpoint, declarations] of byBreakpoint) {
|
|
318
|
-
const minWidth = theme.breakpoints?.[breakpoint];
|
|
319
|
-
if (!minWidth) {
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
rules.push(`@media (min-width: ${minWidth}) { ${selector} { ${declarations.join(" ")} } }`);
|
|
323
|
-
}
|
|
324
|
-
return rules.join("\n");
|
|
325
|
-
};
|
|
326
|
-
var buildThemeCss = (screenId, theme) => {
|
|
327
|
-
const selector = `[data-tailorkit-screen="${cssEscape(screenId)}"]`;
|
|
328
|
-
const declarations = [];
|
|
329
|
-
const resolvedTheme = resolveTheme(theme);
|
|
330
|
-
for (const group of tokenGroups) {
|
|
331
|
-
for (const [name, value] of Object.entries(resolvedTheme.tokens?.[group] ?? {})) {
|
|
332
|
-
declarations.push(`--tailorkit-${group}-${cssEscape(name)}: ${value};`);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return `${selector} { ${declarations.join(" ")} }`;
|
|
336
|
-
};
|
|
7
|
+
import { buildPrimitiveCss } from "@tailorkit/client-core";
|
|
8
|
+
import { createContext, useContext, useId, useMemo, useState } from "react";
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
var PrimitiveThemeContext = createContext(null);
|
|
337
11
|
var usePrimitiveNodeId = () => {
|
|
338
12
|
const id = useId();
|
|
339
|
-
return
|
|
13
|
+
return useMemo(() => `tailorkit-${id.replaceAll(":", "")}`, [id]);
|
|
340
14
|
};
|
|
341
15
|
var Primitive = ({
|
|
342
16
|
children,
|
|
@@ -344,160 +18,162 @@ var Primitive = ({
|
|
|
344
18
|
element,
|
|
345
19
|
props
|
|
346
20
|
}) => {
|
|
347
|
-
const context =
|
|
21
|
+
const context = useContext(PrimitiveThemeContext);
|
|
348
22
|
const nodeId = usePrimitiveNodeId();
|
|
349
23
|
const Element = element;
|
|
350
24
|
const css = context ? buildPrimitiveCss({
|
|
351
25
|
display,
|
|
352
26
|
nodeId,
|
|
353
27
|
props,
|
|
354
|
-
|
|
355
|
-
|
|
28
|
+
theme: context.theme,
|
|
29
|
+
viewId: context.viewId
|
|
356
30
|
}) : "";
|
|
357
31
|
return /* @__PURE__ */ jsxs(Element, { "data-tailorkit-node": nodeId, children: [
|
|
358
|
-
css === "" ? null : /* @__PURE__ */
|
|
32
|
+
css === "" ? null : /* @__PURE__ */ jsx("style", { "data-tailorkit-node-style": nodeId, children: css }),
|
|
359
33
|
children
|
|
360
34
|
] });
|
|
361
35
|
};
|
|
36
|
+
var isStringValue = (value) => typeof value === "string";
|
|
37
|
+
var isPressCallback = (value) => typeof value === "function";
|
|
38
|
+
var Pressable = ({
|
|
39
|
+
props,
|
|
40
|
+
children
|
|
41
|
+
}) => {
|
|
42
|
+
const context = useContext(PrimitiveThemeContext);
|
|
43
|
+
const nodeId = usePrimitiveNodeId();
|
|
44
|
+
const displays = {
|
|
45
|
+
box: "block",
|
|
46
|
+
flex: "flex",
|
|
47
|
+
grid: "grid",
|
|
48
|
+
inline: "inline-flex"
|
|
49
|
+
};
|
|
50
|
+
const { ariaLabel, layout, onPress } = props;
|
|
51
|
+
const display = layout === "box" || layout === "flex" || layout === "grid" ? displays[layout] : displays.inline;
|
|
52
|
+
const disabled = props.disabled === true;
|
|
53
|
+
const [pressedKey, setPressedKey] = useState(null);
|
|
54
|
+
if (disabled && pressedKey !== null) {
|
|
55
|
+
setPressedKey(null);
|
|
56
|
+
}
|
|
57
|
+
const css = context ? buildPrimitiveCss({
|
|
58
|
+
display,
|
|
59
|
+
nodeId,
|
|
60
|
+
pressable: true,
|
|
61
|
+
props,
|
|
62
|
+
theme: context.theme,
|
|
63
|
+
viewId: context.viewId
|
|
64
|
+
}) : "";
|
|
65
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
66
|
+
css === "" ? null : /* @__PURE__ */ jsx("style", { "data-tailorkit-node-style": nodeId, children: css }),
|
|
67
|
+
/* @__PURE__ */ jsx(
|
|
68
|
+
"div",
|
|
69
|
+
{
|
|
70
|
+
"aria-disabled": disabled || void 0,
|
|
71
|
+
"aria-label": isStringValue(ariaLabel) ? ariaLabel : void 0,
|
|
72
|
+
"data-pressed": !disabled && pressedKey !== null ? "" : void 0,
|
|
73
|
+
"data-tailorkit-node": nodeId,
|
|
74
|
+
onBlur: () => {
|
|
75
|
+
setPressedKey(null);
|
|
76
|
+
},
|
|
77
|
+
onClick: (event) => {
|
|
78
|
+
if (disabled) {
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
event.stopPropagation();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (event.button === 0 && isPressCallback(onPress)) {
|
|
84
|
+
onPress();
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
onKeyDown: (event) => {
|
|
88
|
+
const { key } = event;
|
|
89
|
+
if (event.target !== event.currentTarget || key !== "Enter" && key !== " ") {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
if (disabled || event.repeat || pressedKey !== null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
setPressedKey(key);
|
|
97
|
+
if (key === "Enter" && isPressCallback(onPress)) {
|
|
98
|
+
onPress();
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
onKeyUp: (event) => {
|
|
102
|
+
const { key } = event;
|
|
103
|
+
if (event.target !== event.currentTarget || key !== "Enter" && key !== " ") {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
const activate = !disabled && key === " " && pressedKey === " ";
|
|
108
|
+
setPressedKey(null);
|
|
109
|
+
if (activate && isPressCallback(onPress)) {
|
|
110
|
+
onPress();
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
onPointerDown: (event) => {
|
|
114
|
+
if (disabled) {
|
|
115
|
+
event.preventDefault();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (event.button === 0) {
|
|
119
|
+
event.currentTarget.focus();
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
role: "button",
|
|
123
|
+
tabIndex: disabled ? -1 : 0,
|
|
124
|
+
children
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
] });
|
|
128
|
+
};
|
|
362
129
|
var primitives = {
|
|
363
|
-
Box: ({
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
130
|
+
Box: ({
|
|
131
|
+
props,
|
|
132
|
+
children
|
|
133
|
+
}) => /* @__PURE__ */ jsx(Primitive, { display: "block", element: "div", props, children }),
|
|
134
|
+
Flex: ({
|
|
135
|
+
props,
|
|
136
|
+
children
|
|
137
|
+
}) => /* @__PURE__ */ jsx(Primitive, { display: "flex", element: "div", props, children }),
|
|
138
|
+
Grid: ({
|
|
139
|
+
props,
|
|
140
|
+
children
|
|
141
|
+
}) => /* @__PURE__ */ jsx(Primitive, { display: "grid", element: "div", props, children }),
|
|
142
|
+
Inline: ({
|
|
143
|
+
props,
|
|
144
|
+
children
|
|
145
|
+
}) => /* @__PURE__ */ jsx(Primitive, { display: "inline", element: "span", props, children }),
|
|
146
|
+
Pressable: ({
|
|
147
|
+
props,
|
|
148
|
+
children
|
|
149
|
+
}) => /* @__PURE__ */ jsx(Pressable, { props, children })
|
|
367
150
|
};
|
|
368
151
|
|
|
369
152
|
// src/remote-view.tsx
|
|
153
|
+
import { useStore } from "@nanostores/react";
|
|
154
|
+
import {
|
|
155
|
+
createRemoteViewStore,
|
|
156
|
+
createRemoteElementProps
|
|
157
|
+
} from "@tailorkit/client-core";
|
|
370
158
|
import {
|
|
371
159
|
Component,
|
|
372
|
-
Fragment,
|
|
373
|
-
createElement
|
|
160
|
+
Fragment as Fragment2,
|
|
161
|
+
createElement,
|
|
162
|
+
createContext as createContext2,
|
|
374
163
|
memo,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
useRef as useRef2,
|
|
380
|
-
useState,
|
|
381
|
-
useSyncExternalStore as useSyncExternalStore2
|
|
164
|
+
useContext as useContext2,
|
|
165
|
+
useEffect,
|
|
166
|
+
useMemo as useMemo2,
|
|
167
|
+
useState as useState2
|
|
382
168
|
} from "react";
|
|
383
|
-
import {
|
|
384
|
-
|
|
385
|
-
// src/node-store.ts
|
|
386
|
-
var childIds = (children) => children.map((c) => c.id).join(",");
|
|
387
|
-
var nodeSignature = (node) => {
|
|
388
|
-
if (node.kind === "text") {
|
|
389
|
-
return `text:${node.text}`;
|
|
390
|
-
}
|
|
391
|
-
if (node.kind === "fragment") {
|
|
392
|
-
return `frag:${childIds(node.children)}`;
|
|
393
|
-
}
|
|
394
|
-
const propsStr = JSON.stringify(node.props);
|
|
395
|
-
const callbacksStr = (node.callbacks ?? []).map((binding) => `${binding.callback}:${binding.event}`).join(",");
|
|
396
|
-
return `elem:${node.type}|${childIds(node.children)}|${propsStr}|${callbacksStr}`;
|
|
397
|
-
};
|
|
398
|
-
var flattenTree = (node, out) => {
|
|
399
|
-
out.set(node.id, node);
|
|
400
|
-
if (node.kind === "text") {
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
for (const child of node.children) {
|
|
404
|
-
flattenTree(child, out);
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
var NodeStore = class {
|
|
408
|
-
nodes = /* @__PURE__ */ new Map();
|
|
409
|
-
signatures = /* @__PURE__ */ new Map();
|
|
410
|
-
nodeListeners = /* @__PURE__ */ new Map();
|
|
411
|
-
rootListeners = /* @__PURE__ */ new Set();
|
|
412
|
-
rootId = null;
|
|
413
|
-
clear() {
|
|
414
|
-
const nodeIds = [...this.nodeListeners.keys()];
|
|
415
|
-
const hadRoot = this.rootId !== null;
|
|
416
|
-
this.nodes = /* @__PURE__ */ new Map();
|
|
417
|
-
this.signatures = /* @__PURE__ */ new Map();
|
|
418
|
-
this.rootId = null;
|
|
419
|
-
for (const id of nodeIds) {
|
|
420
|
-
const subs = this.nodeListeners.get(id);
|
|
421
|
-
if (subs) {
|
|
422
|
-
for (const l of subs) {
|
|
423
|
-
l();
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
if (hadRoot) {
|
|
428
|
-
for (const l of this.rootListeners) {
|
|
429
|
-
l();
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
setSnapshot(tree) {
|
|
434
|
-
const next = /* @__PURE__ */ new Map();
|
|
435
|
-
flattenTree(tree, next);
|
|
436
|
-
const changed = /* @__PURE__ */ new Set();
|
|
437
|
-
for (const [id, node] of next) {
|
|
438
|
-
const sig = nodeSignature(node);
|
|
439
|
-
if (this.signatures.get(id) !== sig) {
|
|
440
|
-
changed.add(id);
|
|
441
|
-
this.signatures.set(id, sig);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
for (const id of this.signatures.keys()) {
|
|
445
|
-
if (!next.has(id)) {
|
|
446
|
-
this.signatures.delete(id);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
this.nodes = next;
|
|
450
|
-
const prevRootId = this.rootId;
|
|
451
|
-
this.rootId = tree.id;
|
|
452
|
-
for (const id of changed) {
|
|
453
|
-
const subs = this.nodeListeners.get(id);
|
|
454
|
-
if (subs) {
|
|
455
|
-
for (const l of subs) {
|
|
456
|
-
l();
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
if (prevRootId !== this.rootId) {
|
|
461
|
-
for (const l of this.rootListeners) {
|
|
462
|
-
l();
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
getRootId() {
|
|
467
|
-
return this.rootId;
|
|
468
|
-
}
|
|
469
|
-
getNode(id) {
|
|
470
|
-
return this.nodes.get(id) ?? null;
|
|
471
|
-
}
|
|
472
|
-
subscribe(id, listener) {
|
|
473
|
-
let subs = this.nodeListeners.get(id);
|
|
474
|
-
if (!subs) {
|
|
475
|
-
subs = /* @__PURE__ */ new Set();
|
|
476
|
-
this.nodeListeners.set(id, subs);
|
|
477
|
-
}
|
|
478
|
-
subs.add(listener);
|
|
479
|
-
return () => {
|
|
480
|
-
subs.delete(listener);
|
|
481
|
-
if (subs.size === 0) {
|
|
482
|
-
this.nodeListeners.delete(id);
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
subscribeRoot(listener) {
|
|
487
|
-
this.rootListeners.add(listener);
|
|
488
|
-
return () => this.rootListeners.delete(listener);
|
|
489
|
-
}
|
|
490
|
-
};
|
|
491
|
-
|
|
492
|
-
// src/remote-context.ts
|
|
493
|
-
import { createContext as createContext3 } from "react";
|
|
494
|
-
var RemoteUIContext = createContext3(null);
|
|
495
|
-
|
|
496
|
-
// src/remote-view.tsx
|
|
497
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
169
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
170
|
+
var RemoteUIContext = createContext2(null);
|
|
498
171
|
var formatError = (error) => error.message;
|
|
499
172
|
var RemoteErrorBoundary = class extends Component {
|
|
500
|
-
|
|
173
|
+
constructor(props) {
|
|
174
|
+
super(props);
|
|
175
|
+
this.state = { error: null };
|
|
176
|
+
}
|
|
501
177
|
static getDerivedStateFromError(error) {
|
|
502
178
|
return { error };
|
|
503
179
|
}
|
|
@@ -506,415 +182,350 @@ var RemoteErrorBoundary = class extends Component {
|
|
|
506
182
|
}
|
|
507
183
|
render() {
|
|
508
184
|
if (this.state.error) {
|
|
509
|
-
return
|
|
185
|
+
return createElement("div", null, formatError(this.state.error));
|
|
510
186
|
}
|
|
511
187
|
return this.props.children;
|
|
512
188
|
}
|
|
513
189
|
};
|
|
514
|
-
|
|
190
|
+
var RemoteRoot = ({ store }) => {
|
|
191
|
+
const rootId = useStore(store.nodes.root);
|
|
192
|
+
return rootId === null ? null : /* @__PURE__ */ jsx2(RemoteView, { nodeId: rootId });
|
|
193
|
+
};
|
|
194
|
+
var RemoteViewHost = ({
|
|
515
195
|
appUrl,
|
|
196
|
+
toolBridge,
|
|
197
|
+
getBackendSession,
|
|
516
198
|
components: components2,
|
|
517
199
|
createIframe,
|
|
518
|
-
props
|
|
519
|
-
|
|
520
|
-
}) {
|
|
200
|
+
props
|
|
201
|
+
}) => {
|
|
521
202
|
const appKey = appUrl.toString();
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
store
|
|
539
|
-
|
|
540
|
-
useEffect3(() => {
|
|
541
|
-
ctxRef.current.components = components2;
|
|
542
|
-
}, [components2]);
|
|
543
|
-
const ui = useMemo5(() => {
|
|
544
|
-
const ctx = ctxRef.current;
|
|
545
|
-
return createElement2(
|
|
546
|
-
RemoteUIContext.Provider,
|
|
547
|
-
{ value: ctx },
|
|
548
|
-
createElement2(
|
|
549
|
-
RemoteErrorBoundary,
|
|
550
|
-
{ key: appKey },
|
|
551
|
-
createElement2(RemoteRoot, { store: ctx.store })
|
|
552
|
-
)
|
|
553
|
-
);
|
|
554
|
-
}, [appKey]);
|
|
555
|
-
useEffect3(() => {
|
|
556
|
-
const host = createIframeUiHost(appUrl, {
|
|
203
|
+
const [state, setState] = useState2(() => ({
|
|
204
|
+
appKey,
|
|
205
|
+
store: createRemoteViewStore({ components: components2, props })
|
|
206
|
+
}));
|
|
207
|
+
if (state.appKey !== appKey) {
|
|
208
|
+
setState({ appKey, store: createRemoteViewStore({ components: components2, props }) });
|
|
209
|
+
}
|
|
210
|
+
const { store } = state;
|
|
211
|
+
const snapshot = useStore(store.state);
|
|
212
|
+
useEffect(() => {
|
|
213
|
+
store.setComponents(components2);
|
|
214
|
+
}, [components2, store]);
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
store.setProps(props);
|
|
217
|
+
}, [props, store]);
|
|
218
|
+
useEffect(
|
|
219
|
+
() => store.mount({
|
|
220
|
+
appUrl,
|
|
557
221
|
createIframe,
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
});
|
|
566
|
-
dispatchRef.current = (payload) => host.dispatch(payload);
|
|
567
|
-
const unsubscribe = host.subscribe(() => {
|
|
568
|
-
const tree = host.getSnapshot();
|
|
569
|
-
if (tree !== null) {
|
|
570
|
-
store.setSnapshot(tree);
|
|
571
|
-
setStatus("ready");
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
setStatus("starting");
|
|
575
|
-
setError(null);
|
|
576
|
-
host.mount();
|
|
577
|
-
return () => {
|
|
578
|
-
unsubscribe();
|
|
579
|
-
dispatchRef.current = null;
|
|
580
|
-
host.destroy();
|
|
581
|
-
};
|
|
582
|
-
}, [appUrl, createIframe, props, runtimeUrl, store]);
|
|
583
|
-
if (status === "error" && error) {
|
|
584
|
-
return createElement2("div", null, formatError(error));
|
|
585
|
-
}
|
|
586
|
-
return ui;
|
|
587
|
-
}
|
|
588
|
-
function RemoteRoot({ store }) {
|
|
589
|
-
const subscribe = useCallback2((listener) => store.subscribeRoot(listener), [store]);
|
|
590
|
-
const getSnapshot = useCallback2(() => store.getRootId(), [store]);
|
|
591
|
-
const rootId = useSyncExternalStore2(subscribe, getSnapshot, getSnapshot);
|
|
592
|
-
if (rootId === null) {
|
|
593
|
-
return null;
|
|
222
|
+
getBackendSession,
|
|
223
|
+
toolBridge
|
|
224
|
+
}),
|
|
225
|
+
[appUrl, toolBridge, getBackendSession, createIframe, store]
|
|
226
|
+
);
|
|
227
|
+
if (snapshot.status === "error" && snapshot.error) {
|
|
228
|
+
return createElement("div", null, formatError(snapshot.error));
|
|
594
229
|
}
|
|
595
|
-
return /* @__PURE__ */
|
|
596
|
-
}
|
|
597
|
-
var
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
230
|
+
return /* @__PURE__ */ jsx2(RemoteUIContext.Provider, { value: store, children: /* @__PURE__ */ jsx2(RemoteErrorBoundary, { children: /* @__PURE__ */ jsx2(RemoteRoot, { store }) }, `${appKey}:${snapshot.generation}`) });
|
|
231
|
+
};
|
|
232
|
+
var RemoteElementViewComponent = ({
|
|
233
|
+
ctx,
|
|
234
|
+
node
|
|
235
|
+
}) => {
|
|
236
|
+
const componentStore = useMemo2(
|
|
237
|
+
() => ctx.selectComponent(node.type),
|
|
238
|
+
[ctx, node.type]
|
|
239
|
+
);
|
|
240
|
+
const component = useStore(componentStore);
|
|
241
|
+
const children = node.children.map((child) => (
|
|
242
|
+
// oxlint-disable-next-line no-use-before-define -- This deferred callback runs after initialization; the definitions are mutually dependent.
|
|
243
|
+
/* @__PURE__ */ jsx2(RemoteView, { nodeId: child.id }, child.id)
|
|
244
|
+
));
|
|
601
245
|
if (component === void 0) {
|
|
602
246
|
throw new Error(`TailorKit component "${node.type}" is not registered.`);
|
|
603
247
|
}
|
|
604
|
-
const props =
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
nodeId: node.id
|
|
612
|
-
},
|
|
613
|
-
type: "dispatchCallback"
|
|
614
|
-
});
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
return createElement2(component, props, ...children);
|
|
618
|
-
});
|
|
619
|
-
var RemoteView = memo(function RemoteView2({ nodeId }) {
|
|
620
|
-
const ctx = useContext3(RemoteUIContext);
|
|
621
|
-
if (ctx === null) {
|
|
622
|
-
return null;
|
|
623
|
-
}
|
|
624
|
-
const { store } = ctx;
|
|
625
|
-
const subscribe = useCallback2(
|
|
626
|
-
(listener) => store.subscribe(nodeId, listener),
|
|
627
|
-
[store, nodeId]
|
|
248
|
+
const props = createRemoteElementProps(node, ctx.dispatch.bind(ctx));
|
|
249
|
+
return createElement(
|
|
250
|
+
/* oxlint-disable typescript/no-unsafe-type-assertion -- The renderer was supplied through the typed component registry; React's createElement overload erases its heterogeneous props. */
|
|
251
|
+
component,
|
|
252
|
+
/* oxlint-enable typescript/no-unsafe-type-assertion */
|
|
253
|
+
props,
|
|
254
|
+
...children
|
|
628
255
|
);
|
|
629
|
-
|
|
630
|
-
|
|
256
|
+
};
|
|
257
|
+
var RemoteElementView = memo(RemoteElementViewComponent);
|
|
258
|
+
var RemoteNodeView = ({
|
|
259
|
+
ctx,
|
|
260
|
+
nodeId
|
|
261
|
+
}) => {
|
|
262
|
+
const nodeStore = useMemo2(() => ctx.nodes.selectNode(nodeId), [ctx, nodeId]);
|
|
263
|
+
const node = useStore(nodeStore);
|
|
631
264
|
if (node === null) {
|
|
632
265
|
return null;
|
|
633
266
|
}
|
|
634
267
|
if (node.kind === "text") {
|
|
635
268
|
return node.text;
|
|
636
269
|
}
|
|
637
|
-
const childElements = node.children.map((child) =>
|
|
270
|
+
const childElements = node.children.map((child) => (
|
|
271
|
+
// oxlint-disable-next-line no-use-before-define -- This deferred callback runs after initialization; the definitions are mutually dependent.
|
|
272
|
+
/* @__PURE__ */ jsx2(RemoteView, { nodeId: child.id }, child.id)
|
|
273
|
+
));
|
|
638
274
|
if (node.kind === "fragment") {
|
|
639
|
-
return
|
|
275
|
+
return createElement(Fragment2, { key: node.id }, ...childElements);
|
|
276
|
+
}
|
|
277
|
+
return /* @__PURE__ */ jsx2(RemoteElementView, { node, ctx });
|
|
278
|
+
};
|
|
279
|
+
var RemoteViewComponent = ({ nodeId }) => {
|
|
280
|
+
const ctx = useContext2(RemoteUIContext);
|
|
281
|
+
return ctx === null ? null : /* @__PURE__ */ jsx2(RemoteNodeView, { ctx, nodeId });
|
|
282
|
+
};
|
|
283
|
+
var RemoteView = memo(RemoteViewComponent);
|
|
284
|
+
|
|
285
|
+
// src/components/context.ts
|
|
286
|
+
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
287
|
+
var TailorkitContext = createContext3(
|
|
288
|
+
null
|
|
289
|
+
);
|
|
290
|
+
var useTailorkitContext = (component, expectedClient) => {
|
|
291
|
+
const context = useContext3(TailorkitContext);
|
|
292
|
+
if (!context) {
|
|
293
|
+
throw new Error(
|
|
294
|
+
`${component} must be rendered inside a TailorKit Provider.`
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
if (expectedClient && context.client !== expectedClient) {
|
|
298
|
+
throw new Error(
|
|
299
|
+
`${component} was created for a different TailorKit client than the surrounding Provider.`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
return context;
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/components/render-slot.tsx
|
|
306
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
307
|
+
var SlotRenderer = (options) => {
|
|
308
|
+
const { store, client } = useTailorkitContext(
|
|
309
|
+
options.mode === "managed" ? "RenderSlot" : "RenderSlot.Controlled"
|
|
310
|
+
);
|
|
311
|
+
const reactId = useId2();
|
|
312
|
+
const [state, setState] = useState3(() => ({
|
|
313
|
+
runtime: createSlotRuntime(store, options),
|
|
314
|
+
store
|
|
315
|
+
}));
|
|
316
|
+
if (state.store !== store) {
|
|
317
|
+
setState({ runtime: createSlotRuntime(store, options), store });
|
|
318
|
+
}
|
|
319
|
+
const { runtime } = state;
|
|
320
|
+
useEffect2(() => {
|
|
321
|
+
runtime.setInput(options);
|
|
322
|
+
}, [runtime, options]);
|
|
323
|
+
const snapshot = useStore2(runtime.state);
|
|
324
|
+
const viewId = `tailorkit-view-${reactId.replaceAll(":", "")}`;
|
|
325
|
+
const themeContext = useMemo3(
|
|
326
|
+
() => ({ theme: client.theme, viewId }),
|
|
327
|
+
[client.theme, viewId]
|
|
328
|
+
);
|
|
329
|
+
if (snapshot.status === "hidden") {
|
|
330
|
+
return null;
|
|
640
331
|
}
|
|
641
|
-
|
|
642
|
-
});
|
|
332
|
+
if (snapshot.status === "loading") {
|
|
333
|
+
return /* @__PURE__ */ jsx3("output", { children: snapshot.message });
|
|
334
|
+
}
|
|
335
|
+
if (snapshot.status === "error") {
|
|
336
|
+
return /* @__PURE__ */ jsx3("div", { role: "alert", children: snapshot.error.message });
|
|
337
|
+
}
|
|
338
|
+
return /* @__PURE__ */ jsx3(PrimitiveThemeContext.Provider, { value: themeContext, children: /* @__PURE__ */ jsxs2("div", { "data-tailorkit-view": viewId, children: [
|
|
339
|
+
/* @__PURE__ */ jsx3("style", { "data-tailorkit-theme-style": viewId, children: buildThemeCss(viewId, client.theme) }),
|
|
340
|
+
/* @__PURE__ */ jsx3(
|
|
341
|
+
RemoteViewHost,
|
|
342
|
+
{
|
|
343
|
+
appUrl: snapshot.appUrl,
|
|
344
|
+
toolBridge: snapshot.toolBridge,
|
|
345
|
+
getBackendSession: snapshot.getBackendSession,
|
|
346
|
+
components: client.components,
|
|
347
|
+
props: snapshot.props
|
|
348
|
+
},
|
|
349
|
+
snapshot.hostKey
|
|
350
|
+
)
|
|
351
|
+
] }) });
|
|
352
|
+
};
|
|
353
|
+
var ManagedRenderSlot = (props) => /* @__PURE__ */ jsx3(SlotRenderer, { mode: "managed", ...props });
|
|
354
|
+
var ControlledRenderSlot = (props) => /* @__PURE__ */ jsx3(SlotRenderer, { mode: "controlled", ...props });
|
|
355
|
+
var RenderSlot = Object.assign(
|
|
356
|
+
ManagedRenderSlot,
|
|
357
|
+
{
|
|
358
|
+
Controlled: ControlledRenderSlot
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
// src/tailorkit.tsx
|
|
363
|
+
import {
|
|
364
|
+
createTailorKitClientConfig,
|
|
365
|
+
createComponentRegistry,
|
|
366
|
+
createTailorKitStore
|
|
367
|
+
} from "@tailorkit/client-core";
|
|
368
|
+
import { createElement as createElement2, useEffect as useEffect4, useMemo as useMemo8, useState as useState4 } from "react";
|
|
369
|
+
|
|
370
|
+
// src/hooks/use-apps.ts
|
|
371
|
+
import { createValueMemo, createAppsQuery } from "@tailorkit/client-core";
|
|
372
|
+
import { useMemo as useMemo5 } from "react";
|
|
373
|
+
|
|
374
|
+
// src/hooks/use-query-result.ts
|
|
375
|
+
import { useStore as useStore3 } from "@nanostores/react";
|
|
376
|
+
import { useMemo as useMemo4 } from "react";
|
|
377
|
+
var useQueryResult = (state) => {
|
|
378
|
+
const result = useStore3(state);
|
|
379
|
+
return useMemo4(
|
|
380
|
+
() => ({
|
|
381
|
+
data: result.data,
|
|
382
|
+
error: result.error,
|
|
383
|
+
fetch: result.refetch,
|
|
384
|
+
isPending: result.isPending,
|
|
385
|
+
isRefetching: result.isFetching && !result.isPending
|
|
386
|
+
}),
|
|
387
|
+
[result]
|
|
388
|
+
);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// src/hooks/use-apps.ts
|
|
392
|
+
var useAppsStore = (store, options = {}) => {
|
|
393
|
+
const memoOptions = useMemo5(() => createValueMemo(), []);
|
|
394
|
+
const stableOptions = memoOptions({
|
|
395
|
+
appIds: options.appIds === void 0 ? void 0 : [...new Set(options.appIds)].toSorted(),
|
|
396
|
+
scopes: options.scopes === void 0 ? void 0 : [...new Set(options.scopes)].toSorted()
|
|
397
|
+
});
|
|
398
|
+
const query = useMemo5(
|
|
399
|
+
() => createAppsQuery(store, stableOptions),
|
|
400
|
+
[store, stableOptions]
|
|
401
|
+
);
|
|
402
|
+
return useQueryResult(query.state);
|
|
403
|
+
};
|
|
404
|
+
var useApps = (options = {}) => useAppsStore(useTailorkitContext("useApps").store, options);
|
|
405
|
+
|
|
406
|
+
// src/hooks/use-view-context.ts
|
|
407
|
+
import { useEffect as useEffect3, useMemo as useMemo6 } from "react";
|
|
408
|
+
var useViewContext = (view, options) => {
|
|
409
|
+
const { store } = useTailorkitContext("useViewContext");
|
|
410
|
+
const id = useMemo6(() => /* @__PURE__ */ Symbol("tailorkit-current-view"), []);
|
|
411
|
+
const { context, loading, error } = options;
|
|
412
|
+
useEffect3(
|
|
413
|
+
() => () => {
|
|
414
|
+
store.views.unregister(id);
|
|
415
|
+
},
|
|
416
|
+
[id, store]
|
|
417
|
+
);
|
|
418
|
+
useEffect3(() => {
|
|
419
|
+
store.views.register({ context, error, id, loading, view });
|
|
420
|
+
}, [id, view, context, loading, error, store]);
|
|
421
|
+
};
|
|
643
422
|
|
|
644
|
-
// src/
|
|
645
|
-
import {
|
|
646
|
-
|
|
647
|
-
var
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
423
|
+
// src/hooks/use-views.ts
|
|
424
|
+
import { createValueMemo as createValueMemo2, createViewsQuery } from "@tailorkit/client-core";
|
|
425
|
+
import { useMemo as useMemo7 } from "react";
|
|
426
|
+
var useViews = (options) => {
|
|
427
|
+
const { store } = useTailorkitContext("useViews");
|
|
428
|
+
const memoOptions = useMemo7(() => createValueMemo2(), []);
|
|
429
|
+
const stableOptions = memoOptions({
|
|
430
|
+
appIds: options.appIds === void 0 ? void 0 : [...new Set(options.appIds)].toSorted(),
|
|
431
|
+
scopes: options.scopes === void 0 ? void 0 : [...new Set(options.scopes)].toSorted(),
|
|
432
|
+
slot: options.slot
|
|
433
|
+
});
|
|
434
|
+
const query = useMemo7(
|
|
435
|
+
() => createViewsQuery(store, stableOptions),
|
|
436
|
+
[store, stableOptions]
|
|
437
|
+
);
|
|
438
|
+
return useQueryResult(query.state);
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// src/tailorkit.tsx
|
|
442
|
+
var components = (_contract, customComponents) => (
|
|
443
|
+
/* oxlint-disable typescript/no-unsafe-type-assertion -- The wrapper preserves the declared component or slot props and changes only the rendering adapter; the generic key-to-props relationship is erased at this boundary. */
|
|
444
|
+
customComponents
|
|
445
|
+
);
|
|
446
|
+
var createReactTailorKitClient = (options) => {
|
|
447
|
+
const wrappedComponents = createComponentRegistry(
|
|
448
|
+
options.components ?? {},
|
|
449
|
+
(renderer) => (
|
|
450
|
+
// oxlint-disable-next-line typescript/promise-function-async -- Client components must render synchronously; ReactNode also permits Promise results for server components.
|
|
451
|
+
function TailorKitComponent({
|
|
661
452
|
children,
|
|
662
453
|
...props
|
|
663
454
|
}) {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
});
|
|
668
|
-
};
|
|
669
|
-
wrappedComponents[name] = TailorKitComponent;
|
|
670
|
-
wrappedComponents[toComponentTagName(name)] = TailorKitComponent;
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
const useApps = createUseApps(store);
|
|
674
|
-
const useCurrentScreen = createUseCurrentScreen(store);
|
|
675
|
-
const AppView = ({
|
|
676
|
-
app,
|
|
677
|
-
createIframe,
|
|
678
|
-
fallback = null,
|
|
679
|
-
runtimeUrl,
|
|
680
|
-
...screenProps
|
|
681
|
-
}) => {
|
|
682
|
-
const reactId = useId2();
|
|
683
|
-
const currentScreen = useSyncExternalStore3(
|
|
684
|
-
store.subscribe,
|
|
685
|
-
store.getCurrentScreen,
|
|
686
|
-
store.getCurrentScreen
|
|
687
|
-
);
|
|
688
|
-
const screen = screenProps.screen;
|
|
689
|
-
const context = screenProps.context;
|
|
690
|
-
const status = screenProps.status ?? "ready";
|
|
691
|
-
const props = useMemo6(() => {
|
|
692
|
-
if (screen !== void 0) {
|
|
693
|
-
return {
|
|
694
|
-
screen: {
|
|
695
|
-
context,
|
|
696
|
-
path: screen,
|
|
697
|
-
status
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
return currentScreen === null ? void 0 : {
|
|
702
|
-
screen: {
|
|
703
|
-
context: currentScreen.context,
|
|
704
|
-
path: currentScreen.screen,
|
|
705
|
-
status: currentScreen.status
|
|
706
|
-
}
|
|
707
|
-
};
|
|
708
|
-
}, [context, currentScreen, screen, status]);
|
|
709
|
-
const meta = useSyncExternalStore3(
|
|
710
|
-
store.subscribe,
|
|
711
|
-
store.getMetaSnapshot,
|
|
712
|
-
store.getMetaSnapshot
|
|
713
|
-
);
|
|
714
|
-
const assetsBaseUrl = app.clientPath ? null : meta.assetsBaseUrl;
|
|
715
|
-
const appUrl = useMemo6(
|
|
716
|
-
() => resolveAppUrl(app, store.baseUrl, assetsBaseUrl),
|
|
717
|
-
[app, assetsBaseUrl]
|
|
718
|
-
);
|
|
719
|
-
useEffect4(() => {
|
|
720
|
-
void store.fetchMeta();
|
|
721
|
-
}, []);
|
|
722
|
-
if (props === void 0 || appUrl === null) {
|
|
723
|
-
return fallback;
|
|
724
|
-
}
|
|
725
|
-
const screenId = `tailorkit-screen-${reactId.replaceAll(":", "")}`;
|
|
726
|
-
return /* @__PURE__ */ jsx4(PrimitiveThemeContext.Provider, { value: { screenId, theme }, children: /* @__PURE__ */ jsxs2("div", { "data-tailorkit-screen": screenId, children: [
|
|
727
|
-
/* @__PURE__ */ jsx4("style", { "data-tailorkit-theme-style": screenId, children: buildThemeCss(screenId, theme) }),
|
|
728
|
-
/* @__PURE__ */ jsx4(
|
|
729
|
-
RemoteViewHost,
|
|
730
|
-
{
|
|
731
|
-
appUrl,
|
|
732
|
-
components: wrappedComponents,
|
|
733
|
-
createIframe,
|
|
734
|
-
props,
|
|
735
|
-
runtimeUrl
|
|
455
|
+
const rendererArgs = { props };
|
|
456
|
+
if (children !== void 0) {
|
|
457
|
+
rendererArgs.children = children;
|
|
736
458
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
const client = {
|
|
741
|
-
AppView,
|
|
742
|
-
Root: (props) => /* @__PURE__ */ jsx4(Root, { ...props, tailor: client }),
|
|
743
|
-
getApp: store.getApp,
|
|
744
|
-
getApps: store.getApps,
|
|
745
|
-
useApps,
|
|
746
|
-
useCurrentScreen
|
|
747
|
-
};
|
|
748
|
-
return {
|
|
749
|
-
...client
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
function createTailorKitStore(baseUrlInput) {
|
|
753
|
-
const baseUrl = toBaseUrl(baseUrlInput);
|
|
754
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
755
|
-
const screens = /* @__PURE__ */ new Map();
|
|
756
|
-
let appsSnapshot = {
|
|
757
|
-
apps: [],
|
|
758
|
-
error: null,
|
|
759
|
-
status: "idle"
|
|
760
|
-
};
|
|
761
|
-
let metaSnapshot = {
|
|
762
|
-
assetsBaseUrl: null,
|
|
763
|
-
error: null,
|
|
764
|
-
schema: null,
|
|
765
|
-
status: "idle"
|
|
766
|
-
};
|
|
767
|
-
let currentScreen = null;
|
|
768
|
-
let fetchAppsPromise = null;
|
|
769
|
-
let fetchMetaPromise = null;
|
|
770
|
-
let fetchAppsRequestId = 0;
|
|
771
|
-
let nextOrder = 0;
|
|
772
|
-
const emit = () => {
|
|
773
|
-
for (const listener of listeners) {
|
|
774
|
-
listener();
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
const selectCurrentScreen = () => {
|
|
778
|
-
let selected = null;
|
|
779
|
-
for (const screen of screens.values()) {
|
|
780
|
-
const depth = getScreenDepth(screen.screen);
|
|
781
|
-
const selectedDepth = selected === null ? -1 : getScreenDepth(selected.screen);
|
|
782
|
-
if (selected === null || depth > selectedDepth) {
|
|
783
|
-
selected = screen;
|
|
784
|
-
}
|
|
785
|
-
if (selected !== null && depth === selectedDepth && screen.order > selected.order) {
|
|
786
|
-
selected = screen;
|
|
459
|
+
return renderer(
|
|
460
|
+
rendererArgs
|
|
461
|
+
);
|
|
787
462
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
}
|
|
798
|
-
currentScreen = selected;
|
|
463
|
+
)
|
|
464
|
+
);
|
|
465
|
+
const clientConfig = createTailorKitClientConfig({
|
|
466
|
+
...options,
|
|
467
|
+
components: wrappedComponents
|
|
468
|
+
});
|
|
469
|
+
const ClientRenderSlot = (props) => {
|
|
470
|
+
useTailorkitContext("RenderSlot", client);
|
|
471
|
+
return createElement2(RenderSlot, props);
|
|
799
472
|
};
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
}
|
|
806
|
-
appsSnapshot = { ...appsSnapshot, status: "loading" };
|
|
807
|
-
emit();
|
|
808
|
-
const requestId = ++fetchAppsRequestId;
|
|
809
|
-
fetchAppsPromise = fetch(new URL("apps", baseUrl)).then(async (response) => {
|
|
810
|
-
if (!response.ok) {
|
|
811
|
-
throw new Error(`Unable to fetch TailorKit apps from ${baseUrl.toString()}.`);
|
|
812
|
-
}
|
|
813
|
-
const apps = await response.json();
|
|
814
|
-
if (requestId !== fetchAppsRequestId) {
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
appsSnapshot = {
|
|
473
|
+
const client = {
|
|
474
|
+
...clientConfig,
|
|
475
|
+
Provider: function Provider({ children, apps }) {
|
|
476
|
+
const [store] = useState4(
|
|
477
|
+
() => createTailorKitStore({
|
|
818
478
|
apps,
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
},
|
|
836
|
-
fetchMeta: () => {
|
|
837
|
-
if (fetchMetaPromise) {
|
|
838
|
-
return fetchMetaPromise;
|
|
839
|
-
}
|
|
840
|
-
metaSnapshot = { ...metaSnapshot, status: "loading" };
|
|
841
|
-
emit();
|
|
842
|
-
fetchMetaPromise = fetch(new URL("meta", baseUrl)).then(async (response) => {
|
|
843
|
-
if (!response.ok) {
|
|
844
|
-
throw new Error(`Unable to fetch TailorKit metadata from ${baseUrl.toString()}.`);
|
|
845
|
-
}
|
|
846
|
-
const meta = await response.json();
|
|
847
|
-
metaSnapshot = {
|
|
848
|
-
assetsBaseUrl: meta.assetsBaseUrl ?? null,
|
|
849
|
-
error: null,
|
|
850
|
-
schema: meta.schema,
|
|
851
|
-
status: "ready"
|
|
852
|
-
};
|
|
853
|
-
emit();
|
|
854
|
-
}).catch((error) => {
|
|
855
|
-
metaSnapshot = {
|
|
856
|
-
...metaSnapshot,
|
|
857
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
858
|
-
status: "error"
|
|
859
|
-
};
|
|
860
|
-
emit();
|
|
861
|
-
});
|
|
862
|
-
return fetchMetaPromise;
|
|
479
|
+
assetsBaseUrl: client.assetsBaseUrl,
|
|
480
|
+
baseUrl: client.baseUrl,
|
|
481
|
+
client: clientConfig.fetchClient,
|
|
482
|
+
contract: client.contract,
|
|
483
|
+
tools: client.tools
|
|
484
|
+
})
|
|
485
|
+
);
|
|
486
|
+
useEffect4(() => {
|
|
487
|
+
store.setProvidedApps(apps);
|
|
488
|
+
}, [store, apps]);
|
|
489
|
+
const context = useMemo8(() => ({ client, store }), [store]);
|
|
490
|
+
return createElement2(
|
|
491
|
+
TailorkitContext.Provider,
|
|
492
|
+
{ value: context },
|
|
493
|
+
children
|
|
494
|
+
);
|
|
863
495
|
},
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
order: existing?.order ?? nextOrder
|
|
874
|
-
});
|
|
875
|
-
if (!existing) {
|
|
876
|
-
nextOrder += 1;
|
|
496
|
+
RenderSlot: Object.assign(ClientRenderSlot, {
|
|
497
|
+
Controlled: function Controlled(props) {
|
|
498
|
+
useTailorkitContext("RenderSlot.Controlled", client);
|
|
499
|
+
return createElement2(
|
|
500
|
+
RenderSlot.Controlled,
|
|
501
|
+
/* oxlint-disable typescript/no-unsafe-type-assertion -- The wrapper preserves the declared component or slot props and changes only the rendering adapter; the generic key-to-props relationship is erased at this boundary. */
|
|
502
|
+
props
|
|
503
|
+
/* oxlint-enable typescript/no-unsafe-type-assertion */
|
|
504
|
+
);
|
|
877
505
|
}
|
|
878
|
-
|
|
879
|
-
|
|
506
|
+
}),
|
|
507
|
+
useApps: function useApps2(optionsValue) {
|
|
508
|
+
useTailorkitContext("useApps", client);
|
|
509
|
+
return useApps(optionsValue);
|
|
880
510
|
},
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
listeners.delete(listener);
|
|
885
|
-
};
|
|
511
|
+
useViewContext: function useViewContext2(view, optionsValue2) {
|
|
512
|
+
useTailorkitContext("useViewContext", client);
|
|
513
|
+
useViewContext(view, optionsValue2);
|
|
886
514
|
},
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
515
|
+
useViews: function useViews2(optionsValue3) {
|
|
516
|
+
useTailorkitContext("useViews", client);
|
|
517
|
+
return (
|
|
518
|
+
/* oxlint-disable typescript/no-unsafe-type-assertion -- The wrapper preserves the declared component or slot props and changes only the rendering adapter; the generic key-to-props relationship is erased at this boundary. */
|
|
519
|
+
useViews(optionsValue3)
|
|
520
|
+
);
|
|
891
521
|
}
|
|
892
522
|
};
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
}
|
|
897
|
-
function resolveAppUrl(app, baseUrl, assetsBaseUrl) {
|
|
898
|
-
if (app.clientPath) {
|
|
899
|
-
return new URL(app.clientPath, baseUrl);
|
|
900
|
-
}
|
|
901
|
-
if (!assetsBaseUrl || !app.projectId || !app.currentDeployment?.id) {
|
|
902
|
-
return null;
|
|
903
|
-
}
|
|
904
|
-
return new URL(
|
|
905
|
-
`projects/${app.projectId}/apps/${app.id}/deployments/${app.currentDeployment.id}/files/client.js`,
|
|
906
|
-
toBaseUrl(assetsBaseUrl)
|
|
907
|
-
);
|
|
908
|
-
}
|
|
909
|
-
function toBaseUrl(value) {
|
|
910
|
-
const url = value instanceof URL ? new URL(value) : new URL(value);
|
|
911
|
-
if (!url.pathname.endsWith("/")) {
|
|
912
|
-
url.pathname = `${url.pathname}/`;
|
|
913
|
-
}
|
|
914
|
-
return url;
|
|
915
|
-
}
|
|
523
|
+
return client;
|
|
524
|
+
};
|
|
525
|
+
var createClient = (options) => createReactTailorKitClient(options);
|
|
916
526
|
export {
|
|
527
|
+
RenderSlot,
|
|
917
528
|
components,
|
|
918
|
-
|
|
529
|
+
createClient,
|
|
919
530
|
primitives
|
|
920
531
|
};
|