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,24 +1,26 @@
1
- import type { ReactElement } from "react"
2
- import { Badge } from "../../components/Badge"
3
- import { Divider } from "../../components/Divider"
4
- import { cn } from "../cn"
5
- import type { DynamicRecord, DynamicColumnConfig } from "../../components/DataViews/types"
1
+ import type { ReactElement } from "react";
2
+ import { Badge } from "../../components/Badge";
3
+ import { Divider } from "../../components/Divider";
4
+ import { cn } from "../cn";
5
+ import type { DynamicRecord, DynamicColumnConfig } from "../../components/DataViews/types";
6
6
 
7
7
  export type NestedFieldMetadata = {
8
- key: string
9
- label: string
10
- type: 'object' | 'array' | 'primitive'
11
- valueType?: 'string' | 'number' | 'boolean' | 'date'
12
- isArrayOfObjects?: boolean
13
- depth: number
14
- }
15
-
16
- export function isPlainObject(value: any): boolean {
17
- return value !== null &&
18
- typeof value === 'object' &&
19
- !Array.isArray(value) &&
20
- !(value instanceof Date) &&
21
- Object.keys(value).length > 0
8
+ key: string;
9
+ label: string;
10
+ type: "object" | "array" | "primitive";
11
+ valueType?: "string" | "number" | "boolean" | "date";
12
+ isArrayOfObjects?: boolean;
13
+ depth: number;
14
+ };
15
+
16
+ export function isPlainObject(value: unknown): boolean {
17
+ return (
18
+ value !== null &&
19
+ typeof value === "object" &&
20
+ !Array.isArray(value) &&
21
+ !(value instanceof Date) &&
22
+ Object.keys(value).length > 0
23
+ );
22
24
  }
23
25
 
24
26
  export function formatFieldName(fieldName: string): string {
@@ -26,84 +28,85 @@ export function formatFieldName(fieldName: string): string {
26
28
  return fieldName
27
29
  .split("_")
28
30
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
29
- .join(" ")
31
+ .join(" ");
30
32
  }
31
33
 
32
34
  return fieldName
33
35
  .replace(/([A-Z])/g, " $1")
34
36
  .replace(/^./, (str) => str.toUpperCase())
35
- .trim()
37
+ .trim();
36
38
  }
37
39
 
38
40
  export function analyzeNestedFields(
39
41
  item: DynamicRecord,
40
42
  visibleColumnIds: Set<string> = new Set(),
41
- excludeKeys: string[] = ['id', 'isRead', 'isStarred', 'hasAttachment', 'priority']
43
+ excludeKeys: string[] = ["id", "isRead", "isStarred", "hasAttachment", "priority"],
42
44
  ): NestedFieldMetadata[] {
43
- const nestedFields: NestedFieldMetadata[] = []
45
+ const nestedFields: NestedFieldMetadata[] = [];
44
46
 
45
47
  Object.entries(item).forEach(([key, value]) => {
46
48
  if (visibleColumnIds.has(key) || excludeKeys.includes(key)) {
47
- return
49
+ return;
48
50
  }
49
51
 
50
52
  if (isPlainObject(value)) {
51
53
  nestedFields.push({
52
54
  key,
53
55
  label: formatFieldName(key),
54
- type: 'object',
55
- depth: 0
56
- })
56
+ type: "object",
57
+ depth: 0,
58
+ });
57
59
  } else if (Array.isArray(value) && value.length > 0) {
58
60
  nestedFields.push({
59
61
  key,
60
62
  label: formatFieldName(key),
61
- type: 'array',
63
+ type: "array",
62
64
  isArrayOfObjects: isPlainObject(value[0]),
63
- depth: 0
64
- })
65
+ depth: 0,
66
+ });
65
67
  }
66
- })
68
+ });
67
69
 
68
- return nestedFields
70
+ return nestedFields;
69
71
  }
70
72
 
71
73
  export function isCurrencyField(key: string): boolean {
72
- const lowerKey = key.toLowerCase()
73
- return lowerKey.includes('salary') ||
74
- lowerKey.includes('price') ||
75
- lowerKey.includes('cost') ||
76
- lowerKey.includes('amount') ||
77
- lowerKey.includes('pay') ||
78
- lowerKey.includes('fee')
74
+ const lowerKey = key.toLowerCase();
75
+ return (
76
+ lowerKey.includes("salary") ||
77
+ lowerKey.includes("price") ||
78
+ lowerKey.includes("cost") ||
79
+ lowerKey.includes("amount") ||
80
+ lowerKey.includes("pay") ||
81
+ lowerKey.includes("fee")
82
+ );
79
83
  }
