@attrus-ds/core 0.2.0 → 1.0.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 (80) hide show
  1. package/LICENSE +27 -27
  2. package/dist/assets/flags/Brazil-rounded.svg +15 -15
  3. package/dist/assets/flags/Brazil-square.svg +16 -16
  4. package/dist/assets/flags/Chile-rounded.svg +10 -10
  5. package/dist/assets/flags/Chile-square.svg +10 -10
  6. package/dist/assets/flags/Colombia-rounded.svg +9 -9
  7. package/dist/assets/flags/Colombia-square.svg +9 -9
  8. package/dist/assets/flags/EUA-rounded.svg +10 -10
  9. package/dist/assets/flags/EUA-square.svg +10 -10
  10. package/dist/assets/flags/EUR-rounded.svg +8 -8
  11. package/dist/assets/flags/EUR-square.svg +8 -8
  12. package/dist/assets/flags/Mexico-rounded.svg +18 -18
  13. package/dist/assets/flags/Mexico-square.svg +18 -18
  14. package/dist/assets/icon-attrus-dark.svg +2 -2
  15. package/dist/assets/icon-attrus-light.svg +2 -2
  16. package/dist/assets/logo-attrus-dark.svg +7 -7
  17. package/dist/assets/logo-attrus-light.svg +7 -7
  18. package/dist/css/components/buttons.css +301 -301
  19. package/dist/css/components/callout.css +195 -195
  20. package/dist/css/components/cards.css +272 -272
  21. package/dist/css/components/combobox.css +319 -319
  22. package/dist/css/components/empty-states.css +61 -61
  23. package/dist/css/components/inputs.css +975 -975
  24. package/dist/css/components/number-input.css +138 -138
  25. package/dist/css/components/overlays.css +374 -374
  26. package/dist/css/components/primitives.css +314 -314
  27. package/dist/css/components/sidebar.css +179 -179
  28. package/dist/css/components/smart-search.css +91 -91
  29. package/dist/css/components/status-pills.css +207 -207
  30. package/dist/css/components/stepper.css +309 -309
  31. package/dist/css/components/table.css +602 -602
  32. package/dist/css/components/tabs.css +319 -319
  33. package/dist/css/components/toast.css +243 -243
  34. package/dist/css/components/tooltip.css +231 -231
  35. package/dist/css/components/topbar.css +148 -148
  36. package/dist/css/tokens.css +713 -666
  37. package/dist/react/AppSidebar/AppSidebar.d.ts +50 -50
  38. package/dist/react/AppSidebar/AppSidebar.tsx +197 -197
  39. package/dist/react/AppTopbar/AppTopbar.d.ts +58 -58
  40. package/dist/react/AppTopbar/AppTopbar.tsx +203 -203
  41. package/dist/react/Atoms/Atoms.d.ts +149 -149
  42. package/dist/react/Atoms/Atoms.tsx +407 -407
  43. package/dist/react/Button/Button.d.ts +25 -25
  44. package/dist/react/Button/Button.tsx +83 -83
  45. package/dist/react/Callout/Callout.d.ts +29 -29
  46. package/dist/react/Callout/Callout.tsx +98 -98
  47. package/dist/react/Card/Card.d.ts +38 -38
  48. package/dist/react/Card/Card.tsx +93 -93
  49. package/dist/react/Combobox/Combobox.d.ts +52 -52
  50. package/dist/react/Combobox/Combobox.tsx +254 -254
  51. package/dist/react/DataTable/DataTable.d.ts +81 -81
  52. package/dist/react/DataTable/DataTable.tsx +308 -308
  53. package/dist/react/Drawer/Drawer.d.ts +35 -35
  54. package/dist/react/Drawer/Drawer.tsx +226 -226
  55. package/dist/react/Input/Input.d.ts +155 -155
  56. package/dist/react/Input/Input.tsx +478 -478
  57. package/dist/react/Modal/Modal.d.ts +27 -27
  58. package/dist/react/Modal/Modal.tsx +173 -173
  59. package/dist/react/NumberInput/NumberInput.d.ts +25 -25
  60. package/dist/react/NumberInput/NumberInput.tsx +117 -117
  61. package/dist/react/Pill/Pill.d.ts +31 -31
  62. package/dist/react/Pill/Pill.tsx +104 -104
  63. package/dist/react/SearchPill/SearchPill.d.ts +14 -14
  64. package/dist/react/SearchPill/SearchPill.tsx +40 -40
  65. package/dist/react/SmartSearch/SmartSearch.d.ts +65 -65
  66. package/dist/react/SmartSearch/SmartSearch.tsx +271 -271
  67. package/dist/react/Stepper/Stepper.d.ts +25 -25
  68. package/dist/react/Stepper/Stepper.tsx +94 -94
  69. package/dist/react/Tabs/Tabs.d.ts +32 -32
  70. package/dist/react/Tabs/Tabs.tsx +147 -147
  71. package/dist/react/Toast/Toast.d.ts +30 -30
  72. package/dist/react/Toast/Toast.tsx +94 -94
  73. package/dist/react/Tooltip/Tooltip.d.ts +23 -23
  74. package/dist/react/Tooltip/Tooltip.tsx +80 -80
  75. package/dist/react/ZeroState/ZeroState.d.ts +17 -17
  76. package/dist/react/ZeroState/ZeroState.tsx +45 -45
  77. package/dist/react/index.ts +35 -35
  78. package/dist/tokens/attrus-tokens.flat.json +1234 -1234
  79. package/dist/tokens/attrus-tokens.json +1089 -1089
  80. package/package.json +66 -64
