@scalepad/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/.ai/rules/date-handling.md +39 -0
  2. package/.ai/rules/figma-design-system.md +372 -0
  3. package/.ai/rules/figma-lm-design-system-keys.md +680 -0
  4. package/.ai/rules/file-extensions.md +13 -0
  5. package/.ai/rules/modal-confirmation-mutation.md +56 -0
  6. package/.ai/rules/react-hooks.md +29 -0
  7. package/.ai/rules/styling.md +83 -0
  8. package/AGENTS.md +37 -0
  9. package/README.md +125 -0
  10. package/figma.config.json +9 -0
  11. package/package.json +127 -0
  12. package/scripts/install-ai-rules.mjs +136 -0
  13. package/src/ThemeProvider.tsx +57 -0
  14. package/src/charts.ts +32 -0
  15. package/src/components/ActionCard/ActionCard.css.ts +60 -0
  16. package/src/components/ActionCard/ActionCard.tsx +154 -0
  17. package/src/components/ActionCard/index.ts +2 -0
  18. package/src/components/Anchor/Anchor.tsx +47 -0
  19. package/src/components/Anchor/index.ts +2 -0
  20. package/src/components/AppliedFiltersManagerBar/AppliedFiltersManagerBar.tsx +105 -0
  21. package/src/components/AppliedFiltersManagerBar/FilterBadge.css.ts +23 -0
  22. package/src/components/AppliedFiltersManagerBar/FilterBadge.tsx +50 -0
  23. package/src/components/AppliedFiltersManagerBar/index.ts +5 -0
  24. package/src/components/Badge/Badge.css.ts +72 -0
  25. package/src/components/Badge/Badge.figma.tsx +43 -0
  26. package/src/components/Badge/Badge.tsx +159 -0
  27. package/src/components/Badge/index.ts +2 -0
  28. package/src/components/BreadCrumb/BreadCrumb.tsx +62 -0
  29. package/src/components/BreadCrumb/index.ts +2 -0
  30. package/src/components/BulkActionBar/BulkActionBar.css.ts +26 -0
  31. package/src/components/BulkActionBar/BulkActionBar.tsx +164 -0
  32. package/src/components/BulkActionBar/index.ts +2 -0
  33. package/src/components/Button/Button.css.ts +272 -0
  34. package/src/components/Button/Button.figma.tsx +74 -0
  35. package/src/components/Button/Button.tsx +84 -0
  36. package/src/components/Button/index.ts +2 -0
  37. package/src/components/Charts/ChartTooltip.figma.tsx +33 -0
  38. package/src/components/Charts/ChartTooltip.tsx +101 -0
  39. package/src/components/Charts/MiniBarSparkline.tsx +75 -0
  40. package/src/components/Charts/StackedPatternBarChart.tsx +494 -0
  41. package/src/components/Charts/TrendAreaChart.css.ts +23 -0
  42. package/src/components/Charts/TrendAreaChart.tsx +210 -0
  43. package/src/components/Charts/index.ts +12 -0
  44. package/src/components/CodePanel/CodePanel.css.ts +113 -0
  45. package/src/components/CodePanel/CodePanel.tsx +121 -0
  46. package/src/components/CodePanel/index.ts +2 -0
  47. package/src/components/CommentComposer/CommentComposer.css.ts +60 -0
  48. package/src/components/CommentComposer/CommentComposer.tsx +181 -0
  49. package/src/components/CommentComposer/index.ts +2 -0
  50. package/src/components/ConfirmationModal/ConfirmationModal.tsx +149 -0
  51. package/src/components/ConfirmationModal/index.ts +2 -0
  52. package/src/components/ConfirmationTooltip/ConfirmationTooltip.tsx +132 -0
  53. package/src/components/ConfirmationTooltip/index.ts +2 -0
  54. package/src/components/DataDialog.figma.tsx +33 -0
  55. package/src/components/DataDialog.tsx +46 -0
  56. package/src/components/DataTable/DataTable.tsx +1042 -0
  57. package/src/components/DataTable/RowExpandToggle.tsx +105 -0
  58. package/src/components/DataTable/RowGroupHeader.tsx +190 -0
  59. package/src/components/DataTable/createActionsColumn.tsx +86 -0
  60. package/src/components/DataTable/index.ts +25 -0
  61. package/src/components/DatePicker/CustomRangePicker.tsx +59 -0
  62. package/src/components/DatePicker/DateInput.tsx +329 -0
  63. package/src/components/DatePicker/DateNavigator.tsx +486 -0
  64. package/src/components/DatePicker/DatePicker.tsx +242 -0
  65. package/src/components/DatePicker/MonthlyRangePicker.tsx +231 -0
  66. package/src/components/DatePicker/QuarterlyRangePicker.tsx +224 -0
  67. package/src/components/DatePicker/QuickPicksSidebar.tsx +242 -0
  68. package/src/components/DatePicker/YearlyRangePicker.tsx +171 -0
  69. package/src/components/DatePicker/index.ts +7 -0
  70. package/src/components/DatePicker/types.ts +12 -0
  71. package/src/components/DesignSystemPrimitives/FluidGrid.tsx +44 -0
  72. package/src/components/DesignSystemPrimitives/InteractivePrimitives.tsx +177 -0
  73. package/src/components/DesignSystemPrimitives/LayoutPrimitives.tsx +220 -0
  74. package/src/components/DesignSystemPrimitives/LayoutPrimitives.types.tsx +15 -0
  75. package/src/components/DesignSystemPrimitives/SurfacePrimitives.tsx +46 -0
  76. package/src/components/DesignSystemPrimitives/index.ts +55 -0
  77. package/src/components/Details/Details.css.ts +74 -0
  78. package/src/components/Details/Details.tsx +140 -0
  79. package/src/components/Details/index.ts +2 -0
  80. package/src/components/DownloadCard/DownloadCard.css.ts +22 -0
  81. package/src/components/DownloadCard/DownloadCard.tsx +63 -0
  82. package/src/components/DownloadCard/index.ts +2 -0
  83. package/src/components/Drawer/Drawer.css.ts +32 -0
  84. package/src/components/Drawer/Drawer.tsx +236 -0
  85. package/src/components/Drawer/hooks/useDetailDrawer.ts +61 -0
  86. package/src/components/Drawer/hooks/useDetailDrawerNavigation.ts +125 -0
  87. package/src/components/Drawer/hooks/useDetailDrawerNavigationContext.ts +66 -0
  88. package/src/components/EditableRichText/EditableRichText.css.ts +72 -0
  89. package/src/components/EditableRichText/EditableRichText.tsx +324 -0
  90. package/src/components/EditableRichText/index.ts +2 -0
  91. package/src/components/EditableSelect/EditableSelect.css.ts +62 -0
  92. package/src/components/EditableSelect/EditableSelect.tsx +224 -0
  93. package/src/components/EditableSelect/index.ts +2 -0
  94. package/src/components/EditableText/EditableText.tsx +377 -0
  95. package/src/components/EditableText/index.ts +2 -0
  96. package/src/components/EmptyState/EmptyState.figma.tsx +33 -0
  97. package/src/components/EmptyState/EmptyState.tsx +230 -0
  98. package/src/components/EmptyState/index.ts +2 -0
  99. package/src/components/ErrorBoundary.tsx +135 -0
  100. package/src/components/ErrorState/ErrorState.tsx +197 -0
  101. package/src/components/ErrorState/index.ts +2 -0
  102. package/src/components/FeatureCard.tsx +42 -0
  103. package/src/components/FilterMenu/FilterMenu.figma.tsx +30 -0
  104. package/src/components/FilterMenu/FilterMenu.tsx +198 -0
  105. package/src/components/FilterMenu/FilterSubMenuTypes/BooleanFilterSubmenu.tsx +46 -0
  106. package/src/components/FilterMenu/FilterSubMenuTypes/SearchableFilterSubmenu.tsx +239 -0
  107. package/src/components/FilterMenu/FilterSubMenuTypes/index.ts +8 -0
  108. package/src/components/FilterMenu/defaultFilterSchemas.ts +63 -0
  109. package/src/components/FilterMenu/helpers.ts +115 -0
  110. package/src/components/FilterMenu/index.ts +35 -0
  111. package/src/components/FilterMenu/types.ts +101 -0
  112. package/src/components/IconButton/IconButton.css.ts +272 -0
  113. package/src/components/IconButton/IconButton.figma.tsx +47 -0
  114. package/src/components/IconButton/IconButton.tsx +72 -0
  115. package/src/components/IconButton/README.md +230 -0
  116. package/src/components/IconButton/index.ts +2 -0
  117. package/src/components/InfiniteScrollSentinel.tsx +86 -0
  118. package/src/components/InfiniteScrollTrigger.tsx +78 -0
  119. package/src/components/InfoCard.figma.tsx +47 -0
  120. package/src/components/InfoCard.tsx +216 -0
  121. package/src/components/KbdHint/KbdHint.tsx +23 -0
  122. package/src/components/KbdHint/index.ts +2 -0
  123. package/src/components/LabeledField/LabeledField.tsx +21 -0
  124. package/src/components/LabeledField/index.ts +2 -0
  125. package/src/components/LookupSelect/LookupSelect.css.ts +149 -0
  126. package/src/components/LookupSelect/LookupSelect.tsx +325 -0
  127. package/src/components/LookupSelect/index.ts +2 -0
  128. package/src/components/Menu/Menu.css.ts +89 -0
  129. package/src/components/Menu/Menu.tsx +105 -0
  130. package/src/components/Menu/index.ts +2 -0
  131. package/src/components/MessageBox/MessageBox.tsx +168 -0
  132. package/src/components/MessageBox/index.ts +2 -0
  133. package/src/components/MetricDisplay/MetricDisplay.tsx +55 -0
  134. package/src/components/MetricDisplay/index.ts +1 -0
  135. package/src/components/MultiSelect/MultiSelect.tsx +278 -0
  136. package/src/components/MultiSelect/index.ts +2 -0
  137. package/src/components/Notifications/Notifications.tsx +12 -0
  138. package/src/components/Notifications/README.md +93 -0
  139. package/src/components/Notifications/index.ts +4 -0
  140. package/src/components/Notifications/showToast.tsx +100 -0
  141. package/src/components/PropertyRow/PropertyRow.tsx +96 -0
  142. package/src/components/PropertyRow/index.ts +2 -0
  143. package/src/components/RadioTile/RadioTile.tsx +253 -0
  144. package/src/components/RadioTile/index.ts +2 -0
  145. package/src/components/RichText/FormattingToolbar.css.ts +69 -0
  146. package/src/components/RichText/FormattingToolbar.tsx +112 -0
  147. package/src/components/RichText/RichTextInline.css.ts +54 -0
  148. package/src/components/RichText/RichTextInline.tsx +318 -0
  149. package/src/components/RichText/formattingCommands.ts +181 -0
  150. package/src/components/RichText/formattingTypes.ts +34 -0
  151. package/src/components/RichText/index.ts +49 -0
  152. package/src/components/RichText/richTextExtensions.ts +111 -0
  153. package/src/components/RichText/richTextHelpers.ts +65 -0
  154. package/src/components/RichText/richTextImage.ts +253 -0
  155. package/src/components/RichText/richTextImageHandlers.ts +244 -0
  156. package/src/components/RichText/richTextProse.css.ts +261 -0
  157. package/src/components/RichTextEditor/RichTextEditor.css.ts +82 -0
  158. package/src/components/RichTextEditor/RichTextEditor.tsx +204 -0
  159. package/src/components/RichTextEditor/index.ts +2 -0
  160. package/src/components/RichTextView/RichTextView.css.ts +11 -0
  161. package/src/components/RichTextView/RichTextView.tsx +114 -0
  162. package/src/components/RichTextView/index.ts +2 -0
  163. package/src/components/Schedule/Schedule.tsx +35 -0
  164. package/src/components/SchedulePicker/SchedulePicker.css.ts +42 -0
  165. package/src/components/SchedulePicker/SchedulePicker.tsx +130 -0
  166. package/src/components/SchedulePicker/index.ts +2 -0
  167. package/src/components/SearchableList/types.ts +30 -0
  168. package/src/components/SearchableSubMenu/SearchableSubMenu.css.ts +25 -0
  169. package/src/components/SearchableSubMenu/SearchableSubMenu.tsx +139 -0
  170. package/src/components/SearchableSubMenu/index.ts +2 -0
  171. package/src/components/Select/README.md +114 -0
  172. package/src/components/Select/Select.css.ts +110 -0
  173. package/src/components/Select/Select.tsx +133 -0
  174. package/src/components/Select/index.ts +2 -0
  175. package/src/components/SelectCreatable/SelectCreatable.css.ts +16 -0
  176. package/src/components/SelectCreatable/SelectCreatable.tsx +203 -0
  177. package/src/components/SelectCreatable/index.ts +2 -0
  178. package/src/components/SettingsCard/SettingsCard.tsx +98 -0
  179. package/src/components/SettingsCard/index.ts +2 -0
  180. package/src/components/Sidebar/Sidebar.css.ts +91 -0
  181. package/src/components/Sidebar/Sidebar.tsx +129 -0
  182. package/src/components/Sidebar/index.ts +5 -0
  183. package/src/components/SimpleList/SimpleList.css.ts +12 -0
  184. package/src/components/SimpleList/SimpleList.tsx +44 -0
  185. package/src/components/SimpleList/index.ts +2 -0
  186. package/src/components/SimpleTable/SimpleTable.tsx +296 -0
  187. package/src/components/SimpleTable/index.ts +2 -0
  188. package/src/components/SlashRichTextEditor/SelectionBubbleMenu.css.ts +62 -0
  189. package/src/components/SlashRichTextEditor/SelectionBubbleMenu.tsx +85 -0
  190. package/src/components/SlashRichTextEditor/SlashCommandMenu.css.ts +124 -0
  191. package/src/components/SlashRichTextEditor/SlashCommandMenu.tsx +168 -0
  192. package/src/components/SlashRichTextEditor/SlashRichTextEditor.css.ts +81 -0
  193. package/src/components/SlashRichTextEditor/SlashRichTextEditor.tsx +538 -0
  194. package/src/components/SlashRichTextEditor/SlashSuggestionExtension.ts +48 -0
  195. package/src/components/SlashRichTextEditor/index.ts +13 -0
  196. package/src/components/SlashRichTextEditor/types.ts +48 -0
  197. package/src/components/StatCard/StatCard.css.ts +70 -0
  198. package/src/components/StatCard/StatCard.tsx +201 -0
  199. package/src/components/StatCard/index.ts +1 -0
  200. package/src/components/StatusBadge/StatusBadge.tsx +70 -0
  201. package/src/components/StatusBadge/index.ts +2 -0
  202. package/src/components/StatusIndicator/StatusIndicator.tsx +67 -0
  203. package/src/components/StatusIndicator/index.ts +6 -0
  204. package/src/components/SubNavigation/SubNavigation.css.ts +72 -0
  205. package/src/components/SubNavigation/SubNavigation.tsx +104 -0
  206. package/src/components/SubNavigation/index.ts +2 -0
  207. package/src/components/SuspenseLoader.tsx +22 -0
  208. package/src/components/Table/SortableColumnHeader.tsx +99 -0
  209. package/src/components/Table/TableSkeletonRows.figma.tsx +22 -0
  210. package/src/components/Table/TableSkeletonRows.tsx +113 -0
  211. package/src/components/Table/index.ts +9 -0
  212. package/src/components/TableActionsMenu.tsx +58 -0
  213. package/src/components/TableCard.tsx +29 -0
  214. package/src/components/TableContainer/TableContainer.tsx +86 -0
  215. package/src/components/TableContainer/index.ts +2 -0
  216. package/src/components/TableControlBar/TableControlBar.tsx +156 -0
  217. package/src/components/TableControlBar/TableSelectionButton.tsx +57 -0
  218. package/src/components/TableControlBar/index.ts +13 -0
  219. package/src/components/TableControlBar/useTableControlBar.tsx +314 -0
  220. package/src/components/TableSelection/TableSelection.tsx +43 -0
  221. package/src/components/TableSelection/index.ts +5 -0
  222. package/src/components/Tabs/README.md +76 -0
  223. package/src/components/Tabs/Tabs.css.ts +54 -0
  224. package/src/components/Tabs/Tabs.figma.tsx +47 -0
  225. package/src/components/Tabs/Tabs.tsx +96 -0
  226. package/src/components/Tabs/index.ts +8 -0
  227. package/src/components/TextInput/README.md +98 -0
  228. package/src/components/TextInput/SearchTextInput.figma.tsx +22 -0
  229. package/src/components/TextInput/SearchTextInput.tsx +150 -0
  230. package/src/components/TextInput/TextInput.figma.tsx +44 -0
  231. package/src/components/TextInput/TextInput.tsx +42 -0
  232. package/src/components/TextInput/index.ts +4 -0
  233. package/src/components/ThemeSwitcher.figma.tsx +28 -0
  234. package/src/components/ThemeSwitcher.tsx +69 -0
  235. package/src/components/TrendBadge/TrendBadge.tsx +76 -0
  236. package/src/components/TrendBadge/index.ts +2 -0
  237. package/src/components/TruncatedText.tsx +115 -0
  238. package/src/components/Typography/Text.tsx +74 -0
  239. package/src/components/Typography/Title.tsx +100 -0
  240. package/src/components/Typography/index.ts +4 -0
  241. package/src/geist-fonts.ts +48 -0
  242. package/src/hooks/index.ts +31 -0
  243. package/src/hooks/useFilters.ts +152 -0
  244. package/src/hooks/useInfiniteScroll.ts +62 -0
  245. package/src/hooks/usePlatform.ts +33 -0
  246. package/src/hooks/useServerTable.ts +495 -0
  247. package/src/hooks/useTableSelection.ts +102 -0
  248. package/src/hooks/useTableSort.ts +259 -0
  249. package/src/index.ts +483 -0
  250. package/src/mantine.ts +25 -0
  251. package/src/theme/mantineVars.ts +12 -0
  252. package/src/theme/themeContract.css.ts +131 -0
  253. package/src/theme/themeVars.ts +31 -0
  254. package/src/theme.ts +168 -0
  255. package/src/tokens/color-types.ts +107 -0
  256. package/src/tokens/colors.ts +243 -0
  257. package/src/tokens/index.ts +14 -0
  258. package/src/tokens/radius.ts +17 -0
  259. package/src/tokens/semantic-colors.ts +224 -0
  260. package/src/tokens/semantic-tokens-css.ts +53 -0
  261. package/src/tokens/shadows.ts +11 -0
  262. package/src/tokens/spacing.ts +20 -0
  263. package/src/tokens/text-styles.ts +179 -0
  264. package/src/tokens/typography.ts +40 -0
  265. package/src/tokens/zIndex.ts +27 -0
  266. package/src/types/mantine-theme.d.ts +17 -0
  267. package/src/types/tanstack-table.d.ts +22 -0
  268. package/src/utils/avatar.ts +150 -0
  269. package/src/utils/chartHelpers.ts +53 -0
  270. package/src/utils/color-props.ts +77 -0
  271. package/src/utils/createDesignComponent.tsx +104 -0
  272. package/src/utils/nestFlatRows.ts +111 -0
  273. package/src/utils/withStaticComponents.ts +6 -0
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Design System Layout Primitives
3
+ *
4
+ * Wrapped versions of Mantine layout components with type-safe color props.
5
+ * These replace the direct Mantine re-exports to enforce design system tokens.
6
+ */
7
+
8
+ import { Children, Fragment, type ReactElement } from 'react';
9
+
10
+ import {
11
+ Box as MantineBox,
12
+ Center as MantineCenter,
13
+ factory,
14
+ type Factory,
15
+ Flex as MantineFlex,
16
+ Grid as MantineGrid,
17
+ Group as MantineGroup,
18
+ polymorphicFactory,
19
+ type PolymorphicFactory,
20
+ SimpleGrid as MantineSimpleGrid,
21
+ Stack as MantineStack,
22
+ type BoxProps as MantineBoxProps,
23
+ type CenterProps as MantineCenterProps,
24
+ type FlexProps as MantineFlexProps,
25
+ type GridCssVariables as MantineGridCssVariables,
26
+ type GridProps as MantineGridProps,
27
+ type GridStylesNames as MantineGridStylesNames,
28
+ type GroupProps as MantineGroupProps,
29
+ type SimpleGridProps as MantineSimpleGridProps,
30
+ type StackProps as MantineStackProps,
31
+ } from '@mantine/core';
32
+
33
+ import { Divider } from './InteractivePrimitives';
34
+ import { resolveColorToken } from '../../utils/color-props';
35
+ import {
36
+ createDesignComponent,
37
+ type WithDesignColors,
38
+ } from '../../utils/createDesignComponent';
39
+ import { withStaticComponents } from '../../utils/withStaticComponents';
40
+
41
+ import type { StrokeColor } from '../../tokens/color-types';
42
+
43
+ // Layout primitives - all use the standard DesignSystemColorProps (c, bg, borderColor)
44
+ export const Box = createDesignComponent<
45
+ MantineBoxProps,
46
+ 'div',
47
+ HTMLDivElement
48
+ >(MantineBox, 'Box');
49
+ export const Flex = createDesignComponent<
50
+ MantineFlexProps,
51
+ 'div',
52
+ HTMLDivElement
53
+ >(MantineFlex, 'Flex');
54
+
55
+ export type StackProps = WithDesignColors<MantineStackProps> & {
56
+ /**
57
+ * Render a divider line between direct children (skipped after the last)
58
+ * so a list of items reads as separated rows without each child having to
59
+ * know its own position. Pass `true` for the default subtle stroke or a
60
+ * `StrokeColor` token to customize the colour.
61
+ *
62
+ * Implemented by interleaving Mantine `<Divider />` elements between
63
+ * children so the Stack's `gap` applies symmetrically on both sides — the
64
+ * line lands in the middle of the gutter rather than flush against one row.
65
+ *
66
+ * The interleaved nodes are plain `<div role="separator">` elements, which
67
+ * is fine for the default `<div>` Stack and any flex container that
68
+ * accepts arbitrary children. If you set `component` to a semantic list
69
+ * container (`ul`, `ol`, `dl`, `menu`) we leave the divider off — non-list
70
+ * children inside those wrappers are invalid HTML. A dev-mode warning is
71
+ * emitted so the misuse is caught at the call site.
72
+ */
73
+ divider?: boolean | StrokeColor;
74
+ };
75
+
76
+ // Stacks rendered as semantic list containers reject the divider prop — see
77
+ // the `divider` JSDoc above for why.
78
+ const LIST_LIKE_COMPONENTS = new Set(['ul', 'ol', 'dl', 'menu']);
79
+
80
+ function isListLikeComponent(component: unknown): boolean {
81
+ return typeof component === 'string' && LIST_LIKE_COMPONENTS.has(component);
82
+ }
83
+
84
+ type StackFactory = PolymorphicFactory<{
85
+ props: StackProps;
86
+ defaultComponent: 'div';
87
+ defaultRef: HTMLDivElement;
88
+ }>;
89
+
90
+ export const Stack = polymorphicFactory<StackFactory>(
91
+ ({ c, bg, borderColor, divider, children, ref, ...rest }) => {
92
+ const resolvedProps: Record<string, unknown> = { ...rest, ref };
93
+
94
+ const resolvedC = resolveColorToken(c);
95
+ if (resolvedC !== undefined) {
96
+ resolvedProps.c = resolvedC;
97
+ }
98
+
99
+ const resolvedBg = resolveColorToken(bg);
100
+ if (resolvedBg !== undefined) {
101
+ resolvedProps.bg = resolvedBg;
102
+ }
103
+
104
+ if (borderColor) {
105
+ const resolvedBorderColor = resolveColorToken(borderColor);
106
+ resolvedProps.bd = `1px solid ${resolvedBorderColor}`;
107
+ }
108
+
109
+ const stackComponent = (rest as { component?: unknown }).component;
110
+
111
+ if (!divider) {
112
+ return <MantineStack {...resolvedProps}>{children}</MantineStack>;
113
+ }
114
+
115
+ if (isListLikeComponent(stackComponent)) {
116
+ if (process.env.NODE_ENV !== 'production') {
117
+ // eslint-disable-next-line no-console
118
+ console.warn(
119
+ `<Stack divider> ignored: cannot interleave <Divider /> between <li> children inside <${String(
120
+ stackComponent,
121
+ )}>. Render the list manually or wrap each item in its own bordered row.`,
122
+ );
123
+ }
124
+ return <MantineStack {...resolvedProps}>{children}</MantineStack>;
125
+ }
126
+
127
+ const dividerColor: StrokeColor =
128
+ divider === true ? 'stroke.subdued.default' : divider;
129
+
130
+ // `Children.toArray` filters out null/false/undefined and assigns stable
131
+ // keys, so conditional children don't end up with extra dividers around
132
+ // empty slots.
133
+ const items = Children.toArray(children);
134
+
135
+ return (
136
+ <MantineStack {...resolvedProps}>
137
+ {items.map((child, idx) => {
138
+ const childKey =
139
+ (child as ReactElement).key != null
140
+ ? (child as ReactElement).key
141
+ : `stack-item-${idx}`;
142
+ return (
143
+ <Fragment key={childKey}>
144
+ {child}
145
+ {idx < items.length - 1 ? <Divider color={dividerColor} /> : null}
146
+ </Fragment>
147
+ );
148
+ })}
149
+ </MantineStack>
150
+ );
151
+ },
152
+ );
153
+ Stack.displayName = 'Stack';
154
+ export const Group = createDesignComponent<
155
+ MantineGroupProps,
156
+ 'div',
157
+ HTMLDivElement
158
+ >(MantineGroup, 'Group');
159
+ export const SimpleGrid = createDesignComponent<
160
+ MantineSimpleGridProps,
161
+ 'div',
162
+ HTMLDivElement
163
+ >(MantineSimpleGrid, 'SimpleGrid');
164
+ export const Center = createDesignComponent<
165
+ MantineCenterProps,
166
+ 'div',
167
+ HTMLDivElement
168
+ >(MantineCenter, 'Center');
169
+
170
+ // Grid needs special handling to preserve Grid.Col compound component
171
+ export type GridProps = WithDesignColors<MantineGridProps> & {
172
+ gap?: MantineGridProps['gap'];
173
+ rowGap?: MantineGridProps['rowGap'];
174
+ columnGap?: MantineGridProps['columnGap'];
175
+ };
176
+
177
+ type DesignGridFactory = Factory<{
178
+ props: GridProps;
179
+ ref: HTMLDivElement;
180
+ stylesNames: MantineGridStylesNames;
181
+ vars: MantineGridCssVariables;
182
+ staticComponents: {
183
+ Col: typeof MantineGrid.Col;
184
+ };
185
+ }>;
186
+
187
+ const GridRoot = factory<DesignGridFactory>(
188
+ ({ c, bg, borderColor, ref, ...rest }) => {
189
+ const resolvedProps: Record<string, unknown> = { ...rest, ref };
190
+
191
+ const resolvedC = resolveColorToken(c);
192
+ if (resolvedC !== undefined) {
193
+ resolvedProps.c = resolvedC;
194
+ }
195
+
196
+ const resolvedBg = resolveColorToken(bg);
197
+ if (resolvedBg !== undefined) {
198
+ resolvedProps.bg = resolvedBg;
199
+ }
200
+
201
+ if (borderColor) {
202
+ const resolvedBorderColor = resolveColorToken(borderColor);
203
+ resolvedProps.bd = `1px solid ${resolvedBorderColor}`;
204
+ }
205
+
206
+ return <MantineGrid {...resolvedProps} />;
207
+ },
208
+ );
209
+
210
+ GridRoot.displayName = 'Grid';
211
+
212
+ export const Grid = withStaticComponents(GridRoot, { Col: MantineGrid.Col });
213
+
214
+ // Export prop types for consumers (StackProps is exported above with the
215
+ // `divider` prop so its definition stays next to the wrapped Stack component).
216
+ export type BoxProps = WithDesignColors<MantineBoxProps>;
217
+ export type FlexProps = WithDesignColors<MantineFlexProps>;
218
+ export type GroupProps = WithDesignColors<MantineGroupProps>;
219
+ export type SimpleGridProps = WithDesignColors<MantineSimpleGridProps>;
220
+ export type CenterProps = WithDesignColors<MantineCenterProps>;
@@ -0,0 +1,15 @@
1
+ import { Grid, Group, SimpleGrid, Stack } from './LayoutPrimitives';
2
+
3
+ void (
4
+ <>
5
+ <Grid gap="sm" rowGap="xs" columnGap="md" grow>
6
+ <Grid.Col span="content">Column</Grid.Col>
7
+ </Grid>
8
+ <Group gap="sm">Grouped content</Group>
9
+ <Stack gap="md">Stacked content</Stack>
10
+ <SimpleGrid spacing="sm" verticalSpacing="lg" cols={2}>
11
+ <div>One</div>
12
+ <div>Two</div>
13
+ </SimpleGrid>
14
+ </>
15
+ );
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Design System Surface Primitives
3
+ *
4
+ * Wrapped versions of Mantine surface/container components with type-safe color props.
5
+ */
6
+
7
+ import {
8
+ Card as MantineCard,
9
+ Container as MantineContainer,
10
+ Paper as MantinePaper,
11
+ type CardProps as MantineCardProps,
12
+ type ContainerProps as MantineContainerProps,
13
+ type PaperProps as MantinePaperProps,
14
+ } from '@mantine/core';
15
+
16
+ import {
17
+ createDesignComponent,
18
+ type WithDesignColors,
19
+ } from '../../utils/createDesignComponent';
20
+ import { withStaticComponents } from '../../utils/withStaticComponents';
21
+
22
+ // Surface primitives
23
+ export const Paper = createDesignComponent<
24
+ MantinePaperProps,
25
+ 'div',
26
+ HTMLDivElement
27
+ >(MantinePaper, 'Paper');
28
+ export const Container = createDesignComponent<
29
+ MantineContainerProps,
30
+ 'div',
31
+ HTMLDivElement
32
+ >(MantineContainer, 'Container');
33
+
34
+ // Card needs special handling to preserve Card.Section compound component
35
+ const CardBase = createDesignComponent<MantineCardProps, 'div', HTMLDivElement>(
36
+ MantineCard,
37
+ 'Card',
38
+ );
39
+ export const Card = withStaticComponents(CardBase, {
40
+ Section: MantineCard.Section,
41
+ });
42
+
43
+ // Export prop types for consumers
44
+ export type CardProps = WithDesignColors<MantineCardProps>;
45
+ export type PaperProps = WithDesignColors<MantinePaperProps>;
46
+ export type ContainerProps = WithDesignColors<MantineContainerProps>;
@@ -0,0 +1,55 @@
1
+ import { Menu } from '../Menu';
2
+
3
+ // Design System Primitives - wrapped Mantine components with typed color props
4
+
5
+ // Layout primitives
6
+ export { FluidGrid } from './FluidGrid';
7
+ export type { FluidGridProps } from './FluidGrid';
8
+ export {
9
+ Box,
10
+ Center,
11
+ Flex,
12
+ Grid,
13
+ Group,
14
+ SimpleGrid,
15
+ Stack,
16
+ } from './LayoutPrimitives';
17
+ export type {
18
+ BoxProps,
19
+ CenterProps,
20
+ FlexProps,
21
+ GridProps,
22
+ GroupProps,
23
+ SimpleGridProps,
24
+ StackProps,
25
+ } from './LayoutPrimitives';
26
+
27
+ // Surface primitives
28
+ export { Card, Container, Paper } from './SurfacePrimitives';
29
+ export type {
30
+ CardProps,
31
+ ContainerProps,
32
+ PaperProps,
33
+ } from './SurfacePrimitives';
34
+ export { Menu };
35
+
36
+ export const MenuItem: typeof Menu.Item = Menu.Item;
37
+ export type { MenuItemProps, MenuItemVariant, MenuProps } from '../Menu';
38
+
39
+ // Interactive primitives
40
+ export {
41
+ Alert,
42
+ Avatar,
43
+ Divider,
44
+ Loader,
45
+ NavLink,
46
+ Switch,
47
+ } from './InteractivePrimitives';
48
+ export type {
49
+ AlertProps,
50
+ AvatarProps,
51
+ DividerProps,
52
+ LoaderProps,
53
+ NavLinkProps,
54
+ SwitchProps,
55
+ } from './InteractivePrimitives';
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Details / Summary component styles – vanilla-extract with semantic design tokens
3
+ */
4
+
5
+ import { style } from '@vanilla-extract/css';
6
+
7
+ import { mantineVars } from '../../theme/mantineVars';
8
+ import { tokens } from '../../theme/themeContract.css';
9
+
10
+ export const details = style({
11
+ overflow: 'hidden',
12
+ width: '100%',
13
+ border: `1px solid ${tokens.color.stroke.subduedDefault}`,
14
+ borderRadius: tokens.radius.lg,
15
+ selectors: {
16
+ [`${mantineVars.darkSelector} &`]: {
17
+ backgroundColor: tokens.color.background.default,
18
+ borderColor: tokens.color.stroke.default,
19
+ },
20
+ },
21
+ });
22
+
23
+ export const summary = style({
24
+ cursor: 'pointer',
25
+ listStyle: 'none',
26
+ minHeight: 0,
27
+ selectors: {
28
+ '&:focus-visible': {
29
+ outline: `2px solid ${tokens.color.stroke.primaryDefault}`,
30
+ outlineOffset: '4px',
31
+ borderRadius: tokens.radius.sm,
32
+ },
33
+ },
34
+ });
35
+
36
+ export const chevronWrapper = style({
37
+ display: 'inline-flex',
38
+ alignItems: 'center',
39
+ justifyContent: 'center',
40
+ flexShrink: 0,
41
+ minWidth: 34,
42
+ minHeight: 34,
43
+ color: tokens.color.text.subduedDefault,
44
+ });
45
+
46
+ export const chevronIcon = style({
47
+ flexShrink: 0,
48
+ transition: 'transform 0.2s ease',
49
+ selectors: {
50
+ [`${details}[open] &`]: {
51
+ transform: 'rotate(90deg)',
52
+ },
53
+ },
54
+ });
55
+
56
+ export const summaryContent = style({
57
+ flex: 1,
58
+ minWidth: 0,
59
+ });
60
+
61
+ export const actions = style({
62
+ flexShrink: 0,
63
+ });
64
+
65
+ export const contentWrapper = style({
66
+ borderTop: `1px solid ${tokens.color.stroke.default}`,
67
+ selectors: {
68
+ [`${mantineVars.darkSelector} &`]: {
69
+ borderTopColor: tokens.color.stroke.default,
70
+ },
71
+ },
72
+ });
73
+
74
+ export const content = style({});
@@ -0,0 +1,140 @@
1
+ import { useState, type CSSProperties, type ReactNode } from 'react';
2
+
3
+ import { ChevronRight } from 'lucide-react';
4
+
5
+ import { Box, Flex, type BoxProps } from '../DesignSystemPrimitives';
6
+ import * as classes from './Details.css';
7
+
8
+ export interface DetailsProps {
9
+ /** Content of the summary row (title, subtitle, etc.) */
10
+ summary: ReactNode;
11
+ /** Expandable content shown when open */
12
+ children: ReactNode;
13
+ /** Optional action icons rendered on the far right of the summary row */
14
+ actions?: ReactNode;
15
+ /** Whether the details start expanded (uncontrolled) */
16
+ defaultOpen?: boolean;
17
+ /** Controlled open state */
18
+ open?: boolean;
19
+ /** Callback when open state changes (use with controlled `open`) */
20
+ onOpenChange?: (open: boolean) => void;
21
+ /** Optional background color using the same Mantine-style prop shape as layout primitives */
22
+ bg?: BoxProps['bg'];
23
+ /** Optional border override using Mantine's `bd` prop format */
24
+ bd?: BoxProps['bd'];
25
+ /** Optional border radius override using Mantine's `bdrs` prop format */
26
+ bdrs?: BoxProps['bdrs'];
27
+ /** Optional padding override using Mantine's `p` prop format */
28
+ p?: BoxProps['p'];
29
+ /** Hide the built-in chevron when the summary provides its own icon */
30
+ hideChevron?: boolean;
31
+ }
32
+
33
+ /**
34
+ * Disclosure widget using native <details> and <summary> per W3C spec.
35
+ * Summary row shows a chevron (right when closed, down when open), summary content,
36
+ * and optional actions on the far right. When expanded, a divider and content
37
+ * area are shown; the border encloses the full block.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * <Details
42
+ * summary={<><Text variant="body1.stronger">Sales Department</Text><Text variant="caption1" c="text.subdued.default">21 Members</Text></>}
43
+ * actions={<IconButton variant="ghost" size="sm" aria-label="More"><MoreVertical /></IconButton>}
44
+ * >
45
+ * <Stack gap="md">...</Stack>
46
+ * </Details>
47
+ * ```
48
+ */
49
+ export function Details({
50
+ summary,
51
+ children,
52
+ actions,
53
+ defaultOpen,
54
+ open: controlledOpen,
55
+ onOpenChange,
56
+ bg,
57
+ p = 'md',
58
+ bd,
59
+ bdrs,
60
+ hideChevron = false,
61
+ }: DetailsProps) {
62
+ const isControlled = controlledOpen !== undefined;
63
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(
64
+ defaultOpen ?? false,
65
+ );
66
+
67
+ const handleToggle = (e: React.ToggleEvent<HTMLDetailsElement>) => {
68
+ const nextOpen = e.currentTarget.open;
69
+
70
+ if (isControlled) {
71
+ e.preventDefault();
72
+ onOpenChange?.(!controlledOpen);
73
+ return;
74
+ }
75
+
76
+ setUncontrolledOpen(nextOpen);
77
+ onOpenChange?.(nextOpen);
78
+ };
79
+
80
+ const contentWrapperStyle: CSSProperties | undefined =
81
+ typeof bd === 'string' || typeof bd === 'number'
82
+ ? { borderTop: bd }
83
+ : undefined;
84
+
85
+ return (
86
+ <Box
87
+ component="details"
88
+ className={classes.details}
89
+ open={isControlled ? controlledOpen : uncontrolledOpen}
90
+ onToggle={handleToggle}
91
+ bg={bg}
92
+ bd={bd}
93
+ bdrs={bdrs}
94
+ w="100%"
95
+ >
96
+ <Flex
97
+ component="summary"
98
+ align="center"
99
+ gap="xs"
100
+ p="xs"
101
+ className={classes.summary}
102
+ >
103
+ {!hideChevron ? (
104
+ <Flex
105
+ component="span"
106
+ align="center"
107
+ justify="center"
108
+ className={classes.chevronWrapper}
109
+ aria-hidden
110
+ data-testid="details-chevron"
111
+ >
112
+ <ChevronRight size={16} className={classes.chevronIcon} />
113
+ </Flex>
114
+ ) : null}
115
+ <Box component="span" className={classes.summaryContent}>
116
+ {summary}
117
+ </Box>
118
+ {actions != null ? (
119
+ <Flex
120
+ component="span"
121
+ align="center"
122
+ gap="xs"
123
+ className={classes.actions}
124
+ >
125
+ {actions}
126
+ </Flex>
127
+ ) : null}
128
+ </Flex>
129
+ <Box
130
+ component="div"
131
+ className={classes.contentWrapper}
132
+ style={contentWrapperStyle}
133
+ >
134
+ <Box component="div" p={p} className={classes.content}>
135
+ {children}
136
+ </Box>
137
+ </Box>
138
+ </Box>
139
+ );
140
+ }
@@ -0,0 +1,2 @@
1
+ export { Details } from './Details';
2
+ export type { DetailsProps } from './Details';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * DownloadCard component styles – vanilla-extract with semantic design tokens
3
+ */
4
+
5
+ import { style } from '@vanilla-extract/css';
6
+
7
+ import { mantineVars } from '../../theme/mantineVars';
8
+ import { tokens } from '../../theme/themeContract.css';
9
+
10
+ export const container = style({
11
+ backgroundColor: tokens.color.background.default,
12
+ border: `1px solid ${tokens.color.stroke.default}`,
13
+ borderRadius: tokens.radius.lg,
14
+ padding: `${tokens.spacing.xs} ${tokens.spacing.md}`,
15
+ width: '100%',
16
+ selectors: {
17
+ [`${mantineVars.darkSelector} &`]: {
18
+ backgroundColor: tokens.color.background.default,
19
+ borderColor: tokens.color.stroke.default,
20
+ },
21
+ },
22
+ });
@@ -0,0 +1,63 @@
1
+ import { Download } from 'lucide-react';
2
+
3
+ import { Box, Flex } from '@mantine/core';
4
+
5
+ import { IconButton } from '../IconButton';
6
+ import { Text } from '../Typography';
7
+ import * as classes from './DownloadCard.css';
8
+
9
+ export interface DownloadCardProps {
10
+ /** Platform name (e.g., "Windows", "MacOS") */
11
+ platform: string;
12
+ /** Version information (e.g., "Latest (1.4.2)") */
13
+ version: string;
14
+ /** Callback when download button is clicked */
15
+ onDownload?: () => void;
16
+ }
17
+
18
+ /**
19
+ * DownloadCard component for displaying downloadable installers.
20
+ *
21
+ * Features:
22
+ * - Platform name with medium font weight
23
+ * - Version information with muted color
24
+ * - Download icon button
25
+ * - White background with border
26
+ * - Horizontal layout with space-between
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * <DownloadCard
31
+ * platform="Windows"
32
+ * version="Latest (1.4.2)"
33
+ * onDownload={() => console.log('Download Windows installer')}
34
+ * />
35
+ * ```
36
+ */
37
+ export function DownloadCard({
38
+ platform,
39
+ version,
40
+ onDownload,
41
+ }: DownloadCardProps) {
42
+ return (
43
+ <Box className={classes.container}>
44
+ <Flex justify="space-between" align="center" w="100%">
45
+ <Flex direction="column" gap="3xs">
46
+ <Text variant="body1.strong">{platform}</Text>
47
+ <Text variant="caption1" c="text.subdued.default">
48
+ {version}
49
+ </Text>
50
+ </Flex>
51
+
52
+ <IconButton
53
+ variant="outline"
54
+ size="md"
55
+ onClick={onDownload}
56
+ aria-label={`Download ${platform}`}
57
+ >
58
+ <Download size={16} />
59
+ </IconButton>
60
+ </Flex>
61
+ </Box>
62
+ );
63
+ }
@@ -0,0 +1,2 @@
1
+ export { DownloadCard } from './DownloadCard';
2
+ export type { DownloadCardProps } from './DownloadCard';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Drawer component styles – vanilla-extract
3
+ */
4
+
5
+ import { style } from '@vanilla-extract/css';
6
+
7
+ import { tokens } from '../../theme/themeContract.css';
8
+ import { zIndex } from '../../tokens';
9
+
10
+ export const resizeHandle = style({
11
+ position: 'absolute',
12
+ left: -5,
13
+ top: 0,
14
+ bottom: 0,
15
+ width: 10,
16
+ zIndex: zIndex.resizeHandle,
17
+ background: 'transparent',
18
+ cursor: 'ew-resize',
19
+ transition: 'background 0.2s',
20
+ });
21
+
22
+ export const resizing = style({
23
+ cursor: 'col-resize',
24
+ });
25
+
26
+ export const stickyHeader = style({
27
+ position: 'sticky',
28
+ top: `calc(${tokens.spacing.lg} * -1)`,
29
+ marginTop: `calc(${tokens.spacing.lg} * -1)`,
30
+ zIndex: zIndex.app,
31
+ backgroundColor: tokens.color.background.default,
32
+ });