@povio/ui 5.0.0-rc.13 → 5.0.0-rc.15

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.
Files changed (82) hide show
  1. package/README.md +8 -0
  2. package/dist/{AppCanvasPage-DtWEvs_Y.js → AppCanvasPage-BnyCHO3I.js} +152 -462
  3. package/dist/{AppCanvasPage-BZ2mrKY4.d.ts → AppCanvasPage-U9SxNwjS.d.ts} +1 -1
  4. package/dist/{BottomSheet-BXLE3161.js → BottomSheet-AqYVSMK9.js} +1 -75
  5. package/dist/BottomSheetHeader-Be6Elvs2.js +79 -0
  6. package/dist/{Calendar-DRHruqr_.js → Calendar-1p3VjSED.js} +3 -3
  7. package/dist/{CanvasComponentsFrame-CbgJJv-3.js → CanvasComponentsFrame-Dp0oDDoH.js} +6 -6
  8. package/dist/{UIConfigurator-DekPXjv9.js → CanvasInspector-DdP3mHUY.js} +1707 -522
  9. package/dist/{ComponentGallery-COqEqqN6.js → ComponentGallery-C_rXFvUY.js} +250 -1797
  10. package/dist/{DatePicker-xDEqzNJv.js → DatePicker-CAzuZRmd.js} +6 -6
  11. package/dist/{DatePickerInput-B0fEeCOf.js → DatePickerInput-BeQOVCk0.js} +4 -3
  12. package/dist/{DateRangePicker-DxuVhRaf.js → DateRangePicker-X3mBhfmL.js} +5 -5
  13. package/dist/{DateTimePicker-4N1Pka07.js → DateTimePicker-EtmGtoRe.js} +6 -6
  14. package/dist/{InputItem-Cv19Hwnx.js → InputItem-yC5oMyN-.js} +7 -7
  15. package/dist/{Inputs-D1aE_J9f.js → Inputs-Bd2nRNqk.js} +1 -1
  16. package/dist/{NumberRangeInput-Bzfe-RlV.js → NumberRangeInput-TkPXiWV3.js} +2 -2
  17. package/dist/{RichTextEditor-Bd7F5D8f.js → RichTextEditor-DiaPcBUM.js} +110 -32
  18. package/dist/{Select-CgIhoWgk.js → Select-tNlFSbAC.js} +5 -5
  19. package/dist/{Table-piX1SWvN.js → Table-CgG02oHQ.js} +1 -1
  20. package/dist/{TextArea-uPffb457.js → TextArea-DuvFUjts.js} +1 -1
  21. package/dist/{TimePicker-DN-i98z5.js → TimePicker-CBkiE-Yq.js} +5 -4
  22. package/dist/{TooltipWrapper-CDHFaUKZ.js → TooltipWrapper-CSXs5-E3.js} +2 -2
  23. package/dist/components/autocomplete.js +3 -3
  24. package/dist/components/bottom-sheet.js +1 -1
  25. package/dist/components/date-picker.js +1 -1
  26. package/dist/components/date-range-picker.js +1 -1
  27. package/dist/components/date-time-picker.js +1 -1
  28. package/dist/components/input.js +3 -3
  29. package/dist/components/number-field.js +3 -3
  30. package/dist/components/number-range-input.js +1 -1
  31. package/dist/components/query-autocomplete.js +1 -1
  32. package/dist/components/query-select.js +2 -2
  33. package/dist/components/select.js +1 -1
  34. package/dist/components/text-area.js +1 -1
  35. package/dist/components/time-picker.js +1 -1
  36. package/dist/config/app-canvas-tanstack.d.ts +1 -1
  37. package/dist/config/app-canvas-tanstack.js +1 -1
  38. package/dist/config/app-canvas.d.ts +1 -1
  39. package/dist/config/app-canvas.js +1 -1
  40. package/dist/config/ui-configurator-vite.d.ts +2 -0
  41. package/dist/config/ui-configurator-vite.js +234 -8
  42. package/dist/config/ui-configurator.d.ts +21 -2
  43. package/dist/config/ui-configurator.js +121 -3
  44. package/dist/{datePickerValue.utils-QWR2q5Vv.js → datePickerValue.utils-BDB6KM8q.js} +1 -1
  45. package/dist/demos-DIwj5vc0.js +2011 -0
  46. package/dist/index.js +7 -7
  47. package/dist/{logger-CqZjM-sn.js → logger-CW24po62.js} +10 -1
  48. package/dist/rhf/date-picker.js +1 -1
  49. package/dist/rhf/date-range-picker.js +1 -1
  50. package/dist/rhf/date-time-picker.js +1 -1
  51. package/dist/rhf/number-range-input.js +1 -1
  52. package/dist/rhf/rich-text-editor.js +1 -1
  53. package/dist/rhf/select.js +1 -1
  54. package/dist/rhf/text-area.js +1 -1
  55. package/dist/rhf/time-picker.js +1 -1
  56. package/dist/rhf.js +7 -7
  57. package/dist/rich-text-editor.js +1 -1
  58. package/dist/{staticDateTimeSegments-BWea3HAt.js → staticDateTimeSegments-Bs1_N5MR.js} +1 -1
  59. package/dist/{staticSelect.utils-BfTCi26B.js → staticSelect.utils-BgdYv2vP.js} +5 -4
  60. package/dist/styles/app-canvas.css +30 -24
  61. package/dist/styles/configurator.css +544 -34
  62. package/dist/tanstack/date-picker.js +1 -1
  63. package/dist/tanstack/date-range-picker.js +1 -1
  64. package/dist/tanstack/date-time-picker.js +1 -1
  65. package/dist/tanstack/form.js +1 -1
  66. package/dist/tanstack/inputs.js +1 -1
  67. package/dist/tanstack/number-range-input.js +1 -1
  68. package/dist/tanstack/rich-text-editor.js +1 -1
  69. package/dist/tanstack/select.js +1 -1
  70. package/dist/tanstack/table.js +2 -2
  71. package/dist/tanstack/text-area.js +1 -1
  72. package/dist/tanstack/time-picker.js +1 -1
  73. package/dist/tanstack.js +15 -15
  74. package/dist/token-classes-BqLWiy6O.js +245 -0
  75. package/dist/{useFieldAccessibility-B-bjtrNw.js → useFieldAccessibility-DnCdz938.js} +2 -1
  76. package/dist/{useFormAutosave-pmh35PXp.js → useFormAutosave-CxqZAJAB.js} +1 -1
  77. package/dist/{useStaticInputHandoff-B7DEm75m.js → useStaticInputHandoff-DKsxpVck.js} +2 -1
  78. package/dist/{useTableColumnConfig-CNJ_ZvIN.js → useTableColumnConfig-BnbKElno.js} +1 -1
  79. package/dist/utils/logger.js +1 -1
  80. package/package.json +1 -1
  81. package/dist/groups-oQmSeqXn.js +0 -18
  82. package/dist/underline-66hmELxa.js +0 -81
