@glyphui/ui 0.2.0 → 0.4.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 (116) hide show
  1. package/README.md +65 -12
  2. package/dist/chart.d.ts +202 -0
  3. package/dist/chart.js +466 -0
  4. package/dist/color-mode-script-Bf7LYkOj.js +13 -0
  5. package/dist/color-mode-script-KdwItKN2.d.ts +16 -0
  6. package/dist/data-table.js +3 -2
  7. package/dist/{field-CCecIzdq.js → field-CVbywksE.js} +21 -5
  8. package/dist/{field-context-B6WOcK5m.js → field-context-7I-cWvvS.js} +3 -57
  9. package/dist/form.d.ts +11 -4
  10. package/dist/form.js +34 -8
  11. package/dist/glyph-context-DxGJrdvr.d.ts +50 -0
  12. package/dist/{index-BWK4czIG.d.ts → index-Bi7rZ6ba.d.ts} +11 -0
  13. package/dist/index.d.ts +2334 -283
  14. package/dist/index.js +2952 -326
  15. package/dist/react-router.d.ts +18 -0
  16. package/dist/react-router.js +44 -0
  17. package/dist/{states-Rp8wZ_jH.js → states-IvhjBgna.js} +2 -1
  18. package/dist/tv-DLbT66dC.js +70 -0
  19. package/dist/vite.d.ts +27 -0
  20. package/dist/vite.js +29 -0
  21. package/fonts.css +10 -0
  22. package/package.json +47 -5
  23. package/src/components/accordion/accordion.styles.ts +4 -4
  24. package/src/components/badge/badge.styles.ts +11 -16
  25. package/src/components/banner/banner.styles.ts +4 -4
  26. package/src/components/button/button.styles.ts +3 -1
  27. package/src/components/calendar/calendar.styles.ts +51 -0
  28. package/src/components/calendar/calendar.tsx +84 -0
  29. package/src/components/calendar/index.ts +3 -0
  30. package/src/components/carousel/carousel.styles.ts +43 -0
  31. package/src/components/carousel/carousel.tsx +278 -0
  32. package/src/components/carousel/index.ts +13 -0
  33. package/src/components/collapsible/collapsible.tsx +66 -0
  34. package/src/components/collapsible/index.ts +6 -0
  35. package/src/components/context-menu/context-menu.styles.ts +19 -0
  36. package/src/components/context-menu/context-menu.tsx +226 -0
  37. package/src/components/context-menu/index.ts +19 -0
  38. package/src/components/copy-button/copy-button.tsx +117 -0
  39. package/src/components/copy-button/index.ts +1 -0
  40. package/src/components/date-picker/date-picker.styles.ts +42 -0
  41. package/src/components/date-picker/date-picker.tsx +322 -0
  42. package/src/components/date-picker/index.ts +8 -0
  43. package/src/components/dropdown-menu/dropdown-menu.styles.ts +2 -2
  44. package/src/components/eyebrow/eyebrow.styles.ts +1 -1
  45. package/src/components/field/field-context.ts +2 -0
  46. package/src/components/field/field.styles.ts +4 -2
  47. package/src/components/field/field.tsx +25 -4
  48. package/src/components/file-upload/file-upload.styles.ts +43 -0
  49. package/src/components/file-upload/file-upload.tsx +343 -0
  50. package/src/components/file-upload/index.ts +10 -0
  51. package/src/components/hover-card/hover-card.tsx +41 -0
  52. package/src/components/hover-card/index.ts +1 -0
  53. package/src/components/input-otp/index.ts +10 -0
  54. package/src/components/input-otp/input-otp.styles.ts +38 -0
  55. package/src/components/input-otp/input-otp.tsx +116 -0
  56. package/src/components/link/link.styles.ts +1 -1
  57. package/src/components/modal/index.ts +2 -0
  58. package/src/components/modal/modal.styles.ts +20 -0
  59. package/src/components/modal/modal.tsx +111 -0
  60. package/src/components/navigation-menu/index.ts +14 -0
  61. package/src/components/navigation-menu/navigation-menu.styles.ts +48 -0
  62. package/src/components/navigation-menu/navigation-menu.tsx +208 -0
  63. package/src/components/number-input/index.ts +2 -0
  64. package/src/components/number-input/number-input.styles.ts +41 -0
  65. package/src/components/number-input/number-input.tsx +211 -0
  66. package/src/components/password-input/index.ts +7 -0
  67. package/src/components/password-input/password-input.styles.ts +30 -0
  68. package/src/components/password-input/password-input.tsx +127 -0
  69. package/src/components/prose/prose.tsx +1 -1
  70. package/src/components/resizable/index.ts +9 -0
  71. package/src/components/resizable/resizable.styles.ts +28 -0
  72. package/src/components/resizable/resizable.tsx +69 -0
  73. package/src/components/scroll-area/scroll-area.tsx +23 -1
  74. package/src/components/segmented-control/segmented-control.tsx +17 -2
  75. package/src/components/sheet/sheet.styles.ts +7 -7
  76. package/src/components/slider/slider.tsx +9 -2
  77. package/src/components/stepper/index.ts +2 -0
  78. package/src/components/stepper/stepper.styles.ts +74 -0
  79. package/src/components/stepper/stepper.tsx +138 -0
  80. package/src/components/tag-input/index.ts +2 -0
  81. package/src/components/tag-input/tag-input.styles.ts +39 -0
  82. package/src/components/tag-input/tag-input.tsx +198 -0
  83. package/src/components/text/text.styles.ts +4 -4
  84. package/src/components/timeline/index.ts +8 -0
  85. package/src/components/timeline/timeline.styles.ts +56 -0
  86. package/src/components/timeline/timeline.tsx +91 -0
  87. package/src/components/toggle/index.ts +9 -0
  88. package/src/components/toggle/toggle.styles.ts +39 -0
  89. package/src/components/toggle/toggle.tsx +61 -0
  90. package/src/components/tree-view/index.ts +2 -0
  91. package/src/components/tree-view/tree-view.styles.ts +42 -0
  92. package/src/components/tree-view/tree-view.tsx +274 -0
  93. package/src/components/visually-hidden/index.ts +1 -0
  94. package/src/components/visually-hidden/visually-hidden.tsx +10 -0
  95. package/src/index.ts +20 -0
  96. package/src/integrations/react-router.tsx +39 -0
  97. package/src/integrations/vite.test-d.ts +6 -0
  98. package/src/integrations/vite.test.ts +28 -0
  99. package/src/integrations/vite.ts +33 -0
  100. package/src/internal/dev.ts +12 -0
  101. package/src/patterns/app-shell/app-shell.styles.ts +1 -1
  102. package/src/patterns/app-shell/navbar.tsx +34 -16
  103. package/src/patterns/app-shell/sidebar.tsx +7 -2
  104. package/src/patterns/chart/chart-parts.tsx +179 -0
  105. package/src/patterns/chart/chart.styles.ts +35 -0
  106. package/src/patterns/chart/chart.tsx +386 -0
  107. package/src/patterns/chart/index.ts +13 -0
  108. package/src/patterns/form/form.tsx +48 -6
  109. package/src/patterns/form/index.ts +1 -0
  110. package/src/provider/color-mode-script.ts +28 -0
  111. package/src/provider/color-mode.tsx +14 -20
  112. package/src/provider/glyph-context.ts +38 -0
  113. package/src/provider/glyph-provider.tsx +16 -4
  114. package/src/provider/index.ts +4 -0
  115. package/src/provider/theme-scope.tsx +7 -3
  116. package/styles.css +88 -0
