torch-glare 2.4.0 → 2.4.1

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 (264) hide show
  1. package/README.md +8 -0
  2. package/apps/lib/components/ActionButton.tsx +7 -12
  3. package/apps/lib/components/ActionsGroup.tsx +4 -15
  4. package/apps/lib/components/AlertDialog.tsx +173 -191
  5. package/apps/lib/components/Avatar.tsx +13 -16
  6. package/apps/lib/components/Badge.tsx +1 -3
  7. package/apps/lib/components/BadgeField.tsx +76 -71
  8. package/apps/lib/components/Breadcrumb.tsx +49 -85
  9. package/apps/lib/components/Button.tsx +20 -19
  10. package/apps/lib/components/ButtonGroup.tsx +31 -41
  11. package/apps/lib/components/Calendar.tsx +51 -29
  12. package/apps/lib/components/Card.tsx +2 -13
  13. package/apps/lib/components/ChartBlockTool.ts +17 -52
  14. package/apps/lib/components/Checkbox.tsx +9 -16
  15. package/apps/lib/components/ContextMenu.tsx +97 -96
  16. package/apps/lib/components/CountBadge.tsx +4 -6
  17. package/apps/lib/components/DataTable.tsx +196 -216
  18. package/apps/lib/components/DataViews/DataViewRadio.tsx +1 -6
  19. package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +13 -47
  20. package/apps/lib/components/DataViews/DataViewsHeader.tsx +1 -3
  21. package/apps/lib/components/DataViews/DataViewsLayout.tsx +5 -12
  22. package/apps/lib/components/DataViews/FilterPanel.tsx +155 -149
  23. package/apps/lib/components/DataViews/HeaderSearch.tsx +1 -5
  24. package/apps/lib/components/DataViews/InboxView.tsx +22 -68
  25. package/apps/lib/components/DataViews/InboxViewCard.tsx +68 -77
  26. package/apps/lib/components/DataViews/KanbanView.tsx +8 -25
  27. package/apps/lib/components/DataViews/PanelControls.tsx +3 -13
  28. package/apps/lib/components/DataViews/SettingsPanel.tsx +83 -89
  29. package/apps/lib/components/DataViews/TableView.tsx +8 -28
  30. package/apps/lib/components/DataViews/TreeView.tsx +12 -40
  31. package/apps/lib/components/DataViews/badgeAdapter.ts +32 -28
  32. package/apps/lib/components/DataViews/fieldRenderers.tsx +106 -141
  33. package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +30 -23
  34. package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +39 -32
  35. package/apps/lib/components/DataViews/filters/PresetChips.tsx +15 -15
  36. package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +69 -58
  37. package/apps/lib/components/DataViews/index.ts +26 -26
  38. package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +12 -16
  39. package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +28 -31
  40. package/apps/lib/components/DataViews/types.ts +104 -115
  41. package/apps/lib/components/DatePicker.tsx +198 -196
  42. package/apps/lib/components/Dialog.tsx +92 -105
  43. package/apps/lib/components/Divider.tsx +21 -24
  44. package/apps/lib/components/Drawer.tsx +79 -139
  45. package/apps/lib/components/DropdownMenu.tsx +131 -171
  46. package/apps/lib/components/FieldHint.tsx +4 -11
  47. package/apps/lib/components/Form.tsx +146 -155
  48. package/apps/lib/components/FormStepper.tsx +9 -39
  49. package/apps/lib/components/HeaderBar.tsx +1 -9
  50. package/apps/lib/components/ImageAttachment.tsx +111 -73
  51. package/apps/lib/components/InnerLabelField.tsx +20 -16
  52. package/apps/lib/components/Input.tsx +171 -172
  53. package/apps/lib/components/InputField.tsx +44 -45
  54. package/apps/lib/components/InputOTP.tsx +68 -69
  55. package/apps/lib/components/Label.tsx +31 -35
  56. package/apps/lib/components/LabelField.tsx +4 -5
  57. package/apps/lib/components/LabeledCheckBox.tsx +8 -12
  58. package/apps/lib/components/LabeledRadio.tsx +7 -5
  59. package/apps/lib/components/LinkButton.tsx +2 -9
  60. package/apps/lib/components/LoginButton.tsx +4 -9
  61. package/apps/lib/components/PasswordLevel.tsx +5 -5
  62. package/apps/lib/components/Popover.tsx +15 -33
  63. package/apps/lib/components/ProfileMenu.tsx +67 -72
  64. package/apps/lib/components/Radio.tsx +1 -5
  65. package/apps/lib/components/RadioCard.tsx +9 -28
  66. package/apps/lib/components/ScrollArea.tsx +45 -43
  67. package/apps/lib/components/SearchField.tsx +49 -39
  68. package/apps/lib/components/SearchableSelect.tsx +8 -14
  69. package/apps/lib/components/SearchableTable.tsx +108 -118
  70. package/apps/lib/components/SearchableTree.tsx +469 -0
  71. package/apps/lib/components/SearchableTreeDialog.tsx +493 -0
  72. package/apps/lib/components/SectionBlock.tsx +4 -16
  73. package/apps/lib/components/Select.tsx +53 -80
  74. package/apps/lib/components/SimpleSelect.tsx +196 -187
  75. package/apps/lib/components/Skeleton.tsx +9 -12
  76. package/apps/lib/components/SlideDatePicker.tsx +215 -166
  77. package/apps/lib/components/SpinLoading.tsx +33 -49
  78. package/apps/lib/components/Stepper.tsx +13 -56
  79. package/apps/lib/components/Switch.tsx +8 -10
  80. package/apps/lib/components/TabFormItem.tsx +3 -12
  81. package/apps/lib/components/TabSwitch.tsx +7 -34
  82. package/apps/lib/components/Table.tsx +60 -75
  83. package/apps/lib/components/TableDnDWrapper.ts +15 -48
  84. package/apps/lib/components/TextEditor.tsx +93 -104
  85. package/apps/lib/components/Textarea.tsx +8 -12
  86. package/apps/lib/components/Timeline.tsx +21 -41
  87. package/apps/lib/components/Toast.tsx +83 -83
  88. package/apps/lib/components/Toggle.tsx +112 -114
  89. package/apps/lib/components/ToggleButton.tsx +1 -1
  90. package/apps/lib/components/Tooltip.tsx +24 -19
  91. package/apps/lib/components/TransparentLabel.tsx +61 -62
  92. package/apps/lib/components/TreeDropDown.tsx +86 -52
  93. package/apps/lib/components/TreeFolder/TreeFolder.tsx +15 -48
  94. package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +16 -21
  95. package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +9 -20
  96. package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +3 -3
  97. package/apps/lib/components/TreeFolder/icons.tsx +14 -17
  98. package/apps/lib/components/TreeFolder/index.ts +15 -8
  99. package/apps/lib/components/TreeFolder/treeFolderUtils.ts +47 -52
  100. package/apps/lib/components/TreeFolder/types.ts +32 -32
  101. package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +117 -123
  102. package/apps/lib/hooks/useActiveTreeItem.ts +52 -55
  103. package/apps/lib/hooks/useClickOutside.ts +21 -20
  104. package/apps/lib/hooks/useDataViewsState.ts +86 -80
  105. package/apps/lib/hooks/useIsMobile.ts +12 -12
  106. package/apps/lib/hooks/useResize.ts +54 -65
  107. package/apps/lib/hooks/useTagSelection.ts +201 -201
  108. package/apps/lib/layouts/CNLayout.tsx +181 -140
  109. package/apps/lib/layouts/DataViewCard.tsx +4 -18
  110. package/apps/lib/layouts/FieldSection.tsx +2 -6
  111. package/apps/lib/layouts/TreeSubLayout.tsx +24 -38
  112. package/apps/lib/providers/ThemeProvider.tsx +8 -23
  113. package/apps/lib/registry.json +1004 -0
  114. package/apps/lib/tsconfig.json +9 -0
  115. package/apps/lib/utils/cn.ts +1 -1
  116. package/apps/lib/utils/dataViews/columnUtils.ts +46 -44
  117. package/apps/lib/utils/dataViews/fieldUtils.ts +70 -71
  118. package/apps/lib/utils/dataViews/nestedDataUtils.tsx +129 -122
  119. package/apps/lib/utils/dataViews/pathUtils.ts +74 -67
  120. package/apps/lib/utils/dataViews/rangeUtils.ts +121 -112
  121. package/apps/lib/utils/dataViews/treeUtils.ts +204 -211
  122. package/apps/lib/utils/dateFormat.ts +64 -54
  123. package/apps/lib/utils/markdownParser.ts +2 -7
  124. package/apps/lib/utils/resize.ts +21 -25
  125. package/apps/lib/utils/types.ts +13 -13
  126. package/dist/bin/index.js +8 -2
  127. package/dist/bin/index.js.map +1 -1
  128. package/dist/src/shared/getAvailableFiles.d.ts.map +1 -1
  129. package/dist/src/shared/getAvailableFiles.js +6 -1
  130. package/dist/src/shared/getAvailableFiles.js.map +1 -1
  131. package/dist/src/shared/loadRegistry.d.ts +7 -0
  132. package/dist/src/shared/loadRegistry.d.ts.map +1 -0
  133. package/dist/src/shared/loadRegistry.js +31 -0
  134. package/dist/src/shared/loadRegistry.js.map +1 -0
  135. package/dist/src/shared/resolveInstallPlan.d.ts +12 -0
  136. package/dist/src/shared/resolveInstallPlan.d.ts.map +1 -0
  137. package/dist/src/shared/resolveInstallPlan.js +39 -0
  138. package/dist/src/shared/resolveInstallPlan.js.map +1 -0
  139. package/dist/src/types/main.d.ts +24 -0
  140. package/dist/src/types/main.d.ts.map +1 -1
  141. package/docs/README.md +10 -2
  142. package/docs/components/action-button.md +30 -24
  143. package/docs/components/actions-group.md +26 -20
  144. package/docs/components/alert-dialog.md +45 -45
  145. package/docs/components/avatar.md +6 -2
  146. package/docs/components/badge-field.md +6 -2
  147. package/docs/components/badge.md +7 -1
  148. package/docs/components/breadcrumb.md +15 -40
  149. package/docs/components/button-group.md +13 -10
  150. package/docs/components/button.md +58 -33
  151. package/docs/components/calendar.md +26 -19
  152. package/docs/components/card.md +19 -16
  153. package/docs/components/chart-block-tool.md +128 -0
  154. package/docs/components/checkbox.md +16 -8
  155. package/docs/components/cn-layout.md +7 -1
  156. package/docs/components/context-menu.md +18 -25
  157. package/docs/components/count-badge.md +7 -1
  158. package/docs/components/data-table.md +45 -33
  159. package/docs/components/data-views-config-panel.md +15 -11
  160. package/docs/components/data-views-layout.md +13 -16
  161. package/docs/components/date-picker.md +30 -23
  162. package/docs/components/dialog.md +43 -42
  163. package/docs/components/divider.md +10 -4
  164. package/docs/components/drawer.md +8 -33
  165. package/docs/components/dropdown-menu.md +25 -34
  166. package/docs/components/field-hint.md +37 -25
  167. package/docs/components/field-section.md +9 -3
  168. package/docs/components/form-stepper.md +6 -0
  169. package/docs/components/form.md +17 -20
  170. package/docs/components/header-bar.md +6 -0
  171. package/docs/components/image-attachment.md +33 -41
  172. package/docs/components/inbox-view.md +16 -5
  173. package/docs/components/inner-label-field.md +34 -24
  174. package/docs/components/input-field.md +18 -10
  175. package/docs/components/input-otp.md +14 -11
  176. package/docs/components/input.md +22 -16
  177. package/docs/components/kanban-view.md +15 -5
  178. package/docs/components/label-field.md +32 -22
  179. package/docs/components/label.md +43 -32
  180. package/docs/components/labeled-check-box.md +16 -8
  181. package/docs/components/labeled-radio.md +18 -11
  182. package/docs/components/link-button.md +7 -1
  183. package/docs/components/login-button.md +8 -2
  184. package/docs/components/password-level.md +37 -24
  185. package/docs/components/popover.md +26 -23
  186. package/docs/components/profile-menu.md +38 -27
  187. package/docs/components/radio-card.md +16 -9
  188. package/docs/components/radio.md +16 -8
  189. package/docs/components/scroll-area.md +6 -2
  190. package/docs/components/search-field.md +14 -6
  191. package/docs/components/searchable-select.md +19 -14
  192. package/docs/components/searchable-table.md +18 -13
  193. package/docs/components/searchable-tree-dialog.md +190 -0
  194. package/docs/components/searchable-tree.md +200 -0
  195. package/docs/components/section-block.md +12 -4
  196. package/docs/components/select.md +23 -18
  197. package/docs/components/simple-select.md +14 -10
  198. package/docs/components/skeleton.md +43 -33
  199. package/docs/components/slide-date-picker.md +37 -29
  200. package/docs/components/spin-loading.md +32 -23
  201. package/docs/components/stepper.md +6 -0
  202. package/docs/components/switch.md +14 -6
  203. package/docs/components/tab-form-item.md +7 -1
  204. package/docs/components/tab-switch.md +13 -6
  205. package/docs/components/table-dnd-wrapper.md +105 -0
  206. package/docs/components/table-view.md +15 -5
  207. package/docs/components/table.md +28 -28
  208. package/docs/components/text-editor.md +19 -13
  209. package/docs/components/textarea.md +15 -7
  210. package/docs/components/timeline.md +6 -0
  211. package/docs/components/toast.md +35 -26
  212. package/docs/components/toggle-button.md +24 -21
  213. package/docs/components/toggle.md +23 -15
  214. package/docs/components/tooltip.md +42 -30
  215. package/docs/components/transparent-label.md +29 -20
  216. package/docs/components/tree-drop-down.md +31 -23
  217. package/docs/components/tree-sub-layout.md +6 -2
  218. package/docs/components/tree-view.md +16 -5
  219. package/docs/explanation/architecture.md +54 -0
  220. package/docs/explanation/design-system.md +52 -0
  221. package/docs/how-to/data-views-from-backend-response.md +6 -4
  222. package/docs/how-to/guides.md +24 -18
  223. package/docs/migration/changelog.md +38 -0
  224. package/docs/reference/cli.md +87 -0
  225. package/docs/reference/components.md +11 -12
  226. package/docs/reference/hooks.md +8 -8
  227. package/docs/reference/providers.md +22 -22
  228. package/docs/reference/tailwind-plugins.md +2 -2
  229. package/docs/reference/theme.md +85 -0
  230. package/docs/reference/types.md +4 -4
  231. package/docs/reference/utilities.md +19 -26
  232. package/docs/tutorials/building-first-form.md +20 -13
  233. package/docs/tutorials/component-composition.md +34 -50
  234. package/docs/tutorials/getting-started.md +2 -2
  235. package/docs/tutorials/theming-basics.md +13 -10
  236. package/package.json +31 -3
  237. package/dist/src/commands/block.d.ts +0 -5
  238. package/dist/src/commands/block.d.ts.map +0 -1
  239. package/dist/src/commands/block.js +0 -255
  240. package/dist/src/commands/block.js.map +0 -1
  241. package/dist/src/shared/configureFonts.d.ts +0 -6
  242. package/dist/src/shared/configureFonts.d.ts.map +0 -1
  243. package/dist/src/shared/configureFonts.js +0 -106
  244. package/dist/src/shared/configureFonts.js.map +0 -1
  245. package/dist/src/shared/configureGlobalCss.d.ts +0 -6
  246. package/dist/src/shared/configureGlobalCss.d.ts.map +0 -1
  247. package/dist/src/shared/configureGlobalCss.js +0 -154
  248. package/dist/src/shared/configureGlobalCss.js.map +0 -1
  249. package/dist/src/shared/configureTailwind.d.ts +0 -7
  250. package/dist/src/shared/configureTailwind.d.ts.map +0 -1
  251. package/dist/src/shared/configureTailwind.js +0 -163
  252. package/dist/src/shared/configureTailwind.js.map +0 -1
  253. package/dist/src/shared/detectFramework.d.ts +0 -23
  254. package/dist/src/shared/detectFramework.d.ts.map +0 -1
  255. package/dist/src/shared/detectFramework.js +0 -119
  256. package/dist/src/shared/detectFramework.js.map +0 -1
  257. package/dist/src/shared/installBaseUtils.d.ts +0 -5
  258. package/dist/src/shared/installBaseUtils.d.ts.map +0 -1
  259. package/dist/src/shared/installBaseUtils.js +0 -79
  260. package/dist/src/shared/installBaseUtils.js.map +0 -1
  261. package/dist/src/shared/resolveAliases.d.ts +0 -24
  262. package/dist/src/shared/resolveAliases.d.ts.map +0 -1
  263. package/dist/src/shared/resolveAliases.js +0 -98
  264. package/dist/src/shared/resolveAliases.js.map +0 -1