80
84
 
81
85
  export function isRatingField(key: string): boolean {
82
- const lowerKey = key.toLowerCase()
83
- return lowerKey.includes('rating') ||
84
- lowerKey.includes('score')
86
+ const lowerKey = key.toLowerCase();
87
+ return lowerKey.includes("rating") || lowerKey.includes("score");
85
88
  }
86
89
 
87
90
  export function renderPrimitiveValue(
88
91
  key: string,
89
- value: any,
92
+ value: unknown,
90
93
  options: {
91
- showLabel?: boolean
92
- labelClassName?: string
93
- valueClassName?: string
94
- } = {}
94
+ showLabel?: boolean;
95
+ labelClassName?: string;
96
+ valueClassName?: string;
97
+ } = {},
95
98
  ): ReactElement | null {
96
99
  const {
97
100
  showLabel = true,
98
101
  labelClassName = "text-content-presentation-global-tertiary",
99
- valueClassName = "text-content-presentation-global-primary"
100
- } = options
102
+ valueClassName = "text-content-presentation-global-primary",
103
+ } = options;
101
104
 
102
- if (value == null) return null
105
+ if (value == null) return null;
103
106
 
104
- const label = showLabel ? formatFieldName(key) : null
107
+ const label = showLabel ? formatFieldName(key) : null;
105
108
 