@@ -1,8 +1,8 @@
1
1
  import { t as UIConfig } from "../uiConfig.context-BS3r_kTS.js";
2
2
  import { r as $a8ea2faf2ebe4d2f$re_export$mergeRefs } from "../import-BE0r63d8.js";
3
3
  import { t as FieldController } from "../form.binding-CG1RPv6o.js";
4
- import { t as getStaticInputFocusTarget } from "../useStaticInputHandoff-B7DEm75m.js";
5
- import { t as Select } from "../Select-CgIhoWgk.js";
4
+ import { t as getStaticInputFocusTarget } from "../useStaticInputHandoff-DKsxpVck.js";
5
+ import { t as Select } from "../Select-tNlFSbAC.js";
6
6
  import { n as getQueryItems, r as getSelectionIdsToResolve, t as useQueryAutocomplete } from "../useQueryAutocomplete-CraXvRm_.js";
7
7
  import { memo, useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
8
8
  import { jsx } from "react/jsx-runtime";
@@ -1,2 +1,2 @@
1
- import { t as Select } from "../Select-CgIhoWgk.js";
1
+ import { t as Select } from "../Select-tNlFSbAC.js";
2
2
  export { Select };
@@ -1,2 +1,2 @@
1
- import { t as TextArea } from "../TextArea-uPffb457.js";
1
+ import { t as TextArea } from "../TextArea-DuvFUjts.js";
2
2
  export { TextArea };
@@ -1,2 +1,2 @@
1
- import { t as TimePicker } from "../TimePicker-DN-i98z5.js";
1
+ import { t as TimePicker } from "../TimePicker-CBkiE-Yq.js";
2
2
  export { TimePicker };
@@ -1,4 +1,4 @@
1
- import { n as AppCanvasPage, r as AppCanvasPageProps, t as APP_CANVAS_PATH } from "../AppCanvasPage-BZ2mrKY4.js";
1
+ import { n as AppCanvasPage, r as AppCanvasPageProps, t as APP_CANVAS_PATH } from "../AppCanvasPage-U9SxNwjS.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-DtWEvs_Y.js";
1
+ import { n as AppCanvasPage, r as AppCanvasFrameBridge, t as APP_CANVAS_PATH } from "../AppCanvasPage-BnyCHO3I.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,4 +1,4 @@
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";
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-U9SxNwjS.js";
2
2
  import "../configuration.context-3I7-wBII.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. */
@@ -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-DtWEvs_Y.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-BnyCHO3I.js";
2
2
  export { APP_CANVAS_PATH, AppCanvas, AppCanvasFrameBridge, AppCanvasPage, defaultCanvasBreakpoints, discoverCanvasPages, isAppCanvasFrame, layoutCanvasPages };
@@ -12,6 +12,8 @@ interface UIConfiguratorPluginOptions {
12
12
  * `ui-configuration.json` beside the theme file. Import it with `resolveUIConfiguration`. false disables it.
13
13
  */
14
14
  configurationFile?: string | false;
15
+ /** Existing app CSS entrypoint for installed Fontsource imports. false disables font installation. */
16
+ fontCssFile?: string | false;
15
17
  }
16
18
  /** Adds the configurator's Save theme action to this app's development server. */
17
19
  declare function uiConfigurator(options?: UIConfiguratorPluginOptions): Plugin;
@@ -1,6 +1,9 @@
1
+ import { createRequire } from "node:module";
1
2
  import { createHash, randomUUID } from "node:crypto";
2
- import { lstat, readFile, realpath, rename, unlink, writeFile } from "node:fs/promises";
3
+ import { access, lstat, readFile, realpath, rename, unlink, writeFile } from "node:fs/promises";
3
4
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
+ import { execFile } from "node:child_process";
6
+ import { promisify } from "node:util";
4
7
  //#region src/configurator/repository-storage-protocol.ts
5
8
  const componentConfigurationMetaName = "povio-ui-component-configuration";
6
9
  /** Dev-server event sent when a repository storage file changes, so other tabs reload it. */
@@ -13,7 +16,7 @@ var StorageError = class extends Error {
13
16
  this.status = status;
14
17
  }
15
18
  };