package/dist/chart.js ADDED
@@ -0,0 +1,466 @@
1
+ "use client";
2
+ import { a as themedBorder, s as useComponentConfig, t as tv } from "./tv-DLbT66dC.js";
3
+ import { useId } from "react";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ import * as R from "recharts";
6
+ //#region src/patterns/chart/chart.styles.ts
7
+ const chartStyles = tv({ slots: {
8
+ root: "m-0 grid min-w-0 gap-3",
9
+ caption: "grid gap-0.5",
10
+ title: "text-small font-medium text-foreground",
11
+ description: "text-caption text-muted-foreground",
12
+ plot: "min-w-0 [&_.recharts-surface]:overflow-visible [&_.recharts-text]:fill-muted-foreground",
13
+ legend: "flex flex-wrap items-center gap-x-4 gap-y-1 text-caption text-muted-foreground",
14
+ legendItem: "inline-flex items-center gap-1.5",
15
+ swatch: "size-2.5 shrink-0 rounded-[2px]",
16
+ tooltip: ["grid min-w-36 gap-1.5 rounded-md border-border bg-raised px-3 py-2 text-caption text-foreground shadow-lg", themedBorder],
17
+ tooltipLabel: "font-medium text-foreground",
18
+ tooltipRow: "flex items-center gap-2",
19
+ tooltipName: "flex-1 text-muted-foreground",
20
+ tooltipValue: "font-mono font-medium tabular-nums text-foreground",
21
+ center: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center",
22
+ srOnly: "sr-only"
23
+ } });
24
+ //#endregion
25
+ //#region src/patterns/chart/chart-parts.tsx
26
+ /** Series without a color use the theme's chart palette, in order. */
27
+ const palette = [
28
+ "chart-1",
29
+ "chart-2",
30
+ "chart-3",
31
+ "chart-4",
32
+ "chart-5"
33
+ ];
34
+ function resolveColor(color, index) {
35
+ const value = color ?? palette[index % palette.length];
36
+ return /^[a-z][a-z\d-]*$/.test(value) ? `var(--color-${value})` : value;
37
+ }
38
+ const defaultFormatter = (value) => typeof value === "number" ? value.toLocaleString() : String(value);
39
+ function useChartParts() {
40
+ const [, slots] = useComponentConfig("Chart", {});
41
+ return {
42
+ s: chartStyles(),
43
+ slots
44
+ };
45
+ }
46
+ function ChartLegend({ items }) {
47
+ const { s, slots } = useChartParts();
48
+ return /* @__PURE__ */ jsx("ul", {
49
+ "data-slot": "chart-legend",
50
+ className: s.legend({ class: slots.legend }),
51
+ "aria-hidden": "true",
52
+ children: items.map((item, i) => /* @__PURE__ */ jsxs("li", {
53
+ className: s.legendItem({ class: slots.legendItem }),
54
+ children: [/* @__PURE__ */ jsx("span", {
55
+ className: s.swatch({ class: slots.swatch }),
56
+ style: { background: item.color }
57
+ }), item.label]
58
+ }, i))
59
+ });
60
+ }
61
+ function ChartTooltipCard({ active, payload, label, formatter, labelFormatter }) {
62
+ const { s, slots } = useChartParts();
63
+ if (!active || !payload?.length) return null;
64
+ return /* @__PURE__ */ jsxs("div", {
65
+ "data-slot": "chart-tooltip",
66
+ className: s.tooltip({ class: slots.tooltip }),
67
+ children: [label !== void 0 && label !== "" && /* @__PURE__ */ jsx("p", {
68
+ className: s.tooltipLabel({ class: slots.tooltipLabel }),
69
+ children: labelFormatter ? labelFormatter(label) : label
70
+ }), payload.map((item, i) => /* @__PURE__ */ jsxs("div", {
71
+ className: s.tooltipRow({ class: slots.tooltipRow }),
72
+ children: [
73
+ /* @__PURE__ */ jsx("span", {
74
+ className: s.swatch({ class: slots.swatch }),
75
+ style: { background: item.color ?? item.payload?.fill }
76
+ }),
77
+ /* @__PURE__ */ jsx("span", {
78
+ className: s.tooltipName({ class: slots.tooltipName }),
79
+ children: String(item.name ?? "")
80
+ }),
81
+ /* @__PURE__ */ jsx("span", {
82
+ className: s.tooltipValue({ class: slots.tooltipValue }),
83
+ children: formatter(Number(item.value))
84
+ })
85
+ ]
86
+ }, i))]
87
+ });
88
+ }
89
+ /**
90
+ * Wraps every chart in a `<figure>` with a caption and a visually hidden data table,
91
+ * so screen-reader users get the numbers the chart shows.
92
+ */
93
+ function ChartFrame({ title, description, hideTitle, className, legend, table, children }) {
94
+ const { s, slots } = useChartParts();
95
+ const titleId = useId();
96
+ return /* @__PURE__ */ jsxs("figure", {
97
+ "data-slot": "chart",
98
+ "aria-labelledby": titleId,
99
+ className: s.root({ class: [slots.root, className] }),
100
+ children: [
101
+ /* @__PURE__ */ jsxs("figcaption", {
102
+ className: hideTitle ? s.srOnly() : s.caption({ class: slots.caption }),
103
+ children: [/* @__PURE__ */ jsx("span", {
104
+ id: titleId,
105
+ className: s.title({ class: slots.title }),
106
+ children: title
107
+ }), description && /* @__PURE__ */ jsx("span", {
108
+ className: s.description({ class: slots.description }),
109
+ children: description
110
+ })]
111
+ }),
112
+ /* @__PURE__ */ jsx("div", {
113
+ className: s.plot({ class: slots.plot }),
114
+ "aria-hidden": "true",
115
+ children
116
+ }),
117
+ legend && legend.length > 1 && /* @__PURE__ */ jsx(ChartLegend, { items: legend }),
118
+ /* @__PURE__ */ jsxs("table", {
119
+ className: s.srOnly(),
120
+ children: [
121
+ /* @__PURE__ */ jsx("caption", { children: title }),
122
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: table.columns.map((column) => /* @__PURE__ */ jsx("th", {
123
+ scope: "col",
124
+ children: column
125
+ }, column)) }) }),
126
+ /* @__PURE__ */ jsx("tbody", { children: table.rows.map((row, i) => /* @__PURE__ */ jsx("tr", { children: row.map((cell, j) => j === 0 ? /* @__PURE__ */ jsx("th", {
127
+ scope: "row",
128
+ children: cell
129
+ }, j) : /* @__PURE__ */ jsx("td", { children: cell }, j)) }, i)) })
130
+ ]
131
+ })
132
+ ]
133
+ });
134
+ }
135
+ //#endregion
136
+ //#region src/patterns/chart/chart.tsx
137
+ const axisTick = {
138
+ fill: "var(--color-muted-foreground)",
139
+ fontSize: 12
140
+ };
141
+ function useCartesian(props) {
142
+ const { data, index, series, title, valueFormatter = defaultFormatter } = props;
143
+ const resolved = series.map((item, i) => ({
144
+ ...item,
145
+ label: item.label ?? item.key,
146
+ stroke: resolveColor(item.color, i)
147
+ }));
148
+ return {
149
+ resolved,
150
+ table: {
151
+ columns: [String(index), ...resolved.map((item) => item.label)],
152
+ rows: data.map((row) => [String(row[index]), ...resolved.map((item) => valueFormatter(Number(row[item.key])))])
153
+ },
154
+ legend: props.showLegend ?? series.length > 1 ? resolved.map((item) => ({
155
+ label: item.label,
156
+ color: item.stroke
157
+ })) : void 0,
158
+ valueFormatter,
159
+ title
160
+ };
161
+ }
162
+ function frameProps(props) {
163
+ return {
164
+ title: props.title,
165
+ description: props.description,
166
+ hideTitle: props.hideTitle,
167
+ className: props.className
168
+ };
169
+ }
170
+ function Axes({ index, showGrid = true, showYAxis = true, valueFormatter }) {
171
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
172
+ showGrid && /* @__PURE__ */ jsx(R.CartesianGrid, {
173
+ vertical: false,
174
+ stroke: "var(--color-border)",
175
+ strokeDasharray: "3 3"
176
+ }),
177
+ /* @__PURE__ */ jsx(R.XAxis, {
178
+ dataKey: index,
179
+ tick: axisTick,
180
+ tickLine: false,
181
+ axisLine: false,
182
+ tickMargin: 8,
183
+ minTickGap: 16
184
+ }),
185
+ showYAxis && /* @__PURE__ */ jsx(R.YAxis, {
186
+ tick: axisTick,
187
+ tickLine: false,
188
+ axisLine: false,
189
+ width: 48,
190
+ tickFormatter: valueFormatter
191
+ })
192
+ ] });
193
+ }
194
+ function tooltip(valueFormatter, cursor) {
195
+ return /* @__PURE__ */ jsx(R.Tooltip, {
196
+ cursor,
197
+ content: (p) => /* @__PURE__ */ jsx(ChartTooltipCard, {
198
+ active: p.active,
199
+ payload: p.payload,
200
+ label: p.label,
201
+ formatter: valueFormatter
202
+ })
203
+ });
204
+ }
205
+ /** Trends over time, one line per series. */
206
+ function LineChart(props) {
207
+ const { resolved, table, legend, valueFormatter } = useCartesian(props);
208
+ return /* @__PURE__ */ jsx(ChartFrame, {
209
+ ...frameProps(props),
210
+ legend,
211
+ table,
212
+ children: /* @__PURE__ */ jsx(R.ResponsiveContainer, {
213
+ width: "100%",
214
+ height: props.height ?? 240,
215
+ children: /* @__PURE__ */ jsxs(R.LineChart, {
216
+ accessibilityLayer: false,
217
+ data: props.data,
218
+ margin: {
219
+ top: 8,
220
+ right: 8,
221
+ bottom: 0,
222
+ left: 0
223
+ },
224
+ children: [
225
+ /* @__PURE__ */ jsx(Axes, {
226
+ index: props.index,
227
+ showGrid: props.showGrid,
228
+ showYAxis: props.showYAxis,
229
+ valueFormatter
230
+ }),
231
+ tooltip(valueFormatter, { stroke: "var(--color-border-strong)" }),
232
+ resolved.map((item) => /* @__PURE__ */ jsx(R.Line, {
233
+ dataKey: item.key,
234
+ name: item.label,
235
+ type: props.curve ?? "monotone",
236
+ stroke: item.stroke,
237
+ strokeWidth: 2,
238
+ dot: false,
239
+ activeDot: {
240
+ r: 4,
241
+ strokeWidth: 0
242
+ },
243
+ isAnimationActive: false
244
+ }, item.key))
245
+ ]
246
+ })
247
+ })
248
+ });
249
+ }
250
+ /** Trends with filled areas. `stacked` shows how series add up to a total. */
251
+ function AreaChart(props) {
252
+ const { resolved, table, legend, valueFormatter } = useCartesian(props);
253
+ const id = useId().replace(/:/g, "");
254
+ return /* @__PURE__ */ jsx(ChartFrame, {
255
+ ...frameProps(props),
256
+ legend,
257
+ table,
258
+ children: /* @__PURE__ */ jsx(R.ResponsiveContainer, {
259
+ width: "100%",
260
+ height: props.height ?? 240,
261
+ children: /* @__PURE__ */ jsxs(R.AreaChart, {
262
+ accessibilityLayer: false,
263
+ data: props.data,
264
+ margin: {
265
+ top: 8,
266
+ right: 8,
267
+ bottom: 0,
268
+ left: 0
269
+ },
270
+ children: [
271
+ /* @__PURE__ */ jsx("defs", { children: resolved.map((item, i) => /* @__PURE__ */ jsxs("linearGradient", {
272
+ id: `${id}-${i}`,
273
+ x1: "0",
274
+ x2: "0",
275
+ y1: "0",
276
+ y2: "1",
277
+ children: [/* @__PURE__ */ jsx("stop", {
278
+ offset: "0%",
279
+ stopColor: item.stroke,
280
+ stopOpacity: .3
281
+ }), /* @__PURE__ */ jsx("stop", {
282
+ offset: "100%",
283
+ stopColor: item.stroke,
284
+ stopOpacity: 0
285
+ })]
286
+ }, item.key)) }),
287
+ /* @__PURE__ */ jsx(Axes, {
288
+ index: props.index,
289
+ showGrid: props.showGrid,
290
+ showYAxis: props.showYAxis,
291
+ valueFormatter
292
+ }),
293
+ tooltip(valueFormatter, { stroke: "var(--color-border-strong)" }),
294
+ resolved.map((item, i) => /* @__PURE__ */ jsx(R.Area, {
295
+ dataKey: item.key,
296
+ name: item.label,
297
+ type: "monotone",
298
+ stroke: item.stroke,
299
+ strokeWidth: 2,
300
+ fill: `url(#${id}-${i})`,
301
+ ...props.stacked && { stackId: "stack" },
302
+ isAnimationActive: false
303
+ }, item.key))
304
+ ]
305
+ })
306
+ })
307
+ });
308
+ }
309
+ /** Compare values across categories. `stacked` puts series on top of each other. */
310
+ function BarChart(props) {
311
+ const { resolved, table, legend, valueFormatter } = useCartesian(props);
312
+ const radius = props.barRadius ?? 3;
313
+ return /* @__PURE__ */ jsx(ChartFrame, {
314
+ ...frameProps(props),
315
+ legend,
316
+ table,
317
+ children: /* @__PURE__ */ jsx(R.ResponsiveContainer, {
318
+ width: "100%",
319
+ height: props.height ?? 240,
320
+ children: /* @__PURE__ */ jsxs(R.BarChart, {
321
+ accessibilityLayer: false,
322
+ data: props.data,
323
+ margin: {
324
+ top: 8,
325
+ right: 8,
326
+ bottom: 0,
327
+ left: 0
328
+ },
329
+ children: [
330
+ /* @__PURE__ */ jsx(Axes, {
331
+ index: props.index,
332
+ showGrid: props.showGrid,
333
+ showYAxis: props.showYAxis,
334
+ valueFormatter
335
+ }),
336
+ tooltip(valueFormatter, {
337
+ fill: "var(--color-muted)",
338
+ opacity: .6
339
+ }),
340
+ resolved.map((item, i) => /* @__PURE__ */ jsx(R.Bar, {
341
+ dataKey: item.key,
342
+ name: item.label,
343
+ fill: item.stroke,
344
+ radius: props.stacked && i < resolved.length - 1 ? 0 : [
345
+ radius,
346
+ radius,
347
+ 0,
348
+ 0
349
+ ],
350
+ ...props.stacked && { stackId: "stack" },
351
+ isAnimationActive: false
352
+ }, item.key))
353
+ ]
354
+ })
355
+ })
356
+ });
357
+ }
358
+ /** Parts of a whole. Best with five or fewer slices. */
359
+ function DonutChart(props) {
360
+ const { data, category, value, valueFormatter = defaultFormatter, size = 200 } = props;
361
+ const { s, slots } = useChartParts();
362
+ const rows = data.map((row) => row);
363
+ const colors = rows.map((_, i) => resolveColor(props.colors?.[i], i));
364
+ const table = {
365
+ columns: [String(category), String(value)],
366
+ rows: rows.map((row) => [String(row[category]), valueFormatter(Number(row[value]))])
367
+ };
368
+ const legend = props.showLegend ?? true ? rows.map((row, i) => ({
369
+ label: String(row[category]),
370
+ color: colors[i]
371
+ })) : void 0;
372
+ return /* @__PURE__ */ jsx(ChartFrame, {
373
+ title: props.title,
374
+ description: props.description,
375
+ hideTitle: props.hideTitle,
376
+ className: props.className,
377
+ legend,
378
+ table,
379
+ children: /* @__PURE__ */ jsxs("div", {
380
+ className: "relative mx-auto",
381
+ style: {
382
+ width: size,
383
+ height: size
384
+ },
385
+ children: [/* @__PURE__ */ jsx(R.ResponsiveContainer, {
386
+ width: "100%",
387
+ height: "100%",
388
+ children: /* @__PURE__ */ jsxs(R.PieChart, {
389
+ accessibilityLayer: false,
390
+ children: [tooltip(valueFormatter, false), /* @__PURE__ */ jsx(R.Pie, {
391
+ rootTabIndex: -1,
392
+ data: rows,
393
+ dataKey: value,
394
+ nameKey: category,
395
+ innerRadius: "68%",
396
+ outerRadius: "100%",
397
+ paddingAngle: 2,
398
+ stroke: "var(--color-surface)",
399
+ strokeWidth: 2,
400
+ isAnimationActive: false,
401
+ children: rows.map((_, i) => /* @__PURE__ */ jsx(R.Cell, { fill: colors[i] }, i))
402
+ })]
403
+ })
404
+ }), props.centerLabel && /* @__PURE__ */ jsx("div", {
405
+ className: s.center({ class: slots.center }),
406
+ children: props.centerLabel
407
+ })]
408
+ })
409
+ });
410
+ }
411
+ /** A tiny trend line without axes, for stat cards and table cells. */
412
+ function Sparkline({ values, title, color, height = 36, area = true, className }) {
413
+ const id = useId().replace(/:/g, "");
414
+ const stroke = resolveColor(color, 0);
415
+ const data = values.map((v, i) => ({
416
+ i,
417
+ v
418
+ }));
419
+ return /* @__PURE__ */ jsx("div", {
420
+ role: "img",
421
+ "aria-label": title,
422
+ "data-slot": "sparkline",
423
+ className,
424
+ style: { height },
425
+ children: /* @__PURE__ */ jsx(R.ResponsiveContainer, {
426
+ width: "100%",
427
+ height: "100%",
428
+ children: /* @__PURE__ */ jsxs(R.AreaChart, {
429
+ accessibilityLayer: false,
430
+ data,
431
+ margin: {
432
+ top: 2,
433
+ right: 2,
434
+ bottom: 2,
435
+ left: 2
436
+ },
437
+ children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", {
438
+ id,
439
+ x1: "0",
440
+ x2: "0",
441
+ y1: "0",
442
+ y2: "1",
443
+ children: [/* @__PURE__ */ jsx("stop", {
444
+ offset: "0%",
445
+ stopColor: stroke,
446
+ stopOpacity: area ? .25 : 0
447
+ }), /* @__PURE__ */ jsx("stop", {
448
+ offset: "100%",
449
+ stopColor: stroke,
450
+ stopOpacity: 0
451
+ })]
452
+ }) }), /* @__PURE__ */ jsx(R.Area, {
453
+ dataKey: "v",
454
+ type: "monotone",
455
+ stroke,
456
+ strokeWidth: 1.75,
457
+ fill: `url(#${id})`,
458
+ isAnimationActive: false,
459
+ dot: false
460
+ })]
461
+ })
462
+ })
463
+ });
464
+ }
465
+ //#endregion
466
+ export { AreaChart, BarChart, DonutChart, LineChart, Sparkline, chartStyles };
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ //#region src/provider/color-mode-script.ts
3
+ const DARK_QUERY = "(prefers-color-scheme: dark)";
4
+ const DEFAULT_STORAGE_KEY = "glyph-mode";
5
+ /**
6
+ * A tiny inline script that sets `data-mode` on `<html>` before first paint, so dark-mode
7
+ * visitors never see a light flash. Use the same options as `GlyphProvider`.
8
+ */
9
+ function getColorModeScript({ defaultMode = "system", storageKey = DEFAULT_STORAGE_KEY } = {}) {
10
+ return `(function(){try{var d=${JSON.stringify(defaultMode)},m=null;${storageKey ? `m=localStorage.getItem(${JSON.stringify(storageKey)});` : ""}if(m!=='light'&&m!=='dark'&&m!=='system')m=d;if(m==='system')m=matchMedia('${DARK_QUERY}').matches?'dark':'light';var r=document.documentElement;r.dataset.mode=m;r.style.colorScheme=m}catch(e){}})()`;
11
+ }
12
+ //#endregion
13
+ export { DEFAULT_STORAGE_KEY as n, getColorModeScript as r, DARK_QUERY as t };
@@ -0,0 +1,16 @@
1
+ import { ColorMode } from "@glyphui/tokens";
2
+ //#region src/provider/color-mode-script.d.ts
3
+ type ColorModePreference = ColorMode | 'system';
4
+ interface ColorModeOptions {
5
+ /** Used when nothing is stored yet. */
6
+ defaultMode?: ColorModePreference;
7
+ /** localStorage key. Set to `null` to disable persistence. */
8
+ storageKey?: string | null;
9
+ }
10
+ /**
11
+ * A tiny inline script that sets `data-mode` on `<html>` before first paint, so dark-mode
12
+ * visitors never see a light flash. Use the same options as `GlyphProvider`.
13
+ */
14
+ declare function getColorModeScript({ defaultMode, storageKey }?: ColorModeOptions): string;
15
+ //#endregion
16
+ export { ColorModePreference as n, getColorModeScript as r, ColorModeOptions as t };
@@ -1,6 +1,7 @@
1
1
  "use client";
