banhatten-ui 0.1.2 → 0.2.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.
@@ -0,0 +1,135 @@
1
+ {
2
+ "name": "Menu",
3
+ "description": "Container for menu groups and items. Inserts dividers between MenuGroup children. Used in dropdowns, popovers, and context menus.",
4
+
5
+ "base": {
6
+ "display": "flex",
7
+ "flexDirection": "column",
8
+ "borderRadius": "{radius.sm}",
9
+ "bg": "{alias.bg-primary}",
10
+ "paddingY": "{spacing.md}",
11
+ "paddingX": "{spacing.sm}",
12
+ "shadow": "{shadow.sm}"
13
+ },
14
+
15
+ "behavior": {
16
+ "dividers": "Divider with my-sm inserted between each MenuGroup child"
17
+ },
18
+
19
+ "props": {
20
+ "children": { "type": "ReactNode", "description": "One or more MenuGroup components." }
21
+ },
22
+
23
+ "subComponents": {
24
+ "MenuGroup": {
25
+ "description": "Groups one optional MenuHeading and one or more MenuItem children.",
26
+ "base": {
27
+ "display": "flex",
28
+ "flexDirection": "column"
29
+ },
30
+ "props": {
31
+ "heading": { "type": "ReactNode", "description": "Optional section label. At most one." },
32
+ "headingId": { "type": "string", "description": "ID for heading wrapper. Used for role='group' aria-labelledby." },
33
+ "children": { "type": "ReactNode", "description": "MenuHeading (optional) and MenuItem components." }
34
+ },
35
+ "spacing": {
36
+ "headingToItems": "{spacing.sm}"
37
+ },
38
+ "accessibility": {
39
+ "role": "group",
40
+ "ariaLabelledby": "When heading and headingId provided"
41
+ }
42
+ },
43
+ "MenuHeading": {
44
+ "description": "Non-interactive section label for menu groups.",
45
+ "base": {
46
+ "paddingX": "{spacing.md}",
47
+ "paddingY": "{spacing.xs}",
48
+ "fontSize": "14px",
49
+ "fontWeight": 500,
50
+ "text": "{alias.text-tertiary}"
51
+ },
52
+ "props": {
53
+ "children": { "type": "ReactNode", "description": "Heading content (e.g. 'Section header')." }
54
+ }
55
+ },
56
+ "MenuItem": {
57
+ "description": "Individual menu item. Supports multiple types and slots.",
58
+ "base": {
59
+ "display": "flex",
60
+ "alignItems": "center",
61
+ "width": "100%",
62
+ "gap": "{spacing.md}",
63
+ "borderRadius": "{radius.sm}",
64
+ "paddingX": "{spacing.md}",
65
+ "paddingY": "{spacing.sm}",
66
+ "textAlign": "left",
67
+ "transition": "background-color, color",
68
+ "focusVisible": { "outline": "none", "ring": "2px", "ringColor": "{alias.border-brand}", "ringOffset": "2px" }
69
+ },
70
+ "types": {
71
+ "default": { "layout": "single-line" },
72
+ "multiline": { "layout": "primary + supportingText below", "gap": "{spacing.xxs}" },
73
+ "callToAction": { "layout": "primary + supportingText below + cta slot" },
74
+ "progress": { "layout": "ProgressBar with label and value" }
75
+ },
76
+ "states": {
77
+ "active": {
78
+ "true": { "bg": "{alias.bg-brand-tertiary}", "text": "{alias.text-brand}", "fontWeight": 500 },
79
+ "false": {}
80
+ },
81
+ "disabled": {
82
+ "true": { "opacity": 0.5, "cursor": "default", "pointerEvents": "none" },
83
+ "false": { "cursor": "pointer", "hover": { "bg": "{alias.bg-tertiary}" } }
84
+ }
85
+ },
86
+ "typography": {
87
+ "primary": { "fontSize": "14px", "fontWeight": 500, "lineHeight": "20px" },
88
+ "supportingText": { "fontSize": "14px", "lineHeight": "20px" },
89
+ "textRight": { "fontSize": "14px" }
90
+ },
91
+ "textColorByState": {
92
+ "primary": { "default": "{alias.text-primary}", "disabled": "{alias.text-inactive}" },
93
+ "supportingText": { "default": "{alias.text-secondary}", "disabled": "{alias.text-inactive}" },
94
+ "textRight": { "default": "{alias.text-secondary}", "disabled": "{alias.text-inactive}" }
95
+ },
96
+ "iconColorByState": {
97
+ "default": "{alias.icon-secondary}",
98
+ "disabled": "{alias.icon-inactive-subtle}"
99
+ },
100
+ "slots": {
101
+ "leftIcon": { "element": "Icon", "size": "sm", "position": "start" },
102
+ "rightIcon": { "element": "Icon", "size": "sm", "position": "end" },
103
+ "avatar": { "position": "start", "description": "Use Avatar component" },
104
+ "badge": { "position": "end", "description": "Use Badge component" },
105
+ "switch": { "element": "Toggle", "size": "sm", "togglePosition": "trailing", "position": "end", "description": "Use showSwitch, switchChecked, onSwitchChange props" },
106
+ "textRight": { "position": "end" },
107
+ "cta": { "element": "Button", "position": "end", "description": "For type='callToAction'" },
108
+ "progress": { "element": "ProgressBar", "size": "sm", "showValue": true, "description": "For type='progress'. Uses progressLabel, progressValue props." }
109
+ },
110
+ "props": {
111
+ "type": { "type": "enum", "values": ["default", "multiline", "callToAction", "progress"], "default": "default" },
112
+ "active": { "type": "boolean", "default": false, "description": "Selected/current state. Sets aria-current='page'." },
113
+ "disabled": { "type": "boolean", "default": false },
114
+ "children": { "type": "ReactNode", "description": "Primary content." },
115
+ "supportingText": { "type": "ReactNode", "description": "Supporting text below primary (multiline / callToAction)." },
116
+ "leftIcon": { "type": "string", "description": "Material Symbol name." },
117
+ "rightIcon": { "type": "string", "description": "Material Symbol name." },
118
+ "avatar": { "type": "ReactNode" },
119
+ "badge": { "type": "ReactNode" },
120
+ "showSwitch": { "type": "boolean", "default": false },
121
+ "switchChecked": { "type": "boolean" },
122
+ "onSwitchChange": { "type": "function" },
123
+ "textRight": { "type": "ReactNode" },
124
+ "cta": { "type": "ReactNode" },
125
+ "progressLabel": { "type": "ReactNode" },
126
+ "progressValue": { "type": "number", "description": "0-100" }
127
+ },
128
+ "defaults": { "type": "default", "active": false, "disabled": false }
129
+ }
130
+ },
131
+
132
+ "accessibility": {
133
+ "notes": "MenuItem sets aria-current='page' when active. Switch interactions stop propagation to prevent triggering parent button."
134
+ }
135
+ }
@@ -0,0 +1,104 @@
1
+ {
2
+ "name": "ProgressBar",
3
+ "description": "Horizontal bar indicating task completion or loading state. Supports determinate (0–100%) and indeterminate (animated pulse) modes.",
4
+
5
+ "base": {
6
+ "display": "flex",
7
+ "flexDirection": "column",
8
+ "minWidth": 0
9
+ },
10
+
11
+ "track": {
12
+ "width": "100%",
13
+ "overflow": "hidden",
14
+ "borderRadius": "{radius.sm}",
15
+ "bg": "{alias.bg-tertiary}"
16
+ },
17
+
18
+ "fill": {
19
+ "height": "100%",
20
+ "borderRadius": "{radius.sm}",
21
+ "flexShrink": 0
22
+ },
23
+
24
+ "sizes": {
25
+ "sm": { "trackHeight": "4px" },
26
+ "lg": { "trackHeight": "8px" }
27
+ },
28
+
29
+ "variants": {
30
+ "brand": { "fillBg": "{alias.bg-brand}" },
31
+ "success": { "fillBg": "{alias.bg-success}" },
32
+ "danger": { "fillBg": "{alias.bg-danger}" },
33
+ "info": { "fillBg": "{alias.bg-info}" },
34
+ "neutral": { "fillBg": "{alias.bg-quarterary}" }
35
+ },
36
+
37
+ "states": {
38
+ "indeterminate": {
39
+ "fillWidth": "40%",
40
+ "animation": "pulse"
41
+ }
42
+ },
43
+
44
+ "props": {
45
+ "value": { "type": "number", "description": "Progress value 0–100. Omit for indeterminate (animated) state." },
46
+ "size": { "type": "enum", "values": ["sm", "lg"], "default": "sm" },
47
+ "color": { "type": "enum", "values": ["brand", "success", "danger", "info", "neutral"], "default": "brand" },
48
+ "label": { "type": "ReactNode", "description": "Optional label above the bar." },
49
+ "showLabelInfoIcon": { "type": "boolean", "default": false, "description": "Optional info icon shown next to the label." },
50
+ "helperText": { "type": "ReactNode", "description": "Optional helper text below the bar." },
51
+ "showValue": { "type": "boolean", "default": false, "description": "Whether to show the numeric value (e.g. '40%') beside the bar." },
52
+ "onRefresh": { "type": "function", "description": "Callback for the optional refresh icon button. When set, a refresh icon is shown next to the value." }
53
+ },
54
+
55
+ "slots": {
56
+ "label": {
57
+ "display": "flex",
58
+ "alignItems": "center",
59
+ "gap": "{spacing.xs}",
60
+ "fontSize": "14px",
61
+ "fontWeight": 500,
62
+ "color": "{alias.text-primary}",
63
+ "marginBottom": "{spacing.sm}"
64
+ },
65
+ "labelInfoIcon": {
66
+ "element": "Icon",
67
+ "name": "info",
68
+ "size": "xs",
69
+ "color": "{alias.icon-tertiary}"
70
+ },
71
+ "barContainer": {
72
+ "display": "flex",
73
+ "alignItems": "center",
74
+ "gap": "{spacing.md}",
75
+ "minWidth": 0
76
+ },
77
+ "valueText": {
78
+ "fontSize": "14px",
79
+ "color": "{alias.text-secondary}",
80
+ "flexShrink": 0
81
+ },
82
+ "refreshButton": {
83
+ "element": "button",
84
+ "borderRadius": "{radius.sm}",
85
+ "padding": "{spacing.xxs}",
86
+ "color": "{alias.icon-secondary}",
87
+ "hover": { "color": "{alias.icon-primary}", "bg": "{alias.bg-tertiary}" },
88
+ "focus": { "ring": "2px", "ringColor": "{alias.border-brand}", "ringOffset": "1px" },
89
+ "icon": { "name": "refresh", "size": "xs" }
90
+ },
91
+ "helperText": {
92
+ "fontSize": "14px",
93
+ "color": "{alias.text-secondary}",
94
+ "marginTop": "{spacing.sm}"
95
+ }
96
+ },
97
+
98
+ "defaults": { "size": "sm", "color": "brand", "showValue": false },
99
+
100
+ "accessibility": {
101
+ "role": "progressbar",
102
+ "notes": "Determinate: aria-valuenow, aria-valuemin=0, aria-valuemax=100, aria-valuetext='N%'. Indeterminate: no value attributes, aria-valuetext='Loading'. Refresh button has aria-label='Refresh'. Helper text linked via aria-describedby."
103
+ }
104
+ }
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "RadioCard",
3
+ "description": "Card-style radio with optional icon, label, and description. Supports checked, unchecked, disabled, and focused states.",
4
+
5
+ "base": {
6
+ "display": "flex",
7
+ "position": "relative",
8
+ "borderRadius": "{radius.md}",
9
+ "padding": "{spacing.lg}",
10
+ "border": { "width": "1px" },
11
+ "transition": "background-color, border-color"
12
+ },
13
+
14
+ "states": {
15
+ "unchecked": {
16
+ "bg": "{alias.bg-primary}",
17
+ "borderColor": "{alias.border-default}",
18
+ "cursor": "pointer",
19
+ "hover": { "bg": "{alias.highlight-hover}" }
20
+ },
21
+ "checked": {
22
+ "bg": "{alias.bg-primary}",
23
+ "borderColor": "{alias.border-brand}",
24
+ "cursor": "pointer"
25
+ },
26
+ "disabled": {
27
+ "bg": "{alias.bg-inactive-subtle}",
28
+ "borderColor": "{alias.border-inactive-subtle}",
29
+ "cursor": "default"
30
+ },
31
+ "focused": {
32
+ "overlay": {
33
+ "position": "absolute",
34
+ "inset": "-1px",
35
+ "borderRadius": "{radius.md}",
36
+ "border": { "width": "2px", "color": "{alias.border-focused}" }
37
+ }
38
+ }
39
+ },
40
+
41
+ "layout": {
42
+ "leading": { "gap": "{spacing.md}", "alignItems": "center (no description) / start (with description)" },
43
+ "trailing": { "gap": "{spacing.lg}", "alignItems": "start" }
44
+ },
45
+
46
+ "subComponents": {
47
+ "RadioIndicator": {
48
+ "description": "16×16 radio circle inside a 20×20 hit area.",
49
+ "outerSize": "20px",
50
+ "innerSize": "16px",
51
+ "borderRadius": "{radius.full}",
52
+ "unchecked": {
53
+ "bg": "{alias.bg-primary}",
54
+ "border": { "width": "1px", "color": "{alias.border-strong}" }
55
+ },
56
+ "checked": {
57
+ "bg": "{alias.bg-brand}",
58
+ "dotColor": "{alias.icon-primary-inverse}",
59
+ "dot": "6px circle (SVG)"
60
+ },
61
+ "disabled": {
62
+ "bg": "{alias.bg-inactive-subtle}",
63
+ "border": { "width": "1px", "color": "{alias.border-inactive}" },
64
+ "dotColor": "{alias.icon-inactive-subtle}"
65
+ }
66
+ }
67
+ },
68
+
69
+ "slots": {
70
+ "icon": {
71
+ "element": "Icon",
72
+ "size": "lg",
73
+ "color": "{alias.icon-secondary}",
74
+ "disabledColor": "{alias.icon-inactive}"
75
+ },
76
+ "label": {
77
+ "fontWeight": 500,
78
+ "withDescription": { "fontSize": "14px", "lineHeight": "16px" },
79
+ "withoutDescription": { "fontSize": "16px", "lineHeight": "20px" },
80
+ "color": "{alias.text-primary}",
81
+ "disabledColor": "{alias.text-inactive}"
82
+ },
83
+ "description": {
84
+ "fontSize": "14px",
85
+ "lineHeight": "20px",
86
+ "color": "{alias.text-secondary}",
87
+ "disabledColor": "{alias.text-inactive}",
88
+ "gap": "{spacing.xs}"
89
+ }
90
+ },
91
+
92
+ "props": {
93
+ "label": { "type": "string", "description": "Label text displayed in the card." },
94
+ "description": { "type": "string", "description": "Description text below the label." },
95
+ "icon": { "type": "string", "description": "Material Symbol name for the card icon." },
96
+ "iconVariant": { "type": "enum", "values": ["outlined", "rounded", "sharp"], "default": "outlined" },
97
+ "iconFilled": { "type": "boolean", "default": false },
98
+ "radioPosition": { "type": "enum", "values": ["leading", "trailing"], "default": "trailing" },
99
+ "checked": { "type": "boolean" },
100
+ "disabled": { "type": "boolean", "default": false },
101
+ "name": { "type": "string", "description": "Radio group name for native grouping." },
102
+ "value": { "type": "string", "description": "Radio value." }
103
+ },
104
+
105
+ "defaults": { "radioPosition": "trailing" },
106
+
107
+ "accessibility": {
108
+ "role": "radio",
109
+ "notes": "Hidden native radio input (sr-only) inside a <label>. Focus/selection ring overlay shown when checked or focused (not disabled)."
110
+ }
111
+ }
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "Radio",
3
+ "description": "Radio input with optional label and support text. Used within a group for single selection.",
4
+
5
+ "base": {
6
+ "display": "inline-flex",
7
+ "gap": "{spacing.md}",
8
+ "cursor": "pointer"
9
+ },
10
+
11
+ "indicator": {
12
+ "size": "16px",
13
+ "outerSize": "20px",
14
+ "borderRadius": "{radius.full}",
15
+ "unchecked": {
16
+ "bg": "{alias.bg-primary}",
17
+ "border": { "width": "1px", "color": "{alias.border-strong}" }
18
+ },
19
+ "checked": {
20
+ "bg": "{alias.bg-brand}",
21
+ "hover": { "bg": "{alias.bg-brand-hover}" },
22
+ "dotColor": "{alias.icon-primary-inverse}",
23
+ "dotRadius": "3px"
24
+ }
25
+ },
26
+
27
+ "states": {
28
+ "disabled": {
29
+ "cursor": "default",
30
+ "indicator": {
31
+ "bg": "{alias.bg-inactive-subtle}",
32
+ "border": { "color": "{alias.border-inactive}" },
33
+ "dotColor": "{alias.icon-inactive-subtle}"
34
+ },
35
+ "labelColor": "{alias.text-inactive}"
36
+ },
37
+ "focused": {
38
+ "indicator": {
39
+ "ring": { "width": "2px", "color": "{alias.border-focused}" },
40
+ "border": { "color": "{alias.border-brand}" }
41
+ }
42
+ }
43
+ },
44
+
45
+ "props": {
46
+ "label": { "type": "string", "description": "Label text next to the radio." },
47
+ "supportText": { "type": "string", "description": "Support text below the label." },
48
+ "radioPosition": { "type": "enum", "values": ["leading", "trailing"], "default": "leading" },
49
+ "checked": { "type": "boolean" },
50
+ "disabled": { "type": "boolean", "default": false },
51
+ "name": { "type": "string", "description": "Radio group name." },
52
+ "value": { "type": "string", "description": "Radio value within the group." }
53
+ },
54
+
55
+ "slots": {
56
+ "label": { "fontSize": "14px", "fontWeight": 500, "lineHeight": "16px", "color": "{alias.text-primary}" },
57
+ "supportText": { "fontSize": "14px", "lineHeight": "20px", "color": "{alias.text-secondary}", "gap": "{spacing.xxs}" }
58
+ },
59
+
60
+ "accessibility": {
61
+ "role": "radio",
62
+ "notes": "Native input is visually hidden (sr-only). Use within a fieldset/radiogroup for grouping."
63
+ }
64
+ }
@@ -0,0 +1,254 @@
1
+ {
2
+ "name": "Sidebar",
3
+ "description": "Vertical navigation sidebar with header, scrollable content, and footer sections. Supports collapsed (icon-only) and expanded states via SidebarContext.",
4
+
5
+ "base": {
6
+ "display": "flex",
7
+ "flexDirection": "column",
8
+ "height": "100%",
9
+ "bg": "{alias.bg-primary}",
10
+ "shadow": "{shadow.sm}",
11
+ "borderRadius": "{radius.sm}",
12
+ "transition": "width 200ms ease-out"
13
+ },
14
+
15
+ "variants": {
16
+ "expanded": { "width": "256px", "minWidth": "256px" },
17
+ "collapsed": { "width": "64px", "minWidth": "64px" }
18
+ },
19
+
20
+ "sections": {
21
+ "header": {
22
+ "display": "flex",
23
+ "alignItems": "center",
24
+ "gap": "{spacing.sm}",
25
+ "paddingX": "{spacing.2xl}",
26
+ "paddingY": "{spacing.2xl}",
27
+ "flexShrink": 0,
28
+ "collapseToggle": {
29
+ "size": "32px",
30
+ "borderRadius": "{radius.full}",
31
+ "iconColor": "{alias.icon-secondary}",
32
+ "hover": { "bg": "{alias.bg-tertiary}", "iconColor": "{alias.icon-primary}" },
33
+ "focus": { "ring": "2px", "ringColor": "{alias.border-brand}", "ringOffset": "2px" },
34
+ "icons": { "expanded": "chevron_left", "collapsed": "chevron_right" },
35
+ "iconSize": "sm"
36
+ }
37
+ },
38
+ "divider": {
39
+ "element": "Divider",
40
+ "orientation": "horizontal"
41
+ },
42
+ "content": {
43
+ "display": "flex",
44
+ "flexDirection": "column",
45
+ "flex": 1,
46
+ "minHeight": 0,
47
+ "overflow": "auto (y), hidden (x)",
48
+ "paddingX": "{spacing.xl}",
49
+ "paddingY": "{spacing.xl}",
50
+ "scrollbar": "hidden"
51
+ },
52
+ "footer": {
53
+ "display": "flex",
54
+ "flexDirection": "column",
55
+ "gap": "{spacing.xxs}",
56
+ "flexShrink": 0,
57
+ "borderTop": { "width": "1px", "color": "{alias.border-secondary}" },
58
+ "paddingX": "{spacing.md}",
59
+ "paddingY": "{spacing.md}",
60
+ "paddingTop": "{spacing.lg}"
61
+ }
62
+ },
63
+
64
+ "props": {
65
+ "header": { "type": "ReactNode", "description": "Header content (e.g. logo)." },
66
+ "children": { "type": "ReactNode", "description": "Main scrollable content (SidebarMenuItems)." },
67
+ "footer": { "type": "ReactNode", "description": "Footer content (e.g. settings, account card)." },
68
+ "collapsible": { "type": "boolean", "default": false, "description": "When true, shows collapse toggle in header." },
69
+ "collapsed": { "type": "boolean", "default": false, "description": "Controlled collapsed state." },
70
+ "onCollapsedChange": { "type": "function", "description": "Called when collapse toggle is clicked." },
71
+ "defaultCollapsed": { "type": "boolean", "default": false, "description": "Default collapsed state (uncontrolled)." }
72
+ },
73
+
74
+ "defaults": { "collapsible": false, "collapsed": false },
75
+
76
+ "subComponents": {
77
+ "SidebarMenuItem": {
78
+ "description": "Navigation item supporting expanded (icon + label) and collapsed (icon-only) layout. Optional submenu with expand/collapse.",
79
+ "base": {
80
+ "display": "flex",
81
+ "alignItems": "center",
82
+ "width": "100%",
83
+ "gap": "{spacing.md}",
84
+ "borderRadius": "{radius.sm}",
85
+ "paddingX": "{spacing.md}",
86
+ "paddingY": "{spacing.sm}",
87
+ "fontSize": "14px",
88
+ "fontWeight": 500,
89
+ "lineHeight": "20px",
90
+ "transition": "background-color"
91
+ },
92
+ "states": {
93
+ "default": {
94
+ "bg": "transparent",
95
+ "text": "{alias.text-primary}",
96
+ "iconColor": "{alias.icon-secondary}",
97
+ "hover": { "bg": "{alias.bg-tertiary}" },
98
+ "cursor": "pointer"
99
+ },
100
+ "active": {
101
+ "bg": "{alias.bg-brand-tertiary}",
102
+ "text": "{alias.text-brand}",
103
+ "iconColor": "{alias.icon-brand}"
104
+ },
105
+ "disabled": {
106
+ "opacity": 0.5,
107
+ "pointerEvents": "none",
108
+ "cursor": "default",
109
+ "iconColor": "{alias.icon-inactive-subtle}",
110
+ "text": "{alias.text-inactive}"
111
+ },
112
+ "collapsed": {
113
+ "justifyContent": "center",
114
+ "paddingX": "{spacing.sm}",
115
+ "note": "Label hidden; aria-label used for accessibility."
116
+ },
117
+ "focused": {
118
+ "ring": "2px",
119
+ "ringColor": "{alias.border-brand}",
120
+ "ringOffset": "2px"
121
+ }
122
+ },
123
+ "slots": {
124
+ "leftIcon": { "element": "Icon", "size": "sm" },
125
+ "label": { "truncate": true },
126
+ "chevron": {
127
+ "element": "Icon",
128
+ "size": "sm",
129
+ "expandedIcon": "expand_less",
130
+ "collapsedIcon": "expand_more"
131
+ }
132
+ },
133
+ "submenu": {
134
+ "display": "flex",
135
+ "flexDirection": "column",
136
+ "overflow": "hidden",
137
+ "transition": "height 200ms ease-out",
138
+ "collapsed": "hidden",
139
+ "expanded": "visible"
140
+ },
141
+ "props": {
142
+ "active": { "type": "boolean", "default": false },
143
+ "collapsed": { "type": "boolean", "default": false, "description": "Inherits from SidebarContext when inside Sidebar." },
144
+ "children": { "type": "ReactNode", "description": "Label text." },
145
+ "leftIcon": { "type": "string", "description": "Material Symbol name for leading icon." },
146
+ "submenu": { "type": "ReactNode", "description": "SidebarSubmenuItem children." },
147
+ "expanded": { "type": "boolean", "description": "Controlled expanded state for submenu." },
148
+ "onExpandedChange": { "type": "function", "description": "Called when submenu expand/collapse is toggled." },
149
+ "defaultExpanded": { "type": "boolean", "default": false },
150
+ "disabled": { "type": "boolean", "default": false }
151
+ },
152
+ "accessibility": {
153
+ "role": "button",
154
+ "notes": "aria-current='page' when active. aria-expanded on submenu trigger. aria-controls references submenu region. aria-label set from children when collapsed."
155
+ }
156
+ },
157
+
158
+ "SidebarSubmenuItem": {
159
+ "description": "Nested navigation item under SidebarMenuItem. Visually indented, no leading icon.",
160
+ "base": {
161
+ "display": "flex",
162
+ "alignItems": "center",
163
+ "width": "100%",
164
+ "borderRadius": "{radius.sm}",
165
+ "paddingLeft": "{spacing.xl}",
166
+ "paddingRight": "{spacing.md}",
167
+ "paddingY": "{spacing.sm}",
168
+ "fontSize": "14px",
169
+ "fontWeight": 400,
170
+ "lineHeight": "20px",
171
+ "text": "{alias.text-secondary}",
172
+ "transition": "background-color"
173
+ },
174
+ "states": {
175
+ "default": {
176
+ "cursor": "pointer",
177
+ "hover": { "bg": "{alias.bg-tertiary}", "text": "{alias.text-primary}" }
178
+ },
179
+ "active": {
180
+ "bg": "{alias.bg-brand-tertiary}",
181
+ "text": "{alias.text-brand}",
182
+ "fontWeight": 500
183
+ },
184
+ "disabled": {
185
+ "opacity": 0.5,
186
+ "pointerEvents": "none",
187
+ "cursor": "default",
188
+ "text": "{alias.text-inactive}"
189
+ },
190
+ "focused": {
191
+ "ring": "2px",
192
+ "ringColor": "{alias.border-brand}",
193
+ "ringOffset": "2px"
194
+ }
195
+ },
196
+ "props": {
197
+ "active": { "type": "boolean", "default": false },
198
+ "children": { "type": "ReactNode", "description": "Label text." },
199
+ "disabled": { "type": "boolean", "default": false }
200
+ },
201
+ "accessibility": {
202
+ "role": "button",
203
+ "notes": "aria-current='page' when active. aria-disabled when disabled."
204
+ }
205
+ },
206
+
207
+ "SidebarAccountCard": {
208
+ "description": "User account display card with Avatar, username, supporting text, and optional right icon. Collapses to avatar-only in collapsed sidebar.",
209
+ "base": {
210
+ "display": "flex",
211
+ "alignItems": "center",
212
+ "width": "100%",
213
+ "gap": "{spacing.md}",
214
+ "borderRadius": "{radius.sm}",
215
+ "paddingX": "{spacing.md}",
216
+ "paddingY": "{spacing.md}"
217
+ },
218
+ "states": {
219
+ "default": { "bg": "transparent" },
220
+ "selected": { "bg": "{alias.bg-tertiary}" },
221
+ "collapsed": {
222
+ "justifyContent": "center",
223
+ "paddingX": "0",
224
+ "paddingY": "{spacing.sm}",
225
+ "note": "Avatar only; username, supportingText, and rightIcon are hidden."
226
+ }
227
+ },
228
+ "composition": {
229
+ "avatar": "Avatar (size: md)"
230
+ },
231
+ "slots": {
232
+ "rightIcon": {
233
+ "element": "Icon",
234
+ "size": "sm",
235
+ "color": "{alias.icon-secondary}"
236
+ }
237
+ },
238
+ "props": {
239
+ "username": { "type": "string", "description": "User display name passed to Avatar." },
240
+ "supportingText": { "type": "string", "description": "Supporting line below name passed to Avatar." },
241
+ "initials": { "type": "string", "description": "Initials for Avatar fallback." },
242
+ "rightIcon": { "type": "string", "description": "Material Symbol name for trailing icon." },
243
+ "selected": { "type": "boolean", "default": false },
244
+ "collapsed": { "type": "boolean", "default": false, "description": "Inherits from SidebarContext when inside Sidebar." }
245
+ },
246
+ "defaults": { "selected": false }
247
+ }
248
+ },
249
+
250
+ "accessibility": {
251
+ "role": "complementary (aside)",
252
+ "notes": "aria-label='Sidebar'. SidebarContext provides collapsed state to children. Collapse toggle has aria-label 'Expand/Collapse sidebar'. Submenu regions have role='group' with aria-label."
253
+ }
254
+ }