@@ -1,50 +1,37 @@
1
- "use client"
2
-
3
- import type { ReactNode } from "react"
4
- import { Badge } from "../Badge"
5
- import { Avatar, AvatarFallback, AvatarImage } from "../Avatar"
6
- import { cn } from "../../utils/cn"
7
- import type {
8
- CurrencyOptions,
9
- DynamicRecord,
10
- FieldConfig,
11
- FieldType,
12
- } from "./types"
13
- import { getByPath } from "../../utils/dataViews/pathUtils"
14
- import { resolveBadgeVariant } from "./badgeAdapter"
1
+ "use client";
2
+
3
+ import type { ReactNode } from "react";
4
+ import { Badge } from "../Badge";
5
+ import { Avatar, AvatarFallback, AvatarImage } from "../Avatar";
6
+ import { cn } from "../../utils/cn";
7
+ import type { CurrencyOptions, DynamicRecord, FieldConfig, FieldType } from "./types";
8
+ import { getByPath } from "../../utils/dataViews/pathUtils";
9
+ import { resolveBadgeVariant } from "./badgeAdapter";
15
10
 
16
11
  type RenderArgs = {
17
- value: any
18
- field: FieldConfig
19
- row: DynamicRecord
20
- }
12
+ value: unknown;
13
+ field: FieldConfig;
14
+ row: DynamicRecord;
15
+ };
21
16
 
