@mindlogic-ai/logician-ui 3.2.0-alpha.4 → 4.0.0-alpha.10
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.
- package/dist/components/InlineCode/InlineCode.d.ts.map +1 -1
- package/dist/components/InlineCode/InlineCode.js +8 -1
- package/dist/components/InlineCode/InlineCode.js.map +1 -1
- package/dist/components/InlineCode/InlineCode.mjs +8 -1
- package/dist/components/InlineCode/InlineCode.mjs.map +1 -1
- package/dist/components/Loaders/PageLoader.d.ts.map +1 -1
- package/dist/components/Loaders/PageLoader.js +2 -2
- package/dist/components/Loaders/PageLoader.js.map +1 -1
- package/dist/components/Loaders/PageLoader.mjs +2 -2
- package/dist/components/Loaders/PageLoader.mjs.map +1 -1
- package/dist/components/Loaders/SectionLoader.d.ts.map +1 -1
- package/dist/components/Loaders/SectionLoader.js +2 -2
- package/dist/components/Loaders/SectionLoader.js.map +1 -1
- package/dist/components/Loaders/SectionLoader.mjs +2 -2
- package/dist/components/Loaders/SectionLoader.mjs.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.js +23 -15
- package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.mjs +23 -15
- package/dist/components/SegmentedControl/SegmentedControl.mjs.map +1 -1
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.d.ts.map +1 -1
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.js +6 -1
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.js.map +1 -1
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.mjs +6 -1
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.mjs.map +1 -1
- package/dist/components/Slider/SliderTrack/SliderTrack.d.ts.map +1 -1
- package/dist/components/Slider/SliderTrack/SliderTrack.js +13 -1
- package/dist/components/Slider/SliderTrack/SliderTrack.js.map +1 -1
- package/dist/components/Slider/SliderTrack/SliderTrack.mjs +13 -1
- package/dist/components/Slider/SliderTrack/SliderTrack.mjs.map +1 -1
- package/dist/components/Spinner/Spinner.d.ts.map +1 -1
- package/dist/components/Spinner/Spinner.js +7 -1
- package/dist/components/Spinner/Spinner.js.map +1 -1
- package/dist/components/Spinner/Spinner.mjs +7 -1
- package/dist/components/Spinner/Spinner.mjs.map +1 -1
- package/dist/components/Switch/SwitchControl.d.ts.map +1 -1
- package/dist/components/Switch/SwitchControl.js +7 -1
- package/dist/components/Switch/SwitchControl.js.map +1 -1
- package/dist/components/Switch/SwitchControl.mjs +7 -1
- package/dist/components/Switch/SwitchControl.mjs.map +1 -1
- package/dist/components/Tag/Tag.d.ts.map +1 -1
- package/dist/components/Tag/Tag.js +1 -1
- package/dist/components/Tag/Tag.js.map +1 -1
- package/dist/components/Tag/Tag.mjs +1 -1
- package/dist/components/Tag/Tag.mjs.map +1 -1
- package/dist/components/Tag/Tag.styles.d.ts.map +1 -1
- package/dist/components/Tag/Tag.styles.js +22 -16
- package/dist/components/Tag/Tag.styles.js.map +1 -1
- package/dist/components/Tag/Tag.styles.mjs +22 -16
- package/dist/components/Tag/Tag.styles.mjs.map +1 -1
- package/dist/components/Tree/Tree.d.ts +5 -1
- package/dist/components/Tree/Tree.d.ts.map +1 -1
- package/dist/components/Tree/Tree.types.d.ts +29 -1
- package/dist/components/Tree/Tree.types.d.ts.map +1 -1
- package/dist/components/Tree/TreeBranchIndentGuide.d.ts +5 -1
- package/dist/components/Tree/TreeBranchIndentGuide.d.ts.map +1 -1
- package/dist/components/Tree/TreeBranchIndentGuide.js +107 -8
- package/dist/components/Tree/TreeBranchIndentGuide.js.map +1 -1
- package/dist/components/Tree/TreeBranchIndentGuide.mjs +107 -8
- package/dist/components/Tree/TreeBranchIndentGuide.mjs.map +1 -1
- package/dist/components/Typography/Link.d.ts.map +1 -1
- package/dist/components/Typography/Link.js +6 -1
- package/dist/components/Typography/Link.js.map +1 -1
- package/dist/components/Typography/Link.mjs +6 -1
- package/dist/components/Typography/Link.mjs.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +1 -1
- package/dist/theme/colors.d.ts +7 -1
- package/dist/theme/colors.d.ts.map +1 -1
- package/dist/theme/colors.js +12 -0
- package/dist/theme/colors.js.map +1 -1
- package/dist/theme/colors.mjs +12 -0
- package/dist/theme/colors.mjs.map +1 -1
- package/dist/theme/global.d.ts.map +1 -1
- package/dist/theme/global.js +4 -1
- package/dist/theme/global.js.map +1 -1
- package/dist/theme/global.mjs +4 -1
- package/dist/theme/global.mjs.map +1 -1
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +8 -4
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +8 -4
- package/dist/theme/index.mjs.map +1 -1
- package/package.json +1 -3
- package/src/components/InlineCode/InlineCode.tsx +7 -0
- package/src/components/Loaders/PageLoader.tsx +3 -5
- package/src/components/Loaders/SectionLoader.tsx +3 -2
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +27 -1
- package/src/components/SegmentedControl/SegmentedControl.tsx +22 -15
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.tsx +5 -1
- package/src/components/Slider/SliderTrack/SliderTrack.tsx +10 -1
- package/src/components/Spinner/Spinner.tsx +6 -1
- package/src/components/Switch/SwitchControl.tsx +6 -1
- package/src/components/Tag/Tag.styles.ts +22 -16
- package/src/components/Tag/Tag.tsx +1 -0
- package/src/components/Tree/Tree.GuideElbow.stories.tsx +220 -0
- package/src/components/Tree/Tree.types.ts +29 -1
- package/src/components/Tree/TreeBranchIndentGuide.test.tsx +213 -0
- package/src/components/Tree/TreeBranchIndentGuide.tsx +137 -11
- package/src/components/Typography/Link.tsx +5 -1
- package/src/index.ts +0 -1
- package/src/theme/Surfaces.stories.tsx +208 -0
- package/src/theme/colors.ts +13 -0
- package/src/theme/global.ts +4 -1
- package/src/theme/index.ts +8 -4
- package/dist/components/MDXEditor/MDXEditor.d.ts +0 -6
- package/dist/components/MDXEditor/MDXEditor.d.ts.map +0 -1
- package/dist/components/MDXEditor/MDXEditor.js +0 -237
- package/dist/components/MDXEditor/MDXEditor.js.map +0 -1
- package/dist/components/MDXEditor/MDXEditor.mjs +0 -235
- package/dist/components/MDXEditor/MDXEditor.mjs.map +0 -1
- package/dist/components/MDXEditor/MDXEditor.types.d.ts +0 -7
- package/dist/components/MDXEditor/MDXEditor.types.d.ts.map +0 -1
- package/dist/components/MDXEditor/index.d.ts +0 -3
- package/dist/components/MDXEditor/index.d.ts.map +0 -1
- package/src/components/MDXEditor/MDXEditor.css +0 -40
- package/src/components/MDXEditor/MDXEditor.stories.tsx +0 -56
- package/src/components/MDXEditor/MDXEditor.tsx +0 -337
- package/src/components/MDXEditor/MDXEditor.types.ts +0 -7
- package/src/components/MDXEditor/index.ts +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HStack, Icon, Text } from '@chakra-ui/react';
|
|
1
|
+
import { HStack, Icon, Stack, Text, VStack } from '@chakra-ui/react';
|
|
2
2
|
import { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import React, { useState } from 'react';
|
|
4
4
|
import { FiHome, FiSettings, FiUser } from 'react-icons/fi';
|
|
@@ -143,6 +143,32 @@ export const EditableLabel: StoryObj<
|
|
|
143
143
|
),
|
|
144
144
|
};
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* The same control rendered on each of the three main page-background tokens.
|
|
148
|
+
* The track fill (`bg.subtle`) matches `bg.sunken` in light mode, so without a
|
|
149
|
+
* defining ring the control would disappear on a sunken list/overview page.
|
|
150
|
+
* Confirm the control reads as a bounded control on all three surfaces, in both
|
|
151
|
+
* light and dark (flip the **Color mode** toolbar control).
|
|
152
|
+
*/
|
|
153
|
+
export const OnPageBackgrounds: Story = {
|
|
154
|
+
parameters: { layout: 'fullscreen' },
|
|
155
|
+
render: (props) => {
|
|
156
|
+
const surfaces = ['bg.surface', 'bg.sunken', 'bg.canvas'] as const;
|
|
157
|
+
return (
|
|
158
|
+
<Stack gap={0}>
|
|
159
|
+
{surfaces.map((surface) => (
|
|
160
|
+
<VStack key={surface} bg={surface} p={8} align="start" gap={3}>
|
|
161
|
+
<Text fontSize="sm" fontWeight="600" color="fg.muted">
|
|
162
|
+
on {surface}
|
|
163
|
+
</Text>
|
|
164
|
+
<SegmentedControl {...props} />
|
|
165
|
+
</VStack>
|
|
166
|
+
))}
|
|
167
|
+
</Stack>
|
|
168
|
+
);
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
146
172
|
export const WithCustomContent = {
|
|
147
173
|
args: {
|
|
148
174
|
options: [
|
|
@@ -66,31 +66,38 @@ export const SegmentedControl = forwardRef<
|
|
|
66
66
|
}
|
|
67
67
|
}}
|
|
68
68
|
size={size}
|
|
69
|
-
//
|
|
70
|
-
// bg.
|
|
69
|
+
// Track is bg.subtle (gray.50 light) and the selected indicator rides on
|
|
70
|
+
// `bg.raised` — a raised neutral surface that resolves white in light and
|
|
71
|
+
// the lightest neutral (gray.1100) in dark, so the thumb reads as lifted
|
|
72
|
+
// above the track in both modes (`bg.surface` could not: its dark value is
|
|
73
|
+
// darker than the track). The indicator also gains a shadow: an md drop
|
|
74
|
+
// shadow in light, and in dark — where a drop shadow is invisible on a
|
|
75
|
+
// dark canvas — a soft ambient shadow + a translucent-white hairline edge.
|
|
71
76
|
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
// box
|
|
77
|
+
// The track itself only contrasts where the page wash is darker (light) or
|
|
78
|
+
// lighter (dark) than the fill. It vanishes when the page matches the
|
|
79
|
+
// track: a `bg.sunken` list/overview page is gray.50 in light — identical
|
|
80
|
+
// to the bg.subtle track — and a `bg.surface` card is lighter than the
|
|
81
|
+
// track in dark. In either case the control would read as floating text,
|
|
82
|
+
// so a hairline ring defines its bounds on *any* background: a neutral
|
|
83
|
+
// `border.default` ring in light, a translucent-white ring in dark. (The
|
|
84
|
+
// ring — not the track fill — does the work here: the selected thumb is a
|
|
85
|
+
// raised white surface lifted by its shadow, a relationship that depends
|
|
86
|
+
// on the track staying light, so we outline the group rather than darken
|
|
87
|
+
// it. `border.default` keeps the edge present but light — `border.strong`
|
|
88
|
+
// reads as a heavy box for a control that normally has no outline.) Both
|
|
89
|
+
// rings are box-shadows (not borders) so the matched item-height math is
|
|
90
|
+
// preserved.
|
|
84
91
|
bg="bg.subtle"
|
|
85
92
|
p="1"
|
|
86
93
|
borderRadius={borderRadius}
|
|
87
|
-
boxShadow="none"
|
|
88
94
|
w="fit-content"
|
|
89
95
|
{...rest}
|
|
90
96
|
css={mergeCss(
|
|
91
97
|
{
|
|
92
98
|
'--segment-indicator-bg': `var(--chakra-colors-bg-raised)`,
|
|
93
99
|
'--segment-indicator-shadow': `var(--chakra-shadows-md)`,
|
|
100
|
+
boxShadow: '0 0 0 1px var(--chakra-colors-border-default)',
|
|
94
101
|
'.dark &': {
|
|
95
102
|
'--segment-indicator-shadow':
|
|
96
103
|
'0 1px 2px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.08)',
|
|
@@ -13,7 +13,11 @@ export const SegmentedProgressBar = ({
|
|
|
13
13
|
position="relative"
|
|
14
14
|
flex={1}
|
|
15
15
|
display="flex"
|
|
16
|
-
|
|
16
|
+
// The remainder behind the segments is a meter surface, so it needs a
|
|
17
|
+
// visible fill. bg.muted (gray.100) is ~1.03:1 against the bg.sunken page
|
|
18
|
+
// wash (gray.50) and vanishes there; bg.track (gray.300) reads as a
|
|
19
|
+
// filled track on any background. Filled segments paint over it.
|
|
20
|
+
bgColor="bg.track"
|
|
17
21
|
borderRadius="full"
|
|
18
22
|
w="100%"
|
|
19
23
|
h="16px"
|
|
@@ -9,7 +9,16 @@ export const SliderTrack = forwardRef(
|
|
|
9
9
|
ref?: ForwardedRef<HTMLDivElement>
|
|
10
10
|
) => {
|
|
11
11
|
return (
|
|
12
|
-
<Slider.Track
|
|
12
|
+
<Slider.Track
|
|
13
|
+
// The empty rail is a meter surface — too thin for an outline to read as
|
|
14
|
+
// anything but a hollow edge — so the fill itself must contrast. bg.muted
|
|
15
|
+
// (gray.100) is ~1.03:1 against the bg.sunken page wash (gray.50) and
|
|
16
|
+
// disappears there; bg.track (gray.300) reads as a filled rail on any
|
|
17
|
+
// background. The filled portion stays primary (SliderFilledTrack).
|
|
18
|
+
bg="bg.track"
|
|
19
|
+
{...rest}
|
|
20
|
+
ref={ref}
|
|
21
|
+
>
|
|
13
22
|
{children}
|
|
14
23
|
</Slider.Track>
|
|
15
24
|
);
|
|
@@ -13,7 +13,12 @@ export const Spinner = forwardRef(
|
|
|
13
13
|
animationDuration="0.65s"
|
|
14
14
|
ref={ref}
|
|
15
15
|
{...rest}
|
|
16
|
-
|
|
16
|
+
// The track ring is the only non-animated affordance and can't take a
|
|
17
|
+
// box outline (SVG-style track), so its color carries the contrast.
|
|
18
|
+
// bg.muted (gray.100) is ~1.03:1 against the bg.sunken page wash
|
|
19
|
+
// (gray.50) and vanishes there; bg.track (gray.300) reads on any
|
|
20
|
+
// background and stays mode-aware.
|
|
21
|
+
css={mergeCss({ '--spinner-track-color': 'colors.bg.track' }, css)}
|
|
17
22
|
/>
|
|
18
23
|
);
|
|
19
24
|
}
|
|
@@ -7,7 +7,12 @@ export const SwitchControl = forwardRef<HTMLSpanElement, SwitchControlProps>(
|
|
|
7
7
|
(props, ref) => (
|
|
8
8
|
<ChakraSwitch.Control
|
|
9
9
|
ref={ref}
|
|
10
|
-
|
|
10
|
+
// The off-state track is a meter surface — its extent is the information —
|
|
11
|
+
// so it needs a visible fill, not just an edge. bg.muted (gray.100) is
|
|
12
|
+
// only ~1.03:1 against the bg.sunken page wash (gray.50) and vanishes
|
|
13
|
+
// there; bg.track (gray.300) reads as a filled track on any background.
|
|
14
|
+
// The checked state is the self-defining primary.main fill.
|
|
15
|
+
bg="bg.track"
|
|
11
16
|
_checked={{ bg: 'primary.main' }}
|
|
12
17
|
{...focusRing}
|
|
13
18
|
{...props}
|
|
@@ -17,7 +17,7 @@ export const tagColorPaletteStyles: Record<
|
|
|
17
17
|
soft: {
|
|
18
18
|
bgColor: 'primary.extralight',
|
|
19
19
|
borderColor: 'primary.light',
|
|
20
|
-
color: 'primary.
|
|
20
|
+
color: 'primary.darker',
|
|
21
21
|
},
|
|
22
22
|
solid: {
|
|
23
23
|
bgColor: 'blue.500',
|
|
@@ -27,14 +27,14 @@ export const tagColorPaletteStyles: Record<
|
|
|
27
27
|
outline: {
|
|
28
28
|
bgColor: 'transparent',
|
|
29
29
|
borderColor: 'primary.main',
|
|
30
|
-
color: 'primary.
|
|
30
|
+
color: 'primary.dark',
|
|
31
31
|
},
|
|
32
32
|
},
|
|
33
33
|
secondary: {
|
|
34
34
|
soft: {
|
|
35
35
|
bgColor: 'secondary.extralight',
|
|
36
36
|
borderColor: 'secondary.light',
|
|
37
|
-
color: 'secondary.
|
|
37
|
+
color: 'secondary.darker',
|
|
38
38
|
},
|
|
39
39
|
solid: {
|
|
40
40
|
bgColor: 'violet.500',
|
|
@@ -44,14 +44,14 @@ export const tagColorPaletteStyles: Record<
|
|
|
44
44
|
outline: {
|
|
45
45
|
bgColor: 'transparent',
|
|
46
46
|
borderColor: 'secondary.main',
|
|
47
|
-
color: 'secondary.
|
|
47
|
+
color: 'secondary.dark',
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
50
|
danger: {
|
|
51
51
|
soft: {
|
|
52
52
|
bgColor: 'danger.extralight',
|
|
53
53
|
borderColor: 'danger.light',
|
|
54
|
-
color: 'danger.
|
|
54
|
+
color: 'danger.darker',
|
|
55
55
|
},
|
|
56
56
|
solid: {
|
|
57
57
|
bgColor: 'rose.500',
|
|
@@ -61,14 +61,14 @@ export const tagColorPaletteStyles: Record<
|
|
|
61
61
|
outline: {
|
|
62
62
|
bgColor: 'transparent',
|
|
63
63
|
borderColor: 'danger.main',
|
|
64
|
-
color: 'danger.
|
|
64
|
+
color: 'danger.dark',
|
|
65
65
|
},
|
|
66
66
|
},
|
|
67
67
|
success: {
|
|
68
68
|
soft: {
|
|
69
69
|
bgColor: 'success.extralight',
|
|
70
70
|
borderColor: 'success.light',
|
|
71
|
-
color: 'success.
|
|
71
|
+
color: 'success.darker',
|
|
72
72
|
},
|
|
73
73
|
solid: {
|
|
74
74
|
bgColor: 'green.600',
|
|
@@ -78,34 +78,40 @@ export const tagColorPaletteStyles: Record<
|
|
|
78
78
|
outline: {
|
|
79
79
|
bgColor: 'transparent',
|
|
80
80
|
borderColor: 'success.main',
|
|
81
|
-
color: 'success.
|
|
81
|
+
color: 'success.dark',
|
|
82
82
|
},
|
|
83
83
|
},
|
|
84
84
|
warning: {
|
|
85
85
|
soft: {
|
|
86
86
|
bgColor: 'warning.extralight',
|
|
87
87
|
borderColor: 'warning.light',
|
|
88
|
-
color: 'warning.
|
|
88
|
+
color: 'warning.darker',
|
|
89
89
|
},
|
|
90
90
|
solid: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
// Deepened from gold.500 so white text clears AA and the chip matches the
|
|
92
|
+
// other solids (white on a saturated fill). White/gold.500 was only
|
|
93
|
+
// 2.39:1; white/gold.700 = 5.86:1 ✓ AA. Bright gold + near-black text read
|
|
94
|
+
// harsh on the dark canvas.
|
|
95
|
+
bgColor: 'gold.700',
|
|
96
|
+
borderColor: 'gold.700',
|
|
97
|
+
color: 'white',
|
|
94
98
|
},
|
|
95
99
|
outline: {
|
|
96
100
|
bgColor: 'transparent',
|
|
97
101
|
borderColor: 'warning.main',
|
|
98
|
-
|
|
102
|
+
// warning.dark (gold.700, 5.8:1 AA) over warning.main (gold.500, 3.0:1) —
|
|
103
|
+
// darker text also lifts this off the palette's AA-risk step.
|
|
104
|
+
color: 'warning.dark',
|
|
99
105
|
},
|
|
100
106
|
},
|
|
101
107
|
neutral: {
|
|
102
108
|
soft: {
|
|
103
|
-
// Flip surface + border with the mode so the fg.
|
|
109
|
+
// Flip surface + border with the mode so the fg.default text stays legible
|
|
104
110
|
// in dark. Light values preserved (bg.muted → gray.100, border.default →
|
|
105
111
|
// gray.300).
|
|
106
112
|
bgColor: 'bg.muted',
|
|
107
113
|
borderColor: 'border.default',
|
|
108
|
-
color: 'fg.
|
|
114
|
+
color: 'fg.default',
|
|
109
115
|
},
|
|
110
116
|
solid: {
|
|
111
117
|
bgColor: 'gray.800',
|
|
@@ -115,7 +121,7 @@ export const tagColorPaletteStyles: Record<
|
|
|
115
121
|
outline: {
|
|
116
122
|
bgColor: 'transparent',
|
|
117
123
|
borderColor: 'border.strong', // gray.500 / gray.900 (_dark)
|
|
118
|
-
color: 'fg.
|
|
124
|
+
color: 'fg.muted',
|
|
119
125
|
},
|
|
120
126
|
},
|
|
121
127
|
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { Box, HStack, Stack, Text } from '@chakra-ui/react';
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
import { Tree } from './Tree';
|
|
5
|
+
import { createTreeCollection } from './index';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Stories for the `elbow` option on `Tree.BranchIndentGuide`.
|
|
9
|
+
*
|
|
10
|
+
* `elbow` turns the plain vertical rails into `├` / `└` guide lines:
|
|
11
|
+
* every row gets a horizontal foot joining it to its parent rail, and
|
|
12
|
+
* the last row of each group stops at its centre (`└`). `guideColor`
|
|
13
|
+
* customizes the line color (default `border.default`, which flips
|
|
14
|
+
* with color mode). Pass both through the `indentGuide` element:
|
|
15
|
+
*
|
|
16
|
+
* <Tree.Node indentGuide={<Tree.BranchIndentGuide elbow />} ... />
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
interface Node {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
children?: Node[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const orgSample: Node = {
|
|
26
|
+
id: 'ROOT',
|
|
27
|
+
name: '',
|
|
28
|
+
children: [
|
|
29
|
+
{
|
|
30
|
+
id: 'hq',
|
|
31
|
+
name: '본사',
|
|
32
|
+
children: [
|
|
33
|
+
{
|
|
34
|
+
id: 'hq-dev',
|
|
35
|
+
name: '개발본부',
|
|
36
|
+
children: [
|
|
37
|
+
{
|
|
38
|
+
id: 'hq-dev-backend',
|
|
39
|
+
name: '백엔드그룹',
|
|
40
|
+
children: [
|
|
41
|
+
{ id: 'hq-dev-backend-api', name: 'API팀' },
|
|
42
|
+
{ id: 'hq-dev-backend-db', name: 'DB팀' },
|
|
43
|
+
{ id: 'hq-dev-backend-platform', name: '플랫폼팀' },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'hq-dev-frontend',
|
|
48
|
+
name: '프론트엔드그룹',
|
|
49
|
+
children: [
|
|
50
|
+
{ id: 'hq-dev-frontend-web', name: '웹팀' },
|
|
51
|
+
{ id: 'hq-dev-frontend-mobile', name: '모바일팀' },
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'hq-sales',
|
|
58
|
+
name: '영업본부',
|
|
59
|
+
children: [
|
|
60
|
+
{ id: 'hq-sales-domestic', name: '국내영업팀' },
|
|
61
|
+
{ id: 'hq-sales-global', name: '해외영업팀' },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'rnd',
|
|
68
|
+
name: 'R&D센터',
|
|
69
|
+
children: [
|
|
70
|
+
{ id: 'rnd-ml', name: '머신러닝팀' },
|
|
71
|
+
{ id: 'rnd-data', name: '데이터팀' },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const orgCollection = createTreeCollection<Node>({
|
|
78
|
+
rootNode: orgSample,
|
|
79
|
+
nodeToValue: (node) => node.id,
|
|
80
|
+
nodeToString: (node) => node.name,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const allBranchIds = (function collect(n: Node): string[] {
|
|
84
|
+
if (!n.children) return [];
|
|
85
|
+
return n.children.flatMap((c) => (c.children ? [c.id, ...collect(c)] : []));
|
|
86
|
+
})(orgSample);
|
|
87
|
+
|
|
88
|
+
const renderNode = ({
|
|
89
|
+
node,
|
|
90
|
+
nodeState,
|
|
91
|
+
}: {
|
|
92
|
+
node: Node;
|
|
93
|
+
nodeState: { isBranch: boolean };
|
|
94
|
+
}) =>
|
|
95
|
+
nodeState.isBranch ? (
|
|
96
|
+
<Tree.BranchControl>
|
|
97
|
+
<Tree.BranchIndicator />
|
|
98
|
+
<Tree.BranchText>{node.name}</Tree.BranchText>
|
|
99
|
+
</Tree.BranchControl>
|
|
100
|
+
) : (
|
|
101
|
+
<Tree.Item>
|
|
102
|
+
<Tree.ItemText>{node.name}</Tree.ItemText>
|
|
103
|
+
</Tree.Item>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const meta = {
|
|
107
|
+
title: 'Components/Tree',
|
|
108
|
+
component: Tree.Root,
|
|
109
|
+
parameters: { layout: 'padded' },
|
|
110
|
+
} satisfies Meta<typeof Tree.Root>;
|
|
111
|
+
|
|
112
|
+
export default meta;
|
|
113
|
+
|
|
114
|
+
type Story = StoryObj<typeof meta>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* `elbow` guides — the innermost rail grows a horizontal foot so each
|
|
118
|
+
* row connects to its parent column like a classic file-tree.
|
|
119
|
+
*/
|
|
120
|
+
export const WithElbowGuides: Story = {
|
|
121
|
+
args: {
|
|
122
|
+
collection: orgCollection,
|
|
123
|
+
'aria-label': '조직',
|
|
124
|
+
defaultExpandedValue: allBranchIds,
|
|
125
|
+
defaultSelectedValue: ['hq-dev-frontend-web'],
|
|
126
|
+
},
|
|
127
|
+
render: (args) => (
|
|
128
|
+
<Box maxWidth="360px">
|
|
129
|
+
<Tree.Root {...args}>
|
|
130
|
+
<Tree.Tree>
|
|
131
|
+
<Tree.Node
|
|
132
|
+
indentGuide={<Tree.BranchIndentGuide elbow />}
|
|
133
|
+
render={renderNode}
|
|
134
|
+
/>
|
|
135
|
+
</Tree.Tree>
|
|
136
|
+
</Tree.Root>
|
|
137
|
+
</Box>
|
|
138
|
+
),
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* `guideColor` — customize the guide line color with any Chakra color
|
|
143
|
+
* token. The default `border.default` flips with color mode; pick a
|
|
144
|
+
* stronger token (or any palette color) for more contrast.
|
|
145
|
+
*/
|
|
146
|
+
export const GuideColor: Story = {
|
|
147
|
+
args: {
|
|
148
|
+
collection: orgCollection,
|
|
149
|
+
'aria-label': '조직',
|
|
150
|
+
defaultExpandedValue: allBranchIds,
|
|
151
|
+
},
|
|
152
|
+
render: (args) => (
|
|
153
|
+
<HStack align="flex-start" gap={8}>
|
|
154
|
+
{(
|
|
155
|
+
[
|
|
156
|
+
['border.default (기본)', undefined],
|
|
157
|
+
['border.strong', 'border.strong'],
|
|
158
|
+
['primary.light', 'primary.light'],
|
|
159
|
+
] as const
|
|
160
|
+
).map(([label, guideColor]) => (
|
|
161
|
+
<Stack key={label} gap={2} width="280px">
|
|
162
|
+
<Text fontSize="sm" fontWeight="semibold" color="fg.muted">
|
|
163
|
+
{label}
|
|
164
|
+
</Text>
|
|
165
|
+
<Tree.Root {...args}>
|
|
166
|
+
<Tree.Tree>
|
|
167
|
+
<Tree.Node
|
|
168
|
+
indentGuide={
|
|
169
|
+
<Tree.BranchIndentGuide elbow guideColor={guideColor} />
|
|
170
|
+
}
|
|
171
|
+
render={renderNode}
|
|
172
|
+
/>
|
|
173
|
+
</Tree.Tree>
|
|
174
|
+
</Tree.Root>
|
|
175
|
+
</Stack>
|
|
176
|
+
))}
|
|
177
|
+
</HStack>
|
|
178
|
+
),
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Plain vertical rails (default) vs. `elbow` guides, side by side.
|
|
183
|
+
*/
|
|
184
|
+
export const ElbowGuideComparison: Story = {
|
|
185
|
+
args: {
|
|
186
|
+
collection: orgCollection,
|
|
187
|
+
'aria-label': '조직',
|
|
188
|
+
defaultExpandedValue: allBranchIds,
|
|
189
|
+
},
|
|
190
|
+
render: (args) => (
|
|
191
|
+
<HStack align="flex-start" gap={8}>
|
|
192
|
+
<Stack gap={2} width="320px">
|
|
193
|
+
<Text fontSize="sm" fontWeight="semibold" color="fg.muted">
|
|
194
|
+
기본 — 수직 레일
|
|
195
|
+
</Text>
|
|
196
|
+
<Tree.Root {...args}>
|
|
197
|
+
<Tree.Tree>
|
|
198
|
+
<Tree.Node
|
|
199
|
+
indentGuide={<Tree.BranchIndentGuide />}
|
|
200
|
+
render={renderNode}
|
|
201
|
+
/>
|
|
202
|
+
</Tree.Tree>
|
|
203
|
+
</Tree.Root>
|
|
204
|
+
</Stack>
|
|
205
|
+
<Stack gap={2} width="320px">
|
|
206
|
+
<Text fontSize="sm" fontWeight="semibold" color="fg.muted">
|
|
207
|
+
elbow — ├ / └ 가이드 라인
|
|
208
|
+
</Text>
|
|
209
|
+
<Tree.Root {...args}>
|
|
210
|
+
<Tree.Tree>
|
|
211
|
+
<Tree.Node
|
|
212
|
+
indentGuide={<Tree.BranchIndentGuide elbow />}
|
|
213
|
+
render={renderNode}
|
|
214
|
+
/>
|
|
215
|
+
</Tree.Tree>
|
|
216
|
+
</Tree.Root>
|
|
217
|
+
</Stack>
|
|
218
|
+
</HStack>
|
|
219
|
+
),
|
|
220
|
+
};
|
|
@@ -23,7 +23,35 @@ export type TreeBranchTriggerProps = TreeViewBranchTriggerProps;
|
|
|
23
23
|
export type TreeBranchIndicatorProps = TreeViewBranchIndicatorProps;
|
|
24
24
|
export type TreeBranchTextProps = TreeViewBranchTextProps;
|
|
25
25
|
export type TreeBranchContentProps = TreeViewBranchContentProps;
|
|
26
|
-
export type TreeBranchIndentGuideProps = TreeViewBranchIndentGuideProps
|
|
26
|
+
export type TreeBranchIndentGuideProps = TreeViewBranchIndentGuideProps & {
|
|
27
|
+
/**
|
|
28
|
+
* Draw `├` / `└` guide lines instead of a plain vertical rail: every
|
|
29
|
+
* row gets a horizontal foot joining it to its parent rail, middle
|
|
30
|
+
* rows keep the vertical (`├`), and the last row of each group stops
|
|
31
|
+
* at its centre (`└`). Off by default to preserve the existing
|
|
32
|
+
* plain-vertical-rail look. See `TreeBranchIndentGuide`.
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
elbow?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Length of the elbow foot — the horizontal cross-stroke that joins
|
|
38
|
+
* the rail to the row content, drawn from the parent rail column
|
|
39
|
+
* toward the text. In elbow mode each level indents 4px further than
|
|
40
|
+
* the plain-rail default, and since the default foot length doesn't
|
|
41
|
+
* grow with it, the foot ends 8px short of the row text. Any Chakra
|
|
42
|
+
* width value. Only applies when `elbow` is set.
|
|
43
|
+
* @default 'calc(var(--tree-indentation) - 4px)'
|
|
44
|
+
*/
|
|
45
|
+
footLength?: string | number;
|
|
46
|
+
/**
|
|
47
|
+
* Color of the guide lines (rail, elbow foot and vertical segments).
|
|
48
|
+
* Any Chakra color token. The default is a mode-flipping semantic
|
|
49
|
+
* token, so it darkens in light mode and lightens in dark mode
|
|
50
|
+
* automatically.
|
|
51
|
+
* @default 'border.default'
|
|
52
|
+
*/
|
|
53
|
+
guideColor?: string;
|
|
54
|
+
};
|
|
27
55
|
export type TreeItemProps = TreeViewItemProps;
|
|
28
56
|
export type TreeItemTextProps = TreeViewItemTextProps;
|
|
29
57
|
export type TreeItemIndicatorProps = TreeViewItemIndicatorProps;
|