106
- if (typeof value === 'boolean') {
109
+ if (typeof value === "boolean") {
107
110
  return (
108
111
  <div className="flex items-center gap-2">
109
112
  {label && <span className={labelClassName}>{label}:</span>}
@@ -112,15 +115,14 @@ export function renderPrimitiveValue(
112
115
  badgeStyle={value ? "solid" : "subtle"}
113
116
  label={value ? "Yes" : "No"}
114
117
  size="XS"
115
-
116
118
  />
117
119
  </div>
118
- )
120
+ );
119
121
  }
120
122
 
121
- if (typeof value === 'number') {
122
- const isCurrency = isCurrencyField(key)
123
- const isRating = isRatingField(key)
123
+ if (typeof value === "number") {
124
+ const isCurrency = isCurrencyField(key);
125
+ const isRating = isRatingField(key);
124
126
 
125
127
  if (isRating && value <= 5) {
126
128
  return (
@@ -129,7 +131,10 @@ export function renderPrimitiveValue(
129
131
  <div className="flex items-center gap-2">
130
132
  <div className="flex">
131
133
  {[...Array(5)].map((_, i) => (
132
- <span key={i} className={i < Math.floor(value) ? 'text-yellow-500' : 'text-gray-300'}>
134
+ <span
135
+ key={i}
136
+ className={i < Math.floor(value) ? "text-yellow-500" : "text-gray-300"}
137
+ >
133
138
 
134
139
  </span>
135
140
  ))}
@@ -137,20 +142,17 @@ export function renderPrimitiveValue(
137
142
  <span className="font-semibold text-sm">{value}</span>
138
143
  </div>
139
144
  </div>
140
- )
145
+ );
141
146
  }
142
147
 
143
148
  return (
144
149
  <div className="flex items-center gap-2">
145
150
  {label && <span className={labelClassName}>{label}:</span>}
146
- <span className={cn(
147
- valueClassName,
148
- isCurrency && "font-semibold text-green-600"
149
- )}>
151
+ <span className={cn(valueClassName, isCurrency && "font-semibold text-green-600")}>
150
152
  {isCurrency ? `$${value.toLocaleString()}` : value.toLocaleString()}
151
153
  </span>
152
154
  </div>
153
- )
155
+ );
154
156
  }
155
157
 
156
158
  return (
@@ -158,24 +160,24 @@ export function renderPrimitiveValue(
158
160
  {label && <span className={labelClassName}>{label}:</span>}
159
161
  <span className={valueClassName}>{String(value)}</span>
160
162
  </div>
161
- )
163
+ );
162
164
  }
163
165
 
164
166
  export function renderArrayValue(
165
167
  key: string,
166
- value: any[],
168
+ value: unknown[],
167
169
  options: {
168
- showLabel?: boolean
169
- maxItems?: number
170
- renderItem?: (item: any, index: number) => ReactElement
171
- } = {}
170
+ showLabel?: boolean;
171
+ maxItems?: number;
172
+ renderItem?: (item: unknown, index: number) => ReactElement;
173
+ } = {},
172
174
  ): ReactElement | null {
173
- const { showLabel = true, maxItems, renderItem } = options
175
+ const { showLabel = true, maxItems, renderItem } = options;
174
176
 
175
- if (!Array.isArray(value) || value.length === 0) return null
177
+ if (!Array.isArray(value) || value.length === 0) return null;
176
178
 
177
- const label = showLabel ? formatFieldName(key) : null
178
- const displayItems = maxItems ? value.slice(0, maxItems) : value
179
+ const label = showLabel ? formatFieldName(key) : null;
180
+ const displayItems = maxItems ? value.slice(0, maxItems) : value;
179
181
 
180
182
  if (isPlainObject(value[0])) {
181
183
  return (
@@ -186,15 +188,15 @@ export function renderArrayValue(
186
188
  </div>
187
189
  )}
188
190
  <div className="space-y-2">
189
- {displayItems.map((item: any, idx: number) => {
191
+ {displayItems.map((item: unknown, idx: number) => {
190
192
  if (renderItem) {
191
- return renderItem(item, idx)
193
+ return renderItem(item, idx);
192
194
  }
193
195
  return (
194
196
  <div key={idx} className="p-2 rounded bg-background-presentation-form-field-primary">
195
197
  {renderNestedObject(item, 1)}
196
198
  </div>
197
- )
199
+ );
198
200
  })}
199
201
  {maxItems && value.length > maxItems && (
200
202
  <div className="text-xs text-content-presentation-global-tertiary">
@@ -203,14 +205,14 @@ export function renderArrayValue(
203
205
  )}
204
206
  </div>
205
207
  </div>
206
- )
208
+ );
207
209
  }
208
210
 
209
211
  return (
210
212
  <div className="flex items-start gap-2">
211
213
  {label && <span className="text-content-presentation-global-tertiary">{label}:</span>}
212
214
  <div className="flex flex-wrap gap-1">
213
- {displayItems.map((item: any, idx: number) => (
215
+ {displayItems.map((item: unknown, idx: number) => (
214
216
  <Badge key={idx} color="blue" badgeStyle="solid" label={String(item)} size="XS" />
215
217
  ))}
216
218
  {maxItems && value.length > maxItems && (
@@ -218,26 +220,26 @@ export function renderArrayValue(
218
220
  )}
219
221
  </div>
220
222
  </div>
221
- )
223
+ );
222
224
  }
223
225
 
224
226
  export function renderNestedObject(
225
- obj: any,
227
+ obj: unknown,
226
228
  depth: number = 0,
227
229
  options: {
228
- maxDepth?: number
229
- showSeparators?: boolean
230
- } = {}
230
+ maxDepth?: number;
231
+ showSeparators?: boolean;
232
+ } = {},
231
233
  ): ReactElement {
232
- const { maxDepth = 3 } = options
234
+ const { maxDepth = 3 } = options;
233
235
 
234
236
  if (depth >= maxDepth) {
235
- return <div className="text-xs text-content-presentation-global-tertiary">...</div>
237
+ return <div className="text-xs text-content-presentation-global-tertiary">...</div>;
236
238
  }
237
239
 
238
240
  return (
239
241
  <div className="space-y-2 text-sm">
240
- {Object.entries(obj).map(([key, value]) => {
242
+ {Object.entries(obj as Record<string, unknown>).map(([key, value]) => {
241
243
  if (isPlainObject(value)) {
242
244
  return (
243
245
  <div key={key} className="space-y-1">
@@ -248,34 +250,39 @@ export function renderNestedObject(
248
250
  {renderNestedObject(value, depth + 1, options)}
249
251
  </div>
250
252
  </div>
251
- )
253
+ );
252
254
  }
253
255
 
254
256
  if (Array.isArray(value)) {
255
- return <div key={key}>{renderArrayValue(key, value)}</div>
257
+ return <div key={key}>{renderArrayValue(key, value)}</div>;
256
258
  }
257
259
 
258
- return <div key={key}>{renderPrimitiveValue(key, value)}</div>
260
+ return <div key={key}>{renderPrimitiveValue(key, value)}</div>;
259
261
  })}
260
262
  </div>
261
- )
263
+ );
262
264
  }
263
265
 
264
266
  export function renderDetailView(
265
267
  selectedItem: DynamicRecord,
266
268
  visibleColumns: DynamicColumnConfig[],
267
- renderCellValue: (value: any, column: DynamicColumnConfig, row: DynamicRecord) => React.ReactNode
269
+ renderCellValue: (
270
+ value: unknown,
271
+ column: DynamicColumnConfig,
272
+ row: DynamicRecord,
273
+ ) => React.ReactNode,
268
274
  ): ReactElement {
269
- const visibleColumnIds = new Set(visibleColumns.map(col => col.id))
270
- const nestedFields = analyzeNestedFields(selectedItem, visibleColumnIds)
275
+ const visibleColumnIds = new Set(visibleColumns.map((col) => col.id));
276
+ const nestedFields = analyzeNestedFields(selectedItem, visibleColumnIds);
271
277
 
272
278
  return (
273
279
  <div className="space-y-6">
274
280
  {visibleColumns.slice(2).length > 0 && (
275
281
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
276
282
  {visibleColumns.slice(2).map((col) => {
277
- const value = selectedItem[col.id]
278
- if (value == null && value !== 0 && value !== false) return null
283
+ const value = selectedItem[col.id];
284
+ // Skip empty cells (null/undefined); 0 and false are rendered.
285
+ if (value === null || value === undefined) return null;
279
286
  return (
280
287
  <div key={col.id} className="space-y-1">
281
288
  <dt className="text-xs font-medium text-content-presentation-global-tertiary uppercase tracking-wide">
@@ -285,15 +292,15 @@ export function renderDetailView(
285
292
  {renderCellValue(value, col, selectedItem)}
286
293
  </dd>
287
294
  </div>
288
- )
295
+ );
289
296
  })}
290
297
  </div>
291
298
  )}
292
299
 
293
300
  {nestedFields.map((field, index) => {
294
- const value = selectedItem[field.key]
301
+ const value = selectedItem[field.key];
295
302
 
296
- if (field.type === 'object' && isPlainObject(value)) {
303
+ if (field.type === "object" && isPlainObject(value)) {
297
304
  return (
298
305
  <div key={field.key}>
299
306
  {index > 0 && <Divider />}
@@ -304,10 +311,10 @@ export function renderDetailView(
304
311
  {renderNestedObject(value)}
305
312
  </div>
306
313
  </div>
307
- )
314
+ );
308
315
  }
309
316
 
310
- if (field.type === 'array' && Array.isArray(value)) {
317
+ if (field.type === "array" && Array.isArray(value)) {
311
318
  return (
312
319
  <div key={field.key}>
313
320
  {index > 0 && <Divider />}
@@ -318,47 +325,47 @@ export function renderDetailView(
318
325
  {renderArrayValue(field.key, value, { showLabel: false })}
319
326
  </div>
320
327
  </div>
321
- )
328
+ );
322
329
  }
323
330
 
324
- return null
331
+ return null;
325
332
  })}
326
333
  </div>
327
- )
334
+ );
328
335
  }
329
336
 
330
337
  export function getDataStructureSummary(data: DynamicRecord[]): {
331
- totalFields: number
332
- nestedFields: string[]
333
- arrayFields: string[]
334
- primitiveFields: string[]
338
+ totalFields: number;
339
+ nestedFields: string[];
340
+ arrayFields: string[];
341
+ primitiveFields: string[];
335
342
  } {
336
343
  if (!data || data.length === 0) {
337
- return { totalFields: 0, nestedFields: [], arrayFields: [], primitiveFields: [] }
344
+ return { totalFields: 0, nestedFields: [], arrayFields: [], primitiveFields: [] };
338
345
  }
339
346
 
340
- const allKeys = new Set<string>()
341
- const nestedKeys = new Set<string>()
342
- const arrayKeys = new Set<string>()
343
- const primitiveKeys = new Set<string>()
347
+ const allKeys = new Set<string>();
348
+ const nestedKeys = new Set<string>();
349
+ const arrayKeys = new Set<string>();
350
+ const primitiveKeys = new Set<string>();
344
351
 
345
- data.forEach(item => {
352
+ data.forEach((item) => {
346
353
  Object.entries(item).forEach(([key, value]) => {
347
- allKeys.add(key)
354
+ allKeys.add(key);
348
355
  if (isPlainObject(value)) {
349
- nestedKeys.add(key)
356
+ nestedKeys.add(key);
350
357
  } else if (Array.isArray(value)) {
351
- arrayKeys.add(key)
358
+ arrayKeys.add(key);
352
359
  } else {
353
- primitiveKeys.add(key)
360
+ primitiveKeys.add(key);
354
361
  }
355
- })
356
- })
362
+ });
363
+ });
357
364
 
358
365
  return {
359
366
  totalFields: allKeys.size,
360
367
  nestedFields: Array.from(nestedKeys),
361
368
  arrayFields: Array.from(arrayKeys),
362
- primitiveFields: Array.from(primitiveKeys)
363
- }
369
+ primitiveFields: Array.from(primitiveKeys),
370
+ };
364
371
  }
@@ -1,132 +1,139 @@
1
- export type Path = string
1
+ export type Path = string;
2
2
 
3
- const PATH_CACHE = new Map<string, string[]>()
3
+ const PATH_CACHE = new Map<string, string[]>();
4
4
 
5
5
  function splitPath(path: Path): string[] {
6
- const cached = PATH_CACHE.get(path)
7
- if (cached) return cached
8
- const parts = path.split(".")
9
- PATH_CACHE.set(path, parts)
10
- return parts
6
+ const cached = PATH_CACHE.get(path);
7
+ if (cached) return cached;
8
+ const parts = path.split(".");
9
+ PATH_CACHE.set(path, parts);
10
+ return parts;
11
11
  }
12
12
 
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- generic path accessor returns arbitrary runtime values
13
14
  export function getByPath(obj: unknown, path: Path | undefined | null): any {
14
- if (obj == null || path == null || path === "") return undefined
15
- if (typeof obj !== "object") return undefined
15
+ if (obj == null || path == null || path === "") return undefined;
16
+ if (typeof obj !== "object") return undefined;
16
17
 
17
- const parts = splitPath(path)
18
- let cur: any = obj
18
+ const parts = splitPath(path);
19
+ let cur: unknown = obj;
19
20
  for (let i = 0; i < parts.length; i++) {
20
- if (cur == null) return undefined
21
- cur = cur[parts[i]]
21
+ if (cur == null) return undefined;
22
+ cur = (cur as Record<string, unknown>)[parts[i]];
22
23
  }
23
- return cur
24
+ return cur;
24
25
  }
25
26
 
26
- export function setByPath<T extends Record<string, any>>(
27
+ export function setByPath<T extends Record<string, unknown>>(
27
28
  obj: T,
28
29
  path: Path,
29
- value: any,
30
+ value: unknown,
30
31
  ): T {
31
- if (!path) return obj
32
- const parts = splitPath(path)
33
- if (parts.length === 0) return obj
32
+ if (!path) return obj;
33
+ const parts = splitPath(path);
34
+ if (parts.length === 0) return obj;
34
35
 
35
- const root: any = Array.isArray(obj) ? [...obj] : { ...obj }
36
- let cur: any = root
36
+ const root = (Array.isArray(obj) ? [...obj] : { ...obj }) as Record<string, unknown>;
37
+ let cur: Record<string, unknown> = root;
37
38
 
38
39
  for (let i = 0; i < parts.length - 1; i++) {
39
- const key = parts[i]
40
- const next = cur[key]
41
- const cloned = next != null && typeof next === "object" && !Array.isArray(next)
42
- ? { ...next }
43
- : Array.isArray(next)
44
- ? [...next]
45
- : {}
46
- cur[key] = cloned
47
- cur = cloned
40
+ const key = parts[i];
41
+ const next = cur[key];
42
+ const cloned = (
43
+ next != null && typeof next === "object" && !Array.isArray(next)
44
+ ? { ...next }
45
+ : Array.isArray(next)
46
+ ? [...next]
47
+ : {}
48
+ ) as Record<string, unknown>;
49
+ cur[key] = cloned;
50
+ cur = cloned;
48
51
  }
49
52
 
50
- cur[parts[parts.length - 1]] = value
51
- return root
53
+ cur[parts[parts.length - 1]] = value;
54
+ return root as T;
52
55
  }
53
56
 
54
57
  export function hasPath(obj: unknown, path: Path | undefined | null): boolean {
55
- return getByPath(obj, path) !== undefined
58
+ return getByPath(obj, path) !== undefined;
56
59
  }
57
60
 
58
61
  export function formatPathLabel(path: Path): string {
59
- if (!path) return ""
60
- const tail = path.includes(".") ? path.split(".").pop()! : path
62
+ if (!path) return "";
63
+ const tail = path.includes(".") ? path.split(".").pop()! : path;
61
64
 
62
65
  if (tail.includes("_")) {
63
66
  return tail
64
67
  .split("_")
65
68
  .filter(Boolean)
66
69
  .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
67
- .join(" ")
70
+ .join(" ");
68
71
  }
69
72
 
70
73
  return tail
71
74
  .replace(/([A-Z])/g, " $1")
72
75
  .replace(/^./, (s) => s.toUpperCase())
73
- .trim()
76
+ .trim();
74
77
  }
75
78
 
76
- export function findFirstDefined(data: any[], path: Path): any {
79
+ export function findFirstDefined(data: unknown[], path: Path): unknown {
77
80
  for (const item of data) {
78
- const v = getByPath(item, path)
79
- if (v != null) return v
81
+ const v = getByPath(item, path);
82
+ if (v != null) return v;
80
83
  }
81
- return undefined
84
+ return undefined;
82
85
  }
83
86
 
84
87
  export function matchesFilterValues(
85
88
  item: unknown,
86
89
  path: Path,
87
- filter: string[] | { kind: "number"; min?: number; max?: number } | { kind: "date"; from?: string; to?: string } | undefined,
90
+ filter:
91
+ | string[]
92
+ | { kind: "number"; min?: number; max?: number }
93
+ | { kind: "date"; from?: string; to?: string }
94
+ | undefined,
88
95
  ): boolean {
89
- if (filter == null) return true
96
+ if (filter == null) return true;
90
97
 
91
98
  if (Array.isArray(filter)) {
92
- if (filter.length === 0) return true
93
- const value = getByPath(item, path)
99
+ if (filter.length === 0) return true;
100
+ const value = getByPath(item, path);
94
101
  if (Array.isArray(value)) {
95
- const set = new Set(value.map((v) => String(v)))
96
- return filter.some((s) => set.has(s))
102
+ const set = new Set(value.map((v) => String(v)));
103
+ return filter.some((s) => set.has(s));
97
104
  }
98
105
  if (typeof value === "boolean") {
99
- return filter.includes(value ? "true" : "false")
106
+ return filter.includes(value ? "true" : "false");
100
107
  }
101
- return filter.includes(String(value ?? ""))
108
+ return filter.includes(String(value ?? ""));
102
109
  }
103
110
 
104
111
  if (filter.kind === "number") {
105
- if (filter.min == null && filter.max == null) return true
106
- const raw = getByPath(item, path)
107
- const n = typeof raw === "number" ? raw : Number(raw)
108
- if (!Number.isFinite(n)) return false
109
- if (filter.min != null && n < filter.min) return false
110
- if (filter.max != null && n > filter.max) return false
111
- return true
112
+ if (filter.min == null && filter.max == null) return true;
113
+ const raw = getByPath(item, path);
114
+ const n = typeof raw === "number" ? raw : Number(raw);
115
+ if (!Number.isFinite(n)) return false;
116
+ if (filter.min != null && n < filter.min) return false;
117
+ if (filter.max != null && n > filter.max) return false;
118
+ return true;
112
119
  }
113
120
 
114
121
  if (filter.kind === "date") {
115
- if (filter.from == null && filter.to == null) return true
116
- const raw = getByPath(item, path)
117
- if (raw == null) return false
118
- const ms = raw instanceof Date ? raw.getTime() : Date.parse(String(raw))
119
- if (!Number.isFinite(ms)) return false
122
+ if (filter.from == null && filter.to == null) return true;
123
+ const raw = getByPath(item, path);
124
+ if (raw == null) return false;
125
+ const ms = raw instanceof Date ? raw.getTime() : Date.parse(String(raw));
126
+ if (!Number.isFinite(ms)) return false;
120
127
  if (filter.from != null) {
121
- const fromMs = Date.parse(filter.from)
122
- if (Number.isFinite(fromMs) && ms < fromMs) return false
128
+ const fromMs = Date.parse(filter.from);
129
+ if (Number.isFinite(fromMs) && ms < fromMs) return false;
123
130
  }
124
131
  if (filter.to != null) {
125
- const toMs = Date.parse(filter.to)
126
- if (Number.isFinite(toMs) && ms > toMs + 24 * 60 * 60 * 1000 - 1) return false
132
+ const toMs = Date.parse(filter.to);
133
+ if (Number.isFinite(toMs) && ms > toMs + 24 * 60 * 60 * 1000 - 1) return false;
127
134
  }
128
- return true
135
+ return true;
129
136
  }
130
137
 
131
- return true
138
+ return true;
132
139
  }