@recursica/mantine-adapter 0.35.1 → 0.36.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 (57) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/mantine-adapter.cjs +2 -2
  3. package/dist/mantine-adapter.cjs.map +1 -1
  4. package/dist/mantine-adapter.css +1 -1
  5. package/dist/mantine-adapter.js +1104 -1023
  6. package/dist/mantine-adapter.js.map +1 -1
  7. package/dist/src/components/Tree/Tree.d.ts +9 -5
  8. package/package.json +1 -1
  9. package/src/components/Accordion/Accordion.module.css +123 -62
  10. package/src/components/Accordion/Accordion.stories.tsx +65 -33
  11. package/src/components/Accordion/Accordion.tsx +1 -0
  12. package/src/components/AutoComplete/AutoComplete.module.css +50 -49
  13. package/src/components/AutoComplete/AutoComplete.tsx +2 -2
  14. package/src/components/Avatar/Avatar.module.css +7 -7
  15. package/src/components/Badge/Badge.module.css +8 -8
  16. package/src/components/Button/Button.module.css +22 -89
  17. package/src/components/Card/Card.module.css +3 -3
  18. package/src/components/Checkbox/Checkbox.module.css +54 -15
  19. package/src/components/Chip/Chip.module.css +27 -26
  20. package/src/components/DatePicker/DatePicker.module.css +25 -30
  21. package/src/components/Dropdown/Dropdown.module.css +47 -44
  22. package/src/components/Dropdown/Dropdown.tsx +2 -2
  23. package/src/components/FormControlWrapper/FormControlWrapper.module.css +12 -12
  24. package/src/components/HoverCard/HoverCard.module.css +1 -1
  25. package/src/components/Label/Label.module.css +7 -3
  26. package/src/components/Link/IMPLEMENTATION_NOTES.md +2 -9
  27. package/src/components/Link/Link.module.css +15 -76
  28. package/src/components/Link/USAGE.md +2 -9
  29. package/src/components/Loader/Loader.module.css +3 -3
  30. package/src/components/Menu/Menu.module.css +34 -41
  31. package/src/components/Modal/Modal.module.css +27 -11
  32. package/src/components/NumberInput/NumberInput.module.css +39 -37
  33. package/src/components/NumberInput/NumberInput.tsx +2 -2
  34. package/src/components/Pagination/Pagination.module.css +10 -43
  35. package/src/components/Panel/Panel.module.css +3 -3
  36. package/src/components/Popover/Popover.module.css +1 -1
  37. package/src/components/Radio/Radio.module.css +31 -14
  38. package/src/components/ReadOnlyField/ReadOnlyField.module.css +1 -1
  39. package/src/components/SegmentedControl/SegmentedControl.module.css +29 -29
  40. package/src/components/Slider/IMPLEMENTATION_NOTES.md +9 -0
  41. package/src/components/Slider/Slider.module.css +44 -48
  42. package/src/components/Stepper/Stepper.module.css +3 -3
  43. package/src/components/Switch/Switch.module.css +26 -10
  44. package/src/components/Table/Table.module.css +53 -21
  45. package/src/components/Tabs/Tabs.module.css +309 -170
  46. package/src/components/TextArea/TextArea.module.css +36 -21
  47. package/src/components/TextArea/TextArea.tsx +2 -2
  48. package/src/components/TextField/TextField.module.css +38 -35
  49. package/src/components/TextField/TextField.tsx +2 -2
  50. package/src/components/Timeline/Timeline.module.css +41 -34
  51. package/src/components/Toast/Toast.module.css +19 -11
  52. package/src/components/Tooltip/Tooltip.module.css +4 -2
  53. package/src/components/Tree/IMPLEMENTATION_NOTES.md +17 -0
  54. package/src/components/Tree/Tree.module.css +173 -39
  55. package/src/components/Tree/Tree.stories.tsx +81 -4
  56. package/src/components/Tree/Tree.tsx +117 -15
  57. package/src/components/Tree/USAGE.md +36 -3
