@povio/ui 5.0.0-rc.10 → 5.0.0-rc.12

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.
@@ -1,4 +1,4 @@
1
- import { n as AppCanvasPage, r as AppCanvasPageProps, t as APP_CANVAS_PATH } from "../AppCanvasPage-BIFYeEeS.js";
1
+ import { n as AppCanvasPage, r as AppCanvasPageProps, t as APP_CANVAS_PATH } from "../AppCanvasPage-BZ2mrKY4.js";
2
2
  import { AnyRoute } from "@tanstack/react-router";
3
3
  //#region src/app-canvas/tanstack.d.ts
4
4
  interface AppCanvasRouteOptions {
@@ -1,4 +1,4 @@
1
- import { n as AppCanvasPage, r as AppCanvasFrameBridge, t as APP_CANVAS_PATH } from "../AppCanvasPage-BEER5hHp.js";
1
+ import { n as AppCanvasPage, r as AppCanvasFrameBridge, t as APP_CANVAS_PATH } from "../AppCanvasPage-DCjiFfQW.js";
2
2
  import { c } from "react/compiler-runtime";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { createRoute, notFound, useRouter, useRouterState } from "@tanstack/react-router";
@@ -1,5 +1,5 @@
1
- import { a as AppCanvasProps, c as CanvasPage, d as CanvasRouter, f as discoverCanvasPages, i as AppCanvas, l as CanvasPosition, n as AppCanvasPage, o as CanvasBreakpoint, p as layoutCanvasPages, r as AppCanvasPageProps, s as defaultCanvasBreakpoints, t as APP_CANVAS_PATH, u as CanvasRouteExample } from "../AppCanvasPage-BIFYeEeS.js";
2
- import "../configuration.context-DP4p1cIe.js";
1
+ import { a as AppCanvasProps, c as CanvasPage, d as CanvasRouter, f as discoverCanvasPages, i as AppCanvas, l as CanvasPosition, n as AppCanvasPage, o as CanvasBreakpoint, p as layoutCanvasPages, r as AppCanvasPageProps, s as defaultCanvasBreakpoints, t as APP_CANVAS_PATH, u as CanvasRouteExample } from "../AppCanvasPage-BZ2mrKY4.js";
2
+ import "../configuration.context-iuZu-ie0.js";
3
3
  //#region src/app-canvas/AppCanvasFrameBridge.d.ts
4
4
  /** Mount once inside the application's existing UIConfigurationProvider. No separate app copy or theme fork. */
5
5
  declare function AppCanvasFrameBridge({ href }: {
@@ -1,2 +1,2 @@
1
- import { a as defaultCanvasBreakpoints, c as layoutCanvasPages, i as AppCanvas, n as AppCanvasPage, o as isAppCanvasFrame, r as AppCanvasFrameBridge, s as discoverCanvasPages, t as APP_CANVAS_PATH } from "../AppCanvasPage-BEER5hHp.js";
1
+ import { a as defaultCanvasBreakpoints, c as layoutCanvasPages, i as AppCanvas, n as AppCanvasPage, o as isAppCanvasFrame, r as AppCanvasFrameBridge, s as discoverCanvasPages, t as APP_CANVAS_PATH } from "../AppCanvasPage-DCjiFfQW.js";
2
2
  export { APP_CANVAS_PATH, AppCanvas, AppCanvasFrameBridge, AppCanvasPage, defaultCanvasBreakpoints, discoverCanvasPages, isAppCanvasFrame, layoutCanvasPages };
@@ -1,2 +1,2 @@
1
- import { _ as parseThemeCss, i as exportCss } from "../theme-model-DtYPxNvH.js";
1
+ import { i as exportCss, v as parseThemeCss } from "../theme-model-DtTsIxou.js";
2
2
  export { exportCss, parseThemeCss };
@@ -3,6 +3,8 @@ import { Plugin } from "vite";
3
3
  interface UIConfiguratorPluginOptions {
4
4
  /** CSS file relative to this app's Vite root. Must exist inside that root. */
5
5
  themeFile?: string;
6
+ /** Repository canvas JSON, relative to the Vite root. false disables storage. */
7
+ canvasFile?: string | false;
6
8
  }
7
9
  /** Adds the configurator's Save theme action to this app's development server. */
8
10
  declare function uiConfigurator(options?: UIConfiguratorPluginOptions): Plugin;
@@ -1,6 +1,283 @@
1
- import { randomUUID } from "node:crypto";
2
- import { readFile, realpath, writeFile } from "node:fs/promises";
3
- import { isAbsolute, relative, resolve, sep } from "node:path";
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { lstat, readFile, realpath, rename, unlink, writeFile } from "node:fs/promises";
3
+ import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
4
+ //#region src/app-canvas/manifest.ts
5
+ function createCanvasWorkspace(name, id) {
6
+ return {
7
+ id,
8
+ name: name.trim() || "Workspace",
9
+ enabledPages: null,
10
+ positions: {}
11
+ };
12
+ }
13
+ function createCanvasManifest() {
14
+ return {
15
+ version: 2,
16
+ workspaces: [createCanvasWorkspace("All pages", "default")],
17
+ activeWorkspaceId: "default",
18
+ examples: {},
19
+ breakpoint: "desktop"
20
+ };
21
+ }
22
+ function isRecord(value) {
23
+ return value !== null && typeof value === "object" && !Array.isArray(value);
24
+ }
25
+ function isJSON(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
26
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
27
+ if (typeof value === "number") return Number.isFinite(value);
28
+ if (typeof value !== "object" || depth > 30 || ancestors.has(value)) return false;
29
+ ancestors.add(value);
30
+ const valid = Object.values(value).every((child) => isJSON(child, ancestors, depth + 1));
31
+ ancestors.delete(value);
32
+ return valid;
33
+ }
34
+ function safeJSON(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
35
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
36
+ if (typeof value === "number") return Number.isFinite(value);
37
+ if (typeof value !== "object" || depth > 30 || ancestors.has(value)) return false;
38
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return false;
39
+ ancestors.add(value);
40
+ const valid = Object.entries(value).every(([key, child]) => ![
41
+ "__proto__",
42
+ "prototype",
43
+ "constructor"
44
+ ].includes(key) && safeJSON(child, ancestors, depth + 1));
45
+ ancestors.delete(value);
46
+ return valid;
47
+ }
48
+ const stringMap = (value) => isRecord(value) && Object.values(value).every((item) => typeof item === "string");
49
+ const variantValue = (value) => value === null || typeof value === "string" || typeof value === "boolean";
50
+ function validCvaEdits(value) {
51
+ return isRecord(value) && Object.entries(value).every(([slot, definition]) => {
52
+ if (!/^[a-zA-Z][a-zA-Z0-9]*\.[a-zA-Z][a-zA-Z0-9]*$/.test(slot) || !isRecord(definition) || !Array.isArray(definition.base) || !definition.base.every((item) => typeof item === "string") || !isRecord(definition.config)) return false;
53
+ const config = definition.config;
54
+ return isRecord(config.variants) && Object.values(config.variants).every(stringMap) && isRecord(config.defaultVariants) && Object.values(config.defaultVariants).every(variantValue) && Array.isArray(config.compoundVariants) && config.compoundVariants.every((compound) => isRecord(compound) && Object.values(compound).every((item) => variantValue(item) || Array.isArray(item) && (item.every((part) => typeof part === "string") || item.every((part) => typeof part === "boolean"))));
55
+ });
56
+ }
57
+ /** Returns an independent JSON configuration, or undefined for invalid/unset overrides. */
58
+ function parseCanvasConfiguration(value) {
59
+ if (!isRecord(value) || !safeJSON(value) || !isRecord(value.theme) || ![
60
+ "light",
61
+ "dark",
62
+ "theme"
63
+ ].every((key) => stringMap(value.theme && value.theme[key])) || !isRecord(value.config) || value.overrides !== void 0 && !validCvaEdits(value.overrides)) return void 0;
64
+ return JSON.parse(JSON.stringify(value));
65
+ }
66
+ function parsePositions(input) {
67
+ return Object.fromEntries(Object.entries(isRecord(input) ? input : {}).flatMap(([breakpoint, entries]) => {
68
+ if (!isRecord(entries)) return [];
69
+ return [[breakpoint, Object.fromEntries(Object.entries(entries).flatMap(([id, point]) => isRecord(point) && typeof point.x === "number" && Number.isFinite(point.x) && typeof point.y === "number" && Number.isFinite(point.y) ? [[id, {
70
+ x: point.x,
71
+ y: point.y
72
+ }]] : []))]];
73
+ }));
74
+ }
75
+ /** Sanitize either stored JSON text or an imported value, migrating v1 positions into the default workspace. */
76
+ function parseCanvasManifest(input) {
77
+ const fallback = createCanvasManifest();
78
+ let value = input;
79
+ if (typeof value === "string") try {
80
+ value = JSON.parse(value);
81
+ } catch {
82
+ return fallback;
83
+ }
84
+ if (!isRecord(value) || value.version !== 1 && value.version !== 2) return fallback;
85
+ const examples = Object.fromEntries(Object.entries(isRecord(value.examples) ? value.examples : {}).flatMap(([id, example]) => {
86
+ if (!isRecord(example)) return [];
87
+ const clean = {};
88
+ if (typeof example.title === "string") clean.title = example.title;
89
+ if (isRecord(example.params)) clean.params = Object.fromEntries(Object.entries(example.params).filter((entry) => typeof entry[1] === "string"));
90
+ if (isRecord(example.search)) clean.search = Object.fromEntries(Object.entries(example.search).filter(([, item]) => isJSON(item)));
91
+ return [[id, clean]];
92
+ }));
93
+ const workspaces = [];
94
+ const ids = /* @__PURE__ */ new Set();
95
+ if (value.version === 1) workspaces.push({
96
+ ...createCanvasWorkspace("All pages", "default"),
97
+ positions: parsePositions(value.positions)
98
+ });
99
+ else if (Array.isArray(value.workspaces)) for (const entry of value.workspaces) {
100
+ if (!isRecord(entry) || typeof entry.id !== "string" || !entry.id.trim() || ids.has(entry.id)) continue;
101
+ ids.add(entry.id);
102
+ const configuration = parseCanvasConfiguration(entry.configuration);
103
+ workspaces.push({
104
+ id: entry.id,
105
+ name: typeof entry.name === "string" && entry.name.trim() ? entry.name.trim() : "Workspace",
106
+ enabledPages: Array.isArray(entry.enabledPages) ? [...new Set(entry.enabledPages.filter((id) => typeof id === "string" && id.length > 0))] : null,
107
+ positions: parsePositions(entry.positions),
108
+ ...configuration ? { configuration } : {}
109
+ });
110
+ }
111
+ if (!workspaces.length) workspaces.push(createCanvasWorkspace("All pages", "default"));
112
+ return {
113
+ version: 2,
114
+ workspaces,
115
+ activeWorkspaceId: typeof value.activeWorkspaceId === "string" && workspaces.some((workspace) => workspace.id === value.activeWorkspaceId) ? value.activeWorkspaceId : workspaces[0].id,
116
+ examples,
117
+ breakpoint: typeof value.breakpoint === "string" && value.breakpoint.length > 0 ? value.breakpoint : fallback.breakpoint
118
+ };
119
+ }
120
+ //#endregion
121
+ //#region src/app-canvas/storage-protocol.ts
122
+ const canvasStorageMetaName = "povio-ui-canvas-storage";
123
+ //#endregion
124
+ //#region src/app-canvas/storage-vite.ts
125
+ var StorageError = class extends Error {
126
+ constructor(message, status) {
127
+ super(message);
128
+ this.status = status;
129
+ }
130
+ };
131
+ const maxBytes = 262144;
132
+ const inside = (root, path) => {
133
+ const rel = relative(root, path);
134
+ return !!rel && !isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${sep}`);
135
+ };
136
+ const record = (value) => !!value && typeof value === "object" && !Array.isArray(value);
137
+ function validPositions(value) {
138
+ return record(value) && Object.values(value).every((entries) => record(entries) && Object.values(entries).every((position) => record(position) && typeof position.x === "number" && Number.isFinite(position.x) && typeof position.y === "number" && Number.isFinite(position.y)));
139
+ }
140
+ function decodeManifest(value) {
141
+ if (!record(value) || ![1, 2].includes(Number(value.version)) || typeof value.breakpoint !== "string" || !record(value.examples)) throw new StorageError("Invalid canvas manifest.", 400);
142
+ if (value.version === 1) {
143
+ if (!validPositions(value.positions)) throw new StorageError("Invalid canvas positions.", 400);
144
+ } else if (value.version !== 2 || !Array.isArray(value.workspaces) || !value.workspaces.length || typeof value.activeWorkspaceId !== "string" || !value.workspaces.every((workspace) => record(workspace) && typeof workspace.id === "string" && workspace.id.length > 0 && typeof workspace.name === "string" && (workspace.enabledPages === null || Array.isArray(workspace.enabledPages) && workspace.enabledPages.every((id) => typeof id === "string")) && validPositions(workspace.positions) && (workspace.configuration === void 0 || parseCanvasConfiguration(workspace.configuration) !== void 0))) throw new StorageError("Invalid canvas workspaces.", 400);
145
+ if (!Object.values(value.examples).every((example) => record(example) && (example.title === void 0 || typeof example.title === "string") && (example.params === void 0 || record(example.params) && Object.values(example.params).every((param) => typeof param === "string")) && (example.search === void 0 || record(example.search)))) throw new StorageError("Invalid canvas examples.", 400);
146
+ if (value.version === 2) {
147
+ const workspaces = value.workspaces;
148
+ if (new Set(workspaces.map((workspace) => workspace.id)).size !== workspaces.length || !workspaces.some((workspace) => workspace.id === value.activeWorkspaceId)) throw new StorageError("Invalid canvas workspace identity.", 400);
149
+ }
150
+ return parseCanvasManifest(value);
151
+ }
152
+ const revisionOf = (text) => createHash("sha256").update(text).digest("hex");
153
+ const respond$1 = (res, status, body) => {
154
+ res.writeHead(status, {
155
+ "Content-Type": "application/json",
156
+ "Cache-Control": "no-store"
157
+ });
158
+ res.end(JSON.stringify(body));
159
+ };
160
+ async function readBody(req) {
161
+ let size = 0;
162
+ const chunks = [];
163
+ for await (const chunk of req) {
164
+ size += Buffer.byteLength(chunk);
165
+ if (size > maxBytes) throw new StorageError("Canvas manifest exceeds 256 KB.", 413);
166
+ chunks.push(Buffer.from(chunk));
167
+ }
168
+ try {
169
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
170
+ } catch {
171
+ throw new StorageError("Expected JSON canvas data.", 400);
172
+ }
173
+ }
174
+ /** Fixed-path development persistence only. Never commits or pushes repository changes. */
175
+ async function configureCanvasStorage(server, filename = "povio.canvas.json") {
176
+ const root = await realpath(server.config.root);
177
+ const filePath = resolve(root, filename);
178
+ const parent = dirname(filePath);
179
+ if (!inside(root, filePath) || !filePath.endsWith(".json")) throw new Error("Povio UI canvasFile must be a JSON file inside this app's Vite root.");
180
+ const guard = async () => {
181
+ if (await realpath(parent) !== parent) throw new StorageError("Canvas file parent cannot be a symbolic link.", 409);
182
+ try {
183
+ const stat = await lstat(filePath);
184
+ if (stat.isSymbolicLink() || !stat.isFile()) throw new StorageError("Canvas file must be a regular file, not a symbolic link.", 409);
185
+ if (stat.size > maxBytes) throw new StorageError("Canvas manifest exceeds 256 KB.", 413);
186
+ } catch (error) {
187
+ if (error.code !== "ENOENT") throw error;
188
+ }
189
+ };
190
+ await guard();
191
+ const file = relative(root, filePath).split(sep).join("/");
192
+ const connection = {
193
+ endpoint: `${new URL(server.config.base, "http://localhost").pathname.replace(/\/?$/, "/")}__povio_ui/canvas`,
194
+ token: randomUUID(),
195
+ file
196
+ };
197
+ let pending = Promise.resolve();
198
+ const readCurrent = async () => {
199
+ await guard();
200
+ try {
201
+ const text = await readFile(filePath, "utf8");
202
+ return {
203
+ text,
204
+ revision: revisionOf(text)
205
+ };
206
+ } catch (error) {
207
+ if (error.code === "ENOENT") return {
208
+ text: null,
209
+ revision: null
210
+ };
211
+ throw error;
212
+ }
213
+ };
214
+ const handle = async (req, res) => {
215
+ if (req.headers["x-povio-canvas-token"] !== connection.token) throw new StorageError("Invalid canvas storage token.", 403);
216
+ const origin = req.headers.origin;
217
+ let validOrigin = true;
218
+ if (origin) try {
219
+ validOrigin = new URL(origin).origin === `${server.config.server.https ? "https" : "http"}://${req.headers.host}`;
220
+ } catch {
221
+ validOrigin = false;
222
+ }
223
+ if (!validOrigin || req.headers["sec-fetch-site"] === "cross-site") throw new StorageError("Canvas storage requires the app's origin.", 403);
224
+ if (req.method === "GET") {
225
+ await pending;
226
+ const current = await readCurrent();
227
+ let manifest = null;
228
+ if (current.text !== null) try {
229
+ manifest = decodeManifest(JSON.parse(current.text));
230
+ } catch {
231
+ throw new StorageError("Repository canvas file is invalid. Correct it before saving.", 409);
232
+ }
233
+ return respond$1(res, 200, {
234
+ manifest,
235
+ revision: current.revision,
236
+ file
237
+ });
238
+ }
239
+ if (req.method !== "POST") {
240
+ res.setHeader("Allow", "GET, POST");
241
+ throw new StorageError("Use GET or POST.", 405);
242
+ }
243
+ if (!req.headers["content-type"]?.startsWith("application/json")) throw new StorageError("Expected application/json.", 415);
244
+ const body = await readBody(req);
245
+ if (!record(body) || !(body.revision === null || typeof body.revision === "string")) throw new StorageError("Expected manifest and revision.", 400);
246
+ const manifest = decodeManifest(body.manifest);
247
+ const text = `${JSON.stringify(manifest, null, 2)}\n`;
248
+ if (Buffer.byteLength(text) > maxBytes) throw new StorageError("Canvas manifest exceeds 256 KB.", 413);
249
+ const write = pending.then(async () => {
250
+ if ((await readCurrent()).revision !== body.revision) throw new StorageError("Canvas file changed. Reload its saved layout before saving again.", 409);
251
+ const temporary = `${filePath}.povio-${randomUUID()}.tmp`;
252
+ try {
253
+ await writeFile(temporary, text, {
254
+ encoding: "utf8",
255
+ flag: "wx",
256
+ mode: 384
257
+ });
258
+ await guard();
259
+ await rename(temporary, filePath);
260
+ } finally {
261
+ await unlink(temporary).catch(() => {});
262
+ }
263
+ });
264
+ pending = write.catch(() => {});
265
+ await write;
266
+ return respond$1(res, 200, {
267
+ revision: revisionOf(text),
268
+ file
269
+ });
270
+ };
271
+ server.middlewares.use((req, res, next) => {
272
+ if (req.url?.split("?")[0] !== connection.endpoint) return next();
273
+ handle(req, res).catch((error) => respond$1(res, error instanceof StorageError ? error.status : 500, { error: error instanceof Error ? error.message : "Could not access canvas file." }));
274
+ });
275
+ return {
276
+ connection,
277
+ isStorageFile: (path) => path === filePath || path.startsWith(`${filePath}.povio-`)
278
+ };
279
+ }
280
+ //#endregion
4
281
  //#region src/configurator/theme-model.ts
5
282
  const declarations = (source) => Object.fromEntries([...source.matchAll(/(--[\w-]+)\s*:\s*([^;]+);/g)].map(([, name, value]) => [name, value.trim()]));
6
283
  const selectorDeclarations = (source, selector) => Object.assign({}, ...[...source.matchAll(selector)].map((match) => declarations(match[1])));
@@ -106,10 +383,12 @@ async function readCss(request) {
106
383
  function uiConfigurator(options = {}) {
107
384
  let connection;
108
385
  let pendingWrite = Promise.resolve();
386
+ let canvasStorage;
109
387
  return {
110
388
  name: "vite-plugin-povio-ui-configurator",
111
389
  apply: (_config, environment) => environment.command === "serve" && !environment.isPreview,
112
390
  async configureServer(server) {
391
+ if (options.canvasFile !== false) canvasStorage = await configureCanvasStorage(server, options.canvasFile);
113
392
  const root = await realpath(server.config.root);
114
393
  const configuredFile = resolve(server.config.root, options.themeFile ?? "src/styles/theme.css");
115
394
  const themeFile = await realpath(configuredFile);
@@ -157,6 +436,9 @@ function uiConfigurator(options = {}) {
157
436
  });
158
437
  });
159
438
  },
439
+ handleHotUpdate(context) {
440
+ if (canvasStorage?.isStorageFile(context.file)) return [];
441
+ },
160
442
  transformIndexHtml() {
161
443
  if (!connection) return;
162
444
  return [{
@@ -166,7 +448,14 @@ function uiConfigurator(options = {}) {
166
448
  content: JSON.stringify(connection)
167
449
  },
168
450
  injectTo: "head"
169
- }];
451
+ }, ...canvasStorage ? [{
452
+ tag: "meta",
453
+ attrs: {
454
+ name: canvasStorageMetaName,
455
+ content: JSON.stringify(canvasStorage.connection)
456
+ },
457
+ injectTo: "head"
458
+ }] : []];
170
459
  }