22
- const NULL_PLACEHOLDER = (
23
- <span className="text-content-presentation-global-tertiary">-</span>
24
- )
17
+ const NULL_PLACEHOLDER = <span className="text-content-presentation-global-tertiary">-</span>;
25
18
 
26
- export function renderField(
27
- value: any,
28
- field: FieldConfig,
29
- row: DynamicRecord,
30
- ): ReactNode {
31
- if (field.render) return field.render(value, row)
19
+ export function renderField(value: unknown, field: FieldConfig, row: DynamicRecord): ReactNode {
20
+ if (field.render) return field.render(value, row);
32
21
 
33
- const type = field.type ?? "text"
34
- if (type === "hidden") return null
22
+ const type = field.type ?? "text";
23
+ if (type === "hidden") return null;
35
24
 
36
25
  if (value == null && type !== "boolean" && type !== "progress-bar") {
37
- return NULL_PLACEHOLDER
26
+ return NULL_PLACEHOLDER;
38
27
  }
39
28
 
40
- const renderer = RENDERERS[type] ?? renderText
41
- return renderer({ value, field, row })
29
+ const renderer = RENDERERS[type] ?? renderText;
30
+ return renderer({ value, field, row });
42
31
  }
43
32
 
44
33
  function renderText({ value }: RenderArgs): ReactNode {
45
- return (
46
- <span className="text-content-presentation-global-primary">{String(value)}</span>
47
- )
34
+ return <span className="text-content-presentation-global-primary">{String(value)}</span>;
48
35
  }
49
36
 
50
37
  function renderNumber({ value }: RenderArgs): ReactNode {
@@ -52,107 +39,96 @@ function renderNumber({ value }: RenderArgs): ReactNode {
52
39
  <span className="font-mono text-content-presentation-global-primary">
53
40
  {typeof value === "number" ? value.toLocaleString() : String(value)}
54
41
  </span>
55
- )
42
+ );
56
43
  }