@@ -1,43 +1,177 @@
1
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_border-radius */
2
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_border-size */
3
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_button-node-gap */
4
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_horizontal-padding */
5
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_indent */
6
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_item-gap */
7
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_max-width */
8
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_font-family */
9
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_font-size */
10
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_font-style */
11
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_font-weight */
12
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_letter-spacing */
13
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_line-height */
14
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_text-decoration */
15
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_selected-text_text-transform */
16
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_font-family */
17
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_font-size */
18
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_font-style */
19
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_font-weight */
20
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_letter-spacing */
21
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_line-height */
22
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_text-decoration */
23
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_unselected-text_text-transform */
24
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_vertical-padding */
25
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_colors_hover-background */
26
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_colors_hover-border-color */
27
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_colors_hover-text */
28
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_colors_selected-background */
29
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_colors_selected-border-color */
30
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_colors_selected-text */
31
- /* recursica-ignore: --recursica_ui-kit_components_tree_properties_colors_unselected-text */
1
+ /* HARDCODED VALUES:
2
+ * - list-style/margin/padding resets on .root/.subtree: layout resets, no corresponding
3
+ * design tokens (structural, not visual design values).
4
+ * - .expandIcon size (1em) and rotation transition: no dedicated icon-size/icon-color token
5
+ * exists for Tree; the glyph is drawn with `currentColor` so it always tracks the row's
6
+ * already-tokened text color, and sized relative to the row's own font-size.
7
+ * - Hover overlay uses the generic --recursica_brand_states_hover_* tokens (same technique as
8
+ * Menu/Accordion/Button): Tree has no component-specific hover tokens of its own.
9
+ */
32
10
 
33
11
  .root {
12
+ margin: 0;
13
+ padding: 0;
14
+ list-style: none;
15
+ max-width: var(--recursica_ui-kit_components_tree_properties_max-width);
16
+ display: flex;
17
+ flex-direction: column;
18
+ gap: var(--recursica_ui-kit_components_tree_properties_item-gap);
19
+
20
+ /* Mantine computes each node's --label-offset (per-level indent) from --level-offset via its
21
+ own internal vars resolver (same category of override as Timeline's --mantine-spacing-xl /
22
+ --tl-line-width). Use !important to reliably beat Mantine's own generated rule. */
23
+ --level-offset: var(
24
+ --recursica_ui-kit_components_tree_properties_indent
25
+ ) !important;
26
+ }
27
+
28
+ .subtree {
29
+ margin: 0;
30
+ padding: 0;
31
+ list-style: none;
32
+ display: flex;
33
+ flex-direction: column;
34
+ gap: var(--recursica_ui-kit_components_tree_properties_item-gap);
35
+ }
36
+
37
+ .node {
38
+ /* Mantine's own base class already resets margin/padding/list-style and sets cursor:pointer
39
+ on this <li>; it also holds the subtree as a second child, so all row-level visual styling
40
+ (box model, colors, typography) lives on .row instead, not here. */
41
+ position: relative;
42
+ }
43
+
44
+ .row {
45
+ position: relative;
34
46
  box-sizing: border-box;
35
- font-family: sans-serif;
36
- padding: 24px;
37
- border: 1px dashed #ccc;
38
- border-radius: 8px;
39
- color: #666;
40
- text-align: center;
41
- font-weight: 500;
42
- background-color: #fafafa;
47
+ display: flex;
48
+ align-items: center;
49
+ cursor: pointer;
50
+ margin-left: var(--label-offset, 0px);
51
+ gap: var(--recursica_ui-kit_components_tree_properties_button-node-gap);
52
+ padding: var(--recursica_ui-kit_components_tree_properties_vertical-padding)
53
+ var(--recursica_ui-kit_components_tree_properties_horizontal-padding);
54
+ border-style: solid; /* HARDCODE: structural border rule; thickness/color are tokened */
55
+ border-width: var(--recursica_ui-kit_components_tree_properties_border-size);
56
+ border-radius: var(
57
+ --recursica_ui-kit_components_tree_properties_border-radius
58
+ );
59
+
60
+ font-family: var(
61
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-family
62
+ );
63
+ font-size: var(
64
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-size
65
+ );
66
+ font-style: var(
67
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-style
68
+ );
69
+ font-weight: var(
70
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-weight
71
+ );
72
+ letter-spacing: var(
73
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_letter-spacing
74
+ );
75
+ line-height: var(
76
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_line-height
77
+ );
78
+ text-decoration: var(
79
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_text-decoration
80
+ );
81
+ text-transform: var(
82
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_text-transform
83
+ );
84
+
85
+ color: var(
86
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_colors_text-color
87
+ );
88
+ background-color: var(
89
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_colors_background-color
90
+ );
91
+ border-color: var(
92
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_colors_border-color
93
+ );
94
+ }
95
+
96
+ /* Hover overlay via ::after pseudo-element (same technique as Menu/Accordion) */
97
+ .row::after {
98
+ content: "";
99
+ position: absolute;
100
+ inset: 0;
101
+ border-radius: inherit;
102
+ z-index: 0;
103
+ pointer-events: none;
104
+ background-color: var(--recursica_brand_states_hover_color);
105
+ opacity: 0;
106
+ transition: opacity 150ms ease;
107
+ }
108
+ .row:hover::after,
109
+ .row[data-hovered]::after {
110
+ opacity: var(--recursica_brand_states_hover_opacity);
111
+ }
112
+
113
+ .row[data-selected] {
114
+ font-family: var(
115
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-family
116
+ );
117
+ font-size: var(
118
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-size
119
+ );
120
+ font-style: var(
121
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-style
122
+ );
123
+ font-weight: var(
124
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-weight
125
+ );
126
+ letter-spacing: var(
127
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_letter-spacing
128
+ );
129
+ line-height: var(
130
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_line-height
131
+ );
132
+ text-decoration: var(
133
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_text-decoration
134
+ );
135
+ text-transform: var(
136
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_text-transform
137
+ );
138
+
139
+ color: var(
140
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_colors_text-color
141
+ );
142
+ background-color: var(
143
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_colors_background-color
144
+ );
145
+ border-color: var(
146
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_colors_border-color
147
+ );
148
+ }
149
+
150
+ .expandIcon {
151
+ position: relative;
152
+ z-index: 1;
153
+ display: flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ flex-shrink: 0;
157
+ width: 1em;
158
+ height: 1em;
159
+ color: inherit;
160
+ }
161
+
162
+ .row[data-has-children] .expandIcon {
163
+ transition: transform 150ms ease;
164
+ }
165
+ .row[data-expanded] .expandIcon {
166
+ transform: rotate(90deg);
167
+ }
168
+
169
+ .label {
170
+ position: relative;
171
+ z-index: 1;
172
+ color: inherit;
173
+ font: inherit;
174
+ letter-spacing: inherit;
175
+ text-decoration: inherit;
176
+ text-transform: inherit;
43
177
  }