@@ -1,50 +1,50 @@
1
- import * as React from 'react';
2
-
3
- export interface SidebarChildItem {
4
- key: string;
5
- label: React.ReactNode;
6
- count?: number | string;
7
- }
8
-
9
- export interface SidebarItem {
10
- key: string;
11
- label: React.ReactNode;
12
- /** 15px icon slot (.ic). */
13
- icon?: React.ReactNode;
14
- /** Status badge text (e.g. "NEW") — mutually exclusive with count. */
15
- badge?: string;
16
- badgeTone?: 'alert' | 'warning';
17
- /** Numeric trailing count. */
18
- count?: number | string;
19
- disabled?: boolean;
20
- /** Sub-items — renders a collapsible .sb-group. */
21
- children?: SidebarChildItem[];
22
- }
23
-
24
- export interface SidebarSection {
25
- /** Uppercase section label; omit for the first unlabelled block. */
26
- label?: React.ReactNode;
27
- items: SidebarItem[];
28
- }
29
-
30
- export interface AppSidebarProps {
31
- sections: SidebarSection[];
32
- /** Key of the active item/sub-item. */
33
- active?: string;
34
- onNav?: (key: string) => void;
35
- /** Full-height app rail (.sb-app) instead of card framing. */
36
- app?: boolean;
37
- /** 60px icon rail. */
38
- collapsed?: boolean;
39
- /** Renders the header collapse toggle. */
40
- onToggleCollapse?: () => void;
41
- /** Header brand slot (logo img). */
42
- logo?: React.ReactNode;
43
- /** Footer slot (.sb-foot markup is the caller's). */
44
- foot?: React.ReactNode;
45
- className?: string;
46
- style?: React.CSSProperties;
47
- }
48
-
49
- export declare const AppSidebar: React.FC<AppSidebarProps>;
50
- export default AppSidebar;
1
+ import * as React from 'react';
2
+
3
+ export interface SidebarChildItem {
4
+ key: string;
5
+ label: React.ReactNode;
6
+ count?: number | string;
7
+ }
8
+
9
+ export interface SidebarItem {
10
+ key: string;
11
+ label: React.ReactNode;
12
+ /** 15px icon slot (.ic). */
13
+ icon?: React.ReactNode;
14
+ /** Status badge text (e.g. "NEW") — mutually exclusive with count. */
15
+ badge?: string;
16
+ badgeTone?: 'alert' | 'warning';
17
+ /** Numeric trailing count. */
18
+ count?: number | string;
19
+ disabled?: boolean;
20
+ /** Sub-items — renders a collapsible .sb-group. */
21
+ children?: SidebarChildItem[];
22
+ }
23
+
24
+ export interface SidebarSection {
25
+ /** Uppercase section label; omit for the first unlabelled block. */
26
+ label?: React.ReactNode;
27
+ items: SidebarItem[];
28
+ }
29
+
30
+ export interface AppSidebarProps {
31
+ sections: SidebarSection[];
32
+ /** Key of the active item/sub-item. */
33
+ active?: string;
34
+ onNav?: (key: string) => void;
35
+ /** Full-height app rail (.sb-app) instead of card framing. */
36
+ app?: boolean;
37
+ /** 60px icon rail. */
38
+ collapsed?: boolean;
39
+ /** Renders the header collapse toggle. */
40
+ onToggleCollapse?: () => void;
41
+ /** Header brand slot (logo img). */
42
+ logo?: React.ReactNode;
43
+ /** Footer slot (.sb-foot markup is the caller's). */
44
+ foot?: React.ReactNode;
45
+ className?: string;
46
+ style?: React.CSSProperties;
47
+ }
48
+
49
+ export declare const AppSidebar: React.FC<AppSidebarProps>;
50
+ export default AppSidebar;
@@ -1,197 +1,197 @@
1
- import * as React from 'react';
2
-
3
- /**
4
- * ATTRUS AppSidebar — typed wrapper over the canonical `.sb` system
5
- * (preview/components/sidebar.css). Single visual source shared with
6
- * the live app shell and the doc page. Sections, items with badge OR
7
- * count, collapsible groups, disabled rows, collapsed 60px icon rail.
8
- * (Named AppSidebar — "Shell"/"Sidebar" collide with legacy app files.)
9
- */
10
-
11
- export interface SidebarChildItem {
12
- key: string;
13
- label: React.ReactNode;
14
- count?: number | string;
15
- }
16
-
17
- export interface SidebarItem {
18
- key: string;
19
- label: React.ReactNode;
20
- /** 15px icon slot (.ic). */
21
- icon?: React.ReactNode;
22
- /** Status badge text (e.g. "NEW") — mutually exclusive with count. */
23
- badge?: string;
24
- badgeTone?: 'alert' | 'warning';
25
- /** Numeric trailing count. */
26
- count?: number | string;
27
- disabled?: boolean;
28
- /** Sub-items — renders a collapsible .sb-group. */
29
- children?: SidebarChildItem[];
30
- }
31
-
32
- export interface SidebarSection {
33
- /** Uppercase section label; omit for the first unlabelled block. */
34
- label?: React.ReactNode;
35
- items: SidebarItem[];
36
- }
37
-
38
- export interface AppSidebarProps {
39
- sections: SidebarSection[];
40
- /** Key of the active item/sub-item. */
41
- active?: string;
42
- onNav?: (key: string) => void;
43
- /** Full-height app rail (.sb-app) instead of card framing. */
44
- app?: boolean;
45
- /** 60px icon rail. */
46
- collapsed?: boolean;
47
- /** Renders the header collapse toggle. */
48
- onToggleCollapse?: () => void;
49
- /** Header brand slot (logo img). */
50
- logo?: React.ReactNode;
51
- /** Footer slot (.sb-foot markup is the caller's). */
52
- foot?: React.ReactNode;
53
- className?: string;
54
- style?: React.CSSProperties;
55
- }
56
-
57
- const PanelGlyph: React.FC = () => (
58
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.75} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
59
- <rect x="3" y="3" width="18" height="18" rx="2" />
60
- <line x1="9" y1="3" x2="9" y2="21" />
61
- </svg>
62
- );
63
- const ChevGlyph: React.FC = () => (
64
- <svg className="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
65
- <path d="m9 18 6-6-6-6" />
66
- </svg>
67
- );
68
-
69
- export const AppSidebar: React.FC<AppSidebarProps> = ({
70
- sections,
71
- active,
72
- onNav,
73
- app = false,
74
- collapsed = false,
75
- onToggleCollapse,
76
- logo,
77
- foot,
78
- className,
79
- style,
80
- }) => {
81
- const [openGroups, setOpenGroups] = React.useState<Record<string, boolean>>({});
82
-
83
- const toggleGroup = (key: string) =>
84
- setOpenGroups((g) => ({ ...g, [key]: !g[key] }));
85
-
86
- const renderItem = (item: SidebarItem) => {
87
- const isGroup = !!(item.children && item.children.length);
88
- const childActive = isGroup && item.children!.some((c) => c.key === active);
89
- const expanded = isGroup ? (openGroups[item.key] ?? childActive) : false;
90
- const itemCls = [
91
- 'sb-item',
92
- item.key === active ? 'active' : '',
93
- item.disabled ? 'disabled' : '',
94
- ]
95
- .filter(Boolean)
96
- .join(' ');
97
-
98
- const row = (
99
- <div
100
- className={itemCls}
101
- role="button"
102
- tabIndex={item.disabled ? undefined : 0}
103
- aria-disabled={item.disabled || undefined}
104
- aria-current={item.key === active ? 'page' : undefined}
105
- onClick={() => {
106
- if (item.disabled) return;
107
- if (isGroup) toggleGroup(item.key);
108
- else if (onNav) onNav(item.key);
109
- }}
110
- >
111
- {item.icon != null ? <span className="ic">{item.icon}</span> : null}
112
- <span className="label">{item.label}</span>
113
- {item.badge ? (
114
- <span className={['sb-badge', item.badgeTone || ''].filter(Boolean).join(' ')}>{item.badge}</span>
115
- ) : item.count != null ? (
116
- <span className="sb-count">{item.count}</span>
117
- ) : null}
118
- {isGroup ? <ChevGlyph /> : null}
119
- </div>
120
- );
121
-
122
- if (!isGroup) return <React.Fragment key={item.key}>{row}</React.Fragment>;
123
-
124
- return (
125
- <div key={item.key} className="sb-group" aria-expanded={expanded}>
126
- {row}
127
- <div className="sb-children">
128
- <div className="sb-children-inner">
129
- {item.children!.map((c) => (
130
- <div
131
- key={c.key}
132
- className={['sb-subitem', c.key === active ? 'active' : ''].filter(Boolean).join(' ')}
133
- role="button"
134
- tabIndex={0}
135
- aria-current={c.key === active ? 'page' : undefined}
136
- onClick={() => onNav && onNav(c.key)}
137
- >
138
- <span className="label">{c.label}</span>
139
- {c.count != null ? <span className="sb-count">{c.count}</span> : null}
140
- </div>
141
- ))}
142
- </div>
143
- </div>
144
- </div>
145
- );
146
- };
147
-
148
- return (
149
- <aside
150
- className={['sb', app ? 'sb-app' : '', collapsed ? 'collapsed' : '', className || ''].filter(Boolean).join(' ')}
151
- style={style}
152
- onKeyDown={(e) => {
153
- // Rail keyboard nav (doc a11y contract): ↑/↓ move between items
154
- // (wrapping), Home/End jump; Enter/Space activate via role=button.
155
- const nav = e.currentTarget;
156
- const target = e.target as HTMLElement;
157
- if (e.key === 'Enter' || e.key === ' ') {
158
- if (target.matches('.sb-item, .sb-subitem')) { e.preventDefault(); target.click(); }
159
- return;
160
- }
161
- if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Home' && e.key !== 'End') return;
162
- const rows = Array.from(nav.querySelectorAll<HTMLElement>('.sb-item:not(.disabled), .sb-subitem'))
163
- .filter((el) => el.offsetParent !== null); // skip collapsed-group children
164
- if (!rows.length) return;
165
- e.preventDefault();
166
- const idx = rows.indexOf(target);
167
- let next = 0;
168
- if (e.key === 'ArrowDown') next = idx === -1 ? 0 : (idx + 1) % rows.length;
169
- else if (e.key === 'ArrowUp') next = idx === -1 ? rows.length - 1 : (idx - 1 + rows.length) % rows.length;
170
- else if (e.key === 'End') next = rows.length - 1;
171
- rows[next].focus();
172
- }}
173
- >
174
- {(logo != null || onToggleCollapse) && (
175
- <div className="sb-head">
176
- {logo}
177
- {onToggleCollapse ? (
178
- <button type="button" className="toggle" aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} onClick={onToggleCollapse}>
179
- <PanelGlyph />
180
- </button>
181
- ) : null}
182
- </div>
183
- )}
184
- <div className="sb-body">
185
- {sections.map((s, i) => (
186
- <React.Fragment key={i}>
187
- {s.label != null ? <div className="sb-section">{s.label}</div> : null}
188
- {s.items.map(renderItem)}
189
- </React.Fragment>
190
- ))}
191
- </div>
192
- {foot}
193
- </aside>
194
- );
195
- };
196
-
197
- export default AppSidebar;
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * ATTRUS AppSidebar — typed wrapper over the canonical `.sb` system
5
+ * (preview/components/sidebar.css). Single visual source shared with
6
+ * the live app shell and the doc page. Sections, items with badge OR
7
+ * count, collapsible groups, disabled rows, collapsed 60px icon rail.
8
+ * (Named AppSidebar — "Shell"/"Sidebar" collide with legacy app files.)
9
+ */
10
+
11
+ export interface SidebarChildItem {
12
+ key: string;
13
+ label: React.ReactNode;
14
+ count?: number | string;
15
+ }
16
+
17
+ export interface SidebarItem {
18
+ key: string;
19
+ label: React.ReactNode;
20
+ /** 15px icon slot (.ic). */
21
+ icon?: React.ReactNode;
22
+ /** Status badge text (e.g. "NEW") — mutually exclusive with count. */
23
+ badge?: string;
24
+ badgeTone?: 'alert' | 'warning';
25
+ /** Numeric trailing count. */
26
+ count?: number | string;
27
+ disabled?: boolean;
28
+ /** Sub-items — renders a collapsible .sb-group. */
29
+ children?: SidebarChildItem[];
30
+ }
31
+
32
+ export interface SidebarSection {
33
+ /** Uppercase section label; omit for the first unlabelled block. */
34
+ label?: React.ReactNode;
35
+ items: SidebarItem[];
36
+ }
37
+
38
+ export interface AppSidebarProps {
39
+ sections: SidebarSection[];
40
+ /** Key of the active item/sub-item. */
41
+ active?: string;
42
+ onNav?: (key: string) => void;
43
+ /** Full-height app rail (.sb-app) instead of card framing. */
44
+ app?: boolean;
45
+ /** 60px icon rail. */
46
+ collapsed?: boolean;
47
+ /** Renders the header collapse toggle. */
48
+ onToggleCollapse?: () => void;
49
+ /** Header brand slot (logo img). */
50
+ logo?: React.ReactNode;
51
+ /** Footer slot (.sb-foot markup is the caller's). */
52
+ foot?: React.ReactNode;
53
+ className?: string;
54
+ style?: React.CSSProperties;
55
+ }
56
+
57
+ const PanelGlyph: React.FC = () => (
58
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.75} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
59
+ <rect x="3" y="3" width="18" height="18" rx="2" />
60
+ <line x1="9" y1="3" x2="9" y2="21" />
61
+ </svg>
62
+ );
63
+ const ChevGlyph: React.FC = () => (
64
+ <svg className="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
65
+ <path d="m9 18 6-6-6-6" />
66
+ </svg>
67
+ );
68
+
69
+ export const AppSidebar: React.FC<AppSidebarProps> = ({
70
+ sections,
71
+ active,
72
+ onNav,
73
+ app = false,
74
+ collapsed = false,
75
+ onToggleCollapse,
76
+ logo,
77
+ foot,
78
+ className,
79
+ style,
80
+ }) => {
81
+ const [openGroups, setOpenGroups] = React.useState<Record<string, boolean>>({});
82
+
83
+ const toggleGroup = (key: string) =>
84
+ setOpenGroups((g) => ({ ...g, [key]: !g[key] }));
85
+
86
+ const renderItem = (item: SidebarItem) => {
87
+ const isGroup = !!(item.children && item.children.length);
88
+ const childActive = isGroup && item.children!.some((c) => c.key === active);
89
+ const expanded = isGroup ? (openGroups[item.key] ?? childActive) : false;
90
+ const itemCls = [
91
+ 'sb-item',
92
+ item.key === active ? 'active' : '',
93
+ item.disabled ? 'disabled' : '',
94
+ ]
95
+ .filter(Boolean)
96
+ .join(' ');
97
+
98
+ const row = (
99
+ <div
100
+ className={itemCls}
101
+ role="button"
102
+ tabIndex={item.disabled ? undefined : 0}
103
+ aria-disabled={item.disabled || undefined}
104
+ aria-current={item.key === active ? 'page' : undefined}
105
+ onClick={() => {
106
+ if (item.disabled) return;
107
+ if (isGroup) toggleGroup(item.key);
108
+ else if (onNav) onNav(item.key);
109
+ }}
110
+ >
111
+ {item.icon != null ? <span className="ic">{item.icon}</span> : null}
112
+ <span className="label">{item.label}</span>
113
+ {item.badge ? (
114
+ <span className={['sb-badge', item.badgeTone || ''].filter(Boolean).join(' ')}>{item.badge}</span>
115
+ ) : item.count != null ? (
116
+ <span className="sb-count">{item.count}</span>
117
+ ) : null}
118
+ {isGroup ? <ChevGlyph /> : null}
119
+ </div>
120
+ );
121
+
122
+ if (!isGroup) return <React.Fragment key={item.key}>{row}</React.Fragment>;
123
+
124
+ return (
125
+ <div key={item.key} className="sb-group" aria-expanded={expanded}>
126
+ {row}
127
+ <div className="sb-children">
128
+ <div className="sb-children-inner">
129
+ {item.children!.map((c) => (
130
+ <div
131
+ key={c.key}
132
+ className={['sb-subitem', c.key === active ? 'active' : ''].filter(Boolean).join(' ')}
133
+ role="button"
134
+ tabIndex={0}
135
+ aria-current={c.key === active ? 'page' : undefined}
136
+ onClick={() => onNav && onNav(c.key)}
137
+ >
138
+ <span className="label">{c.label}</span>
139
+ {c.count != null ? <span className="sb-count">{c.count}</span> : null}
140
+ </div>
141
+ ))}
142
+ </div>
143
+ </div>
144
+ </div>
145
+ );
146
+ };
147
+
148
+ return (
149
+ <aside
150
+ className={['sb', app ? 'sb-app' : '', collapsed ? 'collapsed' : '', className || ''].filter(Boolean).join(' ')}
151
+ style={style}
152
+ onKeyDown={(e) => {
153
+ // Rail keyboard nav (doc a11y contract): ↑/↓ move between items
154
+ // (wrapping), Home/End jump; Enter/Space activate via role=button.
155
+ const nav = e.currentTarget;
156
+ const target = e.target as HTMLElement;
157
+ if (e.key === 'Enter' || e.key === ' ') {
158
+ if (target.matches('.sb-item, .sb-subitem')) { e.preventDefault(); target.click(); }
159
+ return;
160
+ }
161
+ if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Home' && e.key !== 'End') return;
162
+ const rows = Array.from(nav.querySelectorAll<HTMLElement>('.sb-item:not(.disabled), .sb-subitem'))
163
+ .filter((el) => el.offsetParent !== null); // skip collapsed-group children
164
+ if (!rows.length) return;
165
+ e.preventDefault();
166
+ const idx = rows.indexOf(target);
167
+ let next = 0;
168
+ if (e.key === 'ArrowDown') next = idx === -1 ? 0 : (idx + 1) % rows.length;
169
+ else if (e.key === 'ArrowUp') next = idx === -1 ? rows.length - 1 : (idx - 1 + rows.length) % rows.length;
170
+ else if (e.key === 'End') next = rows.length - 1;
171
+ rows[next].focus();
172
+ }}
173
+ >
174
+ {(logo != null || onToggleCollapse) && (
175
+ <div className="sb-head">
176
+ {logo}
177
+ {onToggleCollapse ? (
178
+ <button type="button" className="toggle" aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} onClick={onToggleCollapse}>
179
+ <PanelGlyph />
180
+ </button>
181
+ ) : null}
182
+ </div>
183
+ )}
184
+ <div className="sb-body">
185
+ {sections.map((s, i) => (
186
+ <React.Fragment key={i}>
187
+ {s.label != null ? <div className="sb-section">{s.label}</div> : null}
188
+ {s.items.map(renderItem)}
189
+ </React.Fragment>
190
+ ))}
191
+ </div>
192
+ {foot}
193
+ </aside>
194
+ );
195
+ };
196
+
197
+ export default AppSidebar;
@@ -1,58 +1,58 @@
1
- import * as React from 'react';
2
-
3
- export interface AppTopbarProps extends React.HTMLAttributes<HTMLDivElement> {
4
- /** Left CTA slot — the canonical Button (primary). */
5
- primary?: React.ReactNode;
6
- /** Search slot — the canonical SearchPill (grows to fill). */
7
- search?: React.ReactNode;
8
- /** Right-aligned cluster (.tb-spacer): TopbarControl/Live/Bell/Account. */
9
- children?: React.ReactNode;
10
- }
11
-
12
- export interface TopbarControlProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
13
- /** Leading slot (icon, flag…). */
14
- icon?: React.ReactNode;
15
- /** Square icon-only control (.tb-control.icon). */
16
- iconOnly?: boolean;
17
- /** Trailing disclosure chevron. */
18
- chev?: boolean;
19
- }
20
-
21
- export interface TopbarLiveProps {
22
- label?: React.ReactNode;
23
- /** Elapsed mono clock (e.g. "0:19"). */
24
- clock?: React.ReactNode;
25
- }
26
-
27
- export interface TopbarBellProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
28
- /** Unread red dot. */
29
- badge?: boolean;
30
- }
31
-
32
- export interface TopbarAccountItem {
33
- key: string;
34
- label: React.ReactNode;
35
- icon?: React.ReactNode;
36
- danger?: boolean;
37
- /** Renders a separator before this item. */
38
- sep?: boolean;
39
- }
40
-
41
- export interface TopbarAccountProps {
42
- initials: string;
43
- name: React.ReactNode;
44
- company: React.ReactNode;
45
- /** Second line in the dropdown head (e.g. "Acme Corp · Admin"). */
46
- detail?: React.ReactNode;
47
- items?: TopbarAccountItem[];
48
- onSelect?: (key: string) => void;
49
- /** Hide name/company in the trigger (mobile). */
50
- compact?: boolean;
51
- }
52
-
53
- export declare const AppTopbar: React.FC<AppTopbarProps>;
54
- export declare const TopbarControl: React.FC<TopbarControlProps>;
55
- export declare const TopbarLive: React.FC<TopbarLiveProps>;
56
- export declare const TopbarBell: React.FC<TopbarBellProps>;
57
- export declare const TopbarAccount: React.FC<TopbarAccountProps>;
58
- export default AppTopbar;
1
+ import * as React from 'react';
2
+
3
+ export interface AppTopbarProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ /** Left CTA slot — the canonical Button (primary). */
5
+ primary?: React.ReactNode;
6
+ /** Search slot — the canonical SearchPill (grows to fill). */
7
+ search?: React.ReactNode;
8
+ /** Right-aligned cluster (.tb-spacer): TopbarControl/Live/Bell/Account. */
9
+ children?: React.ReactNode;
10
+ }
11
+
12
+ export interface TopbarControlProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
13
+ /** Leading slot (icon, flag…). */
14
+ icon?: React.ReactNode;
15
+ /** Square icon-only control (.tb-control.icon). */
16
+ iconOnly?: boolean;
17
+ /** Trailing disclosure chevron. */
18
+ chev?: boolean;
19
+ }
20
+
21
+ export interface TopbarLiveProps {
22
+ label?: React.ReactNode;
23
+ /** Elapsed mono clock (e.g. "0:19"). */
24
+ clock?: React.ReactNode;
25
+ }
26
+
27
+ export interface TopbarBellProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
28
+ /** Unread red dot. */
29
+ badge?: boolean;
30
+ }
31
+
32
+ export interface TopbarAccountItem {
33
+ key: string;
34
+ label: React.ReactNode;
35
+ icon?: React.ReactNode;
36
+ danger?: boolean;
37
+ /** Renders a separator before this item. */
38
+ sep?: boolean;
39
+ }
40
+
41
+ export interface TopbarAccountProps {
42
+ initials: string;
43
+ name: React.ReactNode;
44
+ company: React.ReactNode;
45
+ /** Second line in the dropdown head (e.g. "Acme Corp · Admin"). */
46
+ detail?: React.ReactNode;
47
+ items?: TopbarAccountItem[];
48
+ onSelect?: (key: string) => void;
49
+ /** Hide name/company in the trigger (mobile). */
50
+ compact?: boolean;
51
+ }
52
+
53
+ export declare const AppTopbar: React.FC<AppTopbarProps>;
54
+ export declare const TopbarControl: React.FC<TopbarControlProps>;
55
+ export declare const TopbarLive: React.FC<TopbarLiveProps>;
56
+ export declare const TopbarBell: React.FC<TopbarBellProps>;
57
+ export declare const TopbarAccount: React.FC<TopbarAccountProps>;
58
+ export default AppTopbar;