57
44
 
58
45
  function renderDate({ value }: RenderArgs): ReactNode {
59
- return <span className="text-content-presentation-global-primary">{String(value)}</span>
46
+ return <span className="text-content-presentation-global-primary">{String(value)}</span>;
60
47
  }
61
48
 
62
49
  function renderDateFormat({ value, field }: RenderArgs): ReactNode {
63
- const opts = field.dateFormat
64
- let formatted = String(value)
50
+ const opts = field.dateFormat;
51
+ let formatted = String(value);
65
52
  try {
66
- const d = value instanceof Date ? value : new Date(value)
53
+ const d = value instanceof Date ? value : new Date(value as string | number);
67
54
  if (!isNaN(d.getTime())) {
68
55
  if (typeof opts === "object" && opts) {
69
- formatted = new Intl.DateTimeFormat(undefined, opts).format(d)
56
+ formatted = new Intl.DateTimeFormat(undefined, opts).format(d);
70
57
  } else if (typeof opts === "string") {
71
- formatted = formatWithToken(d, opts)
58
+ formatted = formatWithToken(d, opts);
72
59
  } else {
73
60
  formatted = new Intl.DateTimeFormat(undefined, {
74
61
  year: "numeric",
75
62
  month: "short",
76
63
  day: "numeric",
77
- }).format(d)
64
+ }).format(d);
78
65
  }
79
66
  }
80
67
  } catch {
81
68
  /* fall through to raw string */
82
69
  }
83
- return <span className="text-content-presentation-global-primary">{formatted}</span>
70
+ return <span className="text-content-presentation-global-primary">{formatted}</span>;
84
71
  }
85
72
 
86
73
  function formatWithToken(d: Date, token: string): string {
87
- const pad = (n: number) => String(n).padStart(2, "0")
74
+ const pad = (n: number) => String(n).padStart(2, "0");
88
75
  return token
89
76
  .replace(/YYYY/g, String(d.getFullYear()))
90
77
  .replace(/MM/g, pad(d.getMonth() + 1))
91
78
  .replace(/DD/g, pad(d.getDate()))
92
79
  .replace(/HH/g, pad(d.getHours()))
93
80
  .replace(/mm/g, pad(d.getMinutes()))
94
- .replace(/ss/g, pad(d.getSeconds()))
81
+ .replace(/ss/g, pad(d.getSeconds()));
95
82
  }