@@ -1,14 +1,91 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { Tree } from "./Tree";
3
+ import { Layer, type RecursicaTreeNode } from "@recursica/adapter-common";
4
+
5
+ const sampleData: RecursicaTreeNode[] = [
6
+ {
7
+ value: "documents",
8
+ label: "Documents",
9
+ children: [
10
+ { value: "documents/resume.pdf", label: "resume.pdf" },
11
+ { value: "documents/cover-letter.docx", label: "cover-letter.docx" },
12
+ {
13
+ value: "documents/taxes",
14
+ label: "Taxes",
15
+ children: [
16
+ { value: "documents/taxes/2023.pdf", label: "2023.pdf" },
17
+ { value: "documents/taxes/2024.pdf", label: "2024.pdf" },
18
+ ],
19
+ },
20
+ ],
21
+ },
22
+ {
23
+ value: "photos",
24
+ label: "Photos",
25
+ children: [
26
+ { value: "photos/vacation.jpg", label: "vacation.jpg" },
27
+ { value: "photos/family.jpg", label: "family.jpg" },
28
+ ],
29
+ },
30
+ { value: "readme.md", label: "readme.md" },
31
+ ];
3
32
 
4
33
  const meta: Meta<typeof Tree> = {
5
- title: "Components/Tree",
34
+ title: "UI-Kit/Tree",
6
35
  component: Tree,
36
+ tags: ["autodocs"],
37
+ parameters: {
38
+ docs: {
39
+ description: {
40
+ component: `
41
+ The \`Tree\` component renders hierarchical \`data\` as an expandable/selectable tree, wrapping \`@mantine/core\`'s \`Tree\` with a fully custom node renderer so every visual property (row box model, selected/unselected colors and typography, indent, item spacing) comes from Recursica's \`tree\` design tokens.
42
+
43
+ Each node needs a unique \`value\` and a \`label\`; a \`children\` array (even empty) makes a node expandable.
44
+ `,
45
+ },
46
+ },
47
+ },
7
48
  };
8
49
 
9
50
  export default meta;
10
- type Story = StoryObj<typeof Tree>;
11
51
 