2
- import { E as SearchIcon, O as useComponentConfig, b as ChevronRightIcon, c as tv, f as themedBorder, g as ArrowUpIcon, h as ArrowDownIcon, i as IconButton, r as Button, u as focusRing, x as ChevronsUpDownIcon, y as ChevronLeftIcon } from "./field-context-B6WOcK5m.js";
3
- import { a as Table, c as TableCell, d as TableRow, h as Input, l as TableHead, n as ErrorState, o as TableBody, p as Skeleton, t as EmptyState, u as TableHeader, v as Checkbox } from "./states-Rp8wZ_jH.js";
2
+ import { a as themedBorder, r as focusRing, s as useComponentConfig, t as tv } from "./tv-DLbT66dC.js";
3
+ import { b as SearchIcon, h as ChevronsUpDownIcon, i as IconButton, l as ArrowDownIcon, m as ChevronRightIcon, p as ChevronLeftIcon, r as Button, u as ArrowUpIcon } from "./field-context-7I-cWvvS.js";
4
+ import { a as Table, c as TableCell, d as TableRow, h as Input, l as TableHead, n as ErrorState, o as TableBody, p as Skeleton, t as EmptyState, u as TableHeader, v as Checkbox } from "./states-IvhjBgna.js";
4
5
  import { useEffect, useMemo, useState } from "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { createColumnHelper, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { O as useComponentConfig, c as tv, t as FieldContext } from "./field-context-B6WOcK5m.js";
