@moldable-ai/ui 0.2.20 → 0.2.21

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 (159) hide show
  1. package/dist/catalog/catalog-coverage.d.ts +15 -0
  2. package/dist/catalog/catalog-coverage.d.ts.map +1 -0
  3. package/dist/catalog/catalog-coverage.js +44 -0
  4. package/dist/catalog/catalog-manifest.d.ts.map +1 -1
  5. package/dist/catalog/catalog-manifest.js +35 -23
  6. package/dist/catalog/catalog-types.d.ts +10 -0
  7. package/dist/catalog/catalog-types.d.ts.map +1 -1
  8. package/dist/catalog/catalog-types.js +6 -0
  9. package/dist/catalog/component-catalog.d.ts.map +1 -1
  10. package/dist/catalog/component-catalog.js +16 -6
  11. package/dist/catalog/core-catalog-exclusions.d.ts +8 -0
  12. package/dist/catalog/core-catalog-exclusions.d.ts.map +1 -0
  13. package/dist/catalog/core-catalog-exclusions.js +151 -0
  14. package/dist/catalog/core-catalog.d.ts +0 -4
  15. package/dist/catalog/core-catalog.d.ts.map +1 -1
  16. package/dist/catalog/core-catalog.js +12 -98
  17. package/dist/catalog/core-collection-stories.d.ts +3 -0
  18. package/dist/catalog/core-collection-stories.d.ts.map +1 -0
  19. package/dist/catalog/core-collection-stories.js +42 -0
  20. package/dist/catalog/core-control-stories.d.ts +3 -0
  21. package/dist/catalog/core-control-stories.d.ts.map +1 -0
  22. package/dist/catalog/core-control-stories.js +94 -0
  23. package/dist/catalog/core-feedback-stories.d.ts +3 -0
  24. package/dist/catalog/core-feedback-stories.d.ts.map +1 -0
  25. package/dist/catalog/core-feedback-stories.js +50 -0
  26. package/dist/catalog/core-foundation-stories.d.ts +3 -0
  27. package/dist/catalog/core-foundation-stories.d.ts.map +1 -0
  28. package/dist/catalog/core-foundation-stories.js +53 -0
  29. package/dist/catalog/core-navigation-stories.d.ts +3 -0
  30. package/dist/catalog/core-navigation-stories.d.ts.map +1 -0
  31. package/dist/catalog/core-navigation-stories.js +25 -0
  32. package/dist/catalog/core-overlay-stories.d.ts +3 -0
  33. package/dist/catalog/core-overlay-stories.d.ts.map +1 -0
  34. package/dist/catalog/core-overlay-stories.js +20 -0
  35. package/dist/catalog/index.d.ts +3 -1
  36. package/dist/catalog/index.d.ts.map +1 -1
  37. package/dist/catalog/index.js +3 -1
  38. package/dist/components/chat/chat-panel.d.ts +0 -1
  39. package/dist/components/chat/chat-panel.d.ts.map +1 -1
  40. package/dist/components/chat/chat-panel.js +7 -11
  41. package/dist/components/ui/alert-dialog.d.ts +7 -3
  42. package/dist/components/ui/alert-dialog.d.ts.map +1 -1
  43. package/dist/components/ui/alert-dialog.js +9 -5
  44. package/dist/components/ui/alert.d.ts +19 -3
  45. package/dist/components/ui/alert.d.ts.map +1 -1
  46. package/dist/components/ui/alert.js +25 -8
  47. package/dist/components/ui/app-frame.d.ts +9 -3
  48. package/dist/components/ui/app-frame.d.ts.map +1 -1
  49. package/dist/components/ui/app-frame.js +45 -6
  50. package/dist/components/ui/collapsible.d.ts +9 -1
  51. package/dist/components/ui/collapsible.d.ts.map +1 -1
  52. package/dist/components/ui/collapsible.js +13 -2
  53. package/dist/components/ui/collection-navigation.d.ts +8 -0
  54. package/dist/components/ui/collection-navigation.d.ts.map +1 -0
  55. package/dist/components/ui/collection-navigation.js +19 -0
  56. package/dist/components/ui/command.d.ts +5 -1
  57. package/dist/components/ui/command.d.ts.map +1 -1
  58. package/dist/components/ui/command.js +13 -1
  59. package/dist/components/ui/confirm-dialog.d.ts +19 -0
  60. package/dist/components/ui/confirm-dialog.d.ts.map +1 -0
  61. package/dist/components/ui/confirm-dialog.js +45 -0
  62. package/dist/components/ui/date-picker.d.ts +24 -0
  63. package/dist/components/ui/date-picker.d.ts.map +1 -0
  64. package/dist/components/ui/date-picker.js +92 -0
  65. package/dist/components/ui/dialog.d.ts +4 -2
  66. package/dist/components/ui/dialog.d.ts.map +1 -1
  67. package/dist/components/ui/dialog.js +8 -5
  68. package/dist/components/ui/empty.d.ts +7 -2
  69. package/dist/components/ui/empty.d.ts.map +1 -1
  70. package/dist/components/ui/empty.js +20 -7
  71. package/dist/components/ui/grid.d.ts.map +1 -1
  72. package/dist/components/ui/grid.js +70 -46
  73. package/dist/components/ui/index.d.ts +4 -0
  74. package/dist/components/ui/index.d.ts.map +1 -1
  75. package/dist/components/ui/index.js +4 -0
  76. package/dist/components/ui/list.d.ts +5 -1
  77. package/dist/components/ui/list.d.ts.map +1 -1
  78. package/dist/components/ui/list.js +27 -16
  79. package/dist/components/ui/material.d.ts +34 -0
  80. package/dist/components/ui/material.d.ts.map +1 -0
  81. package/dist/components/ui/material.js +34 -0
  82. package/dist/components/ui/message-scroller-controller.d.ts +162 -0
  83. package/dist/components/ui/message-scroller-controller.d.ts.map +1 -0
  84. package/dist/components/ui/message-scroller-controller.js +888 -0
  85. package/dist/components/ui/message-scroller-policy.d.ts +74 -0
  86. package/dist/components/ui/message-scroller-policy.d.ts.map +1 -0
  87. package/dist/components/ui/message-scroller-policy.js +129 -0
  88. package/dist/components/ui/message-scroller-primitive.d.ts +55 -0
  89. package/dist/components/ui/message-scroller-primitive.d.ts.map +1 -0
  90. package/dist/components/ui/message-scroller-primitive.js +226 -0
  91. package/dist/components/ui/message-scroller.d.ts +2 -2
  92. package/dist/components/ui/message-scroller.d.ts.map +1 -1
  93. package/dist/components/ui/message-scroller.js +3 -15
  94. package/dist/components/ui/navigation-button-group.d.ts +16 -0
  95. package/dist/components/ui/navigation-button-group.d.ts.map +1 -0
  96. package/dist/components/ui/navigation-button-group.js +9 -0
  97. package/dist/components/ui/popover.d.ts +9 -2
  98. package/dist/components/ui/popover.d.ts.map +1 -1
  99. package/dist/components/ui/popover.js +13 -3
  100. package/dist/components/ui/scroll-area.d.ts +8 -2
  101. package/dist/components/ui/scroll-area.d.ts.map +1 -1
  102. package/dist/components/ui/scroll-area.js +6 -3
  103. package/dist/components/ui/search-field.d.ts.map +1 -1
  104. package/dist/components/ui/segmented-control.d.ts.map +1 -1
  105. package/dist/components/ui/segmented-control.js +6 -5
  106. package/dist/components/ui/sheet.d.ts +4 -2
  107. package/dist/components/ui/sheet.d.ts.map +1 -1
  108. package/dist/components/ui/sheet.js +12 -9
  109. package/dist/components/ui/sonner.d.ts +1 -1
  110. package/dist/components/ui/sonner.d.ts.map +1 -1
  111. package/dist/components/ui/table.d.ts.map +1 -1
  112. package/dist/components/ui/table.js +7 -2
  113. package/dist/components/ui/toggle.d.ts +12 -4
  114. package/dist/components/ui/toggle.d.ts.map +1 -1
  115. package/dist/components/ui/toggle.js +13 -2
  116. package/dist/components/ui/toolbar.d.ts +9 -2
  117. package/dist/components/ui/toolbar.d.ts.map +1 -1
  118. package/dist/components/ui/toolbar.js +23 -4
  119. package/dist/components/ui/tooltip.d.ts +8 -3
  120. package/dist/components/ui/tooltip.d.ts.map +1 -1
  121. package/dist/components/ui/tooltip.js +11 -6
  122. package/dist/lib/frame-lifecycle.d.ts +1 -0
  123. package/dist/lib/frame-lifecycle.d.ts.map +1 -1
  124. package/dist/lib/frame-lifecycle.js +3 -2
  125. package/dist/lib/theme.d.ts.map +1 -1
  126. package/dist/lib/theme.js +2 -1
  127. package/docs/README.md +3 -1
  128. package/docs/adaptive-materials.md +79 -0
  129. package/docs/app-anatomy.md +3 -1
  130. package/docs/component-catalog.md +26 -3
  131. package/docs/design-tokens.md +17 -4
  132. package/docs/foundations.md +5 -3
  133. package/docs/standalone-app-windows.md +8 -0
  134. package/package.json +1 -2
  135. package/src/components/ui/alert-dialog.md +31 -0
  136. package/src/components/ui/alert.md +28 -6
  137. package/src/components/ui/app-frame.md +5 -0
  138. package/src/components/ui/collapsible.md +52 -0
  139. package/src/components/ui/combobox.md +0 -1
  140. package/src/components/ui/command.md +54 -0
  141. package/src/components/ui/date-field.md +1 -1
  142. package/src/components/ui/date-picker.md +55 -0
  143. package/src/components/ui/dialog.md +40 -0
  144. package/src/components/ui/empty.md +8 -3
  145. package/src/components/ui/grid.md +8 -4
  146. package/src/components/ui/icon-button.md +2 -2
  147. package/src/components/ui/list.md +35 -2
  148. package/src/components/ui/material.md +51 -0
  149. package/src/components/ui/navigation-button-group.md +46 -0
  150. package/src/components/ui/popover.md +31 -0
  151. package/src/components/ui/scroll-area.md +11 -7
  152. package/src/components/ui/search-field.md +1 -1
  153. package/src/components/ui/segmented-control.md +2 -5
  154. package/src/components/ui/sheet.md +30 -0
  155. package/src/components/ui/table.md +4 -2
  156. package/src/components/ui/toggle-button.md +48 -0
  157. package/src/components/ui/toolbar.md +5 -0
  158. package/src/components/ui/tooltip.md +31 -0
  159. package/src/styles/index.css +213 -0