12
- export const ComingSoon: Story = {
13
- args: {},
52
+ export const Default: StoryObj<typeof Tree> = {
53
+ render: () => (
54
+ <Tree data={sampleData} initialExpandedValues={["documents"]} />
55
+ ),
56
+ };
57
+
58
+ export const AllExpanded: StoryObj<typeof Tree> = {
59
+ render: () => <Tree data={sampleData} initialExpandedValues="*" />,
60
+ };
61
+
62
+ export const PreSelected: StoryObj<typeof Tree> = {
63
+ render: () => (
64
+ <Tree
65
+ data={sampleData}
66
+ initialExpandedValues={["documents"]}
67
+ initialSelectedValues={["documents/resume.pdf"]}
68
+ />
69
+ ),
70
+ };
71
+
72
+ export const MultipleSelection: StoryObj<typeof Tree> = {
73
+ render: () => (
74
+ <Tree
75
+ data={sampleData}
76
+ initialExpandedValues="*"
77
+ initialSelectedValues={["documents/resume.pdf", "photos/vacation.jpg"]}
78
+ multiple
79
+ />
80
+ ),
81
+ };
82
+
83
+ /** Demonstrates the component nested inside a non-default layer — the one case where an
84
+ * explicit `<Layer>` wrap belongs in a story (see COMPONENT_STORYBOOK_GUIDE.md §9). */
85
+ export const LayerOne: StoryObj<typeof Tree> = {
86
+ render: () => (
87
+ <Layer layer={1} style={{ padding: "24px" }}>
88
+ <Tree data={sampleData} initialExpandedValues={["documents"]} />
89
+ </Layer>
90
+ ),
14
91
  };
@@ -1,24 +1,126 @@
1
- import React, { forwardRef } from "react";
2
- import { type RecursicaOverStyled } from "../../utils/filterStylingProps";
1
+ import React, { forwardRef, useEffect } from "react";
2
+ import {
3
+ Tree as MantineTree,
4
+ useTree,
5
+ getTreeExpandedState,
6
+ type RenderTreeNodePayload,
7
+ } from "@mantine/core";
8
+ import {
9
+ filterStylingProps,
10
+ type RecursicaOverStyled,
11
+ } from "../../utils/filterStylingProps";
12
+ import { type RecursicaTreeProps } from "@recursica/adapter-common";
3
13
  import styles from "./Tree.module.css";
4
14
 
5
- export interface TreeProps extends React.ComponentPropsWithoutRef<"div"> {
6
- overStyled?: boolean;
15
+ export type TreeProps = RecursicaOverStyled<
16
+ RecursicaTreeProps & Omit<React.ComponentPropsWithoutRef<"ul">, "children">
17
+ >;
18
+
19
+ /** Simple chevron glyph; rotates via `[data-expanded]` in CSS. Uses `currentColor` so it
20
+ * always matches the row's tokened text color — Tree has no dedicated icon-color token. */
21
+ function ExpandGlyph() {
22
+ return (
23
+ <svg
24
+ viewBox="0 0 16 16"
25
+ width="1em"
26
+ height="1em"
27
+ fill="none"
28
+ stroke="currentColor"
29
+ strokeWidth="2"
30
+ strokeLinecap="round"
31
+ strokeLinejoin="round"
32
+ aria-hidden="true"
33
+ >
34
+ <path d="M5 3l5 5-5 5" />
35
+ </svg>
36
+ );
37
+ }
38
+
39
+ function renderTreeNode({
40
+ node,
41
+ hasChildren,
42
+ expanded,
43
+ elementProps,
44
+ }: RenderTreeNodePayload) {
45
+ return (
46
+ <div
47
+ {...elementProps}
48
+ className={styles.row}
49
+ data-has-children={hasChildren || undefined}
50
+ data-expanded={hasChildren && expanded ? true : undefined}
51
+ >
52
+ <span className={styles.expandIcon} aria-hidden="true">
53
+ {hasChildren && <ExpandGlyph />}
54
+ </span>
55
+ <span className={styles.label}>{node.label}</span>
56
+ </div>
57
+ );
7
58
  }
8
59
 
9
60
  /**
10
- * Placeholder component for Tree (Coming Soon).
61
+ * Recursively renders hierarchical `data` as an expandable/selectable tree.
62
+ *
63
+ * **Recursica Abstract:**
64
+ * Wraps Mantine's `Tree` with a fully custom node renderer so every visual aspect (row box
65
+ * model, selected/unselected colors and typography, indent, item spacing) comes from
66
+ * Recursica's `tree` design tokens rather than Mantine's defaults.
11
67
  */
12
- export const Tree = forwardRef<HTMLDivElement, RecursicaOverStyled<TreeProps>>(
13
- function Tree({ overStyled: _overStyled = false, className, ...rest }, ref) {
14
- void _overStyled;
15
- const finalClass = className ? `${styles.root} ${className}` : styles.root;
16
- return (
17
- <div ref={ref} className={finalClass} {...rest}>
18
- Tree (Coming Soon)
19
- </div>
20
- );
68
+ export const Tree = forwardRef<HTMLUListElement, TreeProps>(function Tree(
69
+ {
70
+ overStyled = false,
71
+ data,
72
+ initialExpandedValues,
73
+ initialSelectedValues,
74
+ multiple = false,
75
+ expandOnClick = true,
76
+ selectOnClick = true,
77
+ onNodeExpand,
78
+ onNodeCollapse,
79
+ onSelectedChange,
80
+ ...rest
21
81
  },
22
- );
82
+ ref,
83
+ ) {
84
+ const sanitizedProps = filterStylingProps(rest, overStyled);
85
+
86
+ const tree = useTree({
87
+ initialExpandedState: initialExpandedValues
88
+ ? getTreeExpandedState(data, initialExpandedValues)
89
+ : undefined,
90
+ initialSelectedState: initialSelectedValues,
91
+ multiple,
92
+ onNodeExpand,
93
+ onNodeCollapse,
94
+ });
95
+
96
+ // Mantine's `useTree` tracks selection internally but has no `onSelectedChange` callback of
97
+ // its own; surface one at the Recursica layer by watching the controller's selectedState.
98
+ useEffect(() => {
99
+ onSelectedChange?.(tree.selectedState);
100
+ }, [tree.selectedState, onSelectedChange]);
101
+
102
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
103
+ .className as string | undefined;
104
+ const rootClass = classNameProp
105
+ ? `${styles.root} ${classNameProp}`
106
+ : styles.root;
107
+
108
+ return (
109
+ <MantineTree
110
+ ref={ref}
111
+ data={data}
112
+ tree={tree}
113
+ expandOnClick={expandOnClick}
114
+ selectOnClick={selectOnClick}
115
+ renderNode={renderTreeNode}
116
+ classNames={{
117
+ root: rootClass,
118
+ node: styles.node,
119
+ subtree: styles.subtree,
120
+ }}
121
+ {...(sanitizedProps as unknown as Record<string, unknown>)}
122
+ />
123
+ );
124
+ });
23
125
 
24
126
  Tree.displayName = "Tree";
@@ -25,22 +25,55 @@ export default function Demo() {
25
25
  {
26
26
  value: "1",
27
27
  label: "Root",
28
- children: [{ value: "2", label: "Child" }],
28
+ children: [
29
+ { value: "1.1", label: "Child A" },
30
+ { value: "1.2", label: "Child B" },
31
+ ],
29
32
  },
33
+ { value: "2", label: "Sibling" },
30
34
  ]}
31
35
  />
32
36
  );
33
37
  }
