@arbidocs/blocks 0.5.63 → 0.5.65

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 (177) hide show
  1. package/dist/{ConnectedDocumentViewer-7VKAM6KD.js → ConnectedDocumentViewer-HKIBNGGG.js} +10 -9
  2. package/dist/{ConnectedDocumentViewer-7VKAM6KD.js.map → ConnectedDocumentViewer-HKIBNGGG.js.map} +1 -1
  3. package/dist/{ConnectedDocumentViewer-FGQ27H4B.cjs → ConnectedDocumentViewer-YSZWOVGN.cjs} +11 -10
  4. package/dist/{ConnectedDocumentViewer-FGQ27H4B.cjs.map → ConnectedDocumentViewer-YSZWOVGN.cjs.map} +1 -1
  5. package/dist/{ConnectedNativeDocxComparison-HJ4FTVH6.cjs → ConnectedNativeDocxComparison-L3R3ROPZ.cjs} +7 -7
  6. package/dist/{ConnectedNativeDocxComparison-HJ4FTVH6.cjs.map → ConnectedNativeDocxComparison-L3R3ROPZ.cjs.map} +1 -1
  7. package/dist/{ConnectedNativeDocxComparison-FPW3BNBN.js → ConnectedNativeDocxComparison-PSAP3Q7D.js} +6 -6
  8. package/dist/{ConnectedNativeDocxComparison-FPW3BNBN.js.map → ConnectedNativeDocxComparison-PSAP3Q7D.js.map} +1 -1
  9. package/dist/{ConnectedNativeDocxEditor-S7NJMDSU.js → ConnectedNativeDocxEditor-PI6QTPXZ.js} +5 -5
  10. package/dist/{ConnectedNativeDocxEditor-S7NJMDSU.js.map → ConnectedNativeDocxEditor-PI6QTPXZ.js.map} +1 -1
  11. package/dist/{ConnectedNativeDocxEditor-PF46MU5H.cjs → ConnectedNativeDocxEditor-VDBC4XRT.cjs} +7 -7
  12. package/dist/{ConnectedNativeDocxEditor-PF46MU5H.cjs.map → ConnectedNativeDocxEditor-VDBC4XRT.cjs.map} +1 -1
  13. package/dist/{ConnectedStreamedWordArtifact-5MHLV24V.js → ConnectedStreamedWordArtifact-V4MTKVNE.js} +6 -6
  14. package/dist/ConnectedStreamedWordArtifact-V4MTKVNE.js.map +1 -0
  15. package/dist/{ConnectedStreamedWordArtifact-LNGW7YGV.cjs → ConnectedStreamedWordArtifact-YSW6D7AG.cjs} +7 -7
  16. package/dist/ConnectedStreamedWordArtifact-YSW6D7AG.cjs.map +1 -0
  17. package/dist/{DocumentReviewCard-VFNMJSK7.cjs → DocumentReviewCard-BQ6ZD5MD.cjs} +6 -6
  18. package/dist/{DocumentReviewCard-VFNMJSK7.cjs.map → DocumentReviewCard-BQ6ZD5MD.cjs.map} +1 -1
  19. package/dist/{DocumentReviewCard-5U3TGJZA.js → DocumentReviewCard-TQQADJ36.js} +6 -6
  20. package/dist/{DocumentReviewCard-5U3TGJZA.js.map → DocumentReviewCard-TQQADJ36.js.map} +1 -1
  21. package/dist/{WorkspaceTableView-DHMCJRC6.cjs → WorkspaceTableView-GKMVTECZ.cjs} +6 -6
  22. package/dist/{WorkspaceTableView-DHMCJRC6.cjs.map → WorkspaceTableView-GKMVTECZ.cjs.map} +1 -1
  23. package/dist/{WorkspaceTableView-EH5CEB44.js → WorkspaceTableView-YFLVFRJL.js} +4 -4
  24. package/dist/{WorkspaceTableView-EH5CEB44.js.map → WorkspaceTableView-YFLVFRJL.js.map} +1 -1
  25. package/dist/agents/index.cjs +345 -344
  26. package/dist/agents/index.js +6 -5
  27. package/dist/{chunk-NDVLCOWS.js → chunk-2LUA7UDE.js} +7 -7
  28. package/dist/{chunk-NDVLCOWS.js.map → chunk-2LUA7UDE.js.map} +1 -1
  29. package/dist/{chunk-77IAOKZO.js → chunk-2VH2PT3J.js} +5 -38
  30. package/dist/chunk-2VH2PT3J.js.map +1 -0
  31. package/dist/{chunk-IC6SBDYA.js → chunk-4CI42DCG.js} +3 -3
  32. package/dist/{chunk-IC6SBDYA.js.map → chunk-4CI42DCG.js.map} +1 -1
  33. package/dist/{chunk-IFLFLP4K.js → chunk-4Q7ON335.js} +6 -5
  34. package/dist/chunk-4Q7ON335.js.map +1 -0
  35. package/dist/{chunk-IUFS3AYQ.js → chunk-5EGTGHBW.js} +7 -7
  36. package/dist/{chunk-IUFS3AYQ.js.map → chunk-5EGTGHBW.js.map} +1 -1
  37. package/dist/{chunk-OLDGMBEF.cjs → chunk-67AFX23Y.cjs} +185 -91
  38. package/dist/chunk-67AFX23Y.cjs.map +1 -0
  39. package/dist/{chunk-5CWBAINB.js → chunk-6OMIIF76.js} +3 -3
  40. package/dist/{chunk-5CWBAINB.js.map → chunk-6OMIIF76.js.map} +1 -1
  41. package/dist/chunk-6QZ35CTZ.js +594 -0
  42. package/dist/chunk-6QZ35CTZ.js.map +1 -0
  43. package/dist/{chunk-4RJPTXUQ.cjs → chunk-7MOQO6NO.cjs} +5 -5
  44. package/dist/{chunk-4RJPTXUQ.cjs.map → chunk-7MOQO6NO.cjs.map} +1 -1
  45. package/dist/chunk-AESJLGMC.cjs +1228 -0
  46. package/dist/chunk-AESJLGMC.cjs.map +1 -0
  47. package/dist/{chunk-EOIJ5JYP.cjs → chunk-B3CRSCLK.cjs} +4 -4
  48. package/dist/{chunk-EOIJ5JYP.cjs.map → chunk-B3CRSCLK.cjs.map} +1 -1
  49. package/dist/{chunk-GRDLCRNL.js → chunk-BELZ2WD2.js} +5 -5
  50. package/dist/{chunk-GRDLCRNL.js.map → chunk-BELZ2WD2.js.map} +1 -1
  51. package/dist/chunk-C2S246BV.js +1225 -0
  52. package/dist/chunk-C2S246BV.js.map +1 -0
  53. package/dist/{chunk-TAI23FCY.js → chunk-CEKOZAGO.js} +3 -3
  54. package/dist/{chunk-TAI23FCY.js.map → chunk-CEKOZAGO.js.map} +1 -1
  55. package/dist/{chunk-HVOPUYAG.cjs → chunk-CJF7B5A7.cjs} +29 -28
  56. package/dist/chunk-CJF7B5A7.cjs.map +1 -0
  57. package/dist/{chunk-LBKTTQUR.cjs → chunk-CMYJEIZB.cjs} +12 -12
  58. package/dist/{chunk-LBKTTQUR.cjs.map → chunk-CMYJEIZB.cjs.map} +1 -1
  59. package/dist/{chunk-2SLDVFOZ.js → chunk-CRHY7DBO.js} +3 -3
  60. package/dist/{chunk-2SLDVFOZ.js.map → chunk-CRHY7DBO.js.map} +1 -1
  61. package/dist/{chunk-23ACBETH.cjs → chunk-D27BBGUF.cjs} +4 -4
  62. package/dist/{chunk-23ACBETH.cjs.map → chunk-D27BBGUF.cjs.map} +1 -1
  63. package/dist/{chunk-3X37I6QE.cjs → chunk-DJE2E7YH.cjs} +29 -29
  64. package/dist/{chunk-3X37I6QE.cjs.map → chunk-DJE2E7YH.cjs.map} +1 -1
  65. package/dist/{chunk-CCSF7RI4.cjs → chunk-EG3BB32W.cjs} +3 -3
  66. package/dist/{chunk-CCSF7RI4.cjs.map → chunk-EG3BB32W.cjs.map} +1 -1
  67. package/dist/{chunk-MAKTAR7H.cjs → chunk-F777MGVA.cjs} +18 -18
  68. package/dist/{chunk-MAKTAR7H.cjs.map → chunk-F777MGVA.cjs.map} +1 -1
  69. package/dist/{chunk-TFWCREOL.js → chunk-GPYLXEZO.js} +9 -506
  70. package/dist/chunk-GPYLXEZO.js.map +1 -0
  71. package/dist/{chunk-OY3I32ZS.js → chunk-GX37C5QT.js} +4 -4
  72. package/dist/{chunk-OY3I32ZS.js.map → chunk-GX37C5QT.js.map} +1 -1
  73. package/dist/chunk-I4IS6ST6.cjs +48 -0
  74. package/dist/chunk-I4IS6ST6.cjs.map +1 -0
  75. package/dist/{chunk-OZL5ABLF.js → chunk-IRXPUQFP.js} +3 -3
  76. package/dist/{chunk-OZL5ABLF.js.map → chunk-IRXPUQFP.js.map} +1 -1
  77. package/dist/chunk-J77BACGX.js +575 -0
  78. package/dist/chunk-J77BACGX.js.map +1 -0
  79. package/dist/{chunk-X3JJTHQ4.cjs → chunk-JSHBC47B.cjs} +55 -55
  80. package/dist/{chunk-X3JJTHQ4.cjs.map → chunk-JSHBC47B.cjs.map} +1 -1
  81. package/dist/{chunk-Y6ZNWC7E.cjs → chunk-K26RLK2Y.cjs} +3 -3
  82. package/dist/{chunk-Y6ZNWC7E.cjs.map → chunk-K26RLK2Y.cjs.map} +1 -1
  83. package/dist/{chunk-PKDPQS6Z.js → chunk-KNOSLLTC.js} +3 -3
  84. package/dist/{chunk-PKDPQS6Z.js.map → chunk-KNOSLLTC.js.map} +1 -1
  85. package/dist/chunk-LFS6UWSJ.cjs +602 -0
  86. package/dist/chunk-LFS6UWSJ.cjs.map +1 -0
  87. package/dist/{chunk-YQFEN7UJ.js → chunk-LNH6NYG4.js} +6 -90
  88. package/dist/chunk-LNH6NYG4.js.map +1 -0
  89. package/dist/chunk-LRPGXNMA.js +44 -0
  90. package/dist/chunk-LRPGXNMA.js.map +1 -0
  91. package/dist/chunk-NEGFHF3V.cjs +617 -0
  92. package/dist/chunk-NEGFHF3V.cjs.map +1 -0
  93. package/dist/{chunk-NHPBONMR.js → chunk-O4FBMC6S.js} +186 -71
  94. package/dist/chunk-O4FBMC6S.js.map +1 -0
  95. package/dist/{chunk-7P24MJQN.js → chunk-PBIFISDD.js} +3 -3
  96. package/dist/{chunk-7P24MJQN.js.map → chunk-PBIFISDD.js.map} +1 -1
  97. package/dist/{chunk-OWUNCJFO.cjs → chunk-PZOX4JF6.cjs} +30 -30
  98. package/dist/{chunk-OWUNCJFO.cjs.map → chunk-PZOX4JF6.cjs.map} +1 -1
  99. package/dist/{chunk-CKNUL4LM.cjs → chunk-QK546T4C.cjs} +3 -3
  100. package/dist/{chunk-CKNUL4LM.cjs.map → chunk-QK546T4C.cjs.map} +1 -1
  101. package/dist/{chunk-QAXIVZEJ.cjs → chunk-ROWJU4SK.cjs} +13 -513
  102. package/dist/chunk-ROWJU4SK.cjs.map +1 -0
  103. package/dist/{chunk-JWRTUYLC.js → chunk-SBAM3UZX.js} +3 -3
  104. package/dist/{chunk-JWRTUYLC.js.map → chunk-SBAM3UZX.js.map} +1 -1
  105. package/dist/{chunk-COZDIUG7.cjs → chunk-TJ7QEGVP.cjs} +18 -18
  106. package/dist/{chunk-COZDIUG7.cjs.map → chunk-TJ7QEGVP.cjs.map} +1 -1
  107. package/dist/{chunk-PVPGD6QR.js → chunk-VWM3J6ES.js} +3 -3
  108. package/dist/{chunk-PVPGD6QR.js.map → chunk-VWM3J6ES.js.map} +1 -1
  109. package/dist/{chunk-UDMII47W.cjs → chunk-WBLCPCWR.cjs} +7 -7
  110. package/dist/{chunk-UDMII47W.cjs.map → chunk-WBLCPCWR.cjs.map} +1 -1
  111. package/dist/{chunk-3T3IKNGF.cjs → chunk-ZXW6WFZG.cjs} +5 -41
  112. package/dist/chunk-ZXW6WFZG.cjs.map +1 -0
  113. package/dist/{chunk-ODQK3LX5.cjs → chunk-ZZHMJXM5.cjs} +4 -93
  114. package/dist/chunk-ZZHMJXM5.cjs.map +1 -0
  115. package/dist/connect/docx.cjs +11 -11
  116. package/dist/connect/docx.js +7 -7
  117. package/dist/connect/index.cjs +496 -493
  118. package/dist/connect/index.cjs.map +1 -1
  119. package/dist/connect/index.js +36 -33
  120. package/dist/connect/index.js.map +1 -1
  121. package/dist/connect/viewer.cjs +9 -8
  122. package/dist/connect/viewer.js +8 -7
  123. package/dist/dashboards/index.cjs +1 -1
  124. package/dist/dashboards/index.js +1 -1
  125. package/dist/document-tools/index.cjs +17 -17
  126. package/dist/document-tools/index.js +2 -2
  127. package/dist/embed/index.cjs +11 -10
  128. package/dist/embed/index.js +8 -7
  129. package/dist/facts/index.cjs +1 -1
  130. package/dist/facts/index.js +1 -1
  131. package/dist/files/index.cjs +1 -1
  132. package/dist/files/index.js +1 -1
  133. package/dist/index.cjs +653 -618
  134. package/dist/index.cjs.map +1 -1
  135. package/dist/index.d.ts +4 -0
  136. package/dist/index.js +19 -16
  137. package/dist/index.js.map +1 -1
  138. package/dist/shell/index.cjs +78 -77
  139. package/dist/shell/index.js +3 -2
  140. package/dist/site/index.cjs +105 -81
  141. package/dist/site/index.d.ts +3 -1
  142. package/dist/site/index.js +4 -4
  143. package/dist/studio/index.cjs +60 -55
  144. package/dist/studio/index.cjs.map +1 -1
  145. package/dist/studio/index.js +12 -7
  146. package/dist/studio/index.js.map +1 -1
  147. package/dist/theme/ThemeControls.d.ts +71 -0
  148. package/dist/theme/ThemeEditor.d.ts +5 -2
  149. package/dist/theme/ThemePreview.d.ts +20 -0
  150. package/dist/theme/color.d.ts +17 -1
  151. package/dist/theme/derive.d.ts +75 -0
  152. package/dist/theme/editorModel.d.ts +36 -0
  153. package/dist/theme/previewLabels.d.ts +38 -0
  154. package/dist/theme/store.d.ts +51 -13
  155. package/dist/theme/tokens.d.ts +2 -0
  156. package/dist/workflow-canvas/index.cjs +37 -36
  157. package/dist/workflow-canvas/index.cjs.map +1 -1
  158. package/dist/workflow-canvas/index.js +13 -12
  159. package/dist/workflow-canvas/index.js.map +1 -1
  160. package/node_modules/@arbidocs/coedit/package.json +1 -1
  161. package/package.json +5 -5
  162. package/dist/ConnectedStreamedWordArtifact-5MHLV24V.js.map +0 -1
  163. package/dist/ConnectedStreamedWordArtifact-LNGW7YGV.cjs.map +0 -1
  164. package/dist/chunk-3T3IKNGF.cjs.map +0 -1
  165. package/dist/chunk-77IAOKZO.js.map +0 -1
  166. package/dist/chunk-HVOPUYAG.cjs.map +0 -1
  167. package/dist/chunk-IFLFLP4K.js.map +0 -1
  168. package/dist/chunk-N5WJBQYF.cjs +0 -476
  169. package/dist/chunk-N5WJBQYF.cjs.map +0 -1
  170. package/dist/chunk-NHPBONMR.js.map +0 -1
  171. package/dist/chunk-ODQK3LX5.cjs.map +0 -1
  172. package/dist/chunk-OLDGMBEF.cjs.map +0 -1
  173. package/dist/chunk-QAXIVZEJ.cjs.map +0 -1
  174. package/dist/chunk-QCLYRNOC.js +0 -466
  175. package/dist/chunk-QCLYRNOC.js.map +0 -1
  176. package/dist/chunk-TFWCREOL.js.map +0 -1
  177. package/dist/chunk-YQFEN7UJ.js.map +0 -1