@@ -2,11 +2,24 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { cn } from '../../lib/utils';
4
4
  import { cva } from 'class-variance-authority';
5
- function Empty({ className, ...props }) {
6
- return (_jsx("div", { "data-slot": "empty", className: cn('flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12', className), ...props }));
5
+ const emptyVariants = cva('group/empty flex min-w-0 flex-col items-center justify-center text-balance text-center', {
6
+ variants: {
7
+ variant: {
8
+ compact: 'gap-3 p-4',
9
+ pane: 'flex-1 gap-4 p-6',
10
+ full: 'min-h-full flex-1 gap-6 p-8 md:p-10',
11
+ },
12
+ },
13
+ defaultVariants: {
14
+ variant: 'pane',
15
+ },
16
+ });
17
+ function Empty({ className, safeBottom = false, variant = 'pane', ...props }) {
18
+ return (_jsx("div", { "data-slot": "empty", "data-safe-bottom": safeBottom || undefined, "data-variant": variant, className: cn(emptyVariants({ variant }), safeBottom &&
19
+ 'pb-[calc(var(--chat-safe-padding,0px)+var(--density-pane-padding))]', className), ...props }));
7
20
  }
8
21
  function EmptyHeader({ className, ...props }) {
9
- return (_jsx("div", { "data-slot": "empty-header", className: cn('flex max-w-sm flex-col items-center gap-2 text-center', className), ...props }));
22
+ return (_jsx("div", { "data-slot": "empty-header", className: cn('flex max-w-sm flex-col items-center gap-2 text-center group-data-[variant=compact]/empty:gap-1.5', className), ...props }));
10
23
  }
11
24
  const emptyMediaVariants = cva('flex shrink-0 items-center justify-center mb-2 [&_svg]:pointer-events-none [&_svg]:shrink-0', {
12
25
  variants: {
@@ -23,12 +36,12 @@ function EmptyMedia({ className, variant = 'default', ...props }) {
23
36
  return (_jsx("div", { "data-slot": "empty-icon", "data-variant": variant, className: cn(emptyMediaVariants({ variant, className })), ...props }));
24
37
  }
25
38
  function EmptyTitle({ className, ...props }) {
26
- return (_jsx("div", { "data-slot": "empty-title", className: cn('text-lg font-medium tracking-tight', className), ...props }));
39
+ return (_jsx("div", { "data-slot": "empty-title", className: cn('font-medium tracking-tight group-data-[variant=compact]/empty:text-sm group-data-[variant=full]/empty:text-lg group-data-[variant=pane]/empty:text-base', className), ...props }));
27
40
  }
28
41
  function EmptyDescription({ className, ...props }) {
29
- return (_jsx("p", { "data-slot": "empty-description", className: cn('text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4', className), ...props }));
42
+ return (_jsx("p", { "data-slot": "empty-description", className: cn('text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed group-data-[variant=compact]/empty:text-xs/relaxed [&>a]:underline [&>a]:underline-offset-4', className), ...props }));
30
43
  }
31
44
  function EmptyContent({ className, ...props }) {
32
- return (_jsx("div", { "data-slot": "empty-content", className: cn('flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm', className), ...props }));
45
+ return (_jsx("div", { "data-slot": "empty-content", className: cn('flex w-full min-w-0 max-w-sm flex-col items-center gap-3 text-balance text-sm group-data-[variant=compact]/empty:gap-2', className), ...props }));
33
46
  }
34
- export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia, };
47
+ export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia, emptyVariants, };
@@ -1 +1 @@
1
- {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/components/ui/grid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,KAAK,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAA;AAmDvD,KAAK,SAAS,GAAG,IAAI,CACnB,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAC3B,cAAc,GAAG,UAAU,CAC5B,GAAG;IACF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,iBAAiB,CAAA;IACjC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACjC,qBAAqB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACxC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,QAAQ,EACR,OAAW,EACX,aAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,QAAQ,EACR,IAAY,EACZ,QAAgB,EAChB,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,2CA6NX;AAED,KAAK,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,GAAG;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,QAAQ,EACR,KAAK,EACL,QAAgB,EAChB,OAAO,EACP,aAAa,EACb,OAAO,EACP,GAAG,EACH,GAAG,KAAK,EACT,EAAE,aAAa,2CAgFf;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAW7B;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ7B;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ7B;AAED,iBAAS,mBAAmB,CAAC,EAC3B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,2CAQ3B;AAED,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,KAAK,SAAS,EACd,KAAK,iBAAiB,GACvB,CAAA"}
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/components/ui/grid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,KAAK,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAA;AAuCvD,KAAK,SAAS,GAAG,IAAI,CACnB,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAC3B,cAAc,GAAG,UAAU,CAC5B,GAAG;IACF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,iBAAiB,CAAA;IACjC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACjC,qBAAqB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACxC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,QAAQ,EACR,OAAW,EACX,aAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,QAAQ,EACR,IAAY,EACZ,QAAgB,EAChB,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,2CAsRX;AAED,KAAK,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,GAAG;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,QAAQ,EACR,KAAK,EACL,QAAgB,EAChB,OAAO,EACP,aAAa,EACb,OAAO,EACP,GAAG,EACH,GAAG,KAAK,EACT,EAAE,aAAa,2CA4Ef;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAW1E;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ5E;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ1E;AAED,iBAAS,mBAAmB,CAAC,EAC3B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,2CAQ3B;AAED,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,KAAK,SAAS,EACd,KAAK,iBAAiB,GACvB,CAAA"}
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import * as React from 'react';
4
4
  import { cn } from '../../lib/utils';
5
+ import { getCollectionItemsInDomOrder, isInteractiveDescendant, } from './collection-navigation';
5
6
  const GridContext = React.createContext(null);
6
7
  function useGridContext(component) {
7
8
  const context = React.useContext(GridContext);
@@ -22,11 +23,6 @@ function sameSelection(a, b) {
22
23
  }
23
24
  return true;
24
25
  }
25
- function isInteractiveDescendant(target, currentTarget) {
26
- if (!(target instanceof HTMLElement) || target === currentTarget)
27
- return false;
28
- return Boolean(target.closest('a,button,input,select,textarea,[contenteditable="true"],[role="button"],[role="link"]'));
29
- }
30
26
  function Grid({ className, children, columns = 1, selectionMode = 'none', selectedValues, defaultSelectedValues, onSelectionChange, onAction, loop = false, disabled = false, onKeyDown, style, ref, ...props }) {
31
27
  const itemsRef = React.useRef(new Map());
32
28
  const [activeValue, setActiveValueState] = React.useState(null);
@@ -40,18 +36,21 @@ function Grid({ className, children, columns = 1, selectionMode = 'none', select
40
36
  if (!node)
41
37
  return () => undefined;
42
38
  itemsRef.current.set(value, { node, disabled: itemDisabled });
43
- if (!disabled && !itemDisabled) {
44
- setActiveValueState((current) => current ?? value);
45
- }
46
39
  return () => {
47
40
  itemsRef.current.delete(value);
48
- setActiveValueState((current) => {
49
- if (current !== value)
50
- return current;
51
- return ([...itemsRef.current.entries()].find(([, item]) => !disabled && !item.disabled)?.[0] ?? null);
52
- });
41
+ setActiveValueState((current) => (current === value ? null : current));
53
42
  };
54
- }, [disabled]);
43
+ }, []);
44
+ React.useLayoutEffect(() => {
45
+ const items = getCollectionItemsInDomOrder(itemsRef.current).filter(([, item]) => !disabled && !item.disabled);
46
+ setActiveValueState((current) => {
47
+ if (current && items.some(([value]) => value === current))
48
+ return current;
49
+ return (items.find(([value]) => selection.has(value))?.[0] ??
50
+ items[0]?.[0] ??
51
+ null);
52
+ });
53
+ }, [children, disabled, selection]);
55
54
  const setActiveValue = React.useCallback((value) => {
56
55
  const item = itemsRef.current.get(value);
57
56
  if (item && !item.disabled)
@@ -86,41 +85,61 @@ function Grid({ className, children, columns = 1, selectionMode = 'none', select
86
85
  return;
87
86
  onAction?.(value);
88
87
  }, [disabled, onAction]);
89
- const moveFocus = React.useCallback((offset) => {
90
- const entries = [...itemsRef.current.entries()];
88
+ const moveFocus = React.useCallback((direction) => {
89
+ const entries = getCollectionItemsInDomOrder(itemsRef.current);
91
90
  if (entries.length === 0)
92
91
  return;
93
92
  const currentIndex = entries.findIndex(([value]) => value === activeValue);
94
93
  const enabledAt = (index) => entries[index] && !disabled && !entries[index][1].disabled;
95
- let nextIndex = offset === 'first'
96
- ? 0
97
- : offset === 'last'
98
- ? entries.length - 1
99
- : (currentIndex < 0 ? 0 : currentIndex) + offset;
100
- if (loop && typeof offset === 'number') {
101
- nextIndex =
102
- ((nextIndex % entries.length) + entries.length) % entries.length;
94
+ const startIndex = currentIndex < 0 ? 0 : currentIndex;
95
+ const currentRow = Math.floor(startIndex / safeColumns);
96
+ const currentColumn = startIndex % safeColumns;
97
+ const rowStart = currentRow * safeColumns;
98
+ const rowEnd = Math.min(entries.length - 1, rowStart + safeColumns - 1);
99
+ let candidates = [];
100
+ if (direction === 'first') {
101
+ candidates = Array.from({ length: entries.length }, (_, index) => index);
103
102
  }
104
- else {
105
- nextIndex = Math.min(entries.length - 1, Math.max(0, nextIndex));
103
+ else if (direction === 'last') {
104
+ candidates = Array.from({ length: entries.length }, (_, index) => entries.length - index - 1);
105
+ }
106
+ else if (direction === 'row-first') {
107
+ candidates = Array.from({ length: rowEnd - rowStart + 1 }, (_, index) => rowStart + index);
106
108
  }
107
- const direction = offset === 'first' ? 1 : offset === 'last' ? -1 : Math.sign(offset);
108
- let attempts = 0;
109
- while (!enabledAt(nextIndex) && attempts < entries.length) {
110
- nextIndex += direction || 1;
111
- if (loop) {
112
- nextIndex =
113
- ((nextIndex % entries.length) + entries.length) % entries.length;
109
+ else if (direction === 'row-last') {
110
+ candidates = Array.from({ length: rowEnd - rowStart + 1 }, (_, index) => rowEnd - index);
111
+ }
112
+ else if (direction === 'left' || direction === 'right') {
113
+ const step = direction === 'left' ? -1 : 1;
114
+ for (let index = startIndex + step; index >= rowStart && index <= rowEnd; index += step) {
115
+ candidates.push(index);
114
116
  }
115
- else if (nextIndex < 0 || nextIndex >= entries.length) {
116
- return;
117
+ if (loop && candidates.length === 0) {
118
+ candidates =
119
+ direction === 'left'
120
+ ? Array.from({ length: entries.length }, (_, index) => (startIndex - index - 1 + entries.length) % entries.length)
121
+ : Array.from({ length: entries.length }, (_, index) => (startIndex + index + 1) % entries.length);
117
122
  }
118
- attempts += 1;
119
123
  }
124
+ else {
125
+ const step = direction === 'up' ? -safeColumns : safeColumns;
126
+ for (let index = startIndex + step; index >= 0 && index < entries.length; index += step) {
127
+ candidates.push(index);
128
+ }
129
+ if (loop && candidates.length === 0) {
130
+ const sameColumn = entries
131
+ .map((_, index) => index)
132
+ .filter((index) => index % safeColumns === currentColumn);
133
+ candidates = direction === 'up' ? sameColumn.reverse() : sameColumn;
134
+ }
135
+ }
136
+ const nextIndex = candidates.find(enabledAt);
137
+ if (nextIndex === undefined || nextIndex === currentIndex)
138
+ return;
120
139
  const [value, item] = entries[nextIndex];
121
140
  setActiveValueState(value);
122
141
  item.node.focus();
123
- }, [activeValue, disabled, loop]);
142
+ }, [activeValue, disabled, loop, safeColumns]);
124
143
  const handleKeyDown = (event) => {
125
144
  onKeyDown?.(event);
126
145
  if (event.defaultPrevented || disabled)
@@ -129,19 +148,24 @@ function Grid({ className, children, columns = 1, selectionMode = 'none', select
129
148
  if (target.dataset.slot !== 'grid-item')
130
149
  return;
131
150
  const movement = {
132
- ArrowLeft: -1,
133
- ArrowRight: 1,
134
- ArrowUp: -safeColumns,
135
- ArrowDown: safeColumns,
151
+ ArrowLeft: 'left',
152
+ ArrowRight: 'right',
153
+ ArrowUp: 'up',
154
+ ArrowDown: 'down',
136
155
  };
137
- const offset = movement[event.key];
138
- if (offset !== undefined) {
156
+ const direction = movement[event.key];
157
+ if (direction !== undefined) {
139
158
  event.preventDefault();
140
- moveFocus(offset);
159
+ moveFocus(direction);
141
160
  }
142
161
  else if (event.key === 'Home' || event.key === 'End') {
143
162
  event.preventDefault();
144
- moveFocus(event.key === 'Home' ? 'first' : 'last');
163
+ if (event.ctrlKey || event.metaKey) {
164
+ moveFocus(event.key === 'Home' ? 'first' : 'last');
165
+ }
166
+ else {
167
+ moveFocus(event.key === 'Home' ? 'row-first' : 'row-last');
168
+ }
145
169
  }
146
170
  else if (event.key === ' ') {
147
171
  event.preventDefault();
@@ -194,7 +218,7 @@ function GridItem({ className, children, value, disabled = false, onClick, onDou
194
218
  ref.current = node;
195
219
  }, [ref]);
196
220
  React.useLayoutEffect(() => registerItem(value, itemRef.current, isDisabled), [isDisabled, registerItem, value]);
197
- return (_jsx("div", { ref: setRef, role: "gridcell", tabIndex: isDisabled ? -1 : isActive ? 0 : -1, "aria-disabled": isDisabled || undefined, "aria-selected": context.selectionMode === 'none' ? undefined : isSelected, "data-slot": "grid-item", "data-active": isActive || undefined, "data-disabled": isDisabled || undefined, "data-selected": context.selectionMode === 'none' ? undefined : isSelected, "data-value": value, className: cn('group/grid-item relative min-w-0 cursor-default select-none overflow-hidden rounded-lg border border-border bg-card text-card-foreground outline-none transition-[background-color,border-color,box-shadow] duration-100', 'hover:bg-accent/40 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]', 'data-[selected=true]:border-ring data-[selected=true]:bg-accent/60', 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50', className), onClick: (event) => {
221
+ return (_jsx("div", { ref: setRef, role: "gridcell", tabIndex: isDisabled ? -1 : isActive ? 0 : -1, "aria-disabled": isDisabled || undefined, "aria-selected": context.selectionMode === 'none' ? undefined : isSelected, "data-slot": "grid-item", "data-active": isActive || undefined, "data-disabled": isDisabled || undefined, "data-selected": context.selectionMode === 'none' ? undefined : isSelected, "data-value": value, className: cn('group/grid-item border-border bg-card text-card-foreground relative min-w-0 cursor-default select-none overflow-hidden rounded-lg border outline-none transition-[background-color,border-color,box-shadow] duration-100', 'hover:bg-accent/40 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]', 'data-[selected=true]:border-ring data-[selected=true]:bg-accent/60', 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50', className), onClick: (event) => {
198
222
  onClick?.(event);
199
223
  if (event.defaultPrevented ||
200
224
  isDisabled ||
@@ -17,11 +17,13 @@ export * from './collapsible';
17
17
  export * from './color-well';
18
18
  export * from './combobox';
19
19
  export * from './command';
20
+ export * from './confirm-dialog';
20
21
  export * from './context-menu';
21
22
  export * from './dialog';
22
23
  export * from './drawer';
23
24
  export * from './dropdown-menu';
24
25
  export * from './date-field';
26
+ export * from './date-picker';
25
27
  export * from './empty';
26
28
  export * from './edge-fade';
27
29
  export * from './field';
@@ -38,8 +40,10 @@ export * from './kbd';
38
40
  export * from './label';
39
41
  export * from './list';
40
42
  export * from './menubar';
43
+ export * from './material';
41
44
  export * from './message-scroller';
42
45
  export * from './navigation-menu';
46
+ export * from './navigation-button-group';
43
47
  export * from './notification-dot';
44
48
  export * from './number-input';
45
49
  export * from './pagination';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,QAAQ,CAAA;AACtB,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,2BAA2B,CAAA;AACzC,cAAc,oBAAoB,CAAA;AAClC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,QAAQ,CAAA;AACtB,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA"}
@@ -17,11 +17,13 @@ export * from './collapsible';
17
17
  export * from './color-well';
18
18
  export * from './combobox';
19
19
  export * from './command';
20
+ export * from './confirm-dialog';
20
21
  export * from './context-menu';
21
22
  export * from './dialog';
22
23
  export * from './drawer';
23
24
  export * from './dropdown-menu';
24
25
  export * from './date-field';
26
+ export * from './date-picker';
25
27
  export * from './empty';
26
28
  export * from './edge-fade';
27
29
  export * from './field';
@@ -38,8 +40,10 @@ export * from './kbd';
38
40
  export * from './label';
39
41
  export * from './list';
40
42
  export * from './menubar';
43
+ export * from './material';
41
44
  export * from './message-scroller';
42
45
  export * from './navigation-menu';
46
+ export * from './navigation-button-group';
43
47
  export * from './notification-dot';
44
48
  export * from './number-input';
45
49
  export * from './pagination';
@@ -11,6 +11,10 @@ type ListProps = Omit<React.ComponentProps<'div'>, 'defaultValue' | 'onChange'>
11
11
  disabled?: boolean;
12
12
  };
13
13
  declare function List({ className, children, selectionMode, selectedValues, defaultSelectedValues, onSelectionChange, onAction, orientation, loop, disabled, role, onKeyDown, ref, ...props }: ListProps): import("react/jsx-runtime").JSX.Element;
14
+ type ListSectionProps = Omit<React.ComponentProps<'div'>, 'role'>;
15
+ declare function ListSection({ className, children, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }: ListSectionProps): import("react/jsx-runtime").JSX.Element;
16
+ type ListSectionHeaderProps = Omit<React.ComponentProps<'div'>, 'id'>;
17
+ declare function ListSectionHeader({ className, ...props }: ListSectionHeaderProps): import("react/jsx-runtime").JSX.Element;
14
18
  type ListItemProps = Omit<React.ComponentProps<'div'>, 'value'> & {
15
19
  value: string;
16
20
  disabled?: boolean;
@@ -20,5 +24,5 @@ declare function ListItemContent({ className, ...props }: React.ComponentProps<'
20
24
  declare function ListItemTitle({ className, ...props }: React.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
21
25
  declare function ListItemDescription({ className, ...props }: React.ComponentProps<'p'>): import("react/jsx-runtime").JSX.Element;
22
26
  declare function ListItemActions({ className, ...props }: React.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
23
- export { List, ListItem, ListItemActions, ListItemContent, ListItemDescription, ListItemTitle, type ListProps, type ListSelectionMode, };
27
+ export { List, ListItem, ListItemActions, ListItemContent, ListItemDescription, ListItemTitle, ListSection, ListSectionHeader, type ListProps, type ListSectionHeaderProps, type ListSectionProps, type ListSelectionMode, };
24
28
  //# sourceMappingURL=list.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/components/ui/list.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,KAAK,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAA;AAmDvD,KAAK,SAAS,GAAG,IAAI,CACnB,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAC3B,cAAc,GAAG,UAAU,CAC5B,GAAG;IACF,aAAa,CAAC,EAAE,iBAAiB,CAAA;IACjC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACjC,qBAAqB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACxC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,QAAQ,EACR,aAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,QAAQ,EACR,WAAwB,EACxB,IAAY,EACZ,QAAgB,EAChB,IAAI,EACJ,SAAS,EACT,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,2CAsMX;AAED,KAAK,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,GAAG;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,QAAQ,EACR,KAAK,EACL,QAAgB,EAChB,OAAO,EACP,aAAa,EACb,OAAO,EACP,GAAG,EACH,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,aAAa,2CAmFf;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ7B;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ7B;AAED,iBAAS,mBAAmB,CAAC,EAC3B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,2CAQ3B;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ7B;AAED,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,KAAK,SAAS,EACd,KAAK,iBAAiB,GACvB,CAAA"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/components/ui/list.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,KAAK,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAA;AA+CvD,KAAK,SAAS,GAAG,IAAI,CACnB,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAC3B,cAAc,GAAG,UAAU,CAC5B,GAAG;IACF,aAAa,CAAC,EAAE,iBAAiB,CAAA;IACjC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACjC,qBAAqB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACxC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,QAAQ,EACR,aAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,QAAQ,EACR,WAAwB,EACxB,IAAY,EACZ,QAAgB,EAChB,IAAI,EACJ,SAAS,EACT,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,2CAoMX;AAED,KAAK,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAA;AAEjE,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,GAAG,KAAK,EACT,EAAE,gBAAgB,2CAiBlB;AAED,KAAK,sBAAsB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAA;AAErE,iBAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,sBAAsB,2CAiBzE;AAED,KAAK,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,GAAG;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,QAAQ,EACR,KAAK,EACL,QAAgB,EAChB,OAAO,EACP,aAAa,EACb,OAAO,EACP,GAAG,EACH,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,aAAa,2CA+Ef;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ5E;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ1E;AAED,iBAAS,mBAAmB,CAAC,EAC3B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,2CAQ3B;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ5E;AAED,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,CAAA"}
@@ -2,7 +2,9 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import * as React from 'react';
4
4
  import { cn } from '../../lib/utils';
5
+ import { getCollectionItemsInDomOrder, isInteractiveDescendant, } from './collection-navigation';
5
6
  const ListContext = React.createContext(null);
7
+ const ListSectionContext = React.createContext(null);
6
8
  function useListContext(component) {
7
9
  const context = React.useContext(ListContext);
8
10
  if (!context) {
@@ -22,11 +24,6 @@ function sameSelection(a, b) {
22
24
  }
23
25
  return true;
24
26
  }
25
- function isInteractiveDescendant(target, currentTarget) {
26
- if (!(target instanceof HTMLElement) || target === currentTarget)
27
- return false;
28
- return Boolean(target.closest('a,button,input,select,textarea,[contenteditable="true"],[role="button"],[role="link"]'));
29
- }
30
27
  function List({ className, children, selectionMode = 'none', selectedValues, defaultSelectedValues, onSelectionChange, onAction, orientation = 'vertical', loop = false, disabled = false, role, onKeyDown, ref, ...props }) {
31
28
  const rootRef = React.useRef(null);
32
29
  const itemsRef = React.useRef(new Map());
@@ -45,18 +42,21 @@ function List({ className, children, selectionMode = 'none', selectedValues, def
45
42
  if (!node)
46
43
  return () => undefined;
47
44
  itemsRef.current.set(value, { node, disabled: itemDisabled });
48
- if (!disabled && !itemDisabled) {
49
- setActiveValueState((current) => current ?? value);
50
- }
51
45
  return () => {
52
46
  itemsRef.current.delete(value);
53
- setActiveValueState((current) => {
54
- if (current !== value)
55
- return current;
56
- return ([...itemsRef.current.entries()].find(([, item]) => !disabled && !item.disabled)?.[0] ?? null);
57
- });
47
+ setActiveValueState((current) => (current === value ? null : current));
58
48
  };
59
- }, [disabled]);
49
+ }, []);
50
+ React.useLayoutEffect(() => {
51
+ const items = getCollectionItemsInDomOrder(itemsRef.current).filter(([, item]) => !disabled && !item.disabled);
52
+ setActiveValueState((current) => {
53
+ if (current && items.some(([value]) => value === current))
54
+ return current;
55
+ return (items.find(([value]) => selection.has(value))?.[0] ??
56
+ items[0]?.[0] ??
57
+ null);
58
+ });
59
+ }, [children, disabled, selection]);
60
60
  const setActiveValue = React.useCallback((value) => {
61
61
  const item = itemsRef.current.get(value);
62
62
  if (item && !item.disabled)
@@ -92,7 +92,7 @@ function List({ className, children, selectionMode = 'none', selectedValues, def
92
92
  onAction?.(value);
93
93
  }, [disabled, onAction]);
94
94
  const moveFocus = React.useCallback((direction) => {
95
- const items = [...itemsRef.current.entries()].filter(([, item]) => !disabled && !item.disabled);
95
+ const items = getCollectionItemsInDomOrder(itemsRef.current).filter(([, item]) => !disabled && !item.disabled);
96
96
  if (items.length === 0)
97
97
  return;
98
98
  const currentIndex = items.findIndex(([value]) => value === activeValue);
@@ -168,6 +168,17 @@ function List({ className, children, selectionMode = 'none', selectedValues, def
168
168
  ? 'flex-col gap-0.5'
169
169
  : 'flex-row items-center gap-1', className), onKeyDown: handleKeyDown, ...props, children: children }) }));
170
170
  }
171
+ function ListSection({ className, children, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }) {
172
+ const headerId = React.useId();
173
+ return (_jsx(ListSectionContext.Provider, { value: { headerId }, children: _jsx("div", { role: "group", "aria-label": ariaLabel, "aria-labelledby": ariaLabel ? undefined : (ariaLabelledBy ?? headerId), "data-slot": "list-section", className: cn('flex min-w-0 flex-col gap-0.5', className), ...props, children: children }) }));
174
+ }
175
+ function ListSectionHeader({ className, ...props }) {
176
+ const context = React.useContext(ListSectionContext);
177
+ if (!context) {
178
+ throw new Error('ListSectionHeader must be used inside ListSection');
179
+ }
180
+ return (_jsx("div", { id: context.headerId, "data-slot": "list-section-header", className: cn('text-muted-foreground px-2.5 py-1 text-xs font-medium', className), ...props }));
181
+ }
171
182
  function ListItem({ className, children, value, disabled = false, onClick, onDoubleClick, onFocus, ref, role, ...props }) {
172
183
  const context = useListContext('ListItem');
173
184
  const { registerItem } = context;
@@ -221,4 +232,4 @@ function ListItemDescription({ className, ...props }) {
221
232
  function ListItemActions({ className, ...props }) {
222
233
  return (_jsx("div", { "data-slot": "list-item-actions", className: cn('ml-auto flex shrink-0 items-center gap-1', className), ...props }));
223
234
  }
224
- export { List, ListItem, ListItemActions, ListItemContent, ListItemDescription, ListItemTitle, };
235
+ export { List, ListItem, ListItemActions, ListItemContent, ListItemDescription, ListItemTitle, ListSection, ListSectionHeader, };
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ declare const materialVariants: (props?: ({
4
+ shape?: "circle" | "rounded" | "capsule" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ export type MaterialVariant = 'regular' | 'clear';
7
+ export type MaterialShape = NonNullable<VariantProps<typeof materialVariants>['shape']>;
8
+ export type MaterialElevation = 'none' | 'panel' | 'overlay';
9
+ export interface MaterialProps extends React.ComponentPropsWithoutRef<'div'>, VariantProps<typeof materialVariants> {
10
+ /**
11
+ * `regular` is the default for toolbars and control chrome. Reserve `clear`
12
+ * for compact controls floating above media or a richly colored canvas.
13
+ */
14
+ variant?: MaterialVariant;
15
+ elevation?: MaterialElevation;
16
+ interactive?: boolean;
17
+ asChild?: boolean;
18
+ }
19
+ declare function Material({ asChild, className, elevation, interactive, shape, variant, ...props }: MaterialProps): import("react/jsx-runtime").JSX.Element;
20
+ declare const materialGroupSpacing: {
21
+ readonly compact: "gap-0.5 p-0.5";
22
+ readonly default: "gap-1 p-1";
23
+ readonly comfortable: "gap-1.5 p-1.5";
24
+ };
25
+ export interface MaterialGroupProps extends Omit<MaterialProps, 'asChild' | 'interactive'> {
26
+ spacing?: keyof typeof materialGroupSpacing;
27
+ }
28
+ /**
29
+ * A single sampled material layer for a related control cluster. Children
30
+ * should be ordinary transparent or ghost controls, not nested Materials.
31
+ */
32
+ declare function MaterialGroup({ className, spacing, ...props }: MaterialGroupProps): import("react/jsx-runtime").JSX.Element;
33
+ export { Material, MaterialGroup, materialVariants };
34
+ //# sourceMappingURL=material.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../../../src/components/ui/material.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,KAAK,YAAY,EAAO,MAAM,0BAA0B,CAAA;AAEjE,QAAA,MAAM,gBAAgB;;8EAWpB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAA;AACjD,MAAM,MAAM,aAAa,GAAG,WAAW,CACrC,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAC/C,CAAA;AACD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;AAE5D,MAAM,WAAW,aACf,SAAQ,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAC3C,YAAY,CAAC,OAAO,gBAAgB,CAAC;IACvC;;;OAGG;IACH,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,SAAS,CAAC,EAAE,iBAAiB,CAAA;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,iBAAS,QAAQ,CAAC,EAChB,OAAe,EACf,SAAS,EACT,SAAmB,EACnB,WAAmB,EACnB,KAAK,EACL,OAAmB,EACnB,GAAG,KAAK,EACT,EAAE,aAAa,2CAcf;AAED,QAAA,MAAM,oBAAoB;;;;CAIhB,CAAA;AAEV,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,aAAa,CAAC;IACtD,OAAO,CAAC,EAAE,MAAM,OAAO,oBAAoB,CAAA;CAC5C;AAED;;;GAGG;AACH,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,OAAmB,EACnB,GAAG,KAAK,EACT,EAAE,kBAAkB,2CAYpB;AAED,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,CAAA"}
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Slot } from '@radix-ui/react-slot';
4
+ import { cn } from '../../lib/utils';
5
+ import { cva } from 'class-variance-authority';
6
+ const materialVariants = cva('moldable-material border text-inherit', {
7
+ variants: {
8
+ shape: {
9
+ rounded: 'rounded-overlay',
10
+ capsule: 'rounded-full',
11
+ circle: 'aspect-square rounded-full',
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ shape: 'rounded',
16
+ },
17
+ });
18
+ function Material({ asChild = false, className, elevation = 'panel', interactive = false, shape, variant = 'regular', ...props }) {
19
+ const Comp = asChild ? Slot : 'div';
20
+ return (_jsx(Comp, { "data-slot": asChild ? undefined : 'material', "data-material": variant, "data-material-elevation": elevation, "data-material-interactive": interactive || undefined, "data-material-shape": shape ?? 'rounded', className: cn(materialVariants({ shape }), className), ...props }));
21
+ }
22
+ const materialGroupSpacing = {
23
+ compact: 'gap-0.5 p-0.5',
24
+ default: 'gap-1 p-1',
25
+ comfortable: 'gap-1.5 p-1.5',
26
+ };
27
+ /**
28
+ * A single sampled material layer for a related control cluster. Children
29
+ * should be ordinary transparent or ghost controls, not nested Materials.
30
+ */
31
+ function MaterialGroup({ className, spacing = 'default', ...props }) {
32
+ return (_jsx(Material, { "data-slot": "material-group", className: cn('inline-flex min-w-0 items-center', materialGroupSpacing[spacing], className), ...props }));
33
+ }
34
+ export { Material, MaterialGroup, materialVariants };