@vertebr/react 0.9.0 → 0.11.0

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 (89) hide show
  1. package/dist/components/admin/AddonEditor.d.ts +3 -2
  2. package/dist/components/admin/AddonEditor.d.ts.map +1 -1
  3. package/dist/components/admin/AddonEditor.js +14 -10
  4. package/dist/components/admin/AdminContent.d.ts +4 -1
  5. package/dist/components/admin/AdminContent.d.ts.map +1 -1
  6. package/dist/components/admin/AdminContent.js +74 -12
  7. package/dist/components/admin/AdminSaveBar.d.ts.map +1 -1
  8. package/dist/components/admin/AdminSaveBar.js +6 -1
  9. package/dist/components/admin/AdminSyncPage.d.ts.map +1 -1
  10. package/dist/components/admin/AdminSyncPage.js +50 -6
  11. package/dist/components/admin/AdminTopBar.d.ts +6 -2
  12. package/dist/components/admin/AdminTopBar.d.ts.map +1 -1
  13. package/dist/components/admin/AdminTopBar.js +27 -4
  14. package/dist/components/admin/AuditBoard.d.ts +7 -0
  15. package/dist/components/admin/AuditBoard.d.ts.map +1 -0
  16. package/dist/components/admin/AuditBoard.js +43 -0
  17. package/dist/components/admin/HealthModal.d.ts +9 -0
  18. package/dist/components/admin/HealthModal.d.ts.map +1 -0
  19. package/dist/components/admin/HealthModal.js +59 -0
  20. package/dist/components/admin/PagePreviewPane.d.ts +3 -1
  21. package/dist/components/admin/PagePreviewPane.d.ts.map +1 -1
  22. package/dist/components/admin/PagePreviewPane.js +41 -9
  23. package/dist/components/admin/SyncPreviewFrame.d.ts +22 -0
  24. package/dist/components/admin/SyncPreviewFrame.d.ts.map +1 -0
  25. package/dist/components/admin/SyncPreviewFrame.js +135 -0
  26. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  27. package/dist/components/admin/VertebrAdmin.js +88 -22
  28. package/dist/components/admin/adminSearch.d.ts.map +1 -1
  29. package/dist/components/admin/adminSearch.js +9 -0
  30. package/dist/components/admin/breadcrumbs.d.ts.map +1 -1
  31. package/dist/components/admin/breadcrumbs.js +2 -0
  32. package/dist/components/admin/routes.d.ts.map +1 -1
  33. package/dist/components/admin/routes.js +13 -1
  34. package/dist/components/admin/types.d.ts +2 -0
  35. package/dist/components/admin/types.d.ts.map +1 -1
  36. package/dist/components/config/DatetimeInput.d.ts +15 -0
  37. package/dist/components/config/DatetimeInput.d.ts.map +1 -0
  38. package/dist/components/config/DatetimeInput.js +287 -0
  39. package/dist/components/config/EnumInput.d.ts.map +1 -1
  40. package/dist/components/config/EnumInput.js +4 -4
  41. package/dist/components/config/EnumListInput.d.ts.map +1 -1
  42. package/dist/components/config/EnumListInput.js +13 -3
  43. package/dist/components/config/ReferenceInput.d.ts +11 -0
  44. package/dist/components/config/ReferenceInput.d.ts.map +1 -0
  45. package/dist/components/config/ReferenceInput.js +99 -0
  46. package/dist/components/config/RevisionHistory.d.ts +12 -0
  47. package/dist/components/config/RevisionHistory.d.ts.map +1 -0
  48. package/dist/components/config/RevisionHistory.js +139 -0
  49. package/dist/components/config/form/ConfigField.d.ts +3 -2
  50. package/dist/components/config/form/ConfigField.d.ts.map +1 -1
  51. package/dist/components/config/form/ConfigField.js +4 -2
  52. package/dist/components/config/form/ConfigForm.d.ts +1 -1
  53. package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
  54. package/dist/components/config/form/ConfigForm.js +66 -14
  55. package/dist/components/config/form/RecordConfigForm.d.ts +3 -2
  56. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
  57. package/dist/components/config/form/RecordConfigForm.js +2 -1
  58. package/dist/components/config/form/SettingsConfigForm.d.ts +3 -2
  59. package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
  60. package/dist/components/config/form/SettingsConfigForm.js +2 -2
  61. package/dist/components/config/form/types.d.ts +14 -1
  62. package/dist/components/config/form/types.d.ts.map +1 -1
  63. package/dist/components/resources/ResourceTable.d.ts +7 -1
  64. package/dist/components/resources/ResourceTable.d.ts.map +1 -1
  65. package/dist/components/resources/ResourceTable.js +56 -6
  66. package/dist/components/theme/ThemeToggle.d.ts +3 -1
  67. package/dist/components/theme/ThemeToggle.d.ts.map +1 -1
  68. package/dist/components/theme/ThemeToggle.js +2 -2
  69. package/dist/components/ui/icons.d.ts +1 -0
  70. package/dist/components/ui/icons.d.ts.map +1 -1
  71. package/dist/components/ui/icons.js +6 -1
  72. package/dist/hooks/useSaveBar.d.ts +6 -0
  73. package/dist/hooks/useSaveBar.d.ts.map +1 -1
  74. package/dist/index.d.ts +2 -1
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +1 -0
  77. package/dist/lib/capabilities.d.ts +4 -0
  78. package/dist/lib/capabilities.d.ts.map +1 -0
  79. package/dist/lib/capabilities.js +9 -0
  80. package/dist/styles/audit.css +34 -0
  81. package/dist/styles/form.css +587 -9
  82. package/dist/styles/index.css +1 -0
  83. package/dist/styles/modal.css +111 -0
  84. package/dist/styles/page-preview.css +84 -0
  85. package/dist/styles/select.css +23 -0
  86. package/dist/styles/shell.css +234 -18
  87. package/dist/styles/sync.css +388 -4
  88. package/dist/themes/light.css +27 -0
  89. package/package.json +3 -1