96
83
 
97
84
  function renderBoolean({ value, field }: RenderArgs): ReactNode {
98
- const isTrue = !!value
99
- const variant = isTrue ? field.trueVariant ?? "green" : field.falseVariant ?? "gray"
100
- const badgeProps = resolveBadgeVariant(variant)
85
+ const isTrue = !!value;
86
+ const variant = isTrue ? (field.trueVariant ?? "green") : (field.falseVariant ?? "gray");
87
+ const badgeProps = resolveBadgeVariant(variant);
101
88
  return (
102
89
  <Badge
103
90
  {...badgeProps}
104
- label={isTrue ? field.trueLabel ?? "Yes" : field.falseLabel ?? "No"}
91
+ label={isTrue ? (field.trueLabel ?? "Yes") : (field.falseLabel ?? "No")}
105
92
  size="S"
106
-
107
93
  />
108
- )
94
+ );
109
95
  }
110
96
 
111
97
  function renderEnumBadge({ value, field }: RenderArgs): ReactNode {
112
- const key = String(value)
113
- const variant = field.variants?.[key] ?? field.defaultVariant ?? "gray"
114
- const badgeProps = resolveBadgeVariant(variant)
98
+ const key = String(value);
99
+ const variant = field.variants?.[key] ?? field.defaultVariant ?? "gray";
100
+ const badgeProps = resolveBadgeVariant(variant);
115
101
  // Use medium size so the glare badge dot indicator is clearly visible
116
- return <Badge {...badgeProps} label={key} size="S" />
102
+ return <Badge {...badgeProps} label={key} size="S" />;
117
103
  }
118
104
 
119
105
  function renderBadgeArray({ value, field }: RenderArgs): ReactNode {
120
- const badgeProps = resolveBadgeVariant(field.variant ?? "blue")
106
+ const badgeProps = resolveBadgeVariant(field.variant ?? "blue");
121
107
  if (!Array.isArray(value)) {
122
- return <Badge {...badgeProps} label={String(value)} size="XS" />
108
+ return <Badge {...badgeProps} label={String(value)} size="XS" />;
123
109
  }
124
- const limit = field.limit ?? value.length
125
- const head = value.slice(0, limit)
126
- const overflow = value.length - head.length
127
- const overflowProps = resolveBadgeVariant("gray")
110
+ const limit = field.limit ?? value.length;
111
+ const head = value.slice(0, limit);
112
+ const overflow = value.length - head.length;
113
+ const overflowProps = resolveBadgeVariant("gray");
128
114
  return (
129
115
  <div className="flex flex-wrap gap-1">
130
116
  {head.map((v, i) => (
131
- <Badge
132
- key={i}
133
- {...badgeProps}
134
- label={String(v)}
135
- size="XS"
136
-
137
- />
117
+ <Badge key={i} {...badgeProps} label={String(v)} size="XS" />
138
118
  ))}
139
- {overflow > 0 && (
140
- <Badge {...overflowProps} label={`+${overflow}`} size="XS" />
141
- )}
119
+ {overflow > 0 && <Badge {...overflowProps} label={`+${overflow}`} size="XS" />}
142
120
  </div>
143
- )
121
+ );
144
122
  }
145
123
 
146
124
  function renderCurrency({ value, field }: RenderArgs): ReactNode {
147
- const num = Number(value)
148
- if (Number.isNaN(num)) return renderText({ value, field, row: {} as any })
125
+ const num = Number(value);
126
+ if (Number.isNaN(num)) return renderText({ value, field, row: {} as DynamicRecord });
149
127
 
150
128
  const opts: CurrencyOptions =
151
- typeof field.currency === "string"
152
- ? { code: field.currency }
153
- : field.currency ?? {}
129
+ typeof field.currency === "string" ? { code: field.currency } : (field.currency ?? {});
154
130
 
155
- let formatted: string
131
+ let formatted: string;
156
132
  if (opts.code) {
157
133
  try {
158
134
  formatted = new Intl.NumberFormat(opts.locale, {
@@ -160,39 +136,36 @@ function renderCurrency({ value, field }: RenderArgs): ReactNode {
160
136
  currency: opts.code,
161
137
  minimumFractionDigits: opts.decimals,
162
138
  maximumFractionDigits: opts.decimals,
163
- }).format(num)
139
+ }).format(num);
164
140
  } catch {
165
141
  formatted = `${opts.symbol ?? "$"}${num.toLocaleString(opts.locale, {
166
142
  minimumFractionDigits: opts.decimals,
167
143
  maximumFractionDigits: opts.decimals,
168
- })}`
144
+ })}`;
169
145
  }
170
146
  } else {
171
147
  formatted = `${opts.symbol ?? "$"}${num.toLocaleString(opts.locale, {
172
148
  minimumFractionDigits: opts.decimals,
173
149
  maximumFractionDigits: opts.decimals,
174
- })}`
150
+ })}`;
175
151
  }
176
152
 
177
- return <span className="font-semibold text-green-600">{formatted}</span>
153
+ return <span className="font-semibold text-green-600">{formatted}</span>;
178
154
  }
179
155
 
180
156
  function renderNumberFormat({ value, field }: RenderArgs): ReactNode {
181
- const num = Number(value)
182
- if (Number.isNaN(num)) return renderText({ value, field, row: {} as any })
183
- const formatted = new Intl.NumberFormat(undefined, field.format).format(num)
184
- return <span className="font-mono text-content-presentation-global-primary">{formatted}</span>
157
+ const num = Number(value);
158
+ if (Number.isNaN(num)) return renderText({ value, field, row: {} as DynamicRecord });
159
+ const formatted = new Intl.NumberFormat(undefined, field.format).format(num);
160
+ return <span className="font-mono text-content-presentation-global-primary">{formatted}</span>;
185
161
  }
