torch-glare 2.5.1 → 2.5.3

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 (38) hide show
  1. package/apps/lib/components/DataViews/data-views.tsx +1 -1
  2. package/apps/lib/components/DataViews/filters/filters.tsx +8 -12
  3. package/apps/lib/components/DataViews/header.tsx +5 -2
  4. package/apps/lib/components/DataViews/panel/section.tsx +3 -1
  5. package/apps/lib/components/DataViews/views/board-view.tsx +3 -1
  6. package/apps/lib/components/DataViews/views/inbox-view.tsx +4 -1
  7. package/apps/lib/components/DataViews/views/pane-views.tsx +5 -1
  8. package/apps/lib/components/DataViews/views/table-view.tsx +34 -4
  9. package/apps/lib/components/DataViews/views/tree-view.tsx +5 -3
  10. package/apps/lib/components/FormBuilder/context.ts +17 -26
  11. package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +1 -1
  12. package/apps/lib/components/FormBuilder/form-builder.tsx +32 -172
  13. package/apps/lib/components/FormBuilder/index.ts +0 -4
  14. package/apps/lib/components/FormBuilder/submit.tsx +11 -2
  15. package/apps/lib/components/FormBuilder/types.ts +10 -16
  16. package/apps/lib/components/FormRenderer/FormDrawer.tsx +2 -2
  17. package/apps/lib/components/FormRenderer/detail.tsx +6 -6
  18. package/apps/lib/components/FormRenderer/form-renderer.tsx +167 -35
  19. package/apps/lib/components/{FormBuilder → FormRenderer}/header.tsx +12 -25
  20. package/apps/lib/components/FormRenderer/index.ts +4 -0
  21. package/apps/lib/components/FormRenderer/section.tsx +39 -0
  22. package/apps/lib/components/{FormBuilder → FormRenderer}/stepper.tsx +65 -22
  23. package/apps/lib/components/FormRenderer/types.ts +7 -7
  24. package/apps/lib/components/SectionBlock.tsx +11 -1
  25. package/apps/lib/components/Table.tsx +54 -29
  26. package/apps/lib/components/TreeFolder/TreeFolder.tsx +61 -61
  27. package/apps/lib/registry.json +5 -3
  28. package/apps/lib/tsconfig.tsbuildinfo +1 -1
  29. package/docs/components/data-views/index.md +7 -0
  30. package/docs/components/form-builder.md +65 -89
  31. package/docs/components/form-renderer.md +62 -26
  32. package/docs/components/form-summary.md +18 -3
  33. package/docs/components/section-block.md +1 -1
  34. package/docs/components/table.md +33 -0
  35. package/docs/how-to/forms-with-form-builder.md +47 -42
  36. package/docs/migration/changelog.md +3 -0
  37. package/docs/migration/form-builder-2.5.2.md +113 -0
  38. package/package.json +1 -1
@@ -18,6 +18,20 @@ const Table = React.forwardRef<
18
18
  <table
19
19
  data-theme={theme}
20
20
  ref={ref}
21
+ // `overflow-hidden` is the default, and it is load-bearing twice over: the table is `w-auto`,
22
+ // so one wider than its container would otherwise push the whole page wide and put a horizontal
23
+ // scrollbar on the layout; and callers that give the table a radius rely on it to clip the
24
+ // square header band out of the rounded corners.
25
+ //
26
+ // The cost is that it makes the table its own scroll container, and `TableHeader`'s `sticky`
27
+ // resolves against the *nearest* scrollport — so inside a clipping table the header pins to a
28
+ // box that never scrolls, i.e. does nothing. That is the right default: a header only benefits
29
+ // from sticking when the table sits in a scroller, and such a caller passes `overflow-visible`
30
+ // (tailwind-merge lets theirs win) to bind it to that scroller instead. Only do that where the
31
+ // scroller is `min-w-0`, or the width problem above comes back — `DataViews`' table view is the
32
+ // worked example.
33
+ //
34
+ // `[border-collapse:separate]` is what lets the header cells keep their borders while stuck.
21
35
  className={cn("overflow-hidden w-auto [border-collapse:separate] border-spacing-0", className)}
