@ciridae/ui 1.0.2 → 1.0.4

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 (209) hide show
  1. package/dist/app/auth.d.ts +10 -0
  2. package/dist/app/auth.js +60 -0
  3. package/dist/app/error-boundary.d.ts +18 -0
  4. package/dist/app/error-boundary.js +45 -0
  5. package/dist/app/feedback.d.ts +12 -0
  6. package/dist/app/feedback.js +128 -0
  7. package/dist/app/index.d.ts +8 -0
  8. package/dist/app/index.js +8 -0
  9. package/dist/app/request-errors.d.ts +63 -0
  10. package/dist/app/request-errors.js +172 -0
  11. package/dist/app/sentry.d.ts +18 -0
  12. package/dist/app/sentry.js +52 -0
  13. package/dist/app/telemetry.d.ts +7 -0
  14. package/dist/app/telemetry.js +28 -0
  15. package/dist/app/trail.d.ts +9 -0
  16. package/dist/app/trail.js +18 -0
  17. package/dist/chat/chat-query-keys.d.ts +3 -3
  18. package/dist/chat/contract.d.ts +15 -15
  19. package/dist/chat/conversation-items-query-options.d.ts +114 -114
  20. package/dist/chat/conversation-source.d.ts +89 -0
  21. package/dist/chat/conversation-source.js +1 -0
  22. package/dist/chat/describe-tool-call.d.ts +3 -3
  23. package/dist/chat/describe-tool-call.js +3 -3
  24. package/dist/chat/message-text.d.ts +1 -1
  25. package/dist/chat/message-text.js +116 -48
  26. package/dist/chat/use-conversation-list.d.ts +6 -6
  27. package/dist/ciridae.css +16 -4
  28. package/dist/components/activity-feed.d.ts +3 -2
  29. package/dist/components/activity-feed.js +1 -0
  30. package/dist/components/agent-work.d.ts +3 -3
  31. package/dist/components/app-frame.d.ts +91 -0
  32. package/dist/components/app-frame.js +134 -0
  33. package/dist/components/app-navigation.d.ts +30 -3
  34. package/dist/components/app-navigation.js +105 -14
  35. package/dist/components/badge.d.ts +30 -5
  36. package/dist/components/badge.js +134 -15
  37. package/dist/components/brand-icons.d.ts +3 -3
  38. package/dist/components/bulk-action-bar.d.ts +1 -1
  39. package/dist/components/bulk-action-bar.js +3 -3
  40. package/dist/components/button.d.ts +12 -5
  41. package/dist/components/button.js +77 -44
  42. package/dist/components/calendar.d.ts +1 -1
  43. package/dist/components/calendar.js +44 -17
  44. package/dist/components/centered-page.d.ts +1 -1
  45. package/dist/components/centered-page.js +2 -2
  46. package/dist/components/chart.d.ts +22 -2
  47. package/dist/components/chart.js +251 -51
  48. package/dist/components/chat-client-source.d.ts +16 -0
  49. package/dist/components/chat-client-source.js +297 -0
  50. package/dist/components/chat-page.d.ts +9 -8
  51. package/dist/components/chat-page.js +7 -11
  52. package/dist/components/chat-sheet-controller.d.ts +11 -14
  53. package/dist/components/chat-sheet-controller.js +3 -3
  54. package/dist/components/chat-sheet.d.ts +18 -11
  55. package/dist/components/chat-sheet.js +188 -289
  56. package/dist/components/chat.d.ts +109 -19
  57. package/dist/components/chat.js +520 -124
  58. package/dist/components/checkbox-item.d.ts +6 -3
  59. package/dist/components/checkbox-item.js +9 -5
  60. package/dist/components/checkbox-list.d.ts +1 -1
  61. package/dist/components/chip.d.ts +6 -1
  62. package/dist/components/chip.js +27 -1
  63. package/dist/components/collapsible.d.ts +1 -1
  64. package/dist/components/color-theme.d.ts +1 -1
  65. package/dist/components/column-settings.d.ts +1 -1
  66. package/dist/components/column-settings.js +1 -1
  67. package/dist/components/command-menu.d.ts +5 -1
  68. package/dist/components/command-menu.js +98 -32
  69. package/dist/components/command-palette.d.ts +7 -3
  70. package/dist/components/command-palette.js +20 -11
  71. package/dist/components/copyable-id.d.ts +22 -5
  72. package/dist/components/copyable-id.js +46 -6
  73. package/dist/components/data-display.d.ts +39 -8
  74. package/dist/components/data-display.js +138 -19
  75. package/dist/components/data-grid.d.ts +23 -11
  76. package/dist/components/data-grid.js +61 -26
  77. package/dist/components/date-range-picker.d.ts +1 -1
  78. package/dist/components/date-range-picker.js +9 -20
  79. package/dist/components/date-time.d.ts +1 -1
  80. package/dist/components/dialog-height-context.d.ts +1 -1
  81. package/dist/components/document-viewer.d.ts +2 -2
  82. package/dist/components/drawer.d.ts +11 -6
  83. package/dist/components/drawer.js +91 -54
  84. package/dist/components/dropzone.d.ts +4 -4
  85. package/dist/components/editable-field.d.ts +12 -3
  86. package/dist/components/editable-field.js +57 -27
  87. package/dist/components/email-input.d.ts +1 -1
  88. package/dist/components/email-input.js +6 -5
  89. package/dist/components/environment-frame.d.ts +2 -2
  90. package/dist/components/environment-frame.js +37 -6
  91. package/dist/components/expandable-text.d.ts +1 -1
  92. package/dist/components/feedback-screenshot.d.ts +1 -1
  93. package/dist/components/feedback-sheet.d.ts +18 -3
  94. package/dist/components/feedback-sheet.js +216 -55
  95. package/dist/components/field-context.d.ts +1 -1
  96. package/dist/components/filter-bar.d.ts +3 -3
  97. package/dist/components/filter-bar.js +43 -29
  98. package/dist/components/form-controls.d.ts +12 -3
  99. package/dist/components/form-controls.js +46 -22
  100. package/dist/components/form-layout.d.ts +14 -10
  101. package/dist/components/form-layout.js +68 -23
  102. package/dist/components/glass-menu.d.ts +3 -0
  103. package/dist/components/glass-menu.js +63 -0
  104. package/dist/components/gradient-edge.d.ts +9 -0
  105. package/dist/components/gradient-edge.js +31 -0
  106. package/dist/components/hotkeys.d.ts +2 -2
  107. package/dist/components/icon.d.ts +1 -1
  108. package/dist/components/input.d.ts +7 -5
  109. package/dist/components/input.js +29 -17
  110. package/dist/components/keyboard-shortcuts.d.ts +2 -2
  111. package/dist/components/keycap.d.ts +10 -6
  112. package/dist/components/keycap.js +57 -19
  113. package/dist/components/layout.d.ts +13 -13
  114. package/dist/components/lightbox.d.ts +9 -3
  115. package/dist/components/lightbox.js +13 -9
  116. package/dist/components/link.d.ts +1 -1
  117. package/dist/components/locale.d.ts +42 -2
  118. package/dist/components/locale.js +43 -3
  119. package/dist/components/log-entry.d.ts +40 -0
  120. package/dist/components/log-entry.js +146 -0
  121. package/dist/components/log-list.d.ts +3 -3
  122. package/dist/components/mention-input.d.ts +2 -2
  123. package/dist/components/mention-input.js +4 -3
  124. package/dist/components/menu.d.ts +7 -3
  125. package/dist/components/menu.js +34 -37
  126. package/dist/components/meter.d.ts +10 -2
  127. package/dist/components/meter.js +64 -6
  128. package/dist/components/navigation.d.ts +21 -4
  129. package/dist/components/navigation.js +84 -19
  130. package/dist/components/notification-tray.d.ts +1 -1
  131. package/dist/components/notification-tray.js +5 -4
  132. package/dist/components/overlays.d.ts +6 -4
  133. package/dist/components/overlays.js +69 -40
  134. package/dist/components/page-frame.d.ts +4 -4
  135. package/dist/components/page-frame.js +1 -1
  136. package/dist/components/panel.d.ts +4 -4
  137. package/dist/components/panel.js +18 -12
  138. package/dist/components/profile-header.d.ts +1 -1
  139. package/dist/components/progress.d.ts +1 -1
  140. package/dist/components/project-avatar.d.ts +1 -1
  141. package/dist/components/radio-card.d.ts +2 -2
  142. package/dist/components/radio-card.js +10 -9
  143. package/dist/components/record.d.ts +29 -5
  144. package/dist/components/record.js +147 -18
  145. package/dist/components/resolved-file-url.d.ts +19 -0
  146. package/dist/components/resolved-file-url.js +49 -0
  147. package/dist/components/scroll-area.d.ts +1 -1
  148. package/dist/components/secret-dialog.d.ts +1 -1
  149. package/dist/components/segmented-bar.d.ts +4 -2
  150. package/dist/components/segmented-bar.js +16 -6
  151. package/dist/components/select.d.ts +9 -6
  152. package/dist/components/select.js +103 -127
  153. package/dist/components/settings.d.ts +4 -4
  154. package/dist/components/shell-skeleton.d.ts +1 -1
  155. package/dist/components/shell-skeleton.js +1 -1
  156. package/dist/components/shell.d.ts +21 -21
  157. package/dist/components/shell.js +43 -43
  158. package/dist/components/side-panel.d.ts +3 -3
  159. package/dist/components/sidebar.d.ts +13 -8
  160. package/dist/components/sidebar.js +55 -27
  161. package/dist/components/single-line-text.d.ts +2 -0
  162. package/dist/components/single-line-text.js +16 -0
  163. package/dist/components/site-banner.d.ts +5 -2
  164. package/dist/components/site-banner.js +17 -6
  165. package/dist/components/skeleton.d.ts +8 -7
  166. package/dist/components/skeleton.js +28 -16
  167. package/dist/components/skeletons.d.ts +17 -5
  168. package/dist/components/skeletons.js +71 -8
  169. package/dist/components/stages.d.ts +83 -11
  170. package/dist/components/stages.js +512 -156
  171. package/dist/components/stat-card.d.ts +12 -4
  172. package/dist/components/stat-card.js +92 -37
  173. package/dist/components/status-banner.d.ts +1 -1
  174. package/dist/components/status-banner.js +1 -1
  175. package/dist/components/status.d.ts +2 -2
  176. package/dist/components/steps.d.ts +1 -1
  177. package/dist/components/switch.d.ts +1 -1
  178. package/dist/components/tabs.d.ts +8 -8
  179. package/dist/components/tabs.js +26 -13
  180. package/dist/components/theme-customizer.d.ts +2 -2
  181. package/dist/components/theme-toggle.d.ts +4 -0
  182. package/dist/components/theme-toggle.js +67 -0
  183. package/dist/components/toast.d.ts +10 -3
  184. package/dist/components/toast.js +78 -29
  185. package/dist/components/use-new-version-available.d.ts +6 -0
  186. package/dist/components/use-new-version-available.js +29 -0
  187. package/dist/components/user-chip.d.ts +3 -3
  188. package/dist/components/wizard.d.ts +2 -2
  189. package/dist/feedback/contract.d.ts +136 -136
  190. package/dist/feedback/feedback-controller.d.ts +6 -6
  191. package/dist/feedback/generated/zod.gen.d.ts +28 -28
  192. package/dist/feedback/operator-contract.d.ts +11 -11
  193. package/dist/feedback/operator-controller.d.ts +32 -13
  194. package/dist/feedback/operator-controller.js +44 -11
  195. package/dist/preset.js +289 -33
  196. package/dist/styled-system/styles.css +3294 -1079
  197. package/dist/styled-system/tokens/index.mjs +598 -22
  198. package/dist/styled-system/tokens/tokens.d.ts +11 -11
  199. package/dist/styled-system/types/prop-type.d.ts +2 -2
  200. package/dist/styles.css +16 -4
  201. package/dist/theme/color.d.ts +3 -0
  202. package/dist/theme/color.js +5 -0
  203. package/dist/theme/derive.d.ts +9 -2
  204. package/dist/theme/derive.js +72 -12
  205. package/dist/theme/palettes.d.ts +49 -6
  206. package/dist/theme/palettes.js +84 -15
  207. package/dist/theme/tokens.d.ts +3 -3
  208. package/dist/theme/tokens.js +107 -32
  209. package/package.json +40 -3