186
162
 
187
163
  function renderProgressBar({ value, field }: RenderArgs): ReactNode {
188
- const raw = Number(value)
189
- const num = Number.isFinite(raw) ? raw : 0
190
- const pct = Math.max(0, Math.min(100, num))
191
- const [warn, ok] = field.thresholds ?? [40, 70]
192
- const color =
193
- num >= ok ? "bg-green-500"
194
- : num >= warn ? "bg-yellow-500"
195
- : "bg-red-500"
164
+ const raw = Number(value);
165
+ const num = Number.isFinite(raw) ? raw : 0;
166
+ const pct = Math.max(0, Math.min(100, num));
167
+ const [warn, ok] = field.thresholds ?? [40, 70];
168
+ const color = num >= ok ? "bg-green-500" : num >= warn ? "bg-yellow-500" : "bg-red-500";
196
169
 
197
170
  return (
198
171
  <div className="flex items-center gap-2 min-w-[120px]">
@@ -203,91 +176,83 @@ function renderProgressBar({ value, field }: RenderArgs): ReactNode {
203
176
  {Math.round(num)}%
204
177
  </span>
205
178
  </div>
206
- )
179
+ );
207
180
  }
208
181
 
209
182
  function renderStarRating({ value, field }: RenderArgs): ReactNode {
210
- const num = Number(value)
211
- const max = field.max ?? 5
212
- const filled = Math.max(0, Math.min(max, Math.floor(num)))
183
+ const num = Number(value);
184
+ const max = field.max ?? 5;
185
+ const filled = Math.max(0, Math.min(max, Math.floor(num)));
213
186
 
214
187
  return (
215
188
  <div className="flex items-center gap-2">
216
189
  <div className="flex">
217
190
  {Array.from({ length: max }).map((_, i) => (
218
- <span
219
- key={i}
220
- className={i < filled ? "text-yellow-500" : "text-gray-300"}
221
- aria-hidden
222
- >
191
+ <span key={i} className={i < filled ? "text-yellow-500" : "text-gray-300"} aria-hidden>
223
192
 
224
193
  </span>
225
194
  ))}
226
195
  </div>
227
196
  <span className="text-sm font-semibold tabular-nums">{Number.isFinite(num) ? num : "-"}</span>
228
197
  </div>
229
- )
198
+ );
230
199
  }
231
200
 
232
201
  function renderIconText({ value, field }: RenderArgs): ReactNode {
233
- const icon = field.icon ?? ""
234
- const after = field.iconPosition === "after"
202
+ const icon = field.icon ?? "";
203
+ const after = field.iconPosition === "after";
235
204
  return (
236
205
  <span className="inline-flex items-center gap-1.5 text-content-presentation-global-primary">
237
206
  {!after && icon && <IconNode icon={icon} />}
238
207
  <span>{String(value)}</span>
239
208
  {after && icon && <IconNode icon={icon} />}
240
209
  </span>
241
- )
210
+ );
242
211
  }
243
212
 
244
213
  function IconNode({ icon }: { icon: string }) {
245
- if (/^ri-/.test(icon)) return <i className={icon} />
246
- return <span aria-hidden>{icon}</span>
214
+ if (/^ri-/.test(icon)) return <i className={icon} />;
215
+ return <span aria-hidden>{icon}</span>;
247
216
  }
248
217
 
249
218
  function renderTwoLine({ value, field, row }: RenderArgs): ReactNode {
250
- const secondary =
251
- field.secondaryPath != null ? getByPath(row, field.secondaryPath) : null
219
+ const secondary = field.secondaryPath != null ? getByPath(row, field.secondaryPath) : null;
252
220
  return (
253
221
  <div className="leading-tight">
254
- <div className="font-semibold text-content-presentation-global-primary">
255
- {String(value)}
256
- </div>
222
+ <div className="font-semibold text-content-presentation-global-primary">{String(value)}</div>
257
223
  {secondary != null && (
258
224
  <div className="text-xs text-content-presentation-global-secondary">
259
225
  {String(secondary)}
260
226
  </div>
261
227
  )}
262
228
  </div>
263
- )
229
+ );
264
230
  }
265
231
 
266
232
  function renderAvatar({ value, field, row }: RenderArgs): ReactNode {
267
- const src = typeof value === "string" ? value : null
268
- const fallbackSource =
269
- field.fallbackPath != null ? getByPath(row, field.fallbackPath) : null
270
- const initials = toInitials(fallbackSource ?? src ?? "?")
233
+ const src = typeof value === "string" ? value : null;
234
+ const fallbackSource = field.fallbackPath != null ? getByPath(row, field.fallbackPath) : null;
235
+ const initials = toInitials(fallbackSource ?? src ?? "?");
271
236
 
272
237
  return (
273
238
  <Avatar>
274
239
  {src && <AvatarImage src={src} alt={String(initials)} />}
275
240
  <AvatarFallback>{initials}</AvatarFallback>
276
241
  </Avatar>
277
- )
242
+ );
278
243
  }
279
244
 
280
245
  function toInitials(s: string): string {
281
- if (!s) return "?"
282
- const parts = String(s).trim().split(/\s+/).slice(0, 2)
283
- return parts.map((p) => p[0]?.toUpperCase() ?? "").join("") || "?"
246
+ if (!s) return "?";
247
+ const parts = String(s).trim().split(/\s+/).slice(0, 2);
248
+ return parts.map((p) => p[0]?.toUpperCase() ?? "").join("") || "?";
284
249
  }
285
250
 