16
- const inside = (root, path) => {
19
+ const inside$1 = (root, path) => {
17
20
  const rel = relative(root, path);
18
21
  return !!rel && !isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${sep}`);
19
22
  };
@@ -46,7 +49,7 @@ async function configureRepositoryStorage(server, { filename, route, field, labe
46
49
  const root = await realpath(server.config.root);
47
50
  const filePath = resolve(root, filename);
48
51
  const parent = dirname(filePath);
49
- if (!inside(root, filePath) || !filePath.endsWith(".json")) throw new Error(`Povio UI ${noun} file must be a JSON file inside this app's Vite root.`);
52
+ if (!inside$1(root, filePath) || !filePath.endsWith(".json")) throw new Error(`Povio UI ${noun} file must be a JSON file inside this app's Vite root.`);
50
53
  const guard = async () => {
51
54
  if (await realpath(parent) !== parent) throw new StorageError(`${label} file parent cannot be a symbolic link.`, 409);
52
55
  try {
@@ -391,6 +394,231 @@ function configureComponentConfigurationStorage(server, filename) {
391
394
  });
392
395
  }
393
396
  //#endregion
397
+ //#region src/configurator/theme-writer-protocol.ts
398
+ /** Shared by the browser configurator and the isolated Node Vite entry. */
399
+ const themeWriterMetaName = "povio-ui-theme-writer";
400
+ //#endregion
401
+ //#region src/configurator/fontsource-vite.ts
402
+ const execute = promisify(execFile);
403
+ const fontId = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
404
+ const versionPattern = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
405
+ var FontError = class extends Error {
406
+ constructor(message, status = 400) {
407
+ super(message);
408
+ this.status = status;
409
+ }
410
+ };
411
+ const dependencies = {
412
+ fetch: (...args) => globalThis.fetch(...args),
413
+ install: async (command, args, cwd) => {
414
+ await execute(command, args, {
415
+ cwd,
416
+ shell: false,
417
+ timeout: 18e4,
418
+ maxBuffer: 1048576,
419
+ env: {
420
+ ...process.env,
421
+ npm_config_ignore_scripts: "true",
422
+ YARN_ENABLE_SCRIPTS: "false"
423
+ }
424
+ });
425
+ }
426
+ };
427
+ const exists = async (file) => {
428
+ try {
429
+ await access(file);
430
+ return true;
431
+ } catch {
432
+ return false;
433
+ }
434
+ };
435
+ const inside = (root, file) => {
436
+ const path = relative(root, file);
437
+ return !!path && !isAbsolute(path) && path !== ".." && !path.startsWith(`..${sep}`);
438
+ };
439
+ async function manager(root) {
440
+ let directory = root;
441
+ while (true) {
442
+ let declared = "";
443
+ try {
444
+ declared = JSON.parse(await readFile(resolve(directory, "package.json"), "utf8")).packageManager ?? "";
445
+ } catch {}
446
+ if (/^(bun|npm|pnpm|yarn)@/.test(declared)) return {
447
+ name: declared.split("@")[0],
448
+ modernYarn: /^yarn@[2-9]/.test(declared)
449
+ };
450
+ for (const [file, name] of [
451
+ ["bun.lock", "bun"],
452
+ ["bun.lockb", "bun"],
453
+ ["pnpm-lock.yaml", "pnpm"],
454
+ ["package-lock.json", "npm"],
455
+ ["yarn.lock", "yarn"]
456
+ ]) if (await exists(resolve(directory, file))) return {
457
+ name,
458
+ modernYarn: name === "yarn" && (await readFile(resolve(directory, file), "utf8")).includes("__metadata:")
459
+ };
460
+ const parent = dirname(directory);
461
+ if (parent === directory) break;
462
+ directory = parent;
463
+ }
464
+ throw new FontError("No existing package manager was detected. Add a lockfile or packageManager field first.", 409);
465
+ }
466
+ async function metadata(fetcher, url) {
467
+ const response = await fetcher(url, {
468
+ redirect: "error",
469
+ signal: AbortSignal.timeout(2e4)
470
+ });
471
+ if (!response.ok) throw new FontError(response.status === 404 ? "Fontsource font/package was not found." : "Fontsource metadata could not be loaded.", response.status === 404 ? 400 : 502);
472
+ return response.json();
473
+ }
474
+ /** Internal service factory: injection is for server tests, never a plugin/client execution option. */
475
+ async function createFontsourceInstaller(rootInput, cssName, deps = dependencies) {
476
+ const root = await realpath(rootInput), css = resolve(root, cssName), packageFile = resolve(root, "package.json");
477
+ if (!inside(root, css) || !css.endsWith(".css")) throw new FontError("fontCssFile must be a CSS file inside the app root.");
478
+ if (!await exists(css) || !await exists(packageFile)) return void 0;
479
+ const guard = async () => {
480
+ if (await realpath(css) !== css || await realpath(packageFile) !== packageFile) throw new FontError("Font CSS and package.json must not use symbolic links.", 409);
481
+ };
482
+ await guard();
483
+ let pending = Promise.resolve();
484
+ const install = (id) => {
485
+ const task = pending.then(async () => {
486
+ if (typeof id !== "string" || id.length > 100 || !fontId.test(id)) throw new FontError("Expected a valid Fontsource font ID.");
487
+ await guard();
488
+ const font = await metadata(deps.fetch, `https://api.fontsource.org/v1/fonts/${id}`);
489
+ if (font.id !== id || typeof font.family !== "string" || !font.family.trim() || !Array.isArray(font.weights) || !Array.isArray(font.styles)) throw new FontError("Invalid Fontsource font metadata.", 502);
490
+ let variable = false;
491
+ if (font.variable) variable = !!(await metadata(deps.fetch, `https://api.fontsource.org/v1/variable/${id}`)).axes?.wght;
492
+ const packageName = `${variable ? "@fontsource-variable" : "@fontsource"}/${id}`;
493
+ const registry = await metadata(deps.fetch, `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`);
494
+ if (registry.name !== packageName || typeof registry.version !== "string" || !versionPattern.test(registry.version)) throw new FontError("Invalid npm package version metadata.", 502);
495
+ const weights = font.weights.filter((weight) => typeof weight === "number" && Number.isInteger(weight) && weight >= 1 && weight <= 1e3);
496
+ const styles = ["normal", "italic"].filter((style) => font.styles.includes(style));
497
+ if (!weights.length || !styles.length) throw new FontError("This font has no supported styles.");
498
+ const imports = variable ? styles.map((style) => `${packageName}/wght${style === "italic" ? "-italic" : ""}.css`) : weights.flatMap((weight) => styles.map((style) => `${packageName}/${weight}${style === "italic" ? "-italic" : ""}.css`));
499
+ const require = createRequire(packageFile);
500
+ const installed = async (exact = false) => {
501
+ try {
502
+ const declared = JSON.parse(await readFile(packageFile, "utf8"));
503
+ if (!declared.dependencies?.[packageName] && !declared.devDependencies?.[packageName]) return false;
504
+ const pkg = JSON.parse(await readFile(require.resolve(`${packageName}/package.json`), "utf8"));
505
+ if (exact && pkg.version !== registry.version) return false;
506
+ if (!versionPattern.test(pkg.version) || pkg.version.split(".")[0] !== registry.version.split(".")[0]) return false;
507
+ await Promise.all(imports.map((item) => access(require.resolve(item))));
508
+ return true;
509
+ } catch {
510
+ return false;
511
+ }
512
+ };
513
+ const alreadyInstalled = await installed();
514
+ if (!alreadyInstalled) {
515
+ const pm = await manager(root);
516
+ const spec = `${packageName}@${registry.version}`;
517
+ const args = pm.name === "npm" ? [
518
+ "install",
519
+ "--save-exact",
520
+ "--ignore-scripts",
521
+ spec
522
+ ] : pm.name === "yarn" ? [
523
+ "add",
524
+ "--exact",
525
+ ...pm.modernYarn ? [] : ["--ignore-scripts"],
526
+ spec
527
+ ] : [
528
+ "add",
529
+ "--exact",
530
+ "--ignore-scripts",
531
+ spec
532
+ ];
533
+ if (pm.name === "pnpm") args[1] = "--save-exact";
534
+ try {
535
+ await deps.install(pm.name, args, root);
536
+ } catch {
537
+ throw new FontError("Font installation failed. Existing CSS imports were left unchanged.", 502);
538
+ }
539
+ if (!await installed(true)) throw new FontError("Installed font files could not be verified. CSS imports were left unchanged.", 502);
540
+ }
541
+ await guard();
542
+ const source = await readFile(css, "utf8");
543
+ const existing = new Set([...source.matchAll(/@import\s+(?:url\(\s*)?["']([^"']+)["']/g)].map((match) => match[1]));
544
+ const missing = imports.filter((item) => !existing.has(item));
545
+ if (missing.length) {
546
+ const additions = missing.map((item) => `@import "${item}";`).join("\n");
547
+ const charset = source.match(/^(?:\uFEFF)?@charset\s+["'][^"']+["'];\s*/i)?.[0] ?? "";
548
+ const next = `${charset}${additions}\n${source.slice(charset.length)}`;
549
+ const temporary = `${css}.fontsource-${randomUUID()}.tmp`;
550
+ try {
551
+ await writeFile(temporary, next, { flag: "wx" });
552
+ await guard();
553
+ await rename(temporary, css);
554
+ } finally {
555
+ await unlink(temporary).catch(() => {});
556
+ }
557
+ }
558
+ return {
559
+ family: `${font.family}${variable ? " Variable" : ""}`,
560
+ packageName,
561
+ imports,
562
+ alreadyInstalled
563
+ };
564
+ });
565
+ pending = task.then(() => {}, () => {});
566
+ return task;
567
+ };
568
+ return {
569
+ cssFile: relative(root, css).split(sep).join("/"),
570
+ install
571
+ };
572
+ }
573
+ async function configureFontsource(server, cssName, token, base) {
574
+ const installer = await createFontsourceInstaller(server.config.root, cssName);
575
+ if (!installer) return void 0;
576
+ const endpoint = `${base}__povio_ui/fontsource`;
577
+ server.middlewares.use((req, res, next) => {
578
+ if (req.url?.split("?")[0] !== endpoint) return next();
579
+ handle(req, res).catch((error) => respond(res, error instanceof FontError ? error.status : 500, { error: error instanceof Error ? error.message : "Could not install font." }));
580
+ });
581
+ function respond(res, status, body) {
582
+ res.writeHead(status, {
583
+ "Content-Type": "application/json",
584
+ "Cache-Control": "no-store"
585
+ });
586
+ res.end(JSON.stringify(body));
587
+ }
588
+ async function handle(req, res) {
589
+ if (req.method !== "POST") throw new FontError("Use POST to install a font.", 405);
590
+ if (req.headers["x-povio-ui-theme-token"] !== token) throw new FontError("Invalid theme token.", 403);
591
+ if (req.headers["sec-fetch-site"] === "cross-site") throw new FontError("Font installation requires the app origin.", 403);
592
+ if (req.headers.origin) {
593
+ let sameOrigin = false;
594
+ try {
595
+ sameOrigin = new URL(req.headers.origin).origin === `${server.config.server.https ? "https" : "http"}://${req.headers.host}`;
596
+ } catch {}
597
+ if (!sameOrigin) throw new FontError("Font installation requires the app origin.", 403);
598
+ }
599
+ if (!req.headers["content-type"]?.startsWith("application/json")) throw new FontError("Expected application/json.", 415);
600
+ let size = 0;
601
+ const chunks = [];
602
+ for await (const chunk of req) {
603
+ size += Buffer.byteLength(chunk);
604
+ if (size > 1024) throw new FontError("Font request is too large.", 413);
605
+ chunks.push(Buffer.from(chunk));
606
+ }
607
+ let data;
608
+ try {
609
+ data = JSON.parse(Buffer.concat(chunks).toString("utf8"));
610
+ } catch {
611
+ throw new FontError("Expected JSON containing a font ID.");
612
+ }
613
+ const id = data && typeof data === "object" && !Array.isArray(data) ? data.id : void 0;
614
+ respond(res, 200, await installer.install(id));
615
+ }
616
+ return {
617
+ endpoint,
618
+ cssFile: installer.cssFile
619
+ };
620
+ }
621
+ //#endregion
394
622
  //#region src/configurator/theme-model.ts
395
623
  const declarations = (source) => Object.fromEntries([...source.matchAll(/(--[\w-]+)\s*:\s*([^;]+);/g)].map(([, name, value]) => [name, value.trim()]));
396
624
  const selectorDeclarations = (source, selector) => Object.assign({}, ...[...source.matchAll(selector)].map((match) => declarations(match[1])));
@@ -460,10 +688,6 @@ function updateThemeSource(source, exportedCss) {
460
688
  return source;
461
689
  }
462
690
  //#endregion
463
- //#region src/configurator/theme-writer-protocol.ts
464
- /** Shared by the browser configurator and the isolated Node Vite entry. */
465
- const themeWriterMetaName = "povio-ui-theme-writer";
466
- //#endregion
467
691
  //#region src/configurator/vite.ts
468
692
  var ThemeWriteError = class extends Error {
469
693
  constructor(message, status) {
@@ -512,13 +736,15 @@ function uiConfigurator(options = {}) {
512
736
  if (!file || isAbsolute(file) || file === ".." || file.startsWith(`..${sep}`)) throw new Error("Povio UI themeFile must be inside this app's Vite root.");
513
737
  if (!themeFile.endsWith(".css")) throw new Error("Povio UI themeFile must be a CSS file.");
514
738
  if (options.configurationFile !== false) componentStorage = await configureComponentConfigurationStorage(server, options.configurationFile ?? join(dirname(file), "ui-configuration.json"));
515
- const endpoint = `${new URL(server.config.base, "http://localhost").pathname.replace(/\/?$/, "/")}__povio_ui/theme`;
739
+ const base = new URL(server.config.base, "http://localhost").pathname.replace(/\/?$/, "/");
740
+ const endpoint = `${base}__povio_ui/theme`;
516
741
  connection = {
517
742
  endpoint,
518
743
  token: randomUUID(),
519
744
  file: file.split(sep).join("/")
520
745
  };
521
746
  const token = connection.token;
747
+ if (options.fontCssFile !== false) connection.fontsource = await configureFontsource(server, options.fontCssFile ?? "src/styles/globals.css", token, base);
522
748
  const save = async (request, response) => {
523
749
  if (request.method !== "POST") {
524
750
  response.setHeader("Allow", "POST");
@@ -3,7 +3,26 @@ import { n as UIConfigOptions } from "../uiConfig.context-BksnNQyw.js";
3
3
  import { a as CvaDefinition, i as useUIConfiguration, n as UIConfigurationProvider, o as CvaEdits, r as UIConfigurationProviderProps, t as UIConfiguration } from "../configuration.context-3I7-wBII.js";
4
4
  import { a as parseThemeCss, i as exportCss, n as ThemeEdits, r as Tokens, t as Mode } from "../theme-model-T1zIdBg8.js";
5
5
  //#region src/configurator/UIConfigurator.d.ts
6
- declare function UIConfigurationModal(): import("react").JSX.Element | null;
6
+ interface UIConfigurationModalProps {
7
+ /**
8
+ * Show only the editor, in the compact window the App Canvas uses: no components preview, and a 360px floating
9
+ * window. Open it with `openFloating`. Hosts that show the components themselves get this automatically.
10
+ */
11
+ editorOnly?: boolean;
12
+ }
13
+ declare function UIConfigurationModal({ editorOnly: editorOnlyProp }?: UIConfigurationModalProps): import("react").JSX.Element | null;
14
+ //#endregion
15
+ //#region src/configurator/PageInspector.d.ts
16
+ interface PageInspectorProps {
17
+ /** While open, hovering the page inspects it and clicks pin elements instead of activating them. */
18
+ open: boolean;
19
+ onClose: () => void;
20
+ }
21
+ /**
22
+ * The App Canvas inspector for the live page: a sidebar with the box model, typography and colors of the hovered or
23
+ * pinned element, whose token links open the configurator on that token.
24
+ */
25
+ declare function PageInspector({ open, onClose }: PageInspectorProps): import("react").ReactPortal | null;
7
26
  //#endregion
8
27
  //#region src/configurator/component-configuration.d.ts
9
28
  /**
@@ -24,4 +43,4 @@ interface ColorModeSwitchProps {
24
43
  /** Controlled color-mode switch, shared by configurators and application settings. */
25
44
  declare function ColorModeSwitch({ value, onChange, label }: ColorModeSwitchProps): import("react").JSX.Element;
26
45
  //#endregion
27
- export { ColorModeSwitch, type ColorModeSwitchProps, type CvaDefinition, type CvaEdits, type ThemeEdits, type Tokens, type UIConfiguration, UIConfigurationModal, UIConfigurationProvider, type UIConfigurationProviderProps, exportCss, parseThemeCss, resolveUIConfiguration, useUIConfiguration };
46
+ export { ColorModeSwitch, type ColorModeSwitchProps, type CvaDefinition, type CvaEdits, PageInspector, type PageInspectorProps, type ThemeEdits, type Tokens, type UIConfiguration, UIConfigurationModal, type UIConfigurationModalProps, UIConfigurationProvider, type UIConfigurationProviderProps, exportCss, parseThemeCss, resolveUIConfiguration, useUIConfiguration };
@@ -1,3 +1,121 @@
1
- import { d as useUIConfiguration, i as resolveUIConfiguration, n as ColorModeSwitch, t as UIConfigurationModal, u as UIConfigurationProvider } from "../UIConfigurator-DekPXjv9.js";
2
- import { i as exportCss, v as parseThemeCss } from "../theme-model-DtTsIxou.js";
3
- export { ColorModeSwitch, UIConfigurationModal, UIConfigurationProvider, exportCss, parseThemeCss, resolveUIConfiguration, useUIConfiguration };
1
+ import { a as UIConfigurationModal, c as resolveUIConfiguration, i as useCanvasInspector, l as UIConfigurationProvider, n as CanvasInspectorPanel, o as ColorModeSwitch, t as CanvasInspectionOverlay, u as useUIConfiguration } from "../CanvasInspector-DdP3mHUY.js";
2
+ import { c as isEditableToken, i as exportCss, v as parseThemeCss } from "../theme-model-DtTsIxou.js";
3
+ import { useEffect } from "react";
4
+ import { c } from "react/compiler-runtime";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
+ import { createPortal } from "react-dom";
7
+ //#region src/configurator/PageInspector.tsx
8
+ /** Inspector chrome, the configurator and anything a host marks are tools, never inspected or blocked. */
9
+ const toolSelector = "[data-povio-inspector-ignore], .studio-overlay, .studio-floating-launcher";
10
+ const isTool = (event) => event.target instanceof Element && !!event.target.closest(toolSelector);
11
+ /**
12
+ * The App Canvas inspector for the live page: a sidebar with the box model, typography and colors of the hovered or
13
+ * pinned element, whose token links open the configurator on that token.
14
+ */
15
+ function PageInspector(t0) {
16
+ const $ = c(17);
17
+ const { open, onClose } = t0;
18
+ const { defaults, revealToken } = useUIConfiguration();
19
+ let t1;
20
+ if ($[0] !== defaults) {
21
+ t1 = (name) => isEditableToken(name, defaults);
22
+ $[0] = defaults;
23
+ $[1] = t1;
24
+ } else t1 = $[1];
25
+ const inspector = useCanvasInspector(open, void 0, t1);
26
+ const { hoverPoint, selectPoint, clear } = inspector;
27
+ let t2;
28
+ let t3;
29
+ if ($[2] !== clear || $[3] !== hoverPoint || $[4] !== open || $[5] !== selectPoint) {
30
+ t2 = () => {
31
+ if (!open) return;
32
+ const move = (event) => {
33
+ if (!isTool(event)) hoverPoint(document, event.clientX, event.clientY);
34
+ };
35
+ const block = _temp;
36
+ const click = (event_1) => {
37
+ if (isTool(event_1)) return;
38
+ block(event_1);
39
+ selectPoint(document, event_1.clientX, event_1.clientY);
40
+ };
41
+ const key = (event_2) => {
42
+ if (event_2.key === "Escape" && !isTool(event_2)) clear();
43
+ };
44
+ const pressEvents = [
45
+ "pointerdown",
46
+ "mousedown",
47
+ "pointerup",
48
+ "mouseup",
49
+ "auxclick"
50
+ ];
51
+ window.addEventListener("pointermove", move, true);
52
+ for (const type of pressEvents) window.addEventListener(type, block, true);
53
+ window.addEventListener("click", click, true);
54
+ window.addEventListener("keydown", key, true);
55
+ document.documentElement.classList.add("studio-page-inspecting");
56
+ return () => {
57
+ window.removeEventListener("pointermove", move, true);
58
+ for (const type_0 of pressEvents) window.removeEventListener(type_0, block, true);
59
+ window.removeEventListener("click", click, true);
60
+ window.removeEventListener("keydown", key, true);
61
+ document.documentElement.classList.remove("studio-page-inspecting");
62
+ };
63
+ };
64
+ t3 = [
65
+ open,
66
+ hoverPoint,
67
+ selectPoint,
68
+ clear
69
+ ];
70
+ $[2] = clear;
71
+ $[3] = hoverPoint;
72
+ $[4] = open;
73
+ $[5] = selectPoint;
74
+ $[6] = t2;
75
+ $[7] = t3;
76
+ } else {
77
+ t2 = $[6];
78
+ t3 = $[7];
79
+ }
80
+ useEffect(t2, t3);
81
+ if (!open) return null;
82
+ let t4;
83
+ if ($[8] !== inspector.measurement) {
84
+ t4 = inspector.measurement && /* @__PURE__ */ jsx(CanvasInspectionOverlay, {
85
+ className: "studio-page-inspection",
86
+ measurement: inspector.measurement,
87
+ width: window.innerWidth
88
+ });
89
+ $[8] = inspector.measurement;
90
+ $[9] = t4;
91
+ } else t4 = $[9];
92
+ let t5;
93
+ if ($[10] !== inspector || $[11] !== onClose || $[12] !== revealToken) {
94
+ t5 = /* @__PURE__ */ jsx(CanvasInspectorPanel, {
95
+ inspector,
96
+ onClose,
97
+ onSelectToken: revealToken,
98
+ className: "studio-page-inspector",
99
+ emptyHint: "Hover anything on the page to see its padding, margins, borders, radii and gaps."
100
+ });
101
+ $[10] = inspector;
102
+ $[11] = onClose;
103
+ $[12] = revealToken;
104
+ $[13] = t5;
105
+ } else t5 = $[13];
106
+ let t6;
107
+ if ($[14] !== t4 || $[15] !== t5) {
108
+ t6 = createPortal(/* @__PURE__ */ jsxs(Fragment$1, { children: [t4, t5] }), document.body);
109
+ $[14] = t4;
110
+ $[15] = t5;
111
+ $[16] = t6;
112
+ } else t6 = $[16];
113
+ return t6;
114
+ }
115
+ function _temp(event_0) {
116
+ if (isTool(event_0)) return;
117
+ event_0.preventDefault();
118
+ event_0.stopPropagation();
119
+ }
120
+ //#endregion
121
+ export { ColorModeSwitch, PageInspector, UIConfigurationModal, UIConfigurationProvider, exportCss, parseThemeCss, resolveUIConfiguration, useUIConfiguration };
@@ -4,7 +4,7 @@ import { t as clsx } from "./clsx-CnD0nOiA.js";
4
4
  import { t as Typography } from "./Typography-LU4z2pR1.js";
5
5
  import { InlineIconButton } from "./components/inline-icon-button.js";
6
6
  import { t as useBreakpoint } from "./useBreakpoint-DQoMN-BG.js";
7
- import { u as getPlaceholder } from "./staticDateTimeSegments-BWea3HAt.js";
7
+ import { u as getPlaceholder } from "./staticDateTimeSegments-Bs1_N5MR.js";
8
8
  import { useEffect, useRef } from "react";
9
9
  import { c } from "react/compiler-runtime";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";