34
38
  ```
35
39
 
40
+ Each node needs a unique `value` and a `label`. Any node with a `children` array (even an empty one) renders an expand/collapse chevron.
41
+
42
+ ---
43
+
44
+ ## 3. Controlled Selection / Expansion
45
+
46
+ ```tsx
47
+ <Tree
48
+ data={data}
49
+ initialExpandedValues={["1"]}
50
+ initialSelectedValues={["1.1"]}
51
+ multiple
52
+ onSelectedChange={(values) => console.log("selected:", values)}
53
+ onNodeExpand={(value) => console.log("expanded:", value)}
54
+ onNodeCollapse={(value) => console.log("collapsed:", value)}
55
+ />
56
+ ```
57
+
58
+ - `initialExpandedValues` accepts an array of node values, or `"*"` to start with every node expanded.
59
+ - `multiple` allows more than one node to be selected at once (default: single-select).
60
+ - `expandOnClick` / `selectOnClick` (both default `true`) control whether clicking a row toggles its expansion and/or selection.
61
+
36
62
  ---
37
63
 
38
- ## 3. Design System Integration
64
+ ## 4. Design System Integration
39
65
 
40
66
  All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
41
67
 
42
68
  > [!IMPORTANT]
43
69
  >
44
- > - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
70
+ > - **Anti-override protection**: Rogue style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
45
71
  > - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
46
72
  > - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
73
+
74
+ ---
75
+
76
+ ## 5. Known Constraints
77
+
78
+ - No checkbox/multi-check styling is exposed — the underlying Mantine `Tree` supports a `checked` node state, but Recursica's `tree` design tokens don't yet define a checked visual state, so it isn't part of the Recursica API.
79
+ - No per-node `disabled` state — the Figma UI Kit tokens don't define one, and Mantine's `Tree` data shape has no built-in `disabled` field either.