@@ -61,7 +61,7 @@ function scrollingAncestor(element) {
61
61
  * hover-revealed row actions, groups, loading, empty and no-results states. `role="table"`; Enter
62
62
  * on a pressable row opens it.
63
63
  */
64
- export function DataGrid({ data, columns, getRowId, variant = "framed", density = "default", sorting: sortingProp, defaultSorting = emptySorting, onSortingChange, manualSorting = false, enableRowSelection, rowSelection: rowSelectionProp, defaultRowSelection = emptySelection, onRowSelectionChange, stickySelectColumn = false, columnVisibility: columnVisibilityProp, defaultColumnVisibility = emptyVisibility, onColumnVisibilityChange, columnOrder: columnOrderProp, defaultColumnOrder = emptyOrder, onColumnOrderChange, headerMenu = false, filters, onFiltersChange, getRowHref, renderRowLink, onRowClick, activeRowId, keyboardNavigation = false, virtualize = false, rowActions, renderRowDetail, groupBy, renderGroupRow, loading = false, empty, noResults, filtered, hideHeader = false, fill = false, narrowScreenLayout = "columns", footer, labels: ownLabels, className, frameClassName, style, ...props }) {
64
+ export function DataGrid({ data, columns, getRowId, variant = "framed", density = "default", sorting: sortingProp, defaultSorting = emptySorting, onSortingChange, manualSorting = false, page, enableRowSelection, rowSelection: rowSelectionProp, defaultRowSelection = emptySelection, onRowSelectionChange, stickySelectColumn = false, columnVisibility: columnVisibilityProp, defaultColumnVisibility = emptyVisibility, onColumnVisibilityChange, columnOrder: columnOrderProp, defaultColumnOrder = emptyOrder, onColumnOrderChange, headerMenu = false, filters, onFiltersChange, getRowHref, renderRowLink, onRowClick, activeRowId, keyboardNavigation = false, virtualize = false, rowActions, renderRowDetail, groupBy, renderGroupRow, loading = false, empty, noResults, filtered, hideHeader = false, fill = false, narrowScreenLayout = "columns", footer, labels: ownLabels, className, frameClassName, style, ...props }) {
65
65
  const { labels: localeLabels } = useCiridaeLocale();
66
66
  const labels = { ...localeLabels.table, ...ownLabels };
67
67
  const [sorting, setSorting] = useControllableState(sortingProp, defaultSorting, onSortingChange);
@@ -149,7 +149,10 @@ export function DataGrid({ data, columns, getRowId, variant = "framed", density
149
149
  }
150
150
  const selectable = enableRowSelection !== undefined && enableRowSelection !== false;
151
151
  const canSelect = (row) => typeof enableRowSelection === "function" ? enableRowSelection(row) : selectable;
152
- const rows = table.getRowModel().rows;
152
+ const sortedRows = table.getRowModel().rows;
153
+ const rows = page
154
+ ? sortedRows.slice((page.number - 1) * page.rowsPerPage, page.number * page.rowsPerPage)
155
+ : sortedRows;
153
156
  const selectableIds = rows.filter((row) => canSelect(row.original)).map((row) => row.id);
154
157
  const setSelected = (ids, selected) => {
155
158
  const next = Object.fromEntries(Object.entries(rowSelection).filter(([id]) => selected || !ids.includes(id)));
@@ -487,14 +490,12 @@ export function DataGrid({ data, columns, getRowId, variant = "framed", density
487
490
  headRefs.current.set(column.id, element);
488
491
  else
489
492
  headRefs.current.delete(column.id);
490
- }, children: menuItems.length > 0 ? (_jsx(Menu, { align: meta?.align === "end" ? "end" : "start", trigger: _jsxs("button", { type: "button", className: headButton, "data-sorted": sorted || undefined, children: [content, caret] }), items: menuItems })) : column.getCanSort() ? (_jsxs("button", { type: "button", className: headButton, "data-sorted": sorted || undefined, "data-toggle": "", onClick: column.getToggleSortingHandler(), children: [content, caret] })) : (content) }, column.id));
493
+ }, children: menuItems.length > 0 ? (_jsx(Menu, { align: meta?.align === "end" ? "end" : "start", trigger: _jsxs("button", { type: "button", className: headButton, "data-sorted": sorted || undefined, children: [content, caret] }), items: menuItems })) : column.getCanSort() ? (_jsxs("button", { type: "button", className: headButton, "data-sorted": sorted || undefined, onClick: column.getToggleSortingHandler(), children: [content, caret] })) : (content) }, column.id));
491
494
  };