22
36
  {...props}
23
37
  >
@@ -34,9 +48,20 @@ const TableHeader = React.forwardRef<
34
48
  ref={ref}
35
49
  // The header band is one continuous bar, not a per-cell background — a background on each
36
50
  // `<th>` would paint over the half of the previous column's resize handle that overhangs
37
- // the boundary.
51
+ // the boundary. That is also why `sticky` sits here rather than on the `<th>`s: per-cell
52
+ // sticky would leave this background behind and let rows show through it.
53
+ //
54
+ // `z-20` clears the `z-10` on the resize handle and sort button inside the cells. In a table
55
+ // that never scrolls vertically, `sticky` keeps the element in flow and changes nothing.
56
+ //
57
+ // The band's token is translucent (`#0003`), so once rows do slide under it they read through.
58
+ // Making it opaque is deliberately NOT done here: it would mean naming one surface colour, and
59
+ // this header paints over whatever its caller sits on — forcing a surface would visibly recolour
60
+ // every table not on that one. A caller whose table actually scrolls supplies the opaque
61
+ // background itself, where the surface is known; `DataViews`' table view is the worked example.
38
62
  className={cn(
39
63
  "bg-background-presentation-form-header backdrop-blur-[8px]",
64
+ "sticky top-0 z-20",
40
65
  "shadow-[0px_4px_8px_0px_rgba(0,0,0,0.15)]",
41
66
  className,
42
67
  )}
@@ -108,28 +133,28 @@ const MIN_COLUMN_WIDTH = 40;
108
133
  const TableHead = React.forwardRef<
109
134
  HTMLTableCellElement,
110
135
  React.ThHTMLAttributes<HTMLTableCellElement> &