286
251
  function renderLink({ value, field }: RenderArgs): ReactNode {
287
- const v = String(value)
288
- let href = v
289
- if (field.linkType === "mailto" && !v.startsWith("mailto:")) href = `mailto:${v}`
290
- else if (field.linkType === "tel" && !v.startsWith("tel:")) href = `tel:${v}`
252
+ const v = String(value);
253
+ let href = v;
254
+ if (field.linkType === "mailto" && !v.startsWith("mailto:")) href = `mailto:${v}`;
255
+ else if (field.linkType === "tel" && !v.startsWith("tel:")) href = `tel:${v}`;
291
256
 
292
257
  return (
293
258
  <a
@@ -299,36 +264,36 @@ function renderLink({ value, field }: RenderArgs): ReactNode {
299
264
  >
300
265
  {v}
301
266
  </a>
302
- )
267
+ );
303
268
  }
304
269
 
305
270
  function renderImage({ value }: RenderArgs): ReactNode {
306
- if (typeof value !== "string" || !value) return NULL_PLACEHOLDER
271
+ if (typeof value !== "string" || !value) return NULL_PLACEHOLDER;
307
272
  return (
308
273
  <img
309
274
  src={value}
310
275
  alt=""
311
276
  className="h-10 w-10 rounded object-cover border border-border-presentation-global-primary"
312
277
  />
313
- )
278
+ );
314
279
  }
315
280
 
316
281
  const RENDERERS: Record<FieldType, (a: RenderArgs) => ReactNode> = {
317
- "text": renderText,
318
- "number": renderNumber,
319
- "date": renderDate,
320
- "boolean": renderBoolean,
321
- "hidden": () => null,
282
+ text: renderText,
283
+ number: renderNumber,
284
+ date: renderDate,
285
+ boolean: renderBoolean,
286
+ hidden: () => null,
322
287
  "enum-badge": renderEnumBadge,
323
288
  "badge-array": renderBadgeArray,
324
- "currency": renderCurrency,
289
+ currency: renderCurrency,
325
290
  "number-format": renderNumberFormat,
326
291
  "progress-bar": renderProgressBar,
327
292
  "star-rating": renderStarRating,
328
293
  "icon-text": renderIconText,
329
294
  "two-line": renderTwoLine,
330
- "avatar": renderAvatar,
331
- "link": renderLink,
332
- "image": renderImage,
295
+ avatar: renderAvatar,
296
+ link: renderLink,
297
+ image: renderImage,
333
298
  "date-format": renderDateFormat,
334
- }
299
+ };
@@ -1,20 +1,20 @@
1
- "use client"
1
+ "use client";
2
2
 
3
- import { type ChangeEventHandler } from "react"
4
- import { DatePicker } from "../../DatePicker"
5
- import { InputField } from "../../InputField"
6
- import { ActionButton } from "../../ActionButton"
7
- import type { DateRangeFilter } from "../types"
8
- import { toIsoDate } from "../../../utils/dataViews/rangeUtils"
3
+ import { type ChangeEventHandler } from "react";
4
+ import { DatePicker } from "../../DatePicker";
5
+ import { InputField } from "../../InputField";
6
+ import { ActionButton } from "../../ActionButton";
7
+ import type { DateRangeFilter } from "../types";
8
+ import { toIsoDate } from "../../../utils/dataViews/rangeUtils";
9
9
 
10
10
  type Props = {
11
- value: DateRangeFilter | undefined
12
- onChange: (next: DateRangeFilter) => void
13
- }
11
+ value: DateRangeFilter | undefined;
12
+ onChange: (next: DateRangeFilter) => void;
13
+ };
14
14
 
15
15
  /** Parse an ISO `yyyy-MM-dd` string to a local Date (noon-safe, no TZ drift). */
16
16
  function parseIso(iso?: string): Date | undefined {
17
- return iso ? new Date(iso + "T00:00:00") : undefined
17
+ return iso ? new Date(iso + "T00:00:00") : undefined;
18
18
  }
19
19
 
20
20
  /** One labeled single-date Glare DatePicker bound to one end of the range. */