2
+ import { s as useComponentConfig, t as tv } from "./tv-DLbT66dC.js";
3
+ import { t as FieldContext } from "./field-context-7I-cWvvS.js";
3
4
  import { Label } from "radix-ui";
4
5
  import { useId, useMemo } from "react";
5
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -19,10 +20,12 @@ const fieldStyles = tv({
19
20
  slots: {
20
21
  root: "grid gap-1.5",
21
22
  label: "",
22
- required: "text-danger",
23
+ labelRow: "flex items-center justify-between gap-2",
24
+ labelAction: "text-small",
25
+ required: "text-danger-text",
23
26
  text: "grid gap-0.5",
24
27
  description: "text-small text-faint-foreground",
25
- error: "text-small font-medium text-danger"
28
+ error: "text-small font-medium text-danger-text"
26
29
  },
27
30
  variants: { orientation: {
28
31
  vertical: {},
@@ -41,15 +44,17 @@ const fieldStyles = tv({
41
44
  */
42
45
  function Field(inProps) {
43
46
  const [props, slots] = useComponentConfig("Field", inProps);
44
- const { label, description, error, required = false, disabled = false, controlId, orientation, className, children, ...rest } = props;
47
+ const { label, labelAction, description, error, required = false, disabled = false, controlId, orientation, className, children, ...rest } = props;
45
48
  const generated = useId();
46
49
  const id = controlId ?? generated;
47
50
  const invalid = Boolean(error);
51
+ const labelId = label ? `${id}-label` : void 0;
48
52
  const descriptionId = description ? `${id}-description` : void 0;
49
53
  const errorId = invalid ? `${id}-error` : void 0;
50
54
  const s = fieldStyles({ orientation });
51
55
  const context = useMemo(() => ({
52
56
  id,
57
+ labelId,
53
58
  descriptionId,
54
59
  errorId,
55
60
  invalid,
@@ -57,13 +62,15 @@ function Field(inProps) {
57
62
  disabled
58
63
  }), [
59
64
  id,
65
+ labelId,
60
66
  descriptionId,
61
67
  errorId,
62
68
  invalid,
63
69
  required,
64
70
  disabled
65
71
  ]);
66
- const labelNode = label ? /* @__PURE__ */ jsxs(Label$1, {
72
+ const labelElement = label ? /* @__PURE__ */ jsxs(Label$1, {
73
+ id: labelId,
67
74
  htmlFor: id,
68
75
  className: s.label({ class: slots.label }),
69
76
  children: [label, required && /* @__PURE__ */ jsx("span", {
@@ -72,6 +79,15 @@ function Field(inProps) {
72
79
  children: "*"
73
80
  })]
74
81
  }) : null;
82
+ const labelNode = labelElement && labelAction ? /* @__PURE__ */ jsxs("div", {
83
+ "data-slot": "field-label-row",
84
+ className: s.labelRow({ class: slots.labelRow }),
85
+ children: [labelElement, /* @__PURE__ */ jsx("span", {
86
+ "data-slot": "field-label-action",
87
+ className: s.labelAction({ class: slots.labelAction }),
88
+ children: labelAction
89
+ })]
90
+ }) : labelElement;
75
91
  const messages = /* @__PURE__ */ jsxs(Fragment$1, { children: [description && /* @__PURE__ */ jsx("p", {
76
92
  id: descriptionId,
77
93
  "data-slot": "field-description",
@@ -1,40 +1,8 @@
1
1
  "use client";
2
- import { textTokens } from "@glyphui/tokens";
2
+ import { a as themedBorder, o as transition, r as focusRing, s as useComponentConfig, t as tv } from "./tv-DLbT66dC.js";
3
3
  import { Slot } from "radix-ui";
4
4
  import { Fragment, createContext, useContext } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
- import { createTV } from "tailwind-variants";
7
- //#region src/provider/glyph-context.ts
8
- const GlyphContext = createContext(null);
9
- /** The active theme and app-level settings. Must be used under `GlyphProvider`. */
10
- function useGlyph() {
11
- const value = useContext(GlyphContext);
12
- if (!value) throw new Error("useGlyph must be used inside <GlyphProvider>.");
13
- return value;
14
- }
15
- /** The router-aware link component configured on `GlyphProvider`. */
16
- function useLinkComponent() {
17
- return useContext(GlyphContext)?.linkComponent ?? "a";
18
- }
19
- //#endregion
20
- //#region src/hooks/use-component-config.ts
21
- /**
22
- * Applies the theme's per-component settings (`theme.components[name]`):
23
- * fills unset variant props from `defaultVariants` and returns the extra slot classes.
24
- * Every styled component calls this first.
25
- */
26
- function useComponentConfig(name, props) {
27
- const override = (useContext(GlyphContext)?.theme)?.components[name];
28
- if (!override) return [props, {}];
29
- let merged = props;
30
- const defaults = override.defaultVariants;
31
- if (defaults) {
32
- merged = { ...props };
33
- for (const [key, value] of Object.entries(defaults)) if (merged[key] === void 0) merged[key] = value;
34
- }
35
- return [merged, override.className ?? {}];
36
- }
37
- //#endregion
38
6
  //#region src/internal/icons.tsx
39
7
  function Icon({ children, ...props }) {
40
8
  return /* @__PURE__ */ jsx("svg", {
@@ -123,28 +91,6 @@ const AlertIcon = (p) => /* @__PURE__ */ jsxs(Icon, {
123
91
  }), /* @__PURE__ */ jsx("path", { d: "M12 8v4M12 16h.01" })]
124
92
  });
125
93
  //#endregion
126
- //#region src/utils/styles.ts
127
- /** Shared class fragments. Kept as literals so Tailwind's scanner picks them up. */
128
- const focusRing = "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background";
129
- const themedBorder = "border-(length:--glyph-border-width)";
130
- const transition = "transition-[color,background-color,border-color,box-shadow,transform,opacity] duration-(--glyph-duration-base) ease-standard";
131
- /** Popover surfaces: Select, Tooltip-like menus. */
132
- const popover = "z-50 overflow-hidden rounded-[min(var(--radius-md),var(--radius-lg))] border-(length:--glyph-border-width) border-border bg-raised text-foreground shadow-lg animate-pop-in";
133
- //#endregion
134
- //#region src/utils/tw-merge-config.ts
135
- /**
136
- * Teaches tailwind-merge about Glyph's custom utilities so `cn('text-h1', 'text-small')`
137
- * keeps only the last size instead of treating `text-h1` as a color.
138
- */
139
- const twMergeConfig = { extend: { theme: {
140
- text: [...textTokens],
141
- radius: ["pill"]
142
- } } };
143
- //#endregion
144
- //#region src/utils/tv.ts
145
- /** `tailwind-variants` preconfigured with Glyph's merge rules. All component styles use this. */
146
- const tv = createTV({ twMergeConfig });
147
- //#endregion
148
94
  //#region src/components/spinner/spinner.styles.ts
149
95
  const spinnerStyles = tv({
150
96
  slots: {
@@ -211,7 +157,7 @@ const buttonStyles = tv({
211
157
  outline: { base: "border-border bg-surface text-foreground shadow-xs hover:border-border-strong hover:bg-muted" },
212
158
  ghost: { base: "text-muted-foreground hover:bg-muted hover:text-foreground" },
213
159
  danger: { base: "bg-danger text-danger-foreground shadow-sm hover:bg-danger/88" },
214
- link: { base: "h-auto px-0 text-primary underline-offset-4 shadow-none hover:underline" }
160
+ link: { base: "h-auto px-0 text-primary-text underline-offset-4 shadow-none hover:underline" }
215
161
  },
216
162
  size: {
217
163
  sm: {
@@ -318,4 +264,4 @@ function useFieldControl(props) {
318
264
  };
319
265
  }
320
266
  //#endregion
321
- export { useGlyph as A, MenuIcon as C, XIcon as D, SearchIcon as E, useComponentConfig as O, InboxIcon as S, PanelLeftIcon as T, CheckIcon as _, buttonStyles as a, ChevronRightIcon as b, tv as c, popover as d, themedBorder as f, ArrowUpIcon as g, ArrowDownIcon as h, IconButton as i, useLinkComponent as j, GlyphContext as k, twMergeConfig as l, AlertIcon as m, useFieldControl as n, Spinner as o, transition as p, Button as r, spinnerStyles as s, FieldContext as t, focusRing as u, ChevronDownIcon as v, MinusIcon as w, ChevronsUpDownIcon as x, ChevronLeftIcon as y };
267
+ export { MenuIcon as _, buttonStyles as a, SearchIcon as b, AlertIcon as c, CheckIcon as d, ChevronDownIcon as f, InboxIcon as g, ChevronsUpDownIcon as h, IconButton as i, ArrowDownIcon as l, ChevronRightIcon as m, useFieldControl as n, Spinner as o, ChevronLeftIcon as p, Button as r, spinnerStyles as s, FieldContext as t, ArrowUpIcon as u, MinusIcon as v, XIcon as x, PanelLeftIcon as y };