171
460
  };
172
461
  }
@@ -1,4 +1,4 @@
1
- import { a as CvaDefinition, i as useUIConfiguration, n as UIConfigurationProvider, o as CvaEdits, r as UIConfigurationProviderProps, t as UIConfiguration } from "../configuration.context-DP4p1cIe.js";
1
+ import { a as CvaDefinition, i as useUIConfiguration, n as UIConfigurationProvider, o as CvaEdits, r as UIConfigurationProviderProps, t as UIConfiguration } from "../configuration.context-iuZu-ie0.js";
2
2
  import { a as parseThemeCss, i as exportCss, n as ThemeEdits, r as Tokens, t as Mode } from "../theme-model-T1zIdBg8.js";
3
3
  //#region src/configurator/UIConfigurator.d.ts
4
4
  declare function UIConfigurationModal(): import("react").JSX.Element | null;
@@ -1,3 +1,3 @@
1
- import { c as UIConfigurationProvider, l as useUIConfiguration, n as ColorModeSwitch, t as UIConfigurationModal } from "../UIConfigurator-CTlq-hrG.js";
2
- import { _ as parseThemeCss, i as exportCss } from "../theme-model-DtYPxNvH.js";
1
+ import { f as useUIConfiguration, n as ColorModeSwitch, t as UIConfigurationModal, u as UIConfigurationProvider } from "../UIConfigurator-CBU0G6rb.js";
2
+ import { i as exportCss, v as parseThemeCss } from "../theme-model-DtTsIxou.js";
3
3
  export { ColorModeSwitch, UIConfigurationModal, UIConfigurationProvider, exportCss, parseThemeCss, useUIConfiguration };