@@ -24,10 +24,10 @@ function DateBound({
24
24
  placeholder,
25
25
  onPick,
26
26
  }: {
27
- caption: string
28
- iso?: string
29
- placeholder: string
30
- onPick: (next?: string) => void
27
+ caption: string;
28
+ iso?: string;
29
+ placeholder: string;
30
+ onPick: (next?: string) => void;
31
31
  }) {
32
32
  return (
33
33
  <label className="flex items-center gap-2">
@@ -41,10 +41,12 @@ function DateBound({
41
41
  value={parseIso(iso) ?? (undefined as never)}
42
42
  dateFormat="yyyy-MM-dd"
43
43
  // Single mode reports `{ target: { value: Date } }` (it casts internally).
44
- onChange={((e: { target: { value: Date | undefined } }) => {
45
- const d = e?.target?.value
46
- onPick(d instanceof Date ? toIsoDate(d) : undefined)
47
- }) as unknown as ChangeEventHandler<HTMLInputElement>}
44
+ onChange={
45
+ ((e: { target: { value: Date | undefined } }) => {
46
+ const d = e?.target?.value;
47
+ onPick(d instanceof Date ? toIsoDate(d) : undefined);
48
+ }) as unknown as ChangeEventHandler<HTMLInputElement>
49
+ }
48
50
  >
49
51
  <InputField
50
52
  readOnly
@@ -59,7 +61,7 @@ function DateBound({
59
61
  </DatePicker>
60
62
  </div>
61
63
  </label>
62
- )
64
+ );
63
65
  }
64
66
 
65
67
  /**
@@ -69,12 +71,17 @@ function DateBound({
69
71
  */
70
72
  export function DatePickerRangeFilter({ value, onChange }: Props) {
71
73
  const setBound = (key: "from" | "to") => (next?: string) =>
72
- onChange({ kind: "date", from: value?.from, to: value?.to, [key]: next })
74
+ onChange({ kind: "date", from: value?.from, to: value?.to, [key]: next });
73
75
 
74
76
  return (
75
77
  <div className="space-y-2">
76
- <DateBound caption="From" iso={value?.from} placeholder="Start date" onPick={setBound("from")} />
78
+ <DateBound
79
+ caption="From"
80
+ iso={value?.from}
81
+ placeholder="Start date"
82
+ onPick={setBound("from")}
83
+ />
77
84
  <DateBound caption="To" iso={value?.to} placeholder="End date" onPick={setBound("to")} />
78
85
  </div>
79
- )
86
+ );
80
87
  }
@@ -1,47 +1,50 @@
1
- "use client"
1
+ "use client";
2
2
 
3
- import { useState } from "react"
4
- import { DayPicker, type DateRange } from "react-day-picker"
5
- import "react-day-picker/style.css"
6
- import * as PopoverPrimitive from "@radix-ui/react-popover"
7
- import { Calendar, X } from "lucide-react"
8
- import { cn } from "../../../utils/cn"
9
- import type { DateRangeFilter, FieldConfig } from "../types"
10
- import { toIsoDate } from "../../../utils/dataViews/rangeUtils"
11
- import { PresetChips } from "./PresetChips"
3
+ import { useState } from "react";
4
+ import { DayPicker, type DateRange } from "react-day-picker";
5
+ import "react-day-picker/style.css";
6
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
7
+ import { Calendar, X } from "lucide-react";
8
+ import { cn } from "../../../utils/cn";
9
+ import type { DateRangeFilter, FieldConfig, FilterValue } from "../types";
10
+ import { toIsoDate } from "../../../utils/dataViews/rangeUtils";
11
+ import { PresetChips } from "./PresetChips";
12
12
 
13
13
  type Props = {
14
- value: DateRangeFilter | undefined
15
- onChange: (next: DateRangeFilter) => void
16
- presets: FieldConfig["presets"]
17
- }
14
+ value: DateRangeFilter | undefined;
15
+ onChange: (next: DateRangeFilter) => void;
16
+ presets: FieldConfig["presets"];
17
+ };
18
18
 
19
19
  export function DateRangePopover({ value, onChange, presets }: Props) {
20
- const [open, setOpen] = useState(false)
20
+ const [open, setOpen] = useState(false);
21
21
 
22
22
  const range: DateRange | undefined =
23
23
  value && (value.from || value.to)
24
24
  ? {
25
25
  from: value.from ? new Date(value.from + "T00:00:00") : undefined,
26
- to: value.to ? new Date(value.to + "T00:00:00") : undefined,
26
+ to: value.to ? new Date(value.to + "T00:00:00") : undefined,
27
27
  }
28
- : undefined
28
+ : undefined;
29
29
 
30
30
  const label =
31
- value?.from && value?.to ? `${value.from} → ${value.to}`
32
- : value?.from ? `from ${value.from}`
33
- : value?.to ? `until ${value.to}`
34
- : "Any date"
31
+ value?.from && value?.to
32
+ ? `${value.from} ${value.to}`
33
+ : value?.from
34
+ ? `from ${value.from}`
35
+ : value?.to
36
+ ? `until ${value.to}`
37
+ : "Any date";
35
38
 
36
39
  const handleSelect = (next: DateRange | undefined) => {
37
40
  onChange({
38
41
  kind: "date",
39
42
  from: next?.from ? toIsoDate(next.from) : undefined,
40
- to: next?.to ? toIsoDate(next.to) : undefined,
41
- })
42
- }
43
+ to: next?.to ? toIsoDate(next.to) : undefined,
44
+ });
45
+ };
43
46
 
44
- const isActive = !!(value?.from || value?.to)
47
+ const isActive = !!(value?.from || value?.to);
45
48
 
46
49
  return (
47
50
  <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>
@@ -63,14 +66,14 @@ export function DateRangePopover({ value, onChange, presets }: Props) {
63
66
  tabIndex={0}
64
67
  aria-label="Clear date filter"
65
68
  onClick={(e) => {
66
- e.stopPropagation()
67
- onChange({ kind: "date" })
69
+ e.stopPropagation();
70
+ onChange({ kind: "date" });
68
71
  }}
69
72
  onKeyDown={(e) => {
70
73
  if (e.key === "Enter" || e.key === " ") {
71
- e.stopPropagation()
72
- e.preventDefault()
73
- onChange({ kind: "date" })
74
+ e.stopPropagation();
75
+ e.preventDefault();
76
+ onChange({ kind: "date" });
74
77
  }
75
78
  }}
76
79
  className="text-content-presentation-global-tertiary hover:text-content-presentation-global-primary cursor-pointer"
@@ -87,7 +90,11 @@ export function DateRangePopover({ value, onChange, presets }: Props) {
87
90
  className="z-50 bg-background-presentation-body-primary border border-border-presentation-global-primary rounded-lg shadow-lg p-3 space-y-3"
88
91
  >
89
92
  {presets && presets.length > 0 && (
90
- <PresetChips presets={presets} current={value} onSelect={onChange as any} />
93
+ <PresetChips
94
+ presets={presets}
95
+ current={value}
96
+ onSelect={onChange as (value: FilterValue) => void}
97
+ />
91
98
  )}
92
99
  <DayPicker
93
100
  mode="range"
@@ -109,5 +116,5 @@ export function DateRangePopover({ value, onChange, presets }: Props) {
109
116
  </PopoverPrimitive.Content>
110
117
  </PopoverPrimitive.Portal>
111
118
  </PopoverPrimitive.Root>
112
- )
119
+ );
113
120
  }