@@ -25,6 +25,8 @@ export function pathForSelection(selection, catalog) {
25
25
  return "/overview";
26
26
  case "sync":
27
27
  return "/sync";
28
+ case "audit":
29
+ return "/audit";
28
30
  case "addons":
29
31
  return "/addons";
30
32
  case "addon":
@@ -85,6 +87,8 @@ export function selectionFromPath(pathname, basePath, catalog) {
85
87
  return { kind: "overview" };
86
88
  if (head === "sync")
87
89
  return { kind: "sync" };
90
+ if (head === "audit")
91
+ return { kind: "audit" };
88
92
  if (head === "addons") {
89
93
  if (!tail[0])
90
94
  return { kind: "addons" };
@@ -154,6 +158,9 @@ export function coerceSelection(selection, catalog) {
154
158
  if (selection.kind === "sync") {
155
159
  return catalog.sync?.enabled ? selection : defaultSelection(catalog);
156
160
  }
161
+ if (selection.kind === "audit") {
162
+ return catalog.audit ? selection : defaultSelection(catalog);
163
+ }
157
164
  if (selection.kind === "addons") {
158
165
  return catalog.addons?.length ? selection : defaultSelection(catalog);
159
166
  }
@@ -190,7 +197,12 @@ export function selectionsEqual(a, b) {
190
197
  return a === b;
191
198
  if (a.kind !== b.kind)
192
199
  return false;
193
- if (a.kind === "overview" || a.kind === "gallery" || a.kind === "fontLibrary" || a.kind === "sync" || a.kind === "addons") {
200
+ if (a.kind === "overview" ||
201
+ a.kind === "gallery" ||
202
+ a.kind === "fontLibrary" ||
203
+ a.kind === "sync" ||
204
+ a.kind === "audit" ||
205
+ a.kind === "addons") {
194
206
  return true;
195
207
  }
196
208
  if (a.kind === "addon" && b.kind === "addon")
@@ -47,6 +47,8 @@ export type Selection = {
47
47
  } | {
48
48
  kind: "emails";
49
49
  tab?: EmailsTab;
50
+ } | {
51
+ kind: "audit";
50
52
  } | {
51
53
  kind: "config";
52
54
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/admin/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,oEAAoE;IACpE,cAAc,CAAC,EAAE,MACb,MAAM,GACN,IAAI,GACJ,SAAS,GACT,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACvC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAE7D,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,YAAY,CAAC;AAEtE,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,CAAC,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CAAC;AAET,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC,CAAC;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/admin/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,oEAAoE;IACpE,cAAc,CAAC,EAAE,MACb,MAAM,GACN,IAAI,GACJ,SAAS,GACT,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACvC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAE7D,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,YAAY,CAAC;AAEtE,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,CAAC,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CAAC;AAET,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC,CAAC;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,CAAC"}
@@ -0,0 +1,15 @@
1
+ export type DatetimeInputProps = {
2
+ id: string;
3
+ name?: string;
4
+ value: unknown;
5
+ readOnly?: boolean;
6
+ onBlur?: () => void;
7
+ onChange: (next: string) => void;
8
+ inputRef?: React.Ref<HTMLButtonElement>;
9
+ };
10
+ /** @deprecated Prefer parts helpers; kept for callers/tests. */
11
+ export declare function toDatetimeLocalValue(value: unknown): string;
12
+ /** @deprecated Prefer parts helpers; kept for callers/tests. */
13
+ export declare function fromDatetimeLocalValue(local: string): string;
14
+ export declare function DatetimeInput({ id, name, value, readOnly, onBlur, onChange, inputRef, }: DatetimeInputProps): import("react").JSX.Element;
15
+ //# sourceMappingURL=DatetimeInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DatetimeInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/DatetimeInput.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;CACzC,CAAC;AAsMF,gEAAgE;AAChE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI3D;AAED,gEAAgE;AAChE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5D;AAuED,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,+BAgQpB"}
@@ -0,0 +1,287 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as Popover from "@radix-ui/react-popover";
3
+ import { useEffect, useId, useMemo, useState } from "react";
4
+ import { DayPicker } from "react-day-picker";
5
+ function pad(n) {
6
+ return String(n).padStart(2, "0");
7
+ }
8
+ function browserTimeZone() {
9
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
10
+ }
11
+ const TIME_ZONES = [
12
+ { id: "America/New_York", label: "Eastern (ET)" },
13
+ { id: "America/Chicago", label: "Central (CT)" },
14
+ { id: "America/Denver", label: "Mountain (MT)" },
15
+ { id: "America/Los_Angeles", label: "Pacific (PT)" },
16
+ { id: "America/Phoenix", label: "Arizona (MST)" },
17
+ { id: "America/Anchorage", label: "Alaska (AKT)" },
18
+ { id: "Pacific/Honolulu", label: "Hawaii (HST)" },
19
+ { id: "UTC", label: "UTC" },
20
+ { id: "Europe/London", label: "London (GMT/BST)" },
21
+ { id: "Europe/Paris", label: "Central Europe (CET)" },
22
+ { id: "Asia/Tokyo", label: "Tokyo (JST)" },
23
+ { id: "Australia/Sydney", label: "Sydney (AEST)" },
24
+ ];
25
+ function timeZoneOptions(current) {
26
+ const known = new Set(TIME_ZONES.map((zone) => zone.id));
27
+ if (known.has(current))
28
+ return TIME_ZONES;
29
+ return [{ id: current, label: current.replace(/_/g, " ") }, ...TIME_ZONES];
30
+ }
31
+ function zonedParts(instant, timeZone) {
32
+ const bits = Object.fromEntries(new Intl.DateTimeFormat("en-US", {
33
+ timeZone,
34
+ year: "numeric",
35
+ month: "2-digit",
36
+ day: "2-digit",
37
+ hour: "2-digit",
38
+ minute: "2-digit",
39
+ hourCycle: "h23",
40
+ })
41
+ .formatToParts(instant)
42
+ .filter((part) => part.type !== "literal")
43
+ .map((part) => [part.type, part.value]));
44
+ return {
45
+ date: `${bits.year}-${bits.month}-${bits.day}`,
46
+ time: `${bits.hour}:${bits.minute}`,
47
+ };
48
+ }
49
+ /** Wall-clock date/time in `timeZone` → UTC ISO. */
50
+ function toIsoInZone(parts, timeZone) {
51
+ if (!parts.date)
52
+ return "";
53
+ const time = parts.time || "00:00";
54
+ const dateBits = parts.date.split("-").map(Number);
55
+ const timeBits = time.split(":").map(Number);
56
+ const year = dateBits[0];
57
+ const month = dateBits[1];
58
+ const day = dateBits[2];
59
+ const hour = timeBits[0];
60
+ const minute = timeBits[1];
61
+ if (year === undefined ||
62
+ month === undefined ||
63
+ day === undefined ||
64
+ hour === undefined ||
65
+ minute === undefined ||
66
+ ![year, month, day, hour, minute].every(Number.isFinite)) {
67
+ return "";
68
+ }
69
+ const desired = Date.UTC(year, month - 1, day, hour, minute, 0);
70
+ let utcMs = desired;
71
+ for (let i = 0; i < 2; i += 1) {
72
+ const shown = zonedParts(new Date(utcMs), timeZone);
73
+ const shownDate = shown.date.split("-").map(Number);
74
+ const shownTime = shown.time.split(":").map(Number);
75
+ const sy = shownDate[0];
76
+ const sm = shownDate[1];
77
+ const sd = shownDate[2];
78
+ const sh = shownTime[0];
79
+ const smin = shownTime[1];
80
+ if (sy === undefined ||
81
+ sm === undefined ||
82
+ sd === undefined ||
83
+ sh === undefined ||
84
+ smin === undefined) {
85
+ break;
86
+ }
87
+ const asUtc = Date.UTC(sy, sm - 1, sd, sh, smin, 0);
88
+ utcMs -= asUtc - desired;
89
+ }
90
+ return new Date(utcMs).toISOString();
91
+ }
92
+ function partsFromValue(value, timeZone) {
93
+ if (typeof value !== "string")
94
+ return { date: "", time: "" };
95
+ const trimmed = value.trim();
96
+ if (!trimmed)
97
+ return { date: "", time: "" };
98
+ const ms = Date.parse(trimmed);
99
+ if (Number.isFinite(ms))
100
+ return zonedParts(new Date(ms), timeZone);
101
+ const match = trimmed.match(/^(\d{4}-\d{2}-\d{2})(?:[T\s](\d{2}:\d{2})(?::\d{2})?)?/);
102
+ if (!match)
103
+ return { date: "", time: "" };
104
+ return { date: match[1] ?? "", time: match[2] ?? "00:00" };
105
+ }
106
+ function to24h(hour12, meridiem) {
107
+ const hour = ((hour12 - 1) % 12) + 1;
108
+ if (meridiem === "AM")
109
+ return hour === 12 ? 0 : hour;
110
+ return hour === 12 ? 12 : hour + 12;
111
+ }
112
+ function toClock(time) {
113
+ const [hRaw, mRaw] = (time || "12:00").split(":");
114
+ let hour24 = Number(hRaw);
115
+ const minute = pad(Number.isFinite(Number(mRaw)) ? Number(mRaw) : 0);
116
+ if (!Number.isFinite(hour24))
117
+ hour24 = 12;
118
+ const meridiem = hour24 >= 12 ? "PM" : "AM";
119
+ const hour12 = hour24 % 12 === 0 ? 12 : hour24 % 12;
120
+ return { hour12: String(hour12), minute, meridiem };
121
+ }
122
+ function fromClock(clock) {
123
+ const hour12 = Number(clock.hour12);
124
+ const safeHour = Number.isFinite(hour12) ? hour12 : 12;
125
+ return `${pad(to24h(safeHour, clock.meridiem))}:${clock.minute || "00"}`;
126
+ }
127
+ function dateFromYmd(ymd) {
128
+ if (!ymd)
129
+ return undefined;
130
+ const [year, month, day] = ymd.split("-").map(Number);
131
+ if (!year || !month || !day)
132
+ return undefined;
133
+ return new Date(year, month - 1, day);
134
+ }
135
+ function ymdFromDate(date) {
136
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
137
+ }
138
+ function formatDateLabel(ymd) {
139
+ const date = dateFromYmd(ymd);
140
+ if (!date)
141
+ return "mm/dd/yyyy";
142
+ return new Intl.DateTimeFormat(undefined, {
143
+ month: "short",
144
+ day: "numeric",
145
+ year: "numeric",
146
+ }).format(date);
147
+ }
148
+ function formatTimeLabel(time) {
149
+ if (!time)
150
+ return "--:-- --";
151
+ const clock = toClock(time);
152
+ return `${clock.hour12}:${clock.minute} ${clock.meridiem}`;
153
+ }
154
+ function formatTimeZoneShort(timeZone, instant = new Date()) {
155
+ const part = new Intl.DateTimeFormat("en-US", {
156
+ timeZone,
157
+ timeZoneName: "short",
158
+ })
159
+ .formatToParts(instant)
160
+ .find((item) => item.type === "timeZoneName");
161
+ return part?.value ?? timeZone;
162
+ }
163
+ function formatSummary(parts, timeZone) {
164
+ if (!parts.date)
165
+ return null;
166
+ const iso = toIsoInZone(parts, timeZone);
167
+ if (!iso)
168
+ return null;
169
+ const instant = new Date(iso);
170
+ const when = new Intl.DateTimeFormat(undefined, {
171
+ timeZone,
172
+ weekday: "short",
173
+ month: "short",
174
+ day: "numeric",
175
+ year: "numeric",
176
+ hour: "numeric",
177
+ minute: "2-digit",
178
+ }).format(instant);
179
+ return `${when} ${formatTimeZoneShort(timeZone, instant)}`;
180
+ }
181
+ /** @deprecated Prefer parts helpers; kept for callers/tests. */
182
+ export function toDatetimeLocalValue(value) {
183
+ const parts = partsFromValue(value, browserTimeZone());
184
+ if (!parts.date)
185
+ return "";
186
+ return `${parts.date}T${parts.time || "00:00"}`;
187
+ }
188
+ /** @deprecated Prefer parts helpers; kept for callers/tests. */
189
+ export function fromDatetimeLocalValue(local) {
190
+ const trimmed = local.trim();
191
+ if (!trimmed)
192
+ return "";
193
+ const ms = Date.parse(trimmed);
194
+ if (!Number.isFinite(ms))
195
+ return "";
196
+ return new Date(ms).toISOString();
197
+ }
198
+ const HOURS_12 = Array.from({ length: 12 }, (_, i) => String(i + 1));
199
+ const MINUTES = Array.from({ length: 60 }, (_, i) => pad(i));
200
+ function IconCalendar() {
201
+ return (_jsxs("svg", { className: "vertebr-datetime-icon", width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: [_jsx("rect", { x: "3", y: "4.5", width: "14", height: "12", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }), _jsx("path", { d: "M3 8.5h14M7 3v3M13 3v3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }));
202
+ }
203
+ function IconClock() {
204
+ return (_jsxs("svg", { className: "vertebr-datetime-icon", width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: [_jsx("circle", { cx: "10", cy: "10", r: "7", stroke: "currentColor", strokeWidth: "1.5" }), _jsx("path", { d: "M10 6.5V10l2.5 1.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }));
205
+ }
206
+ function IconChevron({ direction }) {
207
+ return (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: _jsx("path", { d: direction === "left" ? "M8.5 3.5 5 7l3.5 3.5" : "M5.5 3.5 9 7l-3.5 3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
208
+ }
209
+ export function DatetimeInput({ id, name, value, readOnly, onBlur, onChange, inputRef, }) {
210
+ const labelId = useId();
211
+ const [open, setOpen] = useState(false);
212
+ const [timeZone, setTimeZone] = useState(browserTimeZone);
213
+ const [parts, setParts] = useState(() => partsFromValue(value, browserTimeZone()));
214
+ const summary = useMemo(() => formatSummary(parts, timeZone), [parts, timeZone]);
215
+ const selected = useMemo(() => dateFromYmd(parts.date), [parts.date]);
216
+ const clock = useMemo(() => toClock(parts.time || "12:00"), [parts.time]);
217
+ const zones = useMemo(() => timeZoneOptions(timeZone), [timeZone]);
218
+ useEffect(() => {
219
+ setParts(partsFromValue(value, timeZone));
220
+ // Re-parse when the stored ISO changes; timezone switches keep wall-clock
221
+ // and rewrite ISO via onTimeZoneChange instead.
222
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- intentional
223
+ }, [value]);
224
+ const commit = (next, zone = timeZone) => {
225
+ setParts(next);
226
+ onChange(toIsoInZone(next, zone));
227
+ };
228
+ const setClock = (next) => {
229
+ const time = fromClock(next);
230
+ if (!parts.date) {
231
+ commit({ date: ymdFromDate(new Date()), time });
232
+ return;
233
+ }
234
+ commit({ date: parts.date, time });
235
+ };
236
+ const onTimeZoneChange = (nextZone) => {
237
+ setTimeZone(nextZone);
238
+ if (!parts.date)
239
+ return;
240
+ // Keep the wall-clock launch time; reinterpret in the new zone.
241
+ onChange(toIsoInZone(parts, nextZone));
242
+ };
243
+ return (_jsxs("div", { className: "vertebr-datetime", "data-empty": parts.date ? "false" : "true", children: [_jsxs(Popover.Root, { open: readOnly ? false : open, onOpenChange: (next) => {
244
+ if (readOnly)
245
+ return;
246
+ setOpen(next);
247
+ if (!next)
248
+ onBlur?.();
249
+ }, children: [_jsxs("div", { className: "vertebr-datetime-shell", children: [_jsx(Popover.Trigger, { asChild: true, children: _jsxs("button", { id: id, ref: inputRef, type: "button", name: name, className: "vertebr-datetime-cell", disabled: readOnly, "aria-labelledby": `${labelId}-date ${labelId}-time`, children: [_jsxs("span", { className: "vertebr-datetime-cell-inner", children: [_jsx(IconCalendar, {}), _jsxs("span", { className: "vertebr-datetime-cell-copy", children: [_jsx("span", { className: "vertebr-datetime-cell-label", id: `${labelId}-date`, children: "Date" }), _jsx("span", { className: "vertebr-datetime-value", "data-empty": parts.date ? "false" : "true", children: formatDateLabel(parts.date) })] })] }), _jsx("span", { className: "vertebr-datetime-divider", "aria-hidden": "true" }), _jsxs("span", { className: "vertebr-datetime-cell-inner", children: [_jsx(IconClock, {}), _jsxs("span", { className: "vertebr-datetime-cell-copy", children: [_jsx("span", { className: "vertebr-datetime-cell-label", id: `${labelId}-time`, children: "Time" }), _jsx("span", { className: "vertebr-datetime-value", "data-empty": parts.time ? "false" : "true", children: parts.time
250
+ ? `${formatTimeLabel(parts.time)} ${formatTimeZoneShort(timeZone)}`
251
+ : "--:-- --" })] })] })] }) }), parts.date && !readOnly ? (_jsx("button", { type: "button", className: "vertebr-datetime-clear", "aria-label": "Clear date and time", onClick: () => {
252
+ commit({ date: "", time: "" });
253
+ setOpen(false);
254
+ }, children: "Clear" })) : null] }), _jsx(Popover.Portal, { children: _jsxs(Popover.Content, { className: "vertebr-datetime-popover", align: "start", sideOffset: 8, collisionPadding: 12, onOpenAutoFocus: (event) => event.preventDefault(), children: [_jsx(DayPicker, { mode: "single", navLayout: "around", selected: selected, defaultMonth: selected ?? new Date(), onSelect: (day) => {
255
+ if (!day)
256
+ return;
257
+ commit({
258
+ date: ymdFromDate(day),
259
+ time: parts.time || fromClock({ hour12: "12", minute: "00", meridiem: "PM" }),
260
+ });
261
+ }, className: "vertebr-day-picker", classNames: {
262
+ root: "vertebr-day-picker",
263
+ months: "vertebr-day-picker-months",
264
+ month: "vertebr-day-picker-month",
265
+ month_caption: "vertebr-day-picker-caption",
266
+ month_grid: "vertebr-day-picker-grid",
267
+ caption_label: "vertebr-day-picker-caption-label",
268
+ nav: "vertebr-day-picker-nav",
269
+ button_previous: "vertebr-day-picker-nav-btn",
270
+ button_next: "vertebr-day-picker-nav-btn",
271
+ weekdays: "vertebr-day-picker-weekdays",
272
+ weekday: "vertebr-day-picker-weekday",
273
+ week: "vertebr-day-picker-week",
274
+ day: "vertebr-day-picker-day",
275
+ day_button: "vertebr-day-picker-day-btn",
276
+ selected: "vertebr-day-picker-selected",
277
+ today: "vertebr-day-picker-today",
278
+ outside: "vertebr-day-picker-outside",
279
+ disabled: "vertebr-day-picker-disabled",
280
+ hidden: "vertebr-day-picker-hidden",
281
+ }, components: {
282
+ Chevron: ({ orientation }) => (_jsx(IconChevron, { direction: orientation === "left" ? "left" : "right" })),
283
+ } }), _jsxs("div", { className: "vertebr-datetime-time-row", children: [_jsxs("label", { className: "vertebr-datetime-time-field", children: [_jsx("span", { children: "Hour" }), _jsx("select", { className: "vertebr-datetime-time-select", value: clock.hour12, onChange: (event) => setClock({ ...clock, hour12: event.target.value }), children: HOURS_12.map((value) => (_jsx("option", { value: value, children: value }, value))) })] }), _jsx("span", { className: "vertebr-datetime-time-sep", "aria-hidden": "true", children: ":" }), _jsxs("label", { className: "vertebr-datetime-time-field", children: [_jsx("span", { children: "Minute" }), _jsx("select", { className: "vertebr-datetime-time-select", value: clock.minute, onChange: (event) => setClock({ ...clock, minute: event.target.value }), children: MINUTES.map((value) => (_jsx("option", { value: value, children: value }, value))) })] }), _jsxs("label", { className: "vertebr-datetime-time-field vertebr-datetime-time-field-meridiem", children: [_jsx("span", { children: "AM/PM" }), _jsxs("select", { className: "vertebr-datetime-time-select", value: clock.meridiem, onChange: (event) => setClock({
284
+ ...clock,
285
+ meridiem: event.target.value,
286
+ }), children: [_jsx("option", { value: "AM", children: "AM" }), _jsx("option", { value: "PM", children: "PM" })] })] })] }), _jsxs("label", { className: "vertebr-datetime-time-field vertebr-datetime-timezone", children: [_jsx("span", { children: "Timezone" }), _jsx("select", { className: "vertebr-datetime-time-select", value: timeZone, onChange: (event) => onTimeZoneChange(event.target.value), children: zones.map((zone) => (_jsx("option", { value: zone.id, children: zone.label }, zone.id))) })] })] }) })] }), summary ? (_jsx("p", { className: "vertebr-datetime-summary", children: summary })) : (_jsx("p", { className: "vertebr-datetime-summary vertebr-datetime-summary-empty", children: "Pick a launch date and time" }))] }));
287
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"EnumInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,+BAmDhB"}
1
+ {"version":3,"file":"EnumInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,+BAkDhB"}
@@ -2,10 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as Select from "@radix-ui/react-select";
3
3
  import { optionLabel } from "./form/helpers/labels";
4
4
  export function EnumInput({ id, value, field, readOnly, onChange, }) {
5
- const options = field.options?.filter(Boolean) ?? [];
6
- const current = typeof value === "string" && options.includes(value)
7
- ? value
8
- : (options[0] ?? "");
5
+ const baseOptions = field.options?.filter(Boolean) ?? [];
6
+ const raw = typeof value === "string" ? value : "";
7
+ const options = raw && !baseOptions.includes(raw) ? [raw, ...baseOptions] : baseOptions;
8
+ const current = raw && options.includes(raw) ? raw : (options[0] ?? "");
9
9
  if (options.length === 0) {
10
10
  return (_jsx("input", { id: id, type: "text", readOnly: readOnly, value: current, disabled: true }));
11
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EnumListInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumListInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC,CAAC;AAiBF,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,+BAiEpB"}
1
+ {"version":3,"file":"EnumListInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumListInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC,CAAC;AAyBF,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,+BAyEpB"}
@@ -1,9 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { optionLabel } from "./form/helpers/labels";
3
3
  function asStringList(value) {
4
- if (!Array.isArray(value))
5
- return [];
6
- return value.map((item) => String(item).trim()).filter(Boolean);
4
+ if (Array.isArray(value)) {
5
+ return value.map((item) => String(item).trim()).filter(Boolean);
6
+ }
7
+ if (typeof value === "string") {
8
+ return value
9
+ .split(",")
10
+ .map((item) => item.trim())
11
+ .filter(Boolean);
12
+ }
13
+ return [];
7
14
  }
8
15
  function orderedRows(options, selected) {
9
16
  const known = new Set(options);
@@ -18,6 +25,9 @@ export function EnumListInput({ id, value, field, readOnly, onChange, }) {
18
25
  const options = field.options?.filter(Boolean) ?? [];
19
26
  const selected = asStringList(value);
20
27
  const rows = orderedRows(options, selected);
28
+ if (options.length === 0) {
29
+ return (_jsx("p", { className: "vertebr-field-files-empty", id: id, children: "No products available in this environment." }));
30
+ }
21
31
  const commit = (nextRows) => {
22
32
  onChange(nextRows.filter((row) => row.on).map((row) => row.id));
23
33
  };
@@ -0,0 +1,11 @@
1
+ import type { FieldSchema, VertebrClient } from "@vertebr/client";
2
+ export type ReferenceInputProps = {
3
+ id?: string;
4
+ value: unknown;
5
+ field: FieldSchema;
6
+ client: VertebrClient;
7
+ readOnly?: boolean;
8
+ onChange: (value: string) => void;
9
+ };
10
+ export declare function ReferenceInput({ id: idProp, value, field, client, readOnly, onChange, }: ReferenceInputProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=ReferenceInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReferenceInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/ReferenceInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAElE,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAuBF,wBAAgB,cAAc,CAAC,EAC7B,EAAE,EAAE,MAAM,EACV,KAAK,EACL,KAAK,EACL,MAAM,EACN,QAAQ,EACR,QAAQ,GACT,EAAE,mBAAmB,+BA0IrB"}
@@ -0,0 +1,99 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from "react";
3
+ function rowValue(row, valueField) {
4
+ const raw = row[valueField] ?? row.id ?? row.slug ?? row.uid;
5
+ if (typeof raw === "string" && raw.trim())
6
+ return raw;
7
+ if (typeof raw === "number")
8
+ return String(raw);
9
+ return null;
10
+ }
11
+ function rowLabel(row, labelField, value) {
12
+ const raw = row[labelField] ?? row.name ?? row.title ?? row.label ?? value;
13
+ return typeof raw === "string" && raw.trim() ? raw.trim() : value;
14
+ }
15
+ export function ReferenceInput({ id: idProp, value, field, client, readOnly, onChange, }) {
16
+ const autoId = useId();
17
+ const id = idProp ?? autoId;
18
+ const resource = field.reference?.resource ?? "";
19
+ const valueField = field.reference?.valueField ?? "id";
20
+ const labelField = field.reference?.labelField ?? "name";
21
+ const current = typeof value === "string" ? value : "";
22
+ const [query, setQuery] = useState("");
23
+ const [open, setOpen] = useState(false);
24
+ const [options, setOptions] = useState([]);
25
+ const [loading, setLoading] = useState(false);
26
+ const [displayLabel, setDisplayLabel] = useState(current);
27
+ const rootRef = useRef(null);
28
+ useEffect(() => {
29
+ setDisplayLabel(current);
30
+ }, [current]);
31
+ useEffect(() => {
32
+ if (!open || !resource || readOnly)
33
+ return;
34
+ let cancelled = false;
35
+ const handle = window.setTimeout(() => {
36
+ void (async () => {
37
+ setLoading(true);
38
+ try {
39
+ const listed = await client.listResource(resource, {
40
+ q: query.trim() || undefined,
41
+ limit: 20,
42
+ fresh: true,
43
+ });
44
+ if (cancelled)
45
+ return;
46
+ const next = [];
47
+ for (const row of listed.items) {
48
+ const v = rowValue(row, valueField);
49
+ if (!v)
50
+ continue;
51
+ next.push({ value: v, label: rowLabel(row, labelField, v) });
52
+ }
53
+ setOptions(next);
54
+ }
55
+ catch {
56
+ if (!cancelled)
57
+ setOptions([]);
58
+ }
59
+ finally {
60
+ if (!cancelled)
61
+ setLoading(false);
62
+ }
63
+ })();
64
+ }, 180);
65
+ return () => {
66
+ cancelled = true;
67
+ window.clearTimeout(handle);
68
+ };
69
+ }, [open, query, resource, client, valueField, labelField, readOnly]);
70
+ useEffect(() => {
71
+ const onPointer = (event) => {
72
+ if (!rootRef.current?.contains(event.target)) {
73
+ setOpen(false);
74
+ }
75
+ };
76
+ document.addEventListener("mousedown", onPointer);
77
+ return () => document.removeEventListener("mousedown", onPointer);
78
+ }, []);
79
+ if (!resource) {
80
+ return (_jsx("input", { id: id, type: "text", readOnly: readOnly, value: current, onChange: (event) => onChange(event.target.value), placeholder: "Missing reference.resource" }));
81
+ }
82
+ return (_jsxs("div", { className: "vertebr-reference", ref: rootRef, "data-open": open || undefined, children: [_jsx("input", { id: id, type: "text", className: "vertebr-reference-input", readOnly: readOnly, value: open ? query : displayLabel || current, placeholder: "Search\u2026", autoComplete: "off", onFocus: () => {
83
+ if (readOnly)
84
+ return;
85
+ setQuery("");
86
+ setOpen(true);
87
+ }, onChange: (event) => {
88
+ setQuery(event.target.value);
89
+ setOpen(true);
90
+ } }), current && !readOnly ? (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-reference-clear", onClick: () => {
91
+ onChange("");
92
+ setDisplayLabel("");
93
+ setQuery("");
94
+ }, children: "Clear" })) : null, open && !readOnly ? (_jsx("ul", { className: "vertebr-reference-menu", role: "listbox", children: loading ? (_jsx("li", { className: "vertebr-reference-empty", children: "Searching\u2026" })) : options.length === 0 ? (_jsx("li", { className: "vertebr-reference-empty", children: "No matches" })) : (options.map((option) => (_jsx("li", { children: _jsxs("button", { type: "button", role: "option", "aria-selected": option.value === current, className: "vertebr-reference-option", onClick: () => {
95
+ onChange(option.value);
96
+ setDisplayLabel(option.label);
97
+ setOpen(false);
98
+ }, children: [_jsx("span", { children: option.label }), _jsx("code", { children: option.value })] }) }, option.value)))) })) : null] }));
99
+ }
@@ -0,0 +1,12 @@
1
+ import type { VertebrClient } from "@vertebr/client";
2
+ export type RevisionHistoryProps = {
3
+ client: VertebrClient;
4
+ configId: string;
5
+ onPublished?: () => void | Promise<void>;
6
+ };
7
+ /**
8
+ * Compact History control — opens revision list in a modal so the
9
+ * editor form stays the primary surface.
10
+ */
11
+ export declare function RevisionHistory({ client, configId, onPublished, }: RevisionHistoryProps): import("react").JSX.Element;
12
+ //# sourceMappingURL=RevisionHistory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RevisionHistory.d.ts","sourceRoot":"","sources":["../../../src/components/config/RevisionHistory.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGnE,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C,CAAC;AAoBF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,QAAQ,EACR,WAAW,GACZ,EAAE,oBAAoB,+BAuNtB"}