@@ -902,6 +902,8 @@ interface ConfigurationContextValue {
902
902
  inheritedOverrides: UIOverrides.Config | null | undefined;
903
903
  draft: UIConfiguration;
904
904
  active: UIConfiguration;
905
+ currentConfiguration: UIConfiguration;
906
+ replaceConfiguration: (value: UIConfiguration, closeEditor?: boolean) => void;
905
907
  setPreviewConfiguration: React.Dispatch<React.SetStateAction<UIConfiguration | null>>;
906
908
  setDraft: React.Dispatch<React.SetStateAction<UIConfiguration>>;
907
909
  isOpen: boolean;
@@ -911,6 +913,18 @@ interface ConfigurationContextValue {
911
913
  cancel: () => void;
912
914
  apply: () => void;
913
915
  revision: number;
916
+ /** Opens the configurator (floating, if closed) on a token's row, e.g. from an inspector outside the modal. */
917
+ revealToken: (name: string) => void;
918
+ /** The pending reveal; the open editor focuses it and then calls `clearTokenRequest`. */
919
+ tokenRequest: {
920
+ name: string;
921
+ id: number;
922
+ } | null;
923
+ clearTokenRequest: () => void;
924
+ /** True while a host such as the App Canvas shows the components, so the configurator omits its own preview. */
925
+ componentsHosted: boolean;
926
+ /** Registers such a host; call the returned function when it unmounts. */
927
+ hostComponents: () => () => void;
914
928
  }
915
929
  interface UIConfigurationProviderProps extends PropsWithChildren {
916
930
  /** The application's base theme. Use parseThemeCss with your Tailwind theme source. */
@@ -0,0 +1,18 @@
1
+ //#region src/configurator/gallery/groups.ts
2
+ /** Gallery sections, kept apart from the demos so a host can list them without loading every component. */
3
+ const galleryGroups = [
4
+ "Buttons",
5
+ "Inputs",
6
+ "Selection",
7
+ "Files",
8
+ "Feedback",
9
+ "Text",
10
+ "Navigation",
11
+ "Overlays",
12
+ "Data"
13
+ ];
14
+ /** One App Canvas artboard per section, after the composed layouts. */
15
+ const layoutsArtboard = "Layouts";
16
+ const componentArtboards = [layoutsArtboard, ...galleryGroups];
17
+ //#endregion
18
+ export { galleryGroups as n, layoutsArtboard as r, componentArtboards as t };