111
- TableHeadVariantsProps &
112
- React.ButtonHTMLAttributes<HTMLButtonElement> & {
113
- sortType?: "asc" | "desc" | undefined;
114
- onSort?: () => void;
115
- /** Column name for the sort button's accessible label. */
116
- sortLabel?: string;
117
- /**
118
- * Called with the new width (px) while the column is being drag-resized. Pass it to take
119
- * **control** of the width — the header then renders `style.width` and expects you to
120
- * feed the new value back. Required whenever the table needs a definite width
121
- * (`table-layout: fixed`), because only the owner of every column width can total them.
122
- * Omit for uncontrolled resizing, where the header keeps the width itself.
123
- */
124
- onResize?: (width: number) => void;
125
- /**
126
- * Classes for the inner layout box (the flex row holding the label and sort toggle).
127
- * `className` and every other prop go to the `<th>` — reach for this only when you need
128
- * to restyle the content box itself, e.g. its typography or colour.
129
- */
130
- contentClassName?: string;
131
- isDummy?: boolean;
132
- }
136
+ TableHeadVariantsProps &
137
+ React.ButtonHTMLAttributes<HTMLButtonElement> & {
138
+ sortType?: "asc" | "desc" | undefined;
139
+ onSort?: () => void;
140
+ /** Column name for the sort button's accessible label. */
141
+ sortLabel?: string;
142
+ /**
143
+ * Called with the new width (px) while the column is being drag-resized. Pass it to take
144
+ * **control** of the width — the header then renders `style.width` and expects you to
145
+ * feed the new value back. Required whenever the table needs a definite width
146
+ * (`table-layout: fixed`), because only the owner of every column width can total them.
147
+ * Omit for uncontrolled resizing, where the header keeps the width itself.
148
+ */
149
+ onResize?: (width: number) => void;
150
+ /**
151
+ * Classes for the inner layout box (the flex row holding the label and sort toggle).
152
+ * `className` and every other prop go to the `<th>` — reach for this only when you need
153
+ * to restyle the content box itself, e.g. its typography or colour.
154
+ */
155
+ contentClassName?: string;
156
+ isDummy?: boolean;
157
+ }
133
158
  >(
134
159
  (
135
160
  {
@@ -287,11 +312,11 @@ const TableCell = React.forwardRef<
287
312
  // Never fade a dummy cell — its content is a centred checkbox or drag handle, not
288
313
  // clippable text.
289
314
  fade &&
290
- !isDummy && [
291
- "[mask-image:linear-gradient(to_right,black_0%,black_0%,black_75%,transparent_100%)]",
292
- "rtl:[mask-image:linear-gradient(to_left,black_0%,black_0%,black_75%,transparent_100%)]",
293
- "[&:has(input)]:[mask-image:none]",
294
- ],
315
+ !isDummy && [
316
+ "[mask-image:linear-gradient(to_right,black_0%,black_0%,black_75%,transparent_100%)]",
317
+ "rtl:[mask-image:linear-gradient(to_left,black_0%,black_0%,black_75%,transparent_100%)]",
318
+ "[&:has(input)]:[mask-image:none]",
319
+ ],
295
320
  { "min-w-fit justify-center": isDummy },
296
321
  childrenClassName,
297
322
  )}
@@ -307,7 +332,7 @@ const TableCheckbox = React.forwardRef<
307
332
  React.ButtonHTMLAttributes<HTMLButtonElement> & {
308
333
  id: string;
309
334
  }
310
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- id destructured to exclude it from the props spread onto Checkbox
335
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- id destructured to exclude it from the props spread onto Checkbox
311
336
  >(({ className, id, ...props }, ref) => {
312
337
  return (
313
338
  <div className={cn(["flex items-center justify-center"], className)}>
@@ -311,68 +311,68 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
311
311
 
312
312
  <TreeFolderStyles />
313
313
  <DndContext {...contextProps}>
314
- <div ref={scrollRef} role="tree" className="tf-scroll flex-1 min-h-0 overflow-auto">
315
- {isEmpty ? (
316
- (emptyState ?? (
317
- <div className="text-xs text-content-presentation-global-tertiary p-3">
318
- Nothing here yet.
314
+ <div ref={scrollRef} role="tree" className="tf-scroll flex-1 min-h-0 overflow-auto pt-[6px]">
315
+ {isEmpty ? (
316
+ (emptyState ?? (
317
+ <div className="text-xs text-content-presentation-global-tertiary p-3">
318
+ Nothing here yet.
319
+ </div>
320
+ ))
321
+ ) : (
322
+ <div className="min-w-max" style={stripStyle}>
323
+ <DragList ids={ids} makeRoom={false}>
324
+ {visibleRows.map((row, idx) => {
325
+ const prevRow = visibleRows[idx - 1];
326
+ const nextRow = visibleRows[idx + 1];
327
+ const isSelected = selectedId === row.node.id;
328
+ const isDescendant = isDescendantOfSelected(row.node.id) && !isSelected;
329
+ const inBand = isSelected || isDescendant;
330
+
331
+ // Neighbour-aware band rounding: a row is "in-band" if it's the selected
332
+ // node itself or one of its descendants. The Set lookup handles deep nesting.
333
+ const prevInBand =
334
+ inBand &&
335
+ !!prevRow &&
336
+ (prevRow.node.id === selectedId || descendantIdSet.has(prevRow.node.id));
337
+ const nextInBand =
338
+ inBand &&
339
+ !!nextRow &&
340
+ (nextRow.node.id === selectedId || descendantIdSet.has(nextRow.node.id));
341
+
342
+ const isDragging = dragIdSet.has(row.node.id);
343
+ const isDropTargetInside =
344
+ dropTarget?.rowId === row.node.id && dropTarget.position === "inside";
345
+ const isDropBefore =
346
+ dropTarget?.rowId === row.node.id && dropTarget.position === "before";
347
+ const isDropAfter =
348
+ dropTarget?.rowId === row.node.id && dropTarget.position === "after";
349
+
350
+ return (
351
+ <TreeFolderRow
352
+ key={row.node.id}
353
+ row={row}
354
+ rowHeight={rowHeight}
355
+ indent={indent}
356
+ iconFor={iconFor}
357
+ isSelected={isSelected}
358
+ isAncestor={isAncestorFn(row.node.id) && !isSelected}
359
+ isDescendantOfSelected={isDescendant}
360
+ isPrevInBand={prevInBand}
361
+ isNextInBand={nextInBand}
362
+ isDragging={isDragging}
363
+ isDropTargetInside={isDropTargetInside}
364
+ isDropBefore={isDropBefore}
365
+ isDropAfter={isDropAfter}
366
+ dndEnabled={dndEnabled}
367
+ onSelect={handleSelect}
368
+ onToggle={handleToggle}
369
+ />
370
+ );
371
+ })}
372
+ </DragList>
319
373
  </div>
320
- ))
321
- ) : (
322
- <div className="min-w-max" style={stripStyle}>
323
- <DragList ids={ids} makeRoom={false}>
324
- {visibleRows.map((row, idx) => {
325
- const prevRow = visibleRows[idx - 1];
326
- const nextRow = visibleRows[idx + 1];
327
- const isSelected = selectedId === row.node.id;
328
- const isDescendant = isDescendantOfSelected(row.node.id) && !isSelected;
329
- const inBand = isSelected || isDescendant;
330
-
331
- // Neighbour-aware band rounding: a row is "in-band" if it's the selected
332
- // node itself or one of its descendants. The Set lookup handles deep nesting.
333
- const prevInBand =
334
- inBand &&
335
- !!prevRow &&
336
- (prevRow.node.id === selectedId || descendantIdSet.has(prevRow.node.id));
337
- const nextInBand =
338
- inBand &&
339
- !!nextRow &&
340
- (nextRow.node.id === selectedId || descendantIdSet.has(nextRow.node.id));
341
-
342
- const isDragging = dragIdSet.has(row.node.id);
343
- const isDropTargetInside =
344
- dropTarget?.rowId === row.node.id && dropTarget.position === "inside";
345
- const isDropBefore =
346
- dropTarget?.rowId === row.node.id && dropTarget.position === "before";
347
- const isDropAfter =
348
- dropTarget?.rowId === row.node.id && dropTarget.position === "after";
349
-
350
- return (
351
- <TreeFolderRow
352
- key={row.node.id}
353
- row={row}
354
- rowHeight={rowHeight}
355
- indent={indent}
356
- iconFor={iconFor}
357
- isSelected={isSelected}
358
- isAncestor={isAncestorFn(row.node.id) && !isSelected}
359
- isDescendantOfSelected={isDescendant}
360
- isPrevInBand={prevInBand}
361
- isNextInBand={nextInBand}
362
- isDragging={isDragging}
363
- isDropTargetInside={isDropTargetInside}
364
- isDropBefore={isDropBefore}
365
- isDropAfter={isDropAfter}
366
- dndEnabled={dndEnabled}
367
- onSelect={handleSelect}
368
- onToggle={handleToggle}
369
- />
370
- );
371
- })}
372
- </DragList>
373
- </div>
374
- )}
375
- </div>
374
+ )}
375
+ </div>
376
376
  </DndContext>
377
377
  </div>
378
378
  );
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.5.1",
2
+ "version": "2.5.3",
3
3
  "generatedBy": "scripts/bin/generateRegistry",
4
4
  "npmVersions": {
5
5
  "@dnd-kit/core": "^6.3.1",
@@ -422,8 +422,6 @@
422
422
  "components/DatePicker",
423
423
  "components/FieldHint",
424
424
  "components/Form",
425
- "components/FormStepper",
426
- "components/HeaderBar",
427
425
  "components/ImageAttachment",
428
426
  "components/Input",
429
427
  "components/InputField",
@@ -456,8 +454,12 @@
456
454
  "react-hook-form"
457
455
  ],
458
456
  "registryDependencies": [
457
+ "components/Button",
459
458
  "components/Drawer",
460
459
  "components/FormBuilder",
460
+ "components/FormStepper",
461
+ "components/HeaderBar",
462
+ "components/SectionBlock",
461
463
  "components/TabFormItem",
462
464
  "utils/cn"
463
465
  ]