@@ -0,0 +1,1225 @@
1
+ "use client";
2
+ import { DEFAULT_THEME_PREVIEW_LABELS, themeMetaVars, themeCssVars, Tabs, applyThemeVars, CONTRAST_PAIRS, contrastIssues, contrastRatio, keysOfInput, toCssColor, toHex, parseColor } from './chunk-J77BACGX.js';
3
+ import { matchFontPairing, FONT_PAIRINGS } from './chunk-NHZK64TQ.js';
4
+ import { Callout } from './chunk-UJE32SST.js';
5
+ import { Sidebar } from './chunk-6QZ35CTZ.js';
6
+ import { Chart } from './chunk-WKYKDTNM.js';
7
+ import { ProgressChevronBar, ProgressChevron } from './chunk-LRPGXNMA.js';
8
+ import { ToneBadge } from './chunk-5LXQPP2K.js';
9
+ import { useMemo, useState, useEffect, useId } from 'react';
10
+ import { Home, Inbox, FileText, Undo2, Redo2, RotateCcw, AlertTriangle, Wand2, Check, ChevronDown, Save, Bell } from 'lucide-react';
11
+ import { cn, Button, Input, Card, CardHeader, CardTitle, CardContent } from '@arbidocs/react/ui';
12
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
+
14
+ var noop = () => void 0;
15
+ function radiusAliased() {
16
+ if (typeof document === "undefined" || typeof getComputedStyle !== "function") return false;
17
+ const root = getComputedStyle(document.documentElement);
18
+ const base = root.getPropertyValue("--radius").trim();
19
+ return base !== "" && root.getPropertyValue("--radius-md").trim() === base;
20
+ }
21
+ function ThemePreview({
22
+ colors,
23
+ fonts,
24
+ radius,
25
+ scheme,
26
+ highlight = null,
27
+ compact = false,
28
+ labels: labelOverrides,
29
+ title,
30
+ subtitle,
31
+ testId = "theme-preview"
32
+ }) {
33
+ const labels = { ...DEFAULT_THEME_PREVIEW_LABELS, ...labelOverrides };
34
+ const aliased = useMemo(radiusAliased, []);
35
+ const style = useMemo(() => {
36
+ const vars = {
37
+ ...themeCssVars(colors),
38
+ ...themeMetaVars({ fonts, radius })
39
+ };
40
+ if (aliased) {
41
+ vars["--radius-sm"] = `${radius}rem`;
42
+ vars["--radius-md"] = `${radius}rem`;
43
+ }
44
+ return vars;
45
+ }, [colors, fonts, radius, aliased]);
46
+ const part = (id, children, className) => /* @__PURE__ */ jsx(
47
+ "div",
48
+ {
49
+ "data-preview-part": id,
50
+ "data-highlighted": highlight?.has(id) || void 0,
51
+ className: cn(
52
+ "min-w-0 rounded-[calc(var(--radius)+4px)] transition-opacity duration-150 motion-reduce:transition-none",
53
+ highlight && !highlight.has(id) && "opacity-30",
54
+ highlight?.has(id) && "outline-2 outline-offset-4 outline-dashed outline-foreground",
55
+ className
56
+ ),
57
+ children
58
+ }
59
+ );
60
+ return /* @__PURE__ */ jsxs(
61
+ "div",
62
+ {
63
+ inert: true,
64
+ "data-testid": testId,
65
+ "data-scheme": scheme,
66
+ style,
67
+ className: cn(
68
+ scheme === "dark" && "dark",
69
+ "@container min-w-0 rounded-lg border border-border bg-background p-4 font-sans text-foreground",
70
+ highlight?.has("page") && "outline-2 outline-offset-2 outline-dashed outline-foreground"
71
+ ),
72
+ children: [
73
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
74
+ /* @__PURE__ */ jsx("p", { className: "font-display text-lg font-semibold leading-tight", children: title ?? labels.title }),
75
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: subtitle ?? labels.subtitle })
76
+ ] }),
77
+ /* @__PURE__ */ jsxs("div", { className: cn("grid gap-4", !compact && "@lg:grid-cols-2"), children: [
78
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [
79
+ part(
80
+ "buttons",
81
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
82
+ /* @__PURE__ */ jsx(Button, { size: "sm", children: labels.primaryAction }),
83
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "accent", children: labels.accentAction }),
84
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", children: labels.secondaryAction }),
85
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", children: labels.outlineAction }),
86
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "destructive", children: labels.dangerAction })
87
+ ] })
88
+ ),
89
+ part(
90
+ "input",
91
+ /* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium", children: [
92
+ labels.fieldLabel,
93
+ /* @__PURE__ */ jsx(Input, { className: "mt-1", placeholder: labels.fieldPlaceholder, readOnly: true })
94
+ ] })
95
+ ),
96
+ part(
97
+ "card",
98
+ /* @__PURE__ */ jsxs(Card, { variant: "outline", className: "border-border shadow-sm", children: [
99
+ /* @__PURE__ */ jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle, { className: "font-display text-base", children: labels.title }) }),
100
+ /* @__PURE__ */ jsx(CardContent, { className: "text-sm text-muted-foreground", children: labels.cardBody })
101
+ ] })
102
+ ),
103
+ part(
104
+ "tabs",
105
+ /* @__PURE__ */ jsx(
106
+ Tabs,
107
+ {
108
+ items: labels.tabs.map((label, i) => ({
109
+ label,
110
+ content: i === 0 ? labels.tabBody : ""
111
+ }))
112
+ }
113
+ )
114
+ ),
115
+ part(
116
+ "sidebar",
117
+ /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-sidebar p-2", children: [
118
+ /* @__PURE__ */ jsx(
119
+ Sidebar.NavItem,
120
+ {
121
+ label: labels.nav[0],
122
+ icon: /* @__PURE__ */ jsx(Home, { className: "size-4" }),
123
+ onSelect: noop,
124
+ active: true
125
+ }
126
+ ),
127
+ /* @__PURE__ */ jsx(
128
+ Sidebar.NavItem,
129
+ {
130
+ label: labels.nav[1],
131
+ icon: /* @__PURE__ */ jsx(Inbox, { className: "size-4" }),
132
+ onSelect: noop,
133
+ count: 3
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsx(
137
+ Sidebar.NavItem,
138
+ {
139
+ label: labels.nav[2],
140
+ icon: /* @__PURE__ */ jsx(FileText, { className: "size-4" }),
141
+ onSelect: noop
142
+ }
143
+ )
144
+ ] })
145
+ )
146
+ ] }),
147
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [
148
+ part(
149
+ "stepbar",
150
+ /* @__PURE__ */ jsxs(ProgressChevronBar, { "aria-label": labels.steps.join(", "), children: [
151
+ /* @__PURE__ */ jsx(ProgressChevron, { kind: "start", phase: "done", children: /* @__PURE__ */ jsx("span", { className: "px-1 text-xs font-medium", children: labels.steps[0] }) }),
152
+ /* @__PURE__ */ jsx(ProgressChevron, { kind: "start", phase: "running", current: true, children: /* @__PURE__ */ jsx("span", { className: "px-1 text-xs font-medium", children: labels.steps[1] }) }),
153
+ /* @__PURE__ */ jsx(ProgressChevron, { phase: "blocked", children: /* @__PURE__ */ jsx("span", { className: "px-1 text-xs font-medium", children: labels.steps[2] }) })
154
+ ] })
155
+ ),
156
+ part(
157
+ "chart",
158
+ /* @__PURE__ */ jsx(
159
+ Chart,
160
+ {
161
+ type: "bar",
162
+ ariaLabel: labels.chartLabel,
163
+ labels: labels.chartMonths,
164
+ series: [
165
+ { key: "a", label: labels.chartSeries[0], values: [12, 18, 15, 22] },
166
+ { key: "b", label: labels.chartSeries[1], values: [9, 14, 13, 19] }
167
+ ]
168
+ }
169
+ )
170
+ ),
171
+ part(
172
+ "toast",
173
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-border bg-card p-3 text-foreground shadow-lg", children: [
174
+ /* @__PURE__ */ jsx(Bell, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
175
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
176
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: labels.toastTitle }),
177
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: labels.toastBody })
178
+ ] }),
179
+ /* @__PURE__ */ jsx("span", { className: "rounded-md bg-primary px-2 py-1 text-xs font-medium text-primary-foreground", children: labels.toastAction })
180
+ ] })
181
+ ),
182
+ part(
183
+ "badges",
184
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1.5", children: [
185
+ /* @__PURE__ */ jsx(ToneBadge, { tone: "neutral", children: labels.badges.neutral }),
186
+ /* @__PURE__ */ jsx(ToneBadge, { tone: "success", children: labels.badges.success }),
187
+ /* @__PURE__ */ jsx(ToneBadge, { tone: "warning", children: labels.badges.warning }),
188
+ /* @__PURE__ */ jsx(ToneBadge, { tone: "danger", children: labels.badges.danger }),
189
+ /* @__PURE__ */ jsx(ToneBadge, { tone: "ai", children: labels.badges.ai })
190
+ ] })
191
+ ),
192
+ part(
193
+ "alerts",
194
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
195
+ /* @__PURE__ */ jsx(Callout, { variant: "info", body: labels.alerts.info }),
196
+ /* @__PURE__ */ jsx(Callout, { variant: "danger", body: labels.alerts.danger })
197
+ ] })
198
+ )
199
+ ] })
200
+ ] })
201
+ ]
202
+ }
203
+ );
204
+ }
205
+
206
+ // src/theme/editorModel.ts
207
+ var SECTION_COPY = {
208
+ brand: {
209
+ title: "Brand",
210
+ affects: "Affects buttons, links, active tabs, focus rings, the step bar, the first chart series and the type."
211
+ },
212
+ surfaces: {
213
+ title: "Surfaces",
214
+ affects: "Affects the page, cards, menus, borders, fields, the sidebar and hover highlights."
215
+ },
216
+ text: {
217
+ title: "Text and readability",
218
+ affects: "Affects every text colour. Pairs below the WCAG AA contrast level are flagged here."
219
+ },
220
+ status: {
221
+ title: "Status",
222
+ affects: "Affects error, warning and success messages, badges and alerts."
223
+ },
224
+ charts: {
225
+ title: "Charts",
226
+ affects: "Affects the series colours of charts and dashboards."
227
+ },
228
+ advanced: {
229
+ title: "Advanced",
230
+ affects: "Set any single colour by hand. A colour you set stops following the brand inputs until you reset it."
231
+ }
232
+ };
233
+ var FONT_DISPLAY = "font-display";
234
+ var FONT_SANS = "font-sans";
235
+ var RADIUS = "radius";
236
+ var STATUS = (hue) => ["bg", "text", "border", "solid", "text-strong"].map((p) => `${hue}-${p}`);
237
+ var PART_TOKENS = {
238
+ page: ["background", "foreground", FONT_SANS],
239
+ buttons: [
240
+ "primary",
241
+ "primary-foreground",
242
+ "ai-accent",
243
+ "ai-accent-foreground",
244
+ "muted",
245
+ "foreground",
246
+ "border",
247
+ "background",
248
+ "destructive",
249
+ "destructive-foreground",
250
+ "ring",
251
+ RADIUS,
252
+ FONT_SANS
253
+ ],
254
+ input: ["input", "background", "foreground", "muted-foreground", "ring", RADIUS],
255
+ card: ["card", "card-foreground", "border", "muted-foreground", FONT_DISPLAY, RADIUS],
256
+ tabs: ["primary", "foreground", "muted-foreground", "border", "ring"],
257
+ sidebar: [
258
+ "sidebar",
259
+ "sidebar-foreground",
260
+ "sidebar-muted",
261
+ "sidebar-accent",
262
+ "sidebar-accent-foreground",
263
+ "sidebar-border",
264
+ "sidebar-primary",
265
+ "accent",
266
+ "accent-foreground",
267
+ "muted",
268
+ "muted-foreground"
269
+ ],
270
+ stepbar: ["wf-start", "muted", "muted-foreground", "card", "foreground", "destructive", "ring"],
271
+ chart: ["chart-1", "chart-2", "chart-3", "chart-4", "chart-5", "muted-foreground", "border"],
272
+ toast: [
273
+ "card",
274
+ "foreground",
275
+ "border",
276
+ "muted-foreground",
277
+ "primary",
278
+ "primary-foreground",
279
+ RADIUS
280
+ ],
281
+ badges: [
282
+ "ai-soft",
283
+ "ai-ink",
284
+ "muted",
285
+ "muted-foreground",
286
+ "accent",
287
+ "primary",
288
+ ...STATUS("red"),
289
+ ...STATUS("green"),
290
+ ...STATUS("yellow")
291
+ ],
292
+ alerts: ["primary", "destructive", "foreground", "muted-foreground", RADIUS]
293
+ };
294
+ function partsOf(keys) {
295
+ const wanted = new Set(keys);
296
+ const parts = /* @__PURE__ */ new Set();
297
+ for (const [part, tokens] of Object.entries(PART_TOKENS)) {
298
+ if (tokens.some((t) => wanted.has(t))) parts.add(part);
299
+ }
300
+ return parts;
301
+ }
302
+ function readDocumentTokens(keys, scheme) {
303
+ if (typeof document === "undefined" || typeof getComputedStyle !== "function") return {};
304
+ const probe = document.createElement("div");
305
+ probe.setAttribute("aria-hidden", "true");
306
+ probe.style.display = "none";
307
+ if (scheme === "dark") probe.className = "dark";
308
+ document.body.appendChild(probe);
309
+ try {
310
+ const style = getComputedStyle(probe);
311
+ const out = {};
312
+ for (const key of keys) {
313
+ const raw = style.getPropertyValue(`--${key}`).trim();
314
+ if (raw) out[key] = raw;
315
+ }
316
+ return out;
317
+ } finally {
318
+ probe.remove();
319
+ }
320
+ }
321
+ function hintProps(keys, onHint) {
322
+ return {
323
+ onPointerEnter: () => onHint(keys),
324
+ onPointerLeave: () => onHint(null),
325
+ onFocus: () => onHint(keys),
326
+ onBlur: () => onHint(null)
327
+ };
328
+ }
329
+ var FIELD = "h-8 rounded-md border border-input bg-background px-2 text-xs text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
330
+ function ColorField({
331
+ label,
332
+ hint,
333
+ value,
334
+ onChange,
335
+ keys,
336
+ onHint,
337
+ testIds,
338
+ trailing
339
+ }) {
340
+ const id = useId();
341
+ const hex = toHex(value, "#000000");
342
+ const [draft, setDraft] = useState(hex);
343
+ useEffect(() => setDraft(hex), [hex]);
344
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", ...hintProps(keys, onHint), children: [
345
+ /* @__PURE__ */ jsx(
346
+ "input",
347
+ {
348
+ id: `${id}-swatch`,
349
+ type: "color",
350
+ value: hex,
351
+ onChange: (e) => onChange(e.target.value),
352
+ className: "size-9 shrink-0 cursor-pointer rounded-md border border-input bg-transparent p-0.5",
353
+ "aria-label": label,
354
+ "data-testid": testIds.color
355
+ }
356
+ ),
357
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
358
+ /* @__PURE__ */ jsx("label", { htmlFor: `${id}-hex`, className: "block text-sm font-medium text-foreground", children: label }),
359
+ hint && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: hint })
360
+ ] }),
361
+ /* @__PURE__ */ jsx(
362
+ "input",
363
+ {
364
+ id: `${id}-hex`,
365
+ value: draft,
366
+ onChange: (e) => {
367
+ setDraft(e.target.value);
368
+ if (/^#[0-9a-fA-F]{6}$/.test(e.target.value) && parseColor(e.target.value)) {
369
+ onChange(e.target.value.toLowerCase());
370
+ }
371
+ },
372
+ onBlur: () => setDraft(hex),
373
+ spellCheck: false,
374
+ "aria-label": `${label} hex value`,
375
+ className: cn(FIELD, "w-[5.5rem] shrink-0 font-mono"),
376
+ "data-testid": testIds.hex
377
+ }
378
+ ),
379
+ trailing
380
+ ] });
381
+ }
382
+ function Segmented({
383
+ label,
384
+ value,
385
+ options,
386
+ onChange,
387
+ keys,
388
+ onHint,
389
+ testId
390
+ }) {
391
+ return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": label, className: "flex flex-wrap gap-1", "data-testid": testId, children: options.map((option) => /* @__PURE__ */ jsx(
392
+ "button",
393
+ {
394
+ type: "button",
395
+ role: "radio",
396
+ "aria-checked": value === option.value,
397
+ onClick: () => onChange(option.value),
398
+ ...hintProps(keys, onHint),
399
+ className: cn(
400
+ "rounded-md border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
401
+ value === option.value ? "border-primary bg-primary text-primary-foreground" : "border-input bg-background text-foreground hover:bg-muted"
402
+ ),
403
+ "data-testid": `${testId}-${option.value}`,
404
+ children: option.label
405
+ },
406
+ option.value
407
+ )) });
408
+ }
409
+ function SliderField({
410
+ label,
411
+ valueText,
412
+ value,
413
+ min,
414
+ max,
415
+ step,
416
+ onChange,
417
+ ends,
418
+ keys,
419
+ onHint,
420
+ testId
421
+ }) {
422
+ const id = useId();
423
+ return /* @__PURE__ */ jsxs("div", { ...hintProps(keys, onHint), children: [
424
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
425
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-sm font-medium text-foreground", children: label }),
426
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: valueText })
427
+ ] }),
428
+ /* @__PURE__ */ jsx(
429
+ "input",
430
+ {
431
+ id,
432
+ type: "range",
433
+ min,
434
+ max,
435
+ step,
436
+ value,
437
+ "aria-valuetext": valueText,
438
+ onChange: (e) => onChange(Number(e.target.value)),
439
+ className: "mt-2 w-full accent-[color:var(--color-primary)]",
440
+ "data-testid": testId
441
+ }
442
+ ),
443
+ ends && /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-xs text-muted-foreground", "aria-hidden": true, children: [
444
+ /* @__PURE__ */ jsx("span", { children: ends[0] }),
445
+ /* @__PURE__ */ jsx("span", { children: ends[1] })
446
+ ] })
447
+ ] });
448
+ }
449
+ function SelectField({
450
+ label,
451
+ value,
452
+ options,
453
+ onChange,
454
+ keys,
455
+ onHint,
456
+ testId,
457
+ hint
458
+ }) {
459
+ const id = useId();
460
+ return /* @__PURE__ */ jsxs("div", { ...hintProps(keys, onHint), children: [
461
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: "block text-sm font-medium text-foreground", children: label }),
462
+ /* @__PURE__ */ jsx(
463
+ "select",
464
+ {
465
+ id,
466
+ value,
467
+ onChange: (e) => onChange(e.target.value),
468
+ className: cn(FIELD, "mt-1 w-full"),
469
+ "data-testid": testId,
470
+ children: options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
471
+ }
472
+ ),
473
+ hint && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: hint })
474
+ ] });
475
+ }
476
+ var CHART_KEYS = ["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"];
477
+ var SURFACE_SWATCHES = [
478
+ ["background", "Page"],
479
+ ["card", "Cards"],
480
+ ["muted", "Muted"],
481
+ ["accent", "Hover"],
482
+ ["border", "Borders"],
483
+ ["sidebar", "Sidebar"]
484
+ ];
485
+ var faceName = (stack) => (stack.split(",")[0] ?? stack).replace(/["']/g, "").replace(/ Variable$/, "").trim();
486
+ function faceOptions(current, stacks) {
487
+ const unique = [...new Set(stacks)];
488
+ const options = unique.map((value) => ({
489
+ value,
490
+ label: value.startsWith("ui-") ? "System" : faceName(value)
491
+ }));
492
+ if (!unique.includes(current))
493
+ options.unshift({ value: current, label: `Custom (${faceName(current)})` });
494
+ return options;
495
+ }
496
+ var isTextEntry = (el) => el instanceof HTMLElement && (el.tagName === "TEXTAREA" || el.tagName === "SELECT" || el.tagName === "INPUT" && !["range", "color", "button"].includes(el.type));
497
+ function ThemeEditor({
498
+ bundle,
499
+ variant = "panel",
500
+ preview,
501
+ previewLabels,
502
+ onSave,
503
+ testIdPrefix = "theme",
504
+ defaultOpen = false
505
+ }) {
506
+ const { useStore, tokens, presets, groupLabels, mode, darkColors } = bundle;
507
+ const hasDark = darkColors !== void 0;
508
+ const colors = useStore((s) => s.colors);
509
+ const dark = useStore((s) => s.dark);
510
+ const fonts = useStore((s) => s.fonts);
511
+ const radius = useStore((s) => s.radius);
512
+ const inputs = useStore((s) => s.inputs);
513
+ const overrides = useStore((s) => s.overrides);
514
+ const activePresetId = useStore((s) => s.activePresetId);
515
+ const canUndo = useStore((s) => s.past.length > 0);
516
+ const canRedo = useStore((s) => s.future.length > 0);
517
+ const store = useStore.getState;
518
+ const [open, setOpen] = useState(defaultOpen);
519
+ const [advancedOpen, setAdvancedOpen] = useState(false);
520
+ const [previewMode, setPreviewMode] = useState("light");
521
+ const [hint, setHint] = useState(null);
522
+ const [saving, setSaving] = useState(false);
523
+ const [savedVia, setSavedVia] = useState(null);
524
+ useEffect(() => {
525
+ applyThemeVars({ colors, fonts, radius }, { mode, dark: hasDark ? dark : void 0 });
526
+ }, [colors, dark, fonts, radius, mode, hasDark]);
527
+ const tid = (suffix) => `${testIdPrefix}-${suffix}`;
528
+ const highlight = useMemo(() => hint ? partsOf(hint) : null, [hint]);
529
+ const schemes = hasDark ? ["light", "dark"] : ["light"];
530
+ const setOf = (scheme) => scheme === "dark" ? dark : colors;
531
+ const neededKeys = useMemo(
532
+ () => [
533
+ .../* @__PURE__ */ new Set([
534
+ ...CONTRAST_PAIRS.flatMap((p) => [p.fg, p.bg]),
535
+ ...CHART_KEYS,
536
+ ...SURFACE_SWATCHES.map(([k]) => k)
537
+ ])
538
+ ],
539
+ []
540
+ );
541
+ const lightMissing = neededKeys.filter((k) => colors[k] === void 0).join(",");
542
+ const darkMissing = neededKeys.filter((k) => dark[k] === void 0).join(",");
543
+ const pageLight = useMemo(
544
+ () => readDocumentTokens(lightMissing ? lightMissing.split(",") : [], "light"),
545
+ [lightMissing]
546
+ );
547
+ const pageDark = useMemo(
548
+ () => hasDark ? readDocumentTokens(darkMissing ? darkMissing.split(",") : [], "dark") : {},
549
+ [darkMissing, hasDark]
550
+ );
551
+ const resolve = (scheme) => (key) => setOf(scheme)[key] ?? (scheme === "dark" ? pageDark : pageLight)[key];
552
+ const issues = schemes.flatMap(
553
+ (scheme) => contrastIssues(resolve(scheme)).map((issue) => ({ ...issue, scheme }))
554
+ );
555
+ const fix = (issue) => store().setColor(issue.fg, issue.fix, issue.scheme);
556
+ const fixAll = () => {
557
+ for (const scheme of schemes) {
558
+ for (const pair of CONTRAST_PAIRS) {
559
+ const s = useStore.getState();
560
+ const set = scheme === "dark" ? s.dark : s.colors;
561
+ const lookup = (k) => set[k] ?? (scheme === "dark" ? pageDark : pageLight)[k];
562
+ const [issue] = contrastIssues(lookup, [pair]);
563
+ if (issue) s.setColor(issue.fg, issue.fix, scheme);
564
+ }
565
+ }
566
+ };
567
+ const save = async () => {
568
+ if (!onSave) return;
569
+ setSaving(true);
570
+ try {
571
+ const via = await onSave();
572
+ setSavedVia(typeof via === "string" ? via : "saved");
573
+ } catch {
574
+ setSavedVia(null);
575
+ } finally {
576
+ setSaving(false);
577
+ }
578
+ };
579
+ const onKeyDown = (e) => {
580
+ if (!(e.metaKey || e.ctrlKey) || isTextEntry(e.target)) return;
581
+ const key = e.key.toLowerCase();
582
+ if (key === "z" && !e.shiftKey) {
583
+ e.preventDefault();
584
+ store().undo();
585
+ } else if (key === "z" && e.shiftKey || key === "y") {
586
+ e.preventDefault();
587
+ store().redo();
588
+ }
589
+ };
590
+ const inputKeys = (input) => keysOfInput(input);
591
+ const setInput = useStore((s) => s.setInput);
592
+ const toolbarButton = "inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11";
593
+ const Toolbar = /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
594
+ presets.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": "Presets", children: [
595
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Start from" }),
596
+ presets.map((p) => /* @__PURE__ */ jsx(
597
+ "button",
598
+ {
599
+ type: "button",
600
+ onClick: () => store().applyPreset(p.id),
601
+ "aria-pressed": activePresetId === p.id,
602
+ className: cn(
603
+ "rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
604
+ activePresetId === p.id ? "border-primary bg-primary text-primary-foreground" : "border-input text-foreground hover:border-primary"
605
+ ),
606
+ "data-testid": tid(`preset-${p.id}`),
607
+ children: p.label
608
+ },
609
+ p.id
610
+ ))
611
+ ] }),
612
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1", children: [
613
+ /* @__PURE__ */ jsxs(
614
+ "button",
615
+ {
616
+ type: "button",
617
+ onClick: () => store().undo(),
618
+ disabled: !canUndo,
619
+ className: toolbarButton,
620
+ "aria-keyshortcuts": "Control+Z Meta+Z",
621
+ "data-testid": tid("undo"),
622
+ children: [
623
+ /* @__PURE__ */ jsx(Undo2, { className: "size-3.5", "aria-hidden": true }),
624
+ " Undo"
625
+ ]
626
+ }
627
+ ),
628
+ /* @__PURE__ */ jsxs(
629
+ "button",
630
+ {
631
+ type: "button",
632
+ onClick: () => store().redo(),
633
+ disabled: !canRedo,
634
+ className: toolbarButton,
635
+ "aria-keyshortcuts": "Control+Shift+Z Meta+Shift+Z",
636
+ "data-testid": tid("redo"),
637
+ children: [
638
+ /* @__PURE__ */ jsx(Redo2, { className: "size-3.5", "aria-hidden": true }),
639
+ " Redo"
640
+ ]
641
+ }
642
+ ),
643
+ /* @__PURE__ */ jsxs(
644
+ "button",
645
+ {
646
+ type: "button",
647
+ onClick: () => store().reset(),
648
+ className: toolbarButton,
649
+ "data-testid": tid("reset"),
650
+ children: [
651
+ /* @__PURE__ */ jsx(RotateCcw, { className: "size-3.5", "aria-hidden": true }),
652
+ " Reset"
653
+ ]
654
+ }
655
+ ),
656
+ hasDark && /* @__PURE__ */ jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsx(
657
+ Segmented,
658
+ {
659
+ label: "Preview",
660
+ value: previewMode,
661
+ options: [
662
+ { value: "light", label: "Light" },
663
+ { value: "dark", label: "Dark" },
664
+ ...variant === "panel" ? [{ value: "both", label: "Both" }] : []
665
+ ],
666
+ onChange: setPreviewMode,
667
+ keys: [],
668
+ onHint: () => void 0,
669
+ testId: tid("preview-mode")
670
+ }
671
+ ) })
672
+ ] })
673
+ ] });
674
+ const Warning = issues.length > 0 && /* @__PURE__ */ jsxs(
675
+ "div",
676
+ {
677
+ className: "flex flex-wrap items-center gap-2 rounded-md border border-yellow-border bg-yellow-bg px-3 py-2 text-sm text-yellow-text",
678
+ "data-testid": tid("contrast-warning"),
679
+ children: [
680
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "size-4 shrink-0", "aria-hidden": true }),
681
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
682
+ issues.length === 1 ? "1 colour pair is hard to read." : `${issues.length} colour pairs are hard to read.`,
683
+ " ",
684
+ "See Text and readability."
685
+ ] }),
686
+ /* @__PURE__ */ jsxs(
687
+ "button",
688
+ {
689
+ type: "button",
690
+ onClick: fixAll,
691
+ className: "inline-flex items-center gap-1 rounded-md border border-yellow-border bg-background px-2 py-1 text-xs font-medium text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
692
+ "data-testid": tid("fix-all"),
693
+ children: [
694
+ /* @__PURE__ */ jsx(Wand2, { className: "size-3.5", "aria-hidden": true }),
695
+ " Fix all"
696
+ ]
697
+ }
698
+ )
699
+ ]
700
+ }
701
+ );
702
+ const section = (id, body) => /* @__PURE__ */ jsxs(
703
+ "section",
704
+ {
705
+ "aria-labelledby": tid(`section-${id}-title`),
706
+ className: "rounded-lg border border-border bg-card p-4",
707
+ "data-testid": tid(`section-${id}`),
708
+ children: [
709
+ /* @__PURE__ */ jsx("h3", { id: tid(`section-${id}-title`), className: "text-sm font-semibold text-foreground", children: SECTION_COPY[id].title }),
710
+ /* @__PURE__ */ jsx("p", { className: "mb-4 mt-0.5 text-xs text-muted-foreground", children: SECTION_COPY[id].affects }),
711
+ /* @__PURE__ */ jsx("div", { className: "space-y-4", children: body })
712
+ ]
713
+ }
714
+ );
715
+ const swatch = (key, title, scheme = "light") => {
716
+ const value = resolve(scheme)(key);
717
+ return /* @__PURE__ */ jsx(
718
+ "span",
719
+ {
720
+ title,
721
+ className: "inline-block size-6 rounded-md border border-border",
722
+ style: { background: value ? toCssColor(value) : "transparent" }
723
+ },
724
+ `${scheme}-${key}`
725
+ );
726
+ };
727
+ const activePairing = matchFontPairing(fonts);
728
+ const warmthWords = Math.abs(inputs.warmth) < 0.05 ? "Neutral" : `${inputs.warmth > 0 ? "Warm" : "Cool"} ${Math.round(Math.abs(inputs.warmth) * 100)}%`;
729
+ const Brand = section(
730
+ "brand",
731
+ /* @__PURE__ */ jsxs(Fragment, { children: [
732
+ /* @__PURE__ */ jsx(
733
+ ColorField,
734
+ {
735
+ label: "Primary colour",
736
+ hint: "Filled buttons, links, the active tab, focus rings.",
737
+ value: inputs.primary,
738
+ onChange: (v) => setInput("primary", v),
739
+ keys: inputKeys("primary"),
740
+ onHint: setHint,
741
+ testIds: { color: tid("color-primary"), hex: tid("hex-primary") }
742
+ }
743
+ ),
744
+ /* @__PURE__ */ jsx(
745
+ ColorField,
746
+ {
747
+ label: "Accent colour",
748
+ hint: "Highlights, AI actions, the second chart series.",
749
+ value: inputs.accent,
750
+ onChange: (v) => setInput("accent", v),
751
+ keys: inputKeys("accent"),
752
+ onHint: setHint,
753
+ testIds: { color: tid("color-accent"), hex: tid("hex-accent") }
754
+ }
755
+ ),
756
+ /* @__PURE__ */ jsx(
757
+ SliderField,
758
+ {
759
+ label: "Corner radius",
760
+ valueText: radius === 0 ? "Square" : `${radius}rem`,
761
+ value: radius,
762
+ min: 0,
763
+ max: 1.5,
764
+ step: 0.125,
765
+ onChange: (v) => store().setRadius(v),
766
+ ends: ["Square", "Round"],
767
+ keys: [RADIUS],
768
+ onHint: setHint,
769
+ testId: tid("radius")
770
+ }
771
+ ),
772
+ /* @__PURE__ */ jsx(
773
+ SelectField,
774
+ {
775
+ label: "Typeface pairing",
776
+ value: activePairing?.id ?? "",
777
+ options: [
778
+ ...activePairing ? [] : [{ value: "", label: "Custom" }],
779
+ ...FONT_PAIRINGS.map((p) => ({ value: p.id, label: p.label }))
780
+ ],
781
+ onChange: (id) => store().setFontPairing(id),
782
+ keys: [FONT_DISPLAY, FONT_SANS],
783
+ onHint: setHint,
784
+ testId: tid("font-pairing"),
785
+ hint: activePairing?.description ?? "Faces chosen one by one."
786
+ }
787
+ ),
788
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 @md:grid-cols-2", children: [
789
+ /* @__PURE__ */ jsx(
790
+ SelectField,
791
+ {
792
+ label: "Headings",
793
+ value: fonts.display,
794
+ options: faceOptions(
795
+ fonts.display,
796
+ FONT_PAIRINGS.flatMap((p) => [p.display, p.sans])
797
+ ),
798
+ onChange: (v) => store().setFont("display", v),
799
+ keys: [FONT_DISPLAY],
800
+ onHint: setHint,
801
+ testId: tid("font-display-face")
802
+ }
803
+ ),
804
+ /* @__PURE__ */ jsx(
805
+ SelectField,
806
+ {
807
+ label: "Body text",
808
+ value: fonts.sans,
809
+ options: faceOptions(
810
+ fonts.sans,
811
+ FONT_PAIRINGS.map((p) => p.sans)
812
+ ),
813
+ onChange: (v) => store().setFont("sans", v),
814
+ keys: [FONT_SANS],
815
+ onHint: setHint,
816
+ testId: tid("font-sans-face")
817
+ }
818
+ )
819
+ ] })
820
+ ] })
821
+ );
822
+ const Surfaces = section(
823
+ "surfaces",
824
+ /* @__PURE__ */ jsxs(Fragment, { children: [
825
+ /* @__PURE__ */ jsx(
826
+ SliderField,
827
+ {
828
+ label: "Surface tone",
829
+ valueText: warmthWords,
830
+ value: inputs.warmth,
831
+ min: -1,
832
+ max: 1,
833
+ step: 0.05,
834
+ onChange: (v) => setInput("warmth", v),
835
+ ends: ["Cool", "Warm"],
836
+ keys: inputKeys("warmth"),
837
+ onHint: setHint,
838
+ testId: tid("warmth")
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsxs("div", { children: [
842
+ /* @__PURE__ */ jsx("p", { className: "mb-1 text-sm font-medium text-foreground", children: "Sidebar" }),
843
+ /* @__PURE__ */ jsx(
844
+ Segmented,
845
+ {
846
+ label: "Sidebar",
847
+ value: inputs.sidebar,
848
+ options: [
849
+ { value: "light", label: "Light" },
850
+ { value: "brand", label: "Brand panel" }
851
+ ],
852
+ onChange: (v) => setInput("sidebar", v),
853
+ keys: inputKeys("sidebar"),
854
+ onHint: setHint,
855
+ testId: tid("sidebar-style")
856
+ }
857
+ )
858
+ ] }),
859
+ /* @__PURE__ */ jsxs(
860
+ "div",
861
+ {
862
+ ...hintProps(
863
+ SURFACE_SWATCHES.map(([k]) => k),
864
+ setHint
865
+ ),
866
+ children: [
867
+ /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs text-muted-foreground", children: "Derived from the tone" }),
868
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", "data-testid": tid("surface-swatches"), children: SURFACE_SWATCHES.map(([key, title]) => swatch(key, title)) })
869
+ ]
870
+ }
871
+ )
872
+ ] })
873
+ );
874
+ const Text = section(
875
+ "text",
876
+ /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border text-sm", "data-testid": tid("contrast-list"), children: CONTRAST_PAIRS.map((pair) => /* @__PURE__ */ jsxs(
877
+ "li",
878
+ {
879
+ className: "flex flex-wrap items-center gap-2 py-2",
880
+ ...hintProps([pair.fg, pair.bg], setHint),
881
+ children: [
882
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 text-foreground", children: pair.label }),
883
+ schemes.map((scheme) => {
884
+ const lookup = resolve(scheme);
885
+ const fg = lookup(pair.fg);
886
+ const bg = lookup(pair.bg);
887
+ const ratio = fg && bg ? contrastRatio(fg, bg) : null;
888
+ const issue = issues.find(
889
+ (i) => i.scheme === scheme && i.fg === pair.fg && i.bg === pair.bg
890
+ );
891
+ const word = hasDark ? scheme === "dark" ? "Dark " : "Light " : "";
892
+ if (ratio === null) {
893
+ return /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
894
+ word,
895
+ "n/a"
896
+ ] }, scheme);
897
+ }
898
+ return issue ? /* @__PURE__ */ jsxs(
899
+ "button",
900
+ {
901
+ type: "button",
902
+ onClick: () => fix(issue),
903
+ className: "inline-flex items-center gap-1 rounded-full border border-red-border bg-red-bg px-2 py-0.5 text-xs font-medium text-red-text hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
904
+ "aria-label": `${pair.label}${word ? `, ${word.trim().toLowerCase()}` : ""}: ${ratio.toFixed(1)} to 1, below ${pair.min}. Fix`,
905
+ "data-testid": tid(`fix-${pair.fg}-${pair.bg}-${scheme}`),
906
+ children: [
907
+ word,
908
+ ratio.toFixed(1),
909
+ ":1 \xB7 Fix"
910
+ ]
911
+ },
912
+ scheme
913
+ ) : /* @__PURE__ */ jsxs(
914
+ "span",
915
+ {
916
+ className: "inline-flex items-center gap-1 rounded-full border border-green-border bg-green-bg px-2 py-0.5 text-xs font-medium text-green-text",
917
+ children: [
918
+ /* @__PURE__ */ jsx(Check, { className: "size-3", "aria-hidden": true }),
919
+ word,
920
+ ratio.toFixed(1),
921
+ ":1"
922
+ ]
923
+ },
924
+ scheme
925
+ );
926
+ })
927
+ ]
928
+ },
929
+ `${pair.fg}/${pair.bg}`
930
+ )) })
931
+ );
932
+ const Status = section(
933
+ "status",
934
+ /* @__PURE__ */ jsxs(Fragment, { children: [
935
+ /* @__PURE__ */ jsx(
936
+ ColorField,
937
+ {
938
+ label: "Danger",
939
+ hint: "Errors, destructive actions.",
940
+ value: inputs.danger,
941
+ onChange: (v) => setInput("danger", v),
942
+ keys: inputKeys("danger"),
943
+ onHint: setHint,
944
+ testIds: { color: tid("color-danger"), hex: tid("hex-danger") }
945
+ }
946
+ ),
947
+ /* @__PURE__ */ jsx(
948
+ ColorField,
949
+ {
950
+ label: "Success",
951
+ hint: "Completed, approved, healthy.",
952
+ value: inputs.success,
953
+ onChange: (v) => setInput("success", v),
954
+ keys: inputKeys("success"),
955
+ onHint: setHint,
956
+ testIds: { color: tid("color-success"), hex: tid("hex-success") }
957
+ }
958
+ ),
959
+ /* @__PURE__ */ jsx(
960
+ ColorField,
961
+ {
962
+ label: "Warning",
963
+ hint: "Needs attention soon.",
964
+ value: inputs.warning,
965
+ onChange: (v) => setInput("warning", v),
966
+ keys: inputKeys("warning"),
967
+ onHint: setHint,
968
+ testIds: { color: tid("color-warning"), hex: tid("hex-warning") }
969
+ }
970
+ )
971
+ ] })
972
+ );
973
+ const Charts = section(
974
+ "charts",
975
+ /* @__PURE__ */ jsxs(Fragment, { children: [
976
+ /* @__PURE__ */ jsx(
977
+ Segmented,
978
+ {
979
+ label: "Chart colours",
980
+ value: inputs.charts,
981
+ options: [
982
+ { value: "harmonious", label: "In harmony with the brand" },
983
+ { value: "distinct", label: "Distinct hues" }
984
+ ],
985
+ onChange: (v) => setInput("charts", v),
986
+ keys: inputKeys("charts"),
987
+ onHint: setHint,
988
+ testId: tid("chart-style")
989
+ }
990
+ ),
991
+ /* @__PURE__ */ jsx(
992
+ "div",
993
+ {
994
+ className: "flex gap-1.5",
995
+ "data-testid": tid("chart-swatches"),
996
+ ...hintProps(CHART_KEYS, setHint),
997
+ children: CHART_KEYS.map((key, i) => swatch(key, `Series ${i + 1}`))
998
+ }
999
+ )
1000
+ ] })
1001
+ );
1002
+ const editScheme = previewMode === "dark" ? "dark" : "light";
1003
+ const groups = [...new Set(tokens.map((t) => t.group))];
1004
+ const Advanced = /* @__PURE__ */ jsxs(
1005
+ "section",
1006
+ {
1007
+ "aria-labelledby": tid("section-advanced-title"),
1008
+ className: "rounded-lg border border-border bg-card p-4",
1009
+ "data-testid": tid("section-advanced"),
1010
+ children: [
1011
+ /* @__PURE__ */ jsxs(
1012
+ "button",
1013
+ {
1014
+ type: "button",
1015
+ onClick: () => setAdvancedOpen((o) => !o),
1016
+ "aria-expanded": advancedOpen,
1017
+ "aria-controls": tid("advanced"),
1018
+ className: "flex w-full items-center justify-between gap-2 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1019
+ "data-testid": tid("advanced-toggle"),
1020
+ children: [
1021
+ /* @__PURE__ */ jsxs("span", { children: [
1022
+ /* @__PURE__ */ jsx(
1023
+ "span",
1024
+ {
1025
+ id: tid("section-advanced-title"),
1026
+ className: "block text-sm font-semibold text-foreground",
1027
+ children: SECTION_COPY.advanced.title
1028
+ }
1029
+ ),
1030
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-xs text-muted-foreground", children: SECTION_COPY.advanced.affects })
1031
+ ] }),
1032
+ /* @__PURE__ */ jsx(
1033
+ ChevronDown,
1034
+ {
1035
+ className: cn("size-4 shrink-0 transition-transform", advancedOpen && "rotate-180"),
1036
+ "aria-hidden": true
1037
+ }
1038
+ )
1039
+ ]
1040
+ }
1041
+ ),
1042
+ advancedOpen && /* @__PURE__ */ jsxs("div", { id: tid("advanced"), className: "mt-4 space-y-5", "data-testid": tid("advanced"), children: [
1043
+ hasDark && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
1044
+ "Editing the ",
1045
+ editScheme,
1046
+ " colours. Switch the preview to edit the other set."
1047
+ ] }),
1048
+ groups.map((group) => /* @__PURE__ */ jsxs("div", { className: "space-y-3", "data-testid": tid(`group-${group}`), children: [
1049
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: groupLabels[group] ?? group }),
1050
+ tokens.filter((t) => t.group === group).map((t) => /* @__PURE__ */ jsx(
1051
+ ColorField,
1052
+ {
1053
+ label: t.label,
1054
+ value: setOf(editScheme)[t.key] ?? resolve(editScheme)(t.key) ?? "#000000",
1055
+ onChange: (v) => store().setColor(t.key, v, editScheme),
1056
+ keys: [t.key],
1057
+ onHint: setHint,
1058
+ testIds: { color: tid(`token-${t.key}`), hex: tid(`token-hex-${t.key}`) },
1059
+ trailing: overrides.includes(t.key) && /* @__PURE__ */ jsx(
1060
+ "button",
1061
+ {
1062
+ type: "button",
1063
+ onClick: () => store().clearOverride(t.key),
1064
+ className: "shrink-0 rounded-md px-1.5 py-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1065
+ "aria-label": `Reset ${t.label} to follow the brand inputs`,
1066
+ "data-testid": tid(`token-reset-${t.key}`),
1067
+ children: "Reset"
1068
+ }
1069
+ )
1070
+ },
1071
+ t.key
1072
+ ))
1073
+ ] }, group)),
1074
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1075
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "Font stacks" }),
1076
+ ["display", "sans"].map((which) => /* @__PURE__ */ jsxs("label", { className: "block text-sm font-medium text-foreground", children: [
1077
+ which === "display" ? "Headings stack" : "Body stack",
1078
+ /* @__PURE__ */ jsx(
1079
+ "input",
1080
+ {
1081
+ value: fonts[which],
1082
+ onChange: (e) => store().setFont(which, e.target.value),
1083
+ spellCheck: false,
1084
+ className: "mt-1 h-8 w-full rounded-md border border-input bg-background px-2 font-mono text-xs text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1085
+ "data-testid": tid(which === "display" ? "font-display" : "font-sans")
1086
+ }
1087
+ )
1088
+ ] }, which))
1089
+ ] })
1090
+ ] })
1091
+ ]
1092
+ }
1093
+ );
1094
+ const Sections = /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1095
+ Brand,
1096
+ Surfaces,
1097
+ Text,
1098
+ Status,
1099
+ Charts,
1100
+ Advanced
1101
+ ] });
1102
+ const previewFor = (scheme, testId, compact) => /* @__PURE__ */ jsx(
1103
+ ThemePreview,
1104
+ {
1105
+ colors: setOf(scheme),
1106
+ fonts,
1107
+ radius,
1108
+ scheme,
1109
+ highlight,
1110
+ compact,
1111
+ labels: previewLabels,
1112
+ title: preview?.title,
1113
+ subtitle: preview?.subtitle,
1114
+ testId
1115
+ },
1116
+ scheme
1117
+ );
1118
+ const Previews = (compact) => {
1119
+ const shown = previewMode === "both" && hasDark ? ["light", "dark"] : [hasDark ? previewMode : "light"];
1120
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", "aria-label": "Live preview", role: "group", children: [
1121
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", "aria-live": "polite", children: [
1122
+ "Live preview",
1123
+ shown.length > 1 ? ", light and dark" : hasDark ? `, ${shown[0]}` : "",
1124
+ ". Point at a control to see what it changes."
1125
+ ] }),
1126
+ shown.map(
1127
+ (scheme, i) => previewFor(scheme, i === 0 ? tid("preview") : tid(`preview-${scheme}`), compact)
1128
+ )
1129
+ ] });
1130
+ };
1131
+ const SaveBar = onSave && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1132
+ /* @__PURE__ */ jsxs(
1133
+ "button",
1134
+ {
1135
+ type: "button",
1136
+ onClick: () => void save(),
1137
+ disabled: saving,
1138
+ className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1139
+ "data-testid": tid("save"),
1140
+ children: [
1141
+ savedVia ? /* @__PURE__ */ jsx(Check, { className: "size-4" }) : /* @__PURE__ */ jsx(Save, { className: "size-4" }),
1142
+ saving ? "Saving\u2026" : savedVia ? "Saved" : "Save theme"
1143
+ ]
1144
+ }
1145
+ ),
1146
+ savedVia && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", "data-testid": tid("via"), children: [
1147
+ "stored via ",
1148
+ savedVia
1149
+ ] })
1150
+ ] });
1151
+ if (variant === "collapsed") {
1152
+ const controlsId = tid("controls");
1153
+ return /* @__PURE__ */ jsxs("div", { className: "@container space-y-3", "data-testid": testIdPrefix, onKeyDown, children: [
1154
+ Toolbar,
1155
+ Warning,
1156
+ /* @__PURE__ */ jsxs(
1157
+ "button",
1158
+ {
1159
+ type: "button",
1160
+ onClick: () => setOpen((o) => !o),
1161
+ "aria-expanded": open,
1162
+ "aria-controls": controlsId,
1163
+ className: "inline-flex items-center gap-1.5 text-sm font-medium text-foreground hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1164
+ "data-testid": tid("customize"),
1165
+ children: [
1166
+ /* @__PURE__ */ jsx(
1167
+ ChevronDown,
1168
+ {
1169
+ className: cn("size-4 transition-transform", open && "rotate-180"),
1170
+ "aria-hidden": true
1171
+ }
1172
+ ),
1173
+ "Customize colours and type"
1174
+ ]
1175
+ }
1176
+ ),
1177
+ open && /* @__PURE__ */ jsxs(
1178
+ "div",
1179
+ {
1180
+ id: controlsId,
1181
+ className: "grid max-h-[36rem] gap-4 overflow-y-auto rounded-md border border-border p-3 @3xl:grid-cols-[minmax(0,1fr)_minmax(0,22rem)]",
1182
+ "data-testid": tid("controls"),
1183
+ children: [
1184
+ Sections,
1185
+ /* @__PURE__ */ jsx("div", { className: "@3xl:sticky @3xl:top-0 @3xl:self-start", children: Previews(true) })
1186
+ ]
1187
+ }
1188
+ ),
1189
+ SaveBar
1190
+ ] });
1191
+ }
1192
+ if (variant === "drawer") {
1193
+ return /* @__PURE__ */ jsxs(
1194
+ "div",
1195
+ {
1196
+ className: "@container flex h-full flex-col gap-4 overflow-y-auto bg-background p-4",
1197
+ "data-testid": testIdPrefix,
1198
+ onKeyDown,
1199
+ children: [
1200
+ /* @__PURE__ */ jsx("h2", { className: "font-display text-lg font-semibold text-foreground", children: "Theme" }),
1201
+ Toolbar,
1202
+ Warning,
1203
+ Previews(true),
1204
+ Sections,
1205
+ SaveBar
1206
+ ]
1207
+ }
1208
+ );
1209
+ }
1210
+ return /* @__PURE__ */ jsxs("div", { className: "@container space-y-4", "data-testid": testIdPrefix, onKeyDown, children: [
1211
+ Toolbar,
1212
+ Warning,
1213
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(0,30rem)]", children: [
1214
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-4", children: [
1215
+ Sections,
1216
+ SaveBar
1217
+ ] }),
1218
+ /* @__PURE__ */ jsx("div", { className: "order-first min-w-0 lg:order-none lg:sticky lg:top-4 lg:self-start", children: Previews(false) })
1219
+ ] })
1220
+ ] });
1221
+ }
1222
+
1223
+ export { ThemeEditor, ThemePreview };
1224
+ //# sourceMappingURL=chunk-C2S246BV.js.map
1225
+ //# sourceMappingURL=chunk-C2S246BV.js.map