torch-glare 2.4.5 → 2.5.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 (142) hide show
  1. package/apps/lib/components/DataViews/{badgeAdapter.ts → badge.ts} +2 -2
  2. package/apps/lib/components/DataViews/cell.tsx +324 -0
  3. package/apps/lib/components/DataViews/context.ts +144 -0
  4. package/apps/lib/components/DataViews/data-views.tsx +383 -0
  5. package/apps/lib/components/DataViews/filters/children.tsx +98 -0
  6. package/apps/lib/components/DataViews/filters/custom.tsx +34 -0
  7. package/apps/lib/components/DataViews/filters/filters.tsx +163 -0
  8. package/apps/lib/components/DataViews/filters/index.ts +4 -0
  9. package/apps/lib/components/DataViews/filters/labelled.tsx +20 -0
  10. package/apps/lib/components/DataViews/filters/presets.tsx +65 -0
  11. package/apps/lib/components/DataViews/filters/summary.tsx +65 -0
  12. package/apps/lib/components/DataViews/filters/sync.tsx +35 -0
  13. package/apps/lib/components/DataViews/filters/values.ts +173 -0
  14. package/apps/lib/components/DataViews/header.tsx +217 -0
  15. package/apps/lib/components/DataViews/hooks/index.ts +5 -0
  16. package/apps/lib/components/DataViews/hooks/useActiveRow.ts +22 -0
  17. package/apps/lib/components/DataViews/hooks/useControllable.ts +52 -0
  18. package/apps/lib/components/DataViews/index.ts +74 -26
  19. package/apps/lib/components/DataViews/panel/columns.tsx +153 -0
  20. package/apps/lib/components/DataViews/panel/controls.tsx +106 -0
  21. package/apps/lib/components/DataViews/panel/index.ts +3 -0
  22. package/apps/lib/components/DataViews/panel/panel.tsx +164 -0
  23. package/apps/lib/components/DataViews/panel/saved-views.tsx +67 -0
  24. package/apps/lib/components/DataViews/panel/section.tsx +79 -0
  25. package/apps/lib/components/DataViews/panel/sort.tsx +42 -0
  26. package/apps/lib/components/DataViews/panel/tab.tsx +31 -0
  27. package/apps/lib/components/DataViews/slots.ts +63 -0
  28. package/apps/lib/components/DataViews/states.tsx +38 -0
  29. package/apps/lib/components/DataViews/types.ts +485 -178
  30. package/apps/lib/components/DataViews/views/board-view.tsx +379 -0
  31. package/apps/lib/components/DataViews/views/card-rows.tsx +36 -0
  32. package/apps/lib/components/DataViews/views/inbox-view.tsx +257 -0
  33. package/apps/lib/components/DataViews/views/pane-views.tsx +192 -0
  34. package/apps/lib/components/DataViews/views/table-view.tsx +426 -0
  35. package/apps/lib/components/DataViews/views/tree-view.tsx +365 -0
  36. package/apps/lib/components/FormBuilder/context.ts +20 -6
  37. package/apps/lib/components/FormBuilder/field-kind.ts +28 -0
  38. package/apps/lib/components/FormBuilder/fields/DateField.tsx +3 -3
  39. package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +7 -6
  40. package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +7 -6
  41. package/apps/lib/components/FormBuilder/fields/SelectField.tsx +7 -7
  42. package/apps/lib/components/FormBuilder/fields/TableField.tsx +1 -1
  43. package/apps/lib/components/FormBuilder/fields/TextField.tsx +9 -9
  44. package/apps/lib/components/FormBuilder/form-builder.tsx +55 -3
  45. package/apps/lib/components/FormBuilder/index.ts +3 -1
  46. package/apps/lib/components/FormBuilder/types.ts +40 -0
  47. package/apps/lib/components/TabSwitch.tsx +16 -4
  48. package/apps/lib/components/TreeFolder/TreeFolder.tsx +6 -3
  49. package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +16 -14
  50. package/apps/lib/components/TreeFolder/index.ts +1 -1
  51. package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +70 -207
  52. package/apps/lib/hooks/useDragDrop.tsx +365 -0
  53. package/apps/lib/hooks/useInfiniteScroll.ts +108 -0
  54. package/apps/lib/registry.json +159 -4
  55. package/apps/lib/tsconfig.tsbuildinfo +1 -1
  56. package/apps/lib/utils/dataViews/path.ts +67 -0
  57. package/apps/lib/utils/dataViews/query.ts +73 -0
  58. package/apps/lib/utils/dataViews/types.ts +187 -0
  59. package/docs/components/breadcrumb.md +1 -1
  60. package/docs/components/button-group.md +1 -1
  61. package/docs/components/button.md +1 -1
  62. package/docs/components/card.md +1 -1
  63. package/docs/components/checkbox.md +1 -1
  64. package/docs/components/data-views/backend-response.md +324 -0
  65. package/docs/components/data-views/examples/a11y-rtl.md +250 -0
  66. package/docs/components/data-views/examples/api-orders-route.md +130 -0
  67. package/docs/components/data-views/examples/fields.md +362 -0
  68. package/docs/components/data-views/examples/filters.md +308 -0
  69. package/docs/components/data-views/examples/inbox-routing.md +218 -0
  70. package/docs/components/data-views/examples/index.md +29 -0
  71. package/docs/components/data-views/examples/overview.md +244 -0
  72. package/docs/components/data-views/examples/panel.md +212 -0
  73. package/docs/components/data-views/examples/scale.md +231 -0
  74. package/docs/components/data-views/examples/server-side.md +210 -0
  75. package/docs/components/data-views/examples/state.md +250 -0
  76. package/docs/components/data-views/examples/tree-custom.md +388 -0
  77. package/docs/components/data-views/examples/view-registry.md +313 -0
  78. package/docs/components/data-views/examples/views.md +534 -0
  79. package/docs/components/data-views/guide.md +405 -0
  80. package/docs/components/data-views/index.md +1504 -0
  81. package/docs/components/data-views/migration.md +79 -0
  82. package/docs/components/date-picker.md +0 -1
  83. package/docs/components/form-builder.md +3 -2
  84. package/docs/components/form-renderer.md +2 -1
  85. package/docs/components/form.md +1 -1
  86. package/docs/components/input-field.md +1 -1
  87. package/docs/components/input-otp.md +1 -1
  88. package/docs/components/input.md +1 -1
  89. package/docs/components/labeled-check-box.md +1 -1
  90. package/docs/components/labeled-radio.md +1 -1
  91. package/docs/components/radio-card.md +1 -1
  92. package/docs/components/radio.md +1 -1
  93. package/docs/components/search-field.md +1 -1
  94. package/docs/components/section-block.md +1 -1
  95. package/docs/components/select.md +1 -1
  96. package/docs/components/simple-select.md +1 -1
  97. package/docs/components/switch.md +1 -1
  98. package/docs/components/tab-switch.md +1 -1
  99. package/docs/components/table.md +1 -1
  100. package/docs/components/text-editor.md +1 -1
  101. package/docs/components/textarea.md +1 -1
  102. package/docs/components/toggle-button.md +1 -1
  103. package/docs/components/toggle.md +1 -1
  104. package/docs/components/tree-folder.md +110 -0
  105. package/docs/how-to/forms-with-form-builder.md +2 -2
  106. package/docs/reference/components.md +16 -6
  107. package/docs/tutorials/component-composition.md +11 -13
  108. package/package.json +3 -2
  109. package/apps/lib/components/DataViews/DataViewRadio.tsx +0 -49
  110. package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +0 -393
  111. package/apps/lib/components/DataViews/DataViewsHeader.tsx +0 -207
  112. package/apps/lib/components/DataViews/DataViewsLayout.tsx +0 -332
  113. package/apps/lib/components/DataViews/FilterPanel.tsx +0 -493
  114. package/apps/lib/components/DataViews/HeaderSearch.tsx +0 -93
  115. package/apps/lib/components/DataViews/InboxView.tsx +0 -463
  116. package/apps/lib/components/DataViews/InboxViewCard.tsx +0 -127
  117. package/apps/lib/components/DataViews/KanbanView.tsx +0 -336
  118. package/apps/lib/components/DataViews/PanelControls.tsx +0 -39
  119. package/apps/lib/components/DataViews/SettingsPanel.tsx +0 -279
  120. package/apps/lib/components/DataViews/TableView.tsx +0 -212
  121. package/apps/lib/components/DataViews/TreeView.tsx +0 -364
  122. package/apps/lib/components/DataViews/fieldRenderers.tsx +0 -299
  123. package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +0 -87
  124. package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +0 -120
  125. package/apps/lib/components/DataViews/filters/PresetChips.tsx +0 -45
  126. package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +0 -165
  127. package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +0 -50
  128. package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +0 -74
  129. package/apps/lib/hooks/useDataViewsState.ts +0 -175
  130. package/apps/lib/utils/dataViews/columnUtils.ts +0 -132
  131. package/apps/lib/utils/dataViews/fieldUtils.ts +0 -197
  132. package/apps/lib/utils/dataViews/nestedDataUtils.tsx +0 -371
  133. package/apps/lib/utils/dataViews/pathUtils.ts +0 -139
  134. package/apps/lib/utils/dataViews/rangeUtils.ts +0 -234
  135. package/apps/lib/utils/dataViews/treeUtils.ts +0 -396
  136. package/docs/components/data-views-config-panel.md +0 -208
  137. package/docs/components/data-views-layout.md +0 -291
  138. package/docs/components/inbox-view.md +0 -170
  139. package/docs/components/kanban-view.md +0 -135
  140. package/docs/components/table-view.md +0 -141
  141. package/docs/components/tree-view.md +0 -147
  142. package/docs/how-to/data-views-from-backend-response.md +0 -194