492
495
  const showEmpty = !loading && rows.length === 0;
493
496
  const isFiltered = filtered ?? (filters !== undefined && filters.length > 0);
494
497
  const emptyContent = isFiltered && noResults !== undefined ? noResults : (empty ?? labels.nothingToShow);
495
- return (_jsxs("div", { ref: frameRef, className: cx(frame, frameClassName), "data-ciridae-ui": "", "data-variant": variant, "data-density": density, "data-fill": fill || undefined, "data-stacked": narrowScreenLayout === "stacked" || undefined, children: [_jsxs("div", { ...props, ref: gridRef, role: "table", "aria-busy": loading || undefined, className: cx(grid, className), style: { ...style, gridTemplateColumns: template }, children: [!hideHeader && (_jsxs("div", { role: "row", className: headRow, children: [selectable && (_jsx("div", { ref: selectHeadRef, role: "columnheader", className: cx(headCell, selectCell, stickySelectColumn && pinnedCell), children: _jsx(Checkbox, { "aria-label": labels.selectAll, checked: allSelected === "all" && selectableIds.length > 0, indeterminate: allSelected === "some", disabled: loading || selectableIds.length === 0, onCheckedChange: (checked) => setSelected(selectableIds, checked) }) })), shownColumns.map(headerCell), rowActions && (_jsx("div", { role: "columnheader", className: headCell, children: _jsx("span", { className: visuallyHidden, children: labels.actions }) }))] })), loading ? (skeletonRows.map((rowIndex) => (_jsxs("div", { role: "row", className: bodyRow, "data-skeleton": "", children: [selectable && _jsx("div", { role: "cell", className: cx(cell, selectCell) }), shownColumns.map((column, columnIndex) => (_jsx("div", { role: "cell", className: cellClass(column), "data-align": column.columnDef.meta?.align, children: column.columnDef.meta?.skeleton ?? (_jsx(Skeleton, { shape: "text", style: {
496
- width: skeletonWidths[(rowIndex + columnIndex) % skeletonWidths.length],
497
- } })) }, column.id))), rowActions && _jsx("div", { role: "cell", className: cell })] }, rowIndex)))) : showEmpty ? (_jsx("div", { role: "row", className: emptyRow, children: _jsx("div", { role: "cell", "aria-colspan": columnCount, className: emptyCell, children: emptyContent }) })) : (drawBody())] }), footer, filterColumn && filterField && onFiltersChange && (_jsx(Popover, { open: true, onOpenChange: (open) => {
498
+ return (_jsxs("div", { ref: frameRef, className: cx(frame, frameClassName), "data-ciridae-ui": "", "data-variant": variant, "data-density": density, "data-fill": fill || undefined, "data-stacked": narrowScreenLayout === "stacked" || undefined, children: [_jsxs("div", { ...props, ref: gridRef, role: "table", "aria-busy": loading || undefined, className: cx(grid, className), style: { ...style, gridTemplateColumns: template }, children: [!hideHeader && (_jsxs("div", { role: "row", className: headRow, children: [selectable && (_jsx("div", { ref: selectHeadRef, role: "columnheader", className: cx(headCell, selectCell, stickySelectColumn && pinnedCell), children: _jsx(Checkbox, { "aria-label": labels.selectAll, checked: allSelected === "all" && selectableIds.length > 0, indeterminate: allSelected === "some", disabled: loading || selectableIds.length === 0, onCheckedChange: (checked) => setSelected(selectableIds, checked) }) })), shownColumns.map(headerCell), rowActions && (_jsx("div", { role: "columnheader", className: headCell, children: _jsx("span", { className: visuallyHidden, children: labels.actions }) }))] })), loading ? (skeletonRows.map((rowIndex) => (_jsxs("div", { role: "row", className: bodyRow, "data-skeleton": "", style: { opacity: 1 - rowIndex * skeletonRowFade }, children: [selectable && (_jsx("div", { role: "cell", className: cx(cell, selectCell), children: _jsx(Skeleton, { shape: "square", className: skeletonCheckbox }) })), shownColumns.map((column, columnIndex) => (_jsx("div", { role: "cell", className: cellClass(column), "data-align": column.columnDef.meta?.align, children: _jsx(SkeletonCell, { shape: column.columnDef.meta?.skeleton, width: skeletonWidths[(rowIndex + columnIndex) % skeletonWidths.length] }) }, column.id))), rowActions && _jsx("div", { role: "cell", className: cell })] }, rowIndex)))) : showEmpty ? (_jsx("div", { role: "row", className: emptyRow, children: _jsx("div", { role: "cell", "aria-colspan": columnCount, className: emptyCell, children: emptyContent }) })) : (drawBody())] }), footer, filterColumn && filterField && onFiltersChange && (_jsx(Popover, { open: true, onOpenChange: (open) => {
498
499
  if (!open)
499
500
  setFilterColumnId(null);
500
501
  }, anchor: headRefs.current.get(filterColumn.id) ?? null, density: "compact", children: _jsx("div", { className: columnFilter, children: _jsx(FilterValueEditor, { field: filterField, value: filters?.find((filter) => filter.field === filterField.key), onChange: (filter) => onFiltersChange(replaceFilter(filters ?? [], filter)) }) }) }))] }));
@@ -511,6 +512,8 @@ const emptySelection = {};
511
512
  const emptyVisibility = {};
512
513
  const emptyOrder = [];
513
514
  const skeletonRows = [0, 1, 2, 3, 4];
515
+ // Each loading row a little fainter than the one above, so the list reads as fading out.
516
+ const skeletonRowFade = 0.08;
514
517
  const skeletonWidths = ["70%", "45%", "85%", "55%"];
515
518
  /** What takes a click of its own inside a row, so pressing it leaves the row alone. */
516
519
  const interactiveSelector = "a:not([data-row-link]), button, input, label, select, textarea, [role=button], [role=checkbox], [role=combobox], [role=menuitem], [contenteditable=true]";
@@ -568,7 +571,7 @@ function compareSortValues(left, right, columnId) {
568
571
  // The surface a pinned cell rebuilds: the list's own surfaces are translucent, so a pinned cell
569
572
  // redraws them on the solid canvas, or the columns scrolling under it would show through.
570
573
  const frame = css({
571
- "--row-gap-inline": "token(spacing.layout.pageGap)",
574
+ "--row-gap-inline": "token(spacing.layout.clusterGap)",
572
575
  "--row-pad-inline": "token(spacing.panel.comfortable)",
573
576
  "--row-pad-block": "token(spacing.panel.default)",
574
577
  "--pinned-background": "token(colors.bg.canvas)",
@@ -583,9 +586,9 @@ const frame = css({
583
586
  "&[data-variant=framed]": {
584
587
  border: "1px solid token(colors.border.panel)",
585
588
  borderRadius: "action",
586
- background: "bg.hover",
589
+ background: "token(gradients.card)",
590
+ boxShadow: "card",
587
591
  _light: {
588
- background: "bg.card",
589
592
  "--pinned-background": "token(colors.bg.card)",
590
593
  "--pinned-layers": "none",
591
594
  },
@@ -593,10 +596,11 @@ const frame = css({
593
596
  "&[data-variant=framed][data-density=compact]": {
594
597
  "--row-pad-block": "token(spacing.control.compactBlock)",
595
598
  },
599
+ // A plain list has no frame to inset from: its cells pad themselves, half the column gap a side.
596
600
  "&[data-variant=plain]": {
597
601
  "--row-gap-inline": "0px",
598
602
  "--row-pad-inline": "0px",
599
- "--row-pad-block": "token(spacing.table.rowBlock)",
603
+ "--row-pad-block": "token(spacing.panel.default)",
600
604
  "--pinned-layers": "inset 0 0 0 999px token(colors.bg.panel)",
601
605
  },
602
606
  "&[data-variant=plain][data-density=compact]": {
@@ -615,6 +619,8 @@ const grid = css({
615
619
  color: "fg.primary",
616
620
  fontSize: "body",
617
621
  letterSpacing: "compact",
622
+ // The kit's cells set their text at 100%; a plain list's lines may wrap, so they keep room.
623
+ lineHeight: "tight",
618
624
  "[data-variant=plain] > &": { lineHeight: "compact" },
619
625
  // On a phone a stacked list lays each row out as one block: the first cell takes the whole
620
626
  // first line and the others wrap under it, an end-aligned one pushed to the far edge.
@@ -646,17 +652,13 @@ const rowBase = {
646
652
  borderBottom: "1px solid token(colors.border.panel)",
647
653
  "[data-variant=plain] &": { borderBottomColor: "border.subtle" },
648
654
  };
655
+ // The kit's header row is 44px: its 12px labels centred, whatever the cells' block padding.
649
656
  const headRow = css(rowBase, {
657
+ minHeight: "table.headRow",
650
658
  color: "fg.primary",
651
659
  fontSize: "code",
652
660
  fontWeight: "medium",
653
661
  lineHeight: "tight",
654
- "[data-variant=plain] &": {
655
- color: "fg.muted",
656
- fontSize: "caption",
657
- letterSpacing: "label",
658
- textTransform: "uppercase",
659
- },
660
662
  "[data-fill] &": {
661
663
  position: "sticky",
662
664
  top: "0",
@@ -671,8 +673,9 @@ const bodyRow = css(rowBase, {
671
673
  position: "relative",
672
674
  outline: "none",
673
675
  "&:last-child": { borderBottom: "0" },
676
+ // 56px: a 32px avatar or two-line cell inside the padding, the bottom hairline inside that.
674
677
  "[data-variant=framed][data-density=default] &": {
675
- minHeight: "calc(token(sizes.control.compact) + var(--row-pad-block) * 2 + 1px)",
678
+ minHeight: "calc(token(sizes.control.compact) + var(--row-pad-block) * 2)",
676
679
  },
677
680
  // The row's wash is one layer over every cell, the pinned ones included, so they tint together.
678
681
  _after: {
@@ -685,10 +688,11 @@ const bodyRow = css(rowBase, {
685
688
  transitionProperty: "background",
686
689
  transitionDuration: "fast",
687
690
  },
691
+ // A ticked row shows it in its checkbox alone; the row open beside the list wears the selected
692
+ // glass, and keeps it under the pointer.
688
693
  "&[data-pressable]": { cursor: "pointer" },
689
- "&[data-pressable]:hover": { "--row-wash": "token(colors.bg.rowHover)" },
690
- "&:is([data-selected], [data-active])": { "--row-wash": "token(colors.bg.selected)" },
691
- "&:is([data-selected], [data-active]):hover": { "--row-wash": "token(colors.bg.selectedHover)" },
694
+ "&[data-pressable]:not([data-active]):hover": { "--row-wash": "token(colors.bg.rowHover)" },
695
+ "&[data-active]": { "--row-wash": "token(gradients.selected)" },
692
696
  _focusVisible: { focusRing: "inset", "--row-wash": "token(colors.bg.rowHover)" },
693
697
  // Its anchor stands for the row and sits in a cell that may clip, so the row draws the ring.
694
698
  "&:has(a[data-row-link]:focus-visible)": {
@@ -715,11 +719,13 @@ const emptyRow = css({ gridColumn: "1 / -1" });
715
719
  const cellBase = {
716
720
  minWidth: "0",
717
721
  paddingBlock: "var(--row-pad-block)",
718
- "[data-variant=plain] &": { paddingInline: "table.cell" },
722
+ "[data-variant=plain] &": { paddingInline: "panel.compact" },
719
723
  "&[data-align=end]": { textAlign: "end", justifyContent: "flex-end" },
720
724
  "&[data-align=end] > [data-shape]": { marginInlineStart: "auto" },
721
725
  };
726
+ // The row's hairline sits inside its bottom padding, as the kit's 56px row draws it.
722
727
  const cell = css(cellBase, {
728
+ paddingBottom: "calc(var(--row-pad-block) - token(sizes.border.hairline))",
723
729
  fontWeight: "medium",
724
730
  "[data-variant=plain] &": { fontWeight: "normal" },
725
731
  "& a": { color: "inherit", textDecoration: "none" },
@@ -817,13 +823,42 @@ const headButton = css({
817
823
  cursor: "pointer",
818
824
  borderRadius: "control",
819
825
  _focusVisible: { focusRing: "outer" },
820
- "& svg": { flexShrink: "0", color: "fg.muted" },
826
+ // The sort caret shows only while the column is sorted, pointed at, focused or its menu open.
827
+ "& svg": { flexShrink: "0", color: "fg.muted", opacity: "0", transition: "opacity .15s" },
821
828
  "&[data-sorted] svg": { color: "fg.primary" },
822
- // A plain list's sort toggle shows its caret only while pointed at or sorted.
823
- // A sort toggle shows its caret only while pointed at or sorted; a head menu's always shows.
824
- "&[data-toggle] svg": { opacity: "0", transition: "opacity .15s" },
825
- "&[data-toggle]:is(:hover, :focus-visible, [data-sorted]) svg": { opacity: "1" },
829
+ "&:is(:hover, :focus-visible, [data-sorted], [data-popup-open]) svg": { opacity: "1" },
826
830
  "[data-align=end] > &": { marginInlineStart: "auto" },
827
831
  });
832
+ // Past the skeleton's own shape sizes, which match on its `data-shape` too.
833
+ const skeletonCheckbox = css({
834
+ "&[data-shape][data-ciridae-ui]": { width: "control.checkbox", borderRadius: "control" },
835
+ });
836
+ // A loading cell in its column's shape: the kit's skeleton row draws two lines for the primary
837
+ // column, a 20px pill for a badge and a 24px circle beside a line for a person.
838
+ const skeletonLines = css({
839
+ display: "grid",
840
+ gap: "layout.controlGap",
841
+ width: "100%",
842
+ lineHeight: "tight",
843
+ });
844
+ const skeletonPill = css({
845
+ "&[data-shape][data-ciridae-ui]": { width: "80px", height: "control.mark", borderRadius: "pill" },
846
+ });
847
+ const skeletonPerson = css({
848
+ display: "flex",
849
+ alignItems: "center",
850
+ gap: "layout.controlGap",
851
+ width: "100%",
852
+ });
853
+ const skeletonAvatar = css({ "&[data-shape][data-ciridae-ui]": { width: "avatar.menu" } });
854
+ function SkeletonCell({ shape, width, }) {
855
+ if (shape === "lines")
856
+ return (_jsxs("span", { className: skeletonLines, children: [_jsx(Skeleton, { shape: "text", width: width }), _jsx(Skeleton, { shape: "text", height: "caption", width: "45%" })] }));
857
+ if (shape === "pill")
858
+ return _jsx(Skeleton, { className: skeletonPill });
859
+ if (shape === "person")
860
+ return (_jsxs("span", { className: skeletonPerson, children: [_jsx(Skeleton, { shape: "circle", className: skeletonAvatar }), _jsx(Skeleton, { shape: "text", width: width })] }));
861
+ return shape ?? _jsx(Skeleton, { shape: "text", width: width });
862
+ }
828
863
  const columnFilter = css({ display: "flex", flexDirection: "column", width: "260px" });
829
864
  const visuallyHidden = css({ srOnly: true });
@@ -41,4 +41,4 @@ export declare function DateRangePicker({ value: ownValue, defaultValue, onValue
41
41
  today?: Date;
42
42
  labels?: Partial<CiridaeLabels["dateRange"]>;
43
43
  className?: string;
44
- }): import("@types/react").JSX.Element;
44
+ }): import("react").JSX.Element;
@@ -9,7 +9,7 @@ import { useState } from "react";
9
9
  import { css, cx } from "#primitives/css";
10
10
  import { Calendar } from "./calendar.js";
11
11
  import { useControllableState } from "./controllable-state.js";
12
- import { Divider } from "./data-display.js";
12
+ import { glassMenuDivider, glassMenuRow } from "./glass-menu.js";
13
13
  import { icon } from "./icon.js";
14
14
  import { useCiridaeLocale } from "./locale.js";
15
15
  import { Popover } from "./overlays.js";
@@ -82,7 +82,7 @@ const trigger = css({
82
82
  paddingInline: "control.compactInline",
83
83
  border: "1px solid transparent",
84
84
  borderRadius: "action",
85
- background: "bg.glass",
85
+ background: "token(gradients.selected)",
86
86
  color: "fg.primary",
87
87
  fontFamily: "sans",
88
88
  fontSize: "body",
@@ -90,31 +90,20 @@ const trigger = css({
90
90
  letterSpacing: "compact",
91
91
  whiteSpace: "nowrap",
92
92
  cursor: "pointer",
93
- _hover: { background: "bg.glassHover" },
93
+ _hover: { background: "token(gradients.raisedHover)" },
94
94
  "&[data-popup-open]": { borderColor: "fg.primary" },
95
95
  _focusVisible: { focusRing: "outer" },
96
96
  });
97
97
  const options = css({ display: "grid", width: "222px" });
98
- const option = css({
99
- display: "flex",
100
- alignItems: "center",
101
- gap: "layout.controlGap",
102
- height: "control.compact",
103
- paddingInline: "menu.itemInline",
98
+ // A menu row on the popover's glass sheet.
99
+ const option = css(glassMenuRow, {
104
100
  border: "0",
105
- borderRadius: "control",
106
101
  background: "transparent",
107
- color: "fg.primary",
108
- font: "inherit",
109
- fontSize: "body",
110
- fontWeight: "medium",
111
- letterSpacing: "compact",
102
+ fontFamily: "inherit",
112
103
  textAlign: "start",
113
- cursor: "pointer",
114
- _hover: { background: "bg.glass" },
115
- _focusVisible: { focusRing: "inset" },
116
104
  });
117
- const checkSlot = css({ display: "inline-flex", width: "14px", flexShrink: "0" });
105
+ const optionsDivider = css(glassMenuDivider);
106
+ const checkSlot = css({ display: "inline-flex", width: "mark.inline", flexShrink: "0" });
118
107
  /**
119
108
  * A select-shaped trigger opening the presets, and Pick dates, which swaps them for a calendar:
120
109
  * the first day picked starts the range and the second ends it.
@@ -149,5 +138,5 @@ export function DateRangePicker({ value: ownValue, defaultValue = { kind: "prese
149
138
  return (_jsx(Popover, { open: open, onOpenChange: changeOpen, density: "compact", trigger: _jsxs("button", { type: "button", className: cx(trigger, className), "aria-label": `${labels.label}: ${valueLabel}`, "data-ciridae-ui": "", "data-edge": "glass", children: [valueLabel, _jsx(CaretDownIcon, { className: icon({ size: "small" }) })] }), children: picking ? (_jsx(Calendar, { month: month, selected: start, onMonthChange: setMonth, onSelect: pickDay })) : (_jsxs("div", { className: options, children: [presets.map((preset) => (_jsxs("button", { type: "button", className: option, onClick: () => {
150
139
  setValue({ kind: "preset", preset: preset.value });
151
140
  changeOpen(false);
152
- }, children: [_jsx("span", { className: checkSlot, children: value.kind === "preset" && value.preset === preset.value && (_jsx(CheckIcon, { className: icon({ size: "small" }), weight: "bold" })) }), preset.label] }, preset.value))), _jsx(Divider, { inset: "menu" }), _jsxs("button", { type: "button", className: option, onClick: () => setPicking(true), children: [_jsx("span", { className: checkSlot, children: value.kind === "custom" && (_jsx(CheckIcon, { className: icon({ size: "small" }), weight: "bold" })) }), labels.pickDates] })] })) }));
141
+ }, children: [_jsx("span", { className: checkSlot, children: value.kind === "preset" && value.preset === preset.value && (_jsx(CheckIcon, { className: icon({ size: "small" }), weight: "bold" })) }), preset.label] }, preset.value))), _jsx("div", { className: optionsDivider, role: "separator" }), _jsxs("button", { type: "button", className: option, onClick: () => setPicking(true), children: [_jsx("span", { className: checkSlot, children: value.kind === "custom" && (_jsx(CheckIcon, { className: icon({ size: "small" }), weight: "bold" })) }), labels.pickDates] })] })) }));
153
142
  }
@@ -8,4 +8,4 @@ import { type DateInput } from "./locale.js";
8
8
  export declare function DateTime({ value, mode, }: {
9
9
  value: DateInput | null;
10
10
  mode?: "auto" | "date" | "dateTime" | "relative";
11
- }): import("@types/react").JSX.Element | null;
11
+ }): import("react").JSX.Element | null;
@@ -1,2 +1,2 @@
1
1
  /** A Wizard starts a new height scope on each step; filtering within that step keeps its height. */
2
- export declare const DialogHeightResetContext: import("@types/react").Context<(() => void) | null>;
2
+ export declare const DialogHeightResetContext: import("react").Context<(() => void) | null>;
@@ -49,7 +49,7 @@ export type DocumentViewerProps = Omit<ComponentProps<"div">, "children"> & {
49
49
  actions?: ReactNode;
50
50
  labels?: Partial<CiridaeLabels["documentViewer"]>;
51
51
  };
52
- export declare function DocumentViewer({ pages, regions, activeRegionId: ownActiveRegionId, defaultActiveRegionId, onActiveRegionChange, pageId: ownPageId, defaultPageId, onPageChange, zoom: ownZoom, defaultZoom, onZoomChange, aside, actions, labels: ownLabels, className, ...props }: DocumentViewerProps): import("@types/react").JSX.Element;
52
+ export declare function DocumentViewer({ pages, regions, activeRegionId: ownActiveRegionId, defaultActiveRegionId, onActiveRegionChange, pageId: ownPageId, defaultPageId, onPageChange, zoom: ownZoom, defaultZoom, onZoomChange, aside, actions, labels: ownLabels, className, ...props }: DocumentViewerProps): import("react").JSX.Element;
53
53
  export type DocumentFieldProps = useRender.ComponentProps<"button"> & {
54
54
  /** The region this field was read from; selecting either marks the other. */
55
55
  regionId: string;
@@ -59,4 +59,4 @@ export type DocumentFieldProps = useRender.ComponentProps<"button"> & {
59
59
  * selected, marked while its region is hovered, and scrolled into view when its region is
60
60
  * selected on the page.
61
61
  */
62
- export declare function DocumentField({ regionId, render, className, onClick, onMouseEnter, onMouseLeave, ...props }: DocumentFieldProps): import("@types/react").ReactElement<unknown, string | import("@types/react").JSXElementConstructor<any>>;
62
+ export declare function DocumentField({ regionId, render, className, onClick, onMouseEnter, onMouseLeave, ...props }: DocumentFieldProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
@@ -14,16 +14,21 @@ export type DrawerProps = Omit<ComponentProps<typeof BaseDrawer.Root>, "children
14
14
  size?: "narrow" | "regular" | "large";
15
15
  children: ReactNode;
16
16
  };
17
- export declare function Drawer({ title, icon: titleIcon, eyebrow, subtitle, titleAccessory, actions, size, children, ...rootProps }: DrawerProps): import("@types/react").JSX.Element;
17
+ /**
18
+ * A sheet docked at the window's right edge beside the page, which stays usable: it is not modal
19
+ * and a click outside leaves it open, so Escape or its close button closes it. Pass `modal` or
20
+ * `disablePointerDismissal` to change either.
21
+ */
22
+ export declare function Drawer({ title, icon: titleIcon, eyebrow, subtitle, titleAccessory, actions, size, children, ...rootProps }: DrawerProps): import("react").JSX.Element;
18
23
  export declare function DrawerBody({ flush, className, ...props }: ComponentProps<"div"> & {
19
24
  flush?: boolean;
20
- }): import("@types/react").JSX.Element;
21
- export declare function DrawerForm({ className, ...props }: ComponentProps<"form">): import("@types/react").JSX.Element;
25
+ }): import("react").JSX.Element;
26
+ export declare function DrawerForm({ className, ...props }: ComponentProps<"form">): import("react").JSX.Element;
22
27
  export type DrawerFooterProps = ComponentProps<"footer"> & {
23
28
  /** Muted text at the footer's leading edge saying what the actions do, before the actions. */
24
29
  note?: ReactNode;
25
30
  };
26
- export declare function DrawerFooter({ note, className, children, ...props }: DrawerFooterProps): import("@types/react").JSX.Element;
31
+ export declare function DrawerFooter({ note, className, children, ...props }: DrawerFooterProps): import("react").JSX.Element;
27
32
  export type DrawerFieldProps = {
28
33
  label: ReactNode;
29
34
  /** Muted after the label, such as `Optional` or where a value was filled in from. */
@@ -39,6 +44,6 @@ export type DrawerFieldProps = {
39
44
  * A labelled form field. Its `<label>` points at the control inside, and its helper or error
40
45
  * describes it: `Input`, `Textarea`, `Select` and `Combobox` take the ids from the field.
41
46
  */
42
- export declare function DrawerField({ label, hint, helper, error, controlId, children }: DrawerFieldProps): import("@types/react").JSX.Element;
47
+ export declare function DrawerField({ label, hint, helper, error, controlId, children }: DrawerFieldProps): import("react").JSX.Element;
43
48
  /** Two fields side by side. */
44
- export declare function DrawerFieldRow({ className, ...props }: ComponentProps<"div">): import("@types/react").JSX.Element;
49
+ export declare function DrawerFieldRow({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
@@ -9,55 +9,51 @@ import { HotkeyLayer } from "./hotkeys.js";
9
9
  import { icon } from "./icon.js";
10
10
  import { Eyebrow, heading } from "./layout.js";
11
11
  import { useCiridaeLocale } from "./locale.js";
12
- const backdrop = css({
13
- position: "fixed",
14
- inset: "none",
15
- zIndex: "drawer",
16
- background: "bg.backdrop",
17
- transitionProperty: "opacity",
18
- transitionDuration: "fast",
19
- "&[data-starting-style], &[data-ending-style]": { opacity: "0" },
20
- _motionReduce: { transitionDuration: "0ms" },
21
- });
22
12
  const viewport = css({ position: "fixed", inset: "none", zIndex: "drawer", pointerEvents: "none" });
13
+ /*
14
+ * A drawer sits beside the page, which stays usable: no scrim, docked to the window's right edge
15
+ * at full height, a glass shell holding the sheet. The shell's padding is what keeps the sheet off
16
+ * the window's edges, level with the main panel; a phone takes the sheet to the edges.
17
+ */
23
18
  const popup = cva({
24
19
  base: {
25
20
  position: "absolute",
26
- // Inset from the window by the shell's gap and rounded like the main panel, so a sheet reads
27
- // as the docked agent sheet does; a phone takes it to the edges, where rounding is a gap.
28
- insetBlock: "panel.compact",
29
- insetInlineEnd: "panel.compact",
21
+ insetBlock: "none",
22
+ insetInlineEnd: "none",
30
23
  display: "flex",
31
- overflow: "hidden",
24
+ padding: "panel.compact",
32
25
  pointerEvents: "auto",
33
26
  outline: "none",
34
27
  textStyle: "body",
35
- background: "bg.surface",
36
- border: "1px solid token(colors.border.control)",
37
- borderRadius: "action",
38
- boxShadow: "card",
39
- _phone: { insetBlock: "none", insetInlineEnd: "none", border: "0", borderRadius: "0" },
28
+ border: "1px solid token(colors.border.divider)",
29
+ borderRadius: "shell",
30
+ background: "bg.drawerShell",
31
+ backdropFilter: "blur(token(blurs.drawerShell))",
32
+ boxShadow: "drawerShell",
33
+ _phone: { padding: "none", border: "0", borderRadius: "0" },
40
34
  // Base UI drives live swipe drag through this custom property; the resting
41
35
  // transform must reference it or dragging won't visually track the pointer.
42
36
  transform: "translateX(var(--drawer-swipe-movement-x, 0px))",
43
37
  transitionProperty: "transform",
44
38
  transitionDuration: "default",
45
39
  "&[data-starting-style], &[data-ending-style]": {
46
- transform: "translateX(calc(100% + token(spacing.panel.compact)))",
47
- _rtl: { transform: "translateX(calc(-100% - token(spacing.panel.compact)))" },
40
+ transform: "translateX(100%)",
41
+ _rtl: { transform: "translateX(-100%)" },
48
42
  },
49
43
  "&[data-swiping]": { transitionDuration: "0ms" },
50
44
  _motionReduce: { transitionDuration: "0ms" },
51
45
  },
46
+ // The sheet's width, plus the shell's padding and its 1px edge on each side.
52
47
  variants: {
53
48
  size: {
54
- // A conversation or a short form, such as the agent sheet.
49
+ // The assistant and a preview.
55
50
  narrow: {
56
- width: "min(calc(100vw - token(spacing.panel.compact) * 2), token(sizes.overlay.sheetNarrow))",
51
+ width: "min(100vw, calc(token(sizes.overlay.sheetNarrow) + token(spacing.panel.compact) * 2 + 2px))",
57
52
  _phone: { width: "100vw" },
58
53
  },
54
+ // Create, edit and act.
59
55
  regular: {
60
- width: "min(calc(100vw - token(spacing.panel.compact) * 2), token(sizes.overlay.sheet))",
56
+ width: "min(100vw, calc(token(sizes.overlay.sheet) + token(spacing.panel.compact) * 2 + 2px))",
61
57
  _phone: { width: "100vw" },
62
58
  },
63
59
  // Near the full viewport, for content such as logs that needs the room.
@@ -72,26 +68,51 @@ const panel = css({
72
68
  minWidth: "0",
73
69
  minHeight: "0",
74
70
  flexDirection: "column",
71
+ overflow: "hidden",
72
+ border: "1px solid token(colors.border.divider)",
73
+ borderRadius: "action",
74
+ background: "bg.drawerSheet",
75
+ boxShadow: "soft",
75
76
  color: "fg.primary",
77
+ _phone: { border: "0", borderRadius: "0" },
76
78
  });
77
- // At least the app header's height, so on a desktop the sheet's header rule lines up with the main
78
- // panel's beside it: both start one shell gap from the window's top.
79
- const header = css({
80
- display: "flex",
81
- flexDirection: "column",
82
- justifyContent: "center",
83
- gap: "layout.contentGap",
84
- minHeight: "shell.header",
85
- paddingBlock: "layout.tightGap",
86
- paddingInlineStart: "panel.comfortable",
87
- paddingInlineEnd: "panel.default",
88
- borderBottom: "1px solid token(colors.border.control)",
79
+ // At least the app header's height, so on a desktop a title-only sheet's header rule lines up with
80
+ // the main panel's beside it: both start one shell gap from the window's top. Under a subtitle it
81
+ // takes the design's even 16px padding, its close button at the top. The narrow sheet's header is
82
+ // one line exactly the app header's height, its 34px round buttons centred in it.
83
+ const header = cva({
84
+ base: {
85
+ display: "flex",
86
+ flexDirection: "column",
87
+ justifyContent: "center",
88
+ gap: "layout.contentGap",
89
+ minHeight: "shell.header",
90
+ paddingBlock: "panel.default",
91
+ paddingInlineStart: "panel.comfortable",
92
+ paddingInlineEnd: "panel.default",
93
+ borderBottom: "1px solid token(colors.border.divider)",
94
+ "&:has([data-sheet-subtitle])": {
95
+ paddingBlock: "panel.comfortable",
96
+ "& > [data-header-line]": { alignItems: "flex-start" },
97
+ },
98
+ },
99
+ // The narrow header is the Ask Ciridae drawer's one line: 8px between its title and actions.
100
+ variants: {
101
+ size: {
102
+ narrow: { gap: "layout.controlGap", height: "shell.header", paddingBlock: "none" },
103
+ regular: { paddingInlineEnd: "panel.comfortable" },
104
+ large: { paddingInlineEnd: "panel.comfortable" },
105
+ },
106
+ },
89
107
  });
90
- const headerLine = css({
91
- display: "flex",
92
- alignItems: "center",
93
- justifyContent: "space-between",
94
- gap: "layout.contentGap",
108
+ const headerLine = cva({
109
+ base: {
110
+ display: "flex",
111
+ alignItems: "center",
112
+ justifyContent: "space-between",
113
+ gap: "layout.contentGap",
114
+ },
115
+ variants: { size: { narrow: { gap: "layout.controlGap" }, regular: {}, large: {} } },
95
116
  });
96
117
  const titleBlock = css({
97
118
  display: "flex",
@@ -107,12 +128,21 @@ const titleLine = css({
107
128
  gap: "layout.contentGap",
108
129
  minWidth: "0",
109
130
  });
110
- const titleStyle = cx(heading(), css({ minWidth: "0", lineHeight: "tight" }));
111
- // The sheet's mark before its title, muted like the agent sheet's sparkle.
131
+ const titleStyle = css({ minWidth: "0", lineHeight: "tight" });
132
+ const subtitleStyle = css({
133
+ margin: "none",
134
+ color: "fg.label",
135
+ fontSize: "code",
136
+ fontWeight: "medium",
137
+ letterSpacing: "compact",
138
+ lineHeight: "tight",
139
+ });
140
+ // The sheet's mark before its title, muted like the agent sheet's sparkle. A flex row of its own,
141
+ // so the heading stays the title's line high rather than an inline box's.
112
142
  const titleMark = css({
113
- display: "inline-flex",
143
+ display: "flex",
114
144
  alignItems: "center",
115
- gap: "control.iconGap",
145
+ gap: "layout.controlGap",
116
146
  minWidth: "0",
117
147
  "& > svg": { flexShrink: "0", color: "fg.muted" },
118
148
  });
@@ -154,10 +184,9 @@ const footer = css({
154
184
  alignItems: "center",
155
185
  justifyContent: "flex-end",
156
186
  flexWrap: "wrap",
157
- gap: "layout.controlGap",
187
+ gap: "layout.tightGap",
158
188
  padding: "panel.comfortable",
159
- borderTop: "1px solid token(colors.border.control)",
160
- background: "bg.card",
189
+ borderTop: "1px solid token(colors.border.divider)",
161
190
  });
162
191
  const footerNote = css({
163
192
  flex: "1",
@@ -166,12 +195,20 @@ const footerNote = css({
166
195
  fontWeight: "medium",
167
196
  letterSpacing: "compact",
168
197
  });
169
- const footerActions = css({ display: "flex", alignItems: "center", gap: "layout.controlGap" });
198
+ const footerActions = css({ display: "flex", alignItems: "center", gap: "layout.tightGap" });
199
+ /**
200
+ * A sheet docked at the window's right edge beside the page, which stays usable: it is not modal
201
+ * and a click outside leaves it open, so Escape or its close button closes it. Pass `modal` or
202
+ * `disablePointerDismissal` to change either.
203
+ */
170
204
  export function Drawer({ title, icon: titleIcon, eyebrow, subtitle, titleAccessory, actions, size = "regular", children, ...rootProps }) {
171
205
  const { labels, dir } = useCiridaeLocale();
172
- const close = (_jsx(BaseDrawer.Close, { render: _jsx(IconButton, { "aria-label": labels.common.close, variant: "ghost", size: "small" }), children: _jsx(XIcon, { className: icon({ size: "small" }) }) }));
206
+ // The narrow sheet's title is body size, as the app header's is, beside a 34px close.
207
+ const narrow = size === "narrow";
208
+ const titleClassName = cx(heading({ size: narrow ? "small" : "medium" }), titleStyle);
209
+ const close = (_jsx(BaseDrawer.Close, { render: _jsx(IconButton, { "aria-label": labels.common.close, size: narrow ? "medium" : "small" }), children: _jsx(XIcon, { className: icon({ size: "small" }) }) }));
173
210
  const titleContent = titleIcon ? (_jsxs("span", { className: titleMark, children: [titleIcon, title] })) : (title);
174
- return (_jsx(BaseDrawer.Root, { ...rootProps, swipeDirection: dir === "rtl" ? "left" : "right", children: _jsx(BaseDrawer.Portal, { children: _jsxs(HotkeyLayer, { children: [_jsx(BaseDrawer.Backdrop, { className: backdrop, "data-ciridae-ui": "" }), _jsx(BaseDrawer.Viewport, { className: viewport, children: _jsx(BaseDrawer.Popup, { className: popup({ size }), "data-ciridae-ui": "", children: _jsxs("div", { className: panel, children: [_jsx("header", { className: header, children: eyebrow ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: eyebrowLine, children: [eyebrow, _jsxs("div", { className: headerActions, children: [actions, close] })] }), _jsxs("div", { className: css({ display: "grid", gap: "layout.controlGap" }), children: [_jsx(BaseDrawer.Title, { className: displayTitle, children: title }), subtitle && _jsx("p", { className: displaySubtitle, children: subtitle })] })] })) : (_jsxs("div", { className: headerLine, children: [_jsxs("div", { className: titleBlock, children: [titleAccessory ? (_jsxs("div", { className: titleLine, children: [_jsx(BaseDrawer.Title, { className: titleStyle, children: titleContent }), titleAccessory] })) : (_jsx(BaseDrawer.Title, { className: titleStyle, children: titleContent })), subtitle && _jsx(Eyebrow, { as: "p", children: subtitle })] }), _jsxs("div", { className: headerActions, children: [actions, close] })] })) }), children] }) }) })] }) }) }));
211
+ return (_jsx(BaseDrawer.Root, { modal: false, disablePointerDismissal: true, ...rootProps, swipeDirection: dir === "rtl" ? "left" : "right", children: _jsx(BaseDrawer.Portal, { children: _jsx(HotkeyLayer, { children: _jsx(BaseDrawer.Viewport, { className: viewport, children: _jsx(BaseDrawer.Popup, { className: popup({ size }), "data-ciridae-ui": "", children: _jsxs("div", { className: panel, children: [_jsx("header", { className: header({ size }), children: eyebrow ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: eyebrowLine, children: [eyebrow, _jsxs("div", { className: headerActions, children: [actions, close] })] }), _jsxs("div", { className: css({ display: "grid", gap: "layout.controlGap" }), children: [_jsx(BaseDrawer.Title, { className: displayTitle, children: title }), subtitle && _jsx("p", { className: displaySubtitle, children: subtitle })] })] })) : (_jsxs("div", { className: headerLine({ size }), "data-header-line": "", children: [_jsxs("div", { className: titleBlock, children: [titleAccessory ? (_jsxs("div", { className: titleLine, children: [_jsx(BaseDrawer.Title, { className: titleClassName, children: titleContent }), titleAccessory] })) : (_jsx(BaseDrawer.Title, { className: titleClassName, children: titleContent })), subtitle && (_jsx("p", { className: subtitleStyle, "data-sheet-subtitle": "", children: subtitle }))] }), _jsxs("div", { className: headerActions, children: [actions, close] })] })) }), children] }) }) }) }) }) }));
175
212
  }
176
213
  export function DrawerBody({ flush = false, className, ...props }) {
177
214
  return (_jsx(BaseDrawer.Content, { ...props, className: cx(body({ flush }), className), "data-ciridae-ui": "" }));
@@ -186,7 +223,7 @@ export function DrawerFooter({ note, className, children, ...props }) {
186
223
  const field = css({
187
224
  display: "flex",
188
225
  flexDirection: "column",
189
- gap: "control.iconGap",
226
+ gap: "layout.controlGap",
190
227
  minWidth: "0",
191
228
  });
192
229
  const fieldLabelRow = css({
@@ -198,7 +235,7 @@ const fieldLabelRow = css({
198
235
  letterSpacing: "compact",
199
236
  lineHeight: "tight",
200
237
  });
201
- const fieldHint = css({ color: "fg.muted" });
238
+ const fieldHint = css({ color: "fg.subtle" });
202
239
  const fieldError = css({
203
240
  margin: "none",
204
241
  color: "accent.red",
@@ -18,16 +18,16 @@ export type DropzoneProps = useRender.ComponentProps<"div"> & {
18
18
  accept?: string;
19
19
  };
20
20
  /** Drop or paste files onto the element; while dragged over it carries `data-dragging`. */
21
- export declare function Dropzone({ onFiles, dropLabel, disabled, accept, render, className, children, ...props }: DropzoneProps): import("@types/react").JSX.Element;
21
+ export declare function Dropzone({ onFiles, dropLabel, disabled, accept, render, className, children, ...props }: DropzoneProps): import("react").JSX.Element;
22
22
  /** The enclosing `Dropzone`'s picker, for a trigger of the caller's own, such as an icon button. */
23
23
  export declare function useDropzonePicker(): DropzoneContextValue;
24
24
  export type DropzoneTriggerProps = Omit<ButtonProps, "onClick">;
25
25
  /** Opens the enclosing `Dropzone`'s file picker; a paperclip unless it sets its own icon. */
26
- export declare function DropzoneTrigger({ icon: triggerIcon, variant, disabled, ...props }: DropzoneTriggerProps): import("@types/react").JSX.Element;
26
+ export declare function DropzoneTrigger({ icon: triggerIcon, variant, disabled, ...props }: DropzoneTriggerProps): import("react").JSX.Element;
27
27
  /** A dashed pad at rest inside a `Dropzone`: drop files on it, or browse for them. */
28
28
  export declare function DropzonePad({ className }: {
29
29
  className?: string;
30
- }): import("@types/react").JSX.Element;
30
+ }): import("react").JSX.Element;
31
31
  export type DropzoneFileListProps = {
32
32
  files: readonly File[];
33
33
  onRemove: (file: File) => void;
@@ -42,6 +42,6 @@ export type DropzoneFileListProps = {
42
42
  className?: string;
43
43
  };
44
44
  /** One row per file: a thumbnail for an image, else its type's icon, its name and size, remove. */
45
- export declare function DropzoneFileList({ files, onRemove, pending, disabled, variant, className, }: DropzoneFileListProps): import("@types/react").JSX.Element | null;
45
+ export declare function DropzoneFileList({ files, onRemove, pending, disabled, variant, className, }: DropzoneFileListProps): import("react").JSX.Element | null;
46
46
  /** A file's type as an icon: PDF, archive, text, or a plain file. */
47
47
  export declare function fileTypeIcon(file: Pick<File, "name" | "type">): ReactNode;