@@ -1,332 +0,0 @@
1
- "use client";
2
-
3
- import {
4
- forwardRef,
5
- useCallback,
6
- useEffect,
7
- useMemo,
8
- useRef,
9
- useState,
10
- type ElementType,
11
- type ReactNode,
12
- } from "react";
13
- import { List, LayoutGrid, Inbox as InboxIcon, Network } from "lucide-react";
14
- import type {
15
- DynamicRecord,
16
- DynamicColumnConfig,
17
- DynamicFilterConfig,
18
- FilterState,
19
- FieldConfig,
20
- InboxConfig,
21
- TreeConfig,
22
- ViewConfig,
23
- ViewType,
24
- ViewVisibility,
25
- } from "./types";
26
- import { TableView } from "./TableView";
27
- import { KanbanView } from "./KanbanView";
28
- import { InboxView } from "./InboxView";
29
- import { TreeView } from "./TreeView";
30
- import { DataViewsHeader, type DataViewsHeaderView } from "./DataViewsHeader";
31
- import { DataViewsConfigPanel } from "./DataViewsConfigPanel";
32
- import { useDataViewsState } from "../../hooks/useDataViewsState";
33
- import { cn } from "../../utils/cn";
34
- import type { Themes } from "../../utils/types";
35
-
36
- export type DataViewsLayoutProps = {
37
- data?: DynamicRecord[];
38
- config?: Partial<ViewConfig>;
39
- title?: string;
40
- description?: string;
41
-
42
- fields?: FieldConfig[];
43
- inboxConfig?: InboxConfig;
44
- treeConfig?: TreeConfig;
45
- kanbanGroupBy?: string;
46
- kanbanTitleField?: string;
47
- onKanbanColumnAction?: (columnId: string) => void;
48
-
49
- views?: ViewVisibility;
50
-
51
- columns?: Partial<DynamicColumnConfig>[];
52
- filters?: DynamicFilterConfig[];
53
-
54
- filterState?: FilterState;
55
- onFilterChange?: (filters: FilterState) => void;
56
-
57
- showFilters?: boolean;
58
- showSettings?: boolean;
59
- showTitle?: boolean;
60
-
61
- onAddNew?: () => void;
62
- addNewLabel?: string;
63
-
64
- inboxItemHref?: (item: DynamicRecord, id: unknown) => string;
65
- /**
66
- * Component used to render inbox item links when `inboxItemHref` is set.
67
- * Defaults to a plain `<a>` (full-page navigation). Pass your router's link
68
- * (e.g. Next.js `Link`, React Router `Link`) for client-side navigation.
69
- */
70
- inboxLinkComponent?: ElementType;
71
- inboxSelectedId?: unknown;
72
- inboxRenderDetail?: (item: DynamicRecord | null) => ReactNode;
73
-
74
- searchValue?: string;
75
- onSearchChange?: (value: string) => void;
76
- searchPlaceholder?: string;
77
-
78
- className?: string;
79
- theme?: Themes;
80
- };
81
-
82
- const VIEW_META: Record<ViewType, { label: string; icon: DataViewsHeaderView["icon"] }> = {
83
- table: { label: "List", icon: <List /> },
84
- kanban: { label: "Board", icon: <LayoutGrid /> },
85
- inbox: { label: "Inbox", icon: <InboxIcon /> },
86
- tree: { label: "Tree", icon: <Network /> },
87
- };
88
-
89
- const VIEW_ORDER: ViewType[] = ["table", "kanban", "inbox", "tree"];
90
-
91
- export const DataViewsLayout = forwardRef<HTMLDivElement, DataViewsLayoutProps>(
92
- function DataViewsLayout(props, ref) {
93
- const {
94
- title = "Data Views",
95
- data,
96
- config: initialConfig,
97
- fields,
98
- inboxConfig,
99
- treeConfig,
100
- kanbanGroupBy,
101
- kanbanTitleField,
102
- onKanbanColumnAction,
103
- views,
104
- columns,
105
- filters,
106
- filterState: externalFilterState,
107
- onFilterChange,
108
- // `showFilters` is retained on the public API but filters now live in the
109
- // right-side config rail rather than an inline per-view panel.
110
- showSettings = true,
111
- showTitle = true,
112
- onAddNew,
113
- addNewLabel,
114
- inboxItemHref,
115
- inboxLinkComponent,
116
- inboxSelectedId,
117
- inboxRenderDetail,
118
- searchValue,
119
- onSearchChange,
120
- searchPlaceholder,
121
- className,
122
- theme,
123
- } = props;
124
-
125
- const {
126
- items,
127
- flatItems,
128
- resolvedFields,
129
- detectedColumns,
130
- config,
131
- setConfig,
132
- currentView,
133
- setCurrentView,
134
- filterState,
135
- setFilterState,
136
- onDataUpdate,
137
- enabledViews,
138
- } = useDataViewsState({
139
- data,
140
- fields,
141
- columns,
142
- config: initialConfig,
143
- treeConfig,
144
- views,
145
- filterState: externalFilterState,
146
- onFilterChange,
147
- });
148
-
149
- // `panelOpen` drives intent; `panelMounted` keeps the panel in the tree
150
- // through the close animation before unmounting.
151
- const [panelOpen, setPanelOpen] = useState(false);
152
- const [panelMounted, setPanelMounted] = useState(false);
153
- const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
154
-
155
- const openPanel = useCallback(() => {
156
- if (closeTimer.current) {
157
- clearTimeout(closeTimer.current);
158
- closeTimer.current = null;
159
- }
160
- // Mount at width 0 first, then flip to open on the next frame so the
161
- // width transition animates from 0 → 260px instead of snapping.
162
- setPanelMounted(true);
163
- requestAnimationFrame(() => requestAnimationFrame(() => setPanelOpen(true)));
164
- }, []);
165
-
166
- const closePanel = useCallback(() => {
167
- setPanelOpen(false);
168
- if (closeTimer.current) clearTimeout(closeTimer.current);
169
- // Keep mounted through the width/fade animation (300ms) before unmounting.
170
- closeTimer.current = setTimeout(() => setPanelMounted(false), 300);
171
- }, []);
172
-
173
- const togglePanel = useCallback(() => {
174
- if (panelOpen) closePanel();
175
- else openPanel();
176
- }, [panelOpen, openPanel, closePanel]);
177
-
178
- useEffect(() => {
179
- return () => {
180
- if (closeTimer.current) clearTimeout(closeTimer.current);
181
- };
182
- }, []);
183
-
184
- const effectiveKanbanGroupBy = kanbanGroupBy ?? config.kanbanGroupBy;
185
- // Filters now live in the right-side rail, not as an inline per-view panel.
186
- const effectiveConfig: ViewConfig = { ...config, showFilters: false };
187
-
188
- const headerViews = useMemo<DataViewsHeaderView[]>(
189
- () =>
190
- VIEW_ORDER.filter((v) => enabledViews[v]).map((v) => ({
191
- id: v,
192
- label: VIEW_META[v].label,
193
- icon: VIEW_META[v].icon,
194
- })),
195
- [enabledViews],
196
- );
197
-
198
- return (
199
- <div
200
- ref={ref}
201
- data-theme={theme}
202
- className={cn(
203
- // Shell is always black (matches Figma): the dark header and config
204
- // rail sit on it; the Master Container is the white surface inside.
205
- // `overflow-hidden` traps any child overflow — without it, a tall
206
- // config-panel body escapes and creates a page-level scrollbar in
207
- // addition to the panel's own.
208
- "flex h-screen gap-2 overflow-hidden bg-black text-content-presentation-global-primary",
209
- className,
210
- )}
211
- >
212
- {/* Left column: header + content. Shrinks as the panel expands. */}
213
- <div className="flex min-w-0 flex-1 flex-col gap-2">
214
- {showTitle && (
215
- <DataViewsHeader
216
- title={title}
217
- views={headerViews}
218
- currentView={currentView}
219
- onViewChange={setCurrentView}
220
- showSettings={showSettings}
221
- settingsOpen={panelOpen}
222
- onToggleSettings={togglePanel}
223
- onAddNew={onAddNew}
224
- addNewLabel={addNewLabel}
225
- searchValue={searchValue}
226
- onSearchChange={onSearchChange}
227
- searchPlaceholder={searchPlaceholder}
228
- />
229
- )}
230
-
231
- <main className="flex min-h-0 flex-1 overflow-hidden ">
232
- {/* Master Container — white card, 16px radius, #D4D4D4 hairline
233
- border. Fixed surface (matches header chrome). */}
234
- <div className="flex flex-1 overflow-hidden rounded-[16px]">
235
- {/* Clip the scrollable surface to the parent radius MINUS the 1px
236
- border (16 − 1 = 15px). Using the full 16px here let the
237
- opaque view background sit flush with the parent's outer edge
238
- and bleed past the border as a ~1px light line on the
239
- left/right straight sides. */}
240
- <div className="flex-1 overflow-auto rounded-[15px]">
241
- {currentView === "table" && enabledViews.table && (
242
- <TableView
243
- data={flatItems}
244
- columns={detectedColumns}
245
- fields={resolvedFields}
246
- config={effectiveConfig}
247
- onDataUpdate={onDataUpdate}
248
- onSortChange={(sortBy, sortOrder) => setConfig({ sortBy, sortOrder })}
249
- filters={filters}
250
- filterState={filterState}
251
- onFilterChange={setFilterState}
252
- showFilters={false}
253
- />
254
- )}
255
- {currentView === "kanban" && enabledViews.kanban && (
256
- <KanbanView
257
- data={flatItems}
258
- columns={detectedColumns}
259
- fields={resolvedFields}
260
- config={effectiveConfig}
261
- onDataUpdate={onDataUpdate}
262
- groupByField={effectiveKanbanGroupBy}
263
- titleField={kanbanTitleField}
264
- onColumnAction={onKanbanColumnAction}
265
- />
266
- )}
267
- {currentView === "inbox" && enabledViews.inbox && (
268
- <InboxView
269
- data={flatItems}
270
- columns={detectedColumns}
271
- fields={resolvedFields}
272
- inboxConfig={inboxConfig}
273
- config={effectiveConfig}
274
- onDataUpdate={onDataUpdate}
275
- filters={filters}
276
- filterState={filterState}
277
- onFilterChange={setFilterState}
278
- showFilters={false}
279
- itemHref={inboxItemHref}
280
- linkComponent={inboxLinkComponent}
281
- selectedItemId={inboxSelectedId}
282
- renderDetail={inboxRenderDetail}
283
- />
284
- )}
285
- {currentView === "tree" && enabledViews.tree && (
286
- <TreeView
287
- data={items}
288
- columns={detectedColumns}
289
- fields={resolvedFields}
290
- treeConfig={treeConfig}
291
- config={effectiveConfig}
292
- onDataUpdate={onDataUpdate}
293
- filters={filters}
294
- filterState={filterState}
295
- onFilterChange={setFilterState}
296
- showFilters={false}
297
- />
298
- )}
299
- </div>
300
- </div>
301
- </main>
302
- </div>
303
-
304
- {/* Right rail: full-height sibling of the [header + content] column, so
305
- opening it pushes the header as well as the content. The wrapper
306
- animates its width so the left column reflows in sync with the
307
- panel's slide-in. */}
308
- {showSettings && panelMounted && (
309
- <div
310
- className={cn(
311
- "shrink-0 overflow-hidden transition-[width] duration-300 ease-in-out",
312
- panelOpen ? "w-[260px]" : "w-0",
313
- )}
314
- >
315
- <DataViewsConfigPanel
316
- state={panelOpen ? "open" : "closed"}
317
- config={config}
318
- onConfigChange={setConfig}
319
- onClose={closePanel}
320
- currentView={currentView}
321
- fields={resolvedFields}
322
- data={flatItems}
323
- filterState={filterState}
324
- onFilterChange={setFilterState}
325
- filterConfig={filters}
326
- />
327
- </div>
328
- )}
329
- </div>
330
- );
331
- },
332
- );