@sovereignfs/ui 0.21.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 (141) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +24 -0
  3. package/dist/Avatar.module.css +38 -0
  4. package/dist/Badge.module.css +88 -0
  5. package/dist/Button.module.css +77 -0
  6. package/dist/Card.module.css +34 -0
  7. package/dist/Dialog.module.css +188 -0
  8. package/dist/Drawer.module.css +30 -0
  9. package/dist/EmptyState.module.css +27 -0
  10. package/dist/FormField.module.css +28 -0
  11. package/dist/Icon.module.css +22 -0
  12. package/dist/Input.module.css +37 -0
  13. package/dist/NavTabs.module.css +48 -0
  14. package/dist/PageHeader.module.css +32 -0
  15. package/dist/Popover.module.css +44 -0
  16. package/dist/SegmentedControl.module.css +53 -0
  17. package/dist/Select.module.css +69 -0
  18. package/dist/Spinner.module.css +39 -0
  19. package/dist/SystemBanner.module.css +67 -0
  20. package/dist/Tabs.module.css +49 -0
  21. package/dist/Toast.module.css +130 -0
  22. package/dist/Toggle.module.css +52 -0
  23. package/dist/Tooltip.module.css +51 -0
  24. package/dist/index.d.ts +327 -0
  25. package/dist/index.js +1370 -0
  26. package/dist/tokens/primitives.css +99 -0
  27. package/dist/tokens/semantic.css +111 -0
  28. package/dist/tokens.css +5 -0
  29. package/package.json +50 -0
  30. package/src/components/Avatar/Avatar.module.css +38 -0
  31. package/src/components/Avatar/Avatar.tsx +42 -0
  32. package/src/components/Badge/Badge.module.css +88 -0
  33. package/src/components/Badge/Badge.stories.tsx +118 -0
  34. package/src/components/Badge/Badge.tsx +59 -0
  35. package/src/components/Badge/__tests__/Badge.test.tsx +64 -0
  36. package/src/components/Button/Button.module.css +77 -0
  37. package/src/components/Button/Button.stories.tsx +76 -0
  38. package/src/components/Button/Button.tsx +36 -0
  39. package/src/components/Button/__tests__/Button.test.tsx +37 -0
  40. package/src/components/Card/Card.module.css +34 -0
  41. package/src/components/Card/Card.tsx +34 -0
  42. package/src/components/Dialog/Dialog.module.css +188 -0
  43. package/src/components/Dialog/Dialog.stories.tsx +97 -0
  44. package/src/components/Dialog/Dialog.tsx +137 -0
  45. package/src/components/Dialog/__tests__/Dialog.test.tsx +73 -0
  46. package/src/components/Drawer/Drawer.module.css +30 -0
  47. package/src/components/Drawer/Drawer.stories.tsx +88 -0
  48. package/src/components/Drawer/Drawer.tsx +103 -0
  49. package/src/components/Drawer/__tests__/Drawer.test.tsx +56 -0
  50. package/src/components/EmptyState/EmptyState.module.css +27 -0
  51. package/src/components/EmptyState/EmptyState.tsx +27 -0
  52. package/src/components/FormField/FormField.module.css +28 -0
  53. package/src/components/FormField/FormField.tsx +53 -0
  54. package/src/components/Icon/Icon.module.css +22 -0
  55. package/src/components/Icon/Icon.stories.tsx +94 -0
  56. package/src/components/Icon/Icon.tsx +43 -0
  57. package/src/components/Icon/__tests__/Icon.test.tsx +40 -0
  58. package/src/components/Icon/icons/activity.tsx +20 -0
  59. package/src/components/Icon/icons/alert-triangle.tsx +22 -0
  60. package/src/components/Icon/icons/bell.tsx +21 -0
  61. package/src/components/Icon/icons/check.tsx +20 -0
  62. package/src/components/Icon/icons/chevron-down.tsx +20 -0
  63. package/src/components/Icon/icons/chevron-left.tsx +20 -0
  64. package/src/components/Icon/icons/chevron-right.tsx +20 -0
  65. package/src/components/Icon/icons/chevron-up.tsx +20 -0
  66. package/src/components/Icon/icons/eye-off.tsx +23 -0
  67. package/src/components/Icon/icons/eye.tsx +21 -0
  68. package/src/components/Icon/icons/grid-2x2.tsx +22 -0
  69. package/src/components/Icon/icons/house.tsx +21 -0
  70. package/src/components/Icon/icons/index.ts +122 -0
  71. package/src/components/Icon/icons/info.tsx +22 -0
  72. package/src/components/Icon/icons/lock.tsx +21 -0
  73. package/src/components/Icon/icons/log-out.tsx +22 -0
  74. package/src/components/Icon/icons/mail.tsx +21 -0
  75. package/src/components/Icon/icons/package.tsx +23 -0
  76. package/src/components/Icon/icons/pencil.tsx +21 -0
  77. package/src/components/Icon/icons/plus.tsx +21 -0
  78. package/src/components/Icon/icons/rotate-ccw.tsx +21 -0
  79. package/src/components/Icon/icons/search.tsx +21 -0
  80. package/src/components/Icon/icons/settings.tsx +21 -0
  81. package/src/components/Icon/icons/shield.tsx +20 -0
  82. package/src/components/Icon/icons/sliders-horizontal.tsx +28 -0
  83. package/src/components/Icon/icons/terminal.tsx +19 -0
  84. package/src/components/Icon/icons/trash-2.tsx +24 -0
  85. package/src/components/Icon/icons/user.tsx +21 -0
  86. package/src/components/Icon/icons/x.tsx +21 -0
  87. package/src/components/Input/Input.module.css +37 -0
  88. package/src/components/Input/Input.stories.tsx +86 -0
  89. package/src/components/Input/Input.tsx +14 -0
  90. package/src/components/Input/__tests__/Input.test.tsx +22 -0
  91. package/src/components/NavTabs/NavTabs.module.css +48 -0
  92. package/src/components/NavTabs/NavTabs.tsx +33 -0
  93. package/src/components/PageHeader/PageHeader.module.css +32 -0
  94. package/src/components/PageHeader/PageHeader.tsx +21 -0
  95. package/src/components/Popover/Popover.module.css +44 -0
  96. package/src/components/Popover/Popover.stories.tsx +232 -0
  97. package/src/components/Popover/Popover.tsx +75 -0
  98. package/src/components/Popover/__tests__/Popover.test.tsx +98 -0
  99. package/src/components/SegmentedControl/SegmentedControl.module.css +53 -0
  100. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +118 -0
  101. package/src/components/SegmentedControl/SegmentedControl.tsx +56 -0
  102. package/src/components/SegmentedControl/__tests__/SegmentedControl.test.tsx +63 -0
  103. package/src/components/Select/Select.module.css +69 -0
  104. package/src/components/Select/Select.stories.tsx +115 -0
  105. package/src/components/Select/Select.tsx +40 -0
  106. package/src/components/Select/__tests__/Select.test.tsx +59 -0
  107. package/src/components/Spinner/Spinner.module.css +39 -0
  108. package/src/components/Spinner/Spinner.tsx +23 -0
  109. package/src/components/SystemBanner/SystemBanner.module.css +67 -0
  110. package/src/components/SystemBanner/SystemBanner.stories.tsx +86 -0
  111. package/src/components/SystemBanner/SystemBanner.tsx +50 -0
  112. package/src/components/SystemBanner/__tests__/SystemBanner.test.tsx +50 -0
  113. package/src/components/Tabs/Tabs.module.css +49 -0
  114. package/src/components/Tabs/Tabs.stories.tsx +100 -0
  115. package/src/components/Tabs/Tabs.tsx +46 -0
  116. package/src/components/Tabs/__tests__/Tabs.test.tsx +45 -0
  117. package/src/components/Toast/Toast.module.css +130 -0
  118. package/src/components/Toast/Toast.stories.tsx +191 -0
  119. package/src/components/Toast/Toast.tsx +139 -0
  120. package/src/components/Toggle/Toggle.module.css +52 -0
  121. package/src/components/Toggle/Toggle.stories.tsx +95 -0
  122. package/src/components/Toggle/Toggle.tsx +39 -0
  123. package/src/components/Toggle/__tests__/Toggle.test.tsx +47 -0
  124. package/src/components/Tooltip/Tooltip.module.css +51 -0
  125. package/src/components/Tooltip/Tooltip.tsx +30 -0
  126. package/src/css-modules.d.ts +4 -0
  127. package/src/index.ts +45 -0
  128. package/src/stories/Avatar.stories.tsx +44 -0
  129. package/src/stories/Card.stories.tsx +35 -0
  130. package/src/stories/DesignSystemOverview.stories.tsx +1683 -0
  131. package/src/stories/EmptyState.stories.tsx +33 -0
  132. package/src/stories/FormField.stories.tsx +47 -0
  133. package/src/stories/MobilePatterns.stories.tsx +1285 -0
  134. package/src/stories/NavTabs.stories.tsx +35 -0
  135. package/src/stories/PageHeader.stories.tsx +31 -0
  136. package/src/stories/Spinner.stories.tsx +25 -0
  137. package/src/stories/TokenGallery.stories.tsx +355 -0
  138. package/src/stories/Tooltip.stories.tsx +59 -0
  139. package/src/tokens/primitives.css +99 -0
  140. package/src/tokens/semantic.css +111 -0
  141. package/src/tokens.css +5 -0
@@ -0,0 +1,35 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { NavTabs } from '../components/NavTabs/NavTabs';
3
+
4
+ const items = [
5
+ { label: 'Overview', href: '#overview', active: true },
6
+ { label: 'Users', href: '#users' },
7
+ { label: 'Plugins', href: '#plugins' },
8
+ { label: 'Settings', href: '#settings' },
9
+ ];
10
+
11
+ const meta = {
12
+ title: 'Components/NavTabs',
13
+ component: NavTabs,
14
+ parameters: { layout: 'padded' },
15
+ args: { items },
16
+ } satisfies Meta<typeof NavTabs>;
17
+
18
+ export default meta;
19
+ type Story = StoryObj<typeof meta>;
20
+
21
+ export const Default: Story = {};
22
+
23
+ export const ManyTabs: Story = {
24
+ args: {
25
+ items: [
26
+ { label: 'Profile', href: '#profile', active: true },
27
+ { label: 'Security', href: '#security' },
28
+ { label: 'Notifications', href: '#notifications' },
29
+ { label: 'Preferences', href: '#preferences' },
30
+ { label: 'Data & Privacy', href: '#data' },
31
+ { label: 'Sessions', href: '#sessions' },
32
+ ],
33
+ },
34
+ parameters: { viewport: { defaultViewport: 'mobile' } },
35
+ };
@@ -0,0 +1,31 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { PageHeader } from '../components/PageHeader/PageHeader';
3
+ import { Button } from '../components/Button/Button';
4
+
5
+ const meta = {
6
+ title: 'Components/PageHeader',
7
+ component: PageHeader,
8
+ parameters: { layout: 'padded' },
9
+ } satisfies Meta<typeof PageHeader>;
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default: Story = {
15
+ args: { title: 'Users' },
16
+ };
17
+
18
+ export const WithDescription: Story = {
19
+ args: {
20
+ title: 'Users',
21
+ description: 'Manage who has access to this instance.',
22
+ },
23
+ };
24
+
25
+ export const WithAction: Story = {
26
+ args: {
27
+ title: 'Users',
28
+ description: 'Manage who has access to this instance.',
29
+ action: <Button size="sm">Invite user</Button>,
30
+ },
31
+ };
@@ -0,0 +1,25 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Spinner } from '../components/Spinner/Spinner';
3
+
4
+ const meta = {
5
+ title: 'Components/Spinner',
6
+ component: Spinner,
7
+ parameters: { layout: 'centered' },
8
+ } satisfies Meta<typeof Spinner>;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default: Story = {};
14
+ export const Small: Story = { args: { size: 'sm' } };
15
+ export const Large: Story = { args: { size: 'lg' } };
16
+
17
+ export const AllSizes: Story = {
18
+ render: () => (
19
+ <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
20
+ <Spinner size="sm" />
21
+ <Spinner size="md" />
22
+ <Spinner size="lg" />
23
+ </div>
24
+ ),
25
+ };
@@ -0,0 +1,355 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Token Gallery — live rendering of every CSS custom property tier.
5
+ // Values are read from the computed style at render time so they always
6
+ // reflect the actual loaded CSS, not a hardcoded snapshot. Toggle dark mode
7
+ // via the Themes toolbar to compare both theme values side-by-side.
8
+ // ---------------------------------------------------------------------------
9
+
10
+ const SEMANTIC_COLORS = [
11
+ '--sv-color-surface',
12
+ '--sv-color-surface-sunken',
13
+ '--sv-color-surface-raised',
14
+ '--sv-color-text-primary',
15
+ '--sv-color-text-muted',
16
+ '--sv-color-text-subtle',
17
+ '--sv-color-text-on-accent',
18
+ '--sv-color-border',
19
+ '--sv-color-border-strong',
20
+ '--sv-color-accent',
21
+ '--sv-color-accent-hover',
22
+ '--sv-color-focus-ring',
23
+ '--sv-color-error-surface',
24
+ '--sv-color-error-text',
25
+ '--sv-color-error-border',
26
+ '--sv-color-warning-surface',
27
+ '--sv-color-warning-text',
28
+ '--sv-color-warning-border',
29
+ '--sv-color-success-surface',
30
+ '--sv-color-success-text',
31
+ '--sv-color-success-border',
32
+ '--sv-color-info-surface',
33
+ '--sv-color-info-text',
34
+ '--sv-color-info-border',
35
+ '--sv-color-scrim',
36
+ ];
37
+
38
+ const SPACE_TOKENS = [
39
+ '--sv-space-1',
40
+ '--sv-space-2',
41
+ '--sv-space-3',
42
+ '--sv-space-4',
43
+ '--sv-space-5',
44
+ '--sv-space-6',
45
+ '--sv-space-8',
46
+ '--sv-space-10',
47
+ '--sv-space-12',
48
+ '--sv-space-16',
49
+ ];
50
+
51
+ const RADIUS_TOKENS = [
52
+ '--sv-radius-sm',
53
+ '--sv-radius-md',
54
+ '--sv-radius-lg',
55
+ '--sv-radius-xl',
56
+ '--sv-radius-2xl',
57
+ '--sv-radius-3xl',
58
+ '--sv-radius-full',
59
+ ];
60
+ const ICON_SIZE_TOKENS = ['--sv-icon-size-sm', '--sv-icon-size-md', '--sv-icon-size-lg'];
61
+
62
+ const FONT_SIZE_TOKENS = [
63
+ '--sv-font-size-label',
64
+ '--sv-font-size-xs',
65
+ '--sv-font-size-caption',
66
+ '--sv-font-size-sm',
67
+ '--sv-font-size-md',
68
+ '--sv-font-size-lg',
69
+ '--sv-font-size-xl',
70
+ '--sv-font-size-2xl',
71
+ ];
72
+
73
+ const FONT_WEIGHT_TOKENS = [
74
+ '--sv-font-weight-normal',
75
+ '--sv-font-weight-medium',
76
+ '--sv-font-weight-semibold',
77
+ '--sv-font-weight-bold',
78
+ ];
79
+
80
+ const SHADOW_TOKENS = [
81
+ '--sv-shadow-card',
82
+ '--sv-shadow-hover',
83
+ '--sv-shadow-popover',
84
+ '--sv-shadow-overlay',
85
+ ];
86
+
87
+ // ---------------------------------------------------------------------------
88
+
89
+ const row: React.CSSProperties = {
90
+ display: 'flex',
91
+ alignItems: 'center',
92
+ gap: '12px',
93
+ padding: '6px 0',
94
+ borderBottom: '1px solid var(--sv-color-border)',
95
+ };
96
+
97
+ const label: React.CSSProperties = {
98
+ fontFamily: 'monospace',
99
+ fontSize: '13px',
100
+ color: 'var(--sv-color-text-primary)',
101
+ minWidth: '300px',
102
+ };
103
+
104
+ const value: React.CSSProperties = {
105
+ fontFamily: 'monospace',
106
+ fontSize: '12px',
107
+ color: 'var(--sv-color-text-muted)',
108
+ flex: 1,
109
+ };
110
+
111
+ // ---------------------------------------------------------------------------
112
+
113
+ function ColorRow({ token }: { token: string }) {
114
+ const computed =
115
+ typeof window !== 'undefined'
116
+ ? getComputedStyle(document.documentElement).getPropertyValue(token).trim()
117
+ : '';
118
+ const swatch: React.CSSProperties = {
119
+ width: 28,
120
+ height: 28,
121
+ borderRadius: 4,
122
+ background: `var(${token})`,
123
+ border: '1px solid var(--sv-color-border)',
124
+ flexShrink: 0,
125
+ };
126
+ return (
127
+ <div style={row}>
128
+ <div style={swatch} />
129
+ <span style={label}>{token}</span>
130
+ <span style={value}>{computed}</span>
131
+ </div>
132
+ );
133
+ }
134
+
135
+ function ScaleRow({
136
+ token,
137
+ renderPreview,
138
+ }: {
139
+ token: string;
140
+ renderPreview: (v: string) => React.ReactNode;
141
+ }) {
142
+ const computed =
143
+ typeof window !== 'undefined'
144
+ ? getComputedStyle(document.documentElement).getPropertyValue(token).trim()
145
+ : '';
146
+ return (
147
+ <div style={row}>
148
+ {renderPreview(computed)}
149
+ <span style={label}>{token}</span>
150
+ <span style={value}>{computed}</span>
151
+ </div>
152
+ );
153
+ }
154
+
155
+ function Section({ title, children }: { title: string; children: React.ReactNode }) {
156
+ return (
157
+ <section style={{ marginBottom: 40 }}>
158
+ <h2
159
+ style={{
160
+ fontFamily: 'var(--sv-font-family)',
161
+ fontSize: 18,
162
+ fontWeight: 600,
163
+ color: 'var(--sv-color-text-primary)',
164
+ marginBottom: 12,
165
+ borderBottom: '2px solid var(--sv-color-accent)',
166
+ paddingBottom: 4,
167
+ }}
168
+ >
169
+ {title}
170
+ </h2>
171
+ {children}
172
+ </section>
173
+ );
174
+ }
175
+
176
+ // ---------------------------------------------------------------------------
177
+
178
+ function TokenGalleryComponent() {
179
+ return (
180
+ <div
181
+ style={{
182
+ padding: 24,
183
+ background: 'var(--sv-color-surface)',
184
+ minHeight: '100vh',
185
+ fontFamily: 'var(--sv-font-family)',
186
+ }}
187
+ >
188
+ <h1
189
+ style={{
190
+ fontSize: 24,
191
+ fontWeight: 700,
192
+ color: 'var(--sv-color-text-primary)',
193
+ marginBottom: 8,
194
+ }}
195
+ >
196
+ Sovereign Design Token Gallery
197
+ </h1>
198
+ <p style={{ color: 'var(--sv-color-text-muted)', marginBottom: 32, fontSize: 14 }}>
199
+ All values are read live from computed styles — they reflect the actual loaded CSS, not a
200
+ hardcoded snapshot. Use the Themes toolbar above to switch dark mode.
201
+ </p>
202
+
203
+ <Section title="Semantic colours">
204
+ {SEMANTIC_COLORS.map((t) => (
205
+ <ColorRow key={t} token={t} />
206
+ ))}
207
+ </Section>
208
+
209
+ <Section title="Space scale">
210
+ {SPACE_TOKENS.map((t) => (
211
+ <ScaleRow
212
+ key={t}
213
+ token={t}
214
+ renderPreview={(_v) => (
215
+ <div
216
+ style={{
217
+ width: `var(${t})`,
218
+ height: 16,
219
+ background: 'var(--sv-color-accent)',
220
+ flexShrink: 0,
221
+ minWidth: 4,
222
+ }}
223
+ />
224
+ )}
225
+ />
226
+ ))}
227
+ </Section>
228
+
229
+ <Section title="Font weight scale">
230
+ {FONT_WEIGHT_TOKENS.map((t) => (
231
+ <ScaleRow
232
+ key={t}
233
+ token={t}
234
+ renderPreview={(_v) => (
235
+ <span
236
+ style={{
237
+ fontFamily: 'var(--sv-font-family)',
238
+ fontSize: 'var(--sv-font-size-md)',
239
+ fontWeight: `var(${t})`,
240
+ color: 'var(--sv-color-text-primary)',
241
+ minWidth: 100,
242
+ }}
243
+ >
244
+ Sovereign
245
+ </span>
246
+ )}
247
+ />
248
+ ))}
249
+ </Section>
250
+
251
+ <Section title="Typography scale">
252
+ {FONT_SIZE_TOKENS.map((t) => (
253
+ <ScaleRow
254
+ key={t}
255
+ token={t}
256
+ renderPreview={(_v) => (
257
+ <span
258
+ style={{
259
+ fontSize: `var(${t})`,
260
+ color: 'var(--sv-color-text-primary)',
261
+ minWidth: 100,
262
+ lineHeight: 1,
263
+ }}
264
+ >
265
+ Aa
266
+ </span>
267
+ )}
268
+ />
269
+ ))}
270
+ </Section>
271
+
272
+ <Section title="Radius scale">
273
+ {RADIUS_TOKENS.map((t) => (
274
+ <ScaleRow
275
+ key={t}
276
+ token={t}
277
+ renderPreview={(_v) => (
278
+ <div
279
+ style={{
280
+ width: 40,
281
+ height: 24,
282
+ background: 'var(--sv-color-accent)',
283
+ borderRadius: `var(${t})`,
284
+ flexShrink: 0,
285
+ }}
286
+ />
287
+ )}
288
+ />
289
+ ))}
290
+ </Section>
291
+
292
+ <Section title="Icon sizes">
293
+ {ICON_SIZE_TOKENS.map((t) => (
294
+ <ScaleRow
295
+ key={t}
296
+ token={t}
297
+ renderPreview={(_v) => (
298
+ <div
299
+ style={{
300
+ width: `var(${t})`,
301
+ height: `var(${t})`,
302
+ background: 'var(--sv-color-accent)',
303
+ borderRadius: 2,
304
+ flexShrink: 0,
305
+ }}
306
+ />
307
+ )}
308
+ />
309
+ ))}
310
+ </Section>
311
+
312
+ <Section title="Shadows">
313
+ {SHADOW_TOKENS.map((t) => (
314
+ <ScaleRow
315
+ key={t}
316
+ token={t}
317
+ renderPreview={(_v) => (
318
+ <div
319
+ style={{
320
+ width: 48,
321
+ height: 28,
322
+ background: 'var(--sv-color-surface-raised)',
323
+ boxShadow: `var(${t})`,
324
+ borderRadius: 4,
325
+ flexShrink: 0,
326
+ }}
327
+ />
328
+ )}
329
+ />
330
+ ))}
331
+ </Section>
332
+ </div>
333
+ );
334
+ }
335
+
336
+ // ---------------------------------------------------------------------------
337
+
338
+ const meta = {
339
+ title: 'Design Tokens/Token Gallery',
340
+ component: TokenGalleryComponent,
341
+ parameters: {
342
+ layout: 'fullscreen',
343
+ docs: {
344
+ description: {
345
+ component:
346
+ 'Live gallery of every `--sv-*` CSS custom property. Values are read from `getComputedStyle` at render time — toggle dark mode via the Themes toolbar to see both themes.',
347
+ },
348
+ },
349
+ },
350
+ } satisfies Meta<typeof TokenGalleryComponent>;
351
+
352
+ export default meta;
353
+ type Story = StoryObj<typeof meta>;
354
+
355
+ export const AllTokens: Story = {};
@@ -0,0 +1,59 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Tooltip } from '../components/Tooltip/Tooltip';
3
+ import { Button } from '../components/Button/Button';
4
+ import { Icon } from '../components/Icon/Icon';
5
+
6
+ const meta = {
7
+ title: 'Components/Tooltip',
8
+ component: Tooltip,
9
+ parameters: { layout: 'centered' },
10
+ } satisfies Meta<typeof Tooltip>;
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof meta>;
14
+
15
+ export const Default: Story = {
16
+ args: {
17
+ content: 'This is a tooltip',
18
+ children: <Button variant="secondary">Hover me</Button>,
19
+ },
20
+ };
21
+
22
+ export const OnIcon: Story = {
23
+ args: {
24
+ content: 'More information',
25
+ children: (
26
+ <span style={{ color: 'var(--sv-color-text-muted)', cursor: 'default' }}>
27
+ <Icon name="info" size="md" aria-label="Info" />
28
+ </span>
29
+ ),
30
+ },
31
+ };
32
+
33
+ export const Sides: Story = {
34
+ args: { content: '', children: <span /> },
35
+ render: () => (
36
+ <div style={{ display: 'flex', gap: 48, alignItems: 'center', padding: 48 }}>
37
+ <Tooltip content="Top" side="top">
38
+ <Button variant="ghost" size="sm">
39
+ Top
40
+ </Button>
41
+ </Tooltip>
42
+ <Tooltip content="Bottom" side="bottom">
43
+ <Button variant="ghost" size="sm">
44
+ Bottom
45
+ </Button>
46
+ </Tooltip>
47
+ <Tooltip content="Left" side="left">
48
+ <Button variant="ghost" size="sm">
49
+ Left
50
+ </Button>
51
+ </Tooltip>
52
+ <Tooltip content="Right" side="right">
53
+ <Button variant="ghost" size="sm">
54
+ Right
55
+ </Button>
56
+ </Tooltip>
57
+ </div>
58
+ ),
59
+ };
@@ -0,0 +1,99 @@
1
+ /*
2
+ * Sovereign Design System — primitive tokens.
3
+ *
4
+ * Raw, context-free scales: the palette, spacing, type, and radii. These are
5
+ * fixed — tenant theming never overrides primitives (it overrides the semantic
6
+ * layer in semantic.css). Plugin code should reference SEMANTIC colour tokens,
7
+ * not these primitives directly.
8
+ */
9
+ :root {
10
+ /* Neutral grey scale (monochrome identity) */
11
+ --sv-white: #ffffff;
12
+
13
+ /* Status colour primitives — amber (warning), green (success), red (error), blue (info).
14
+ Kept minimal: only the swatches the semantic status tokens reference.
15
+ Hex values align with the v3.1 design spec. */
16
+ --sv-amber-100: #fff7ed;
17
+ --sv-amber-200: #fed7aa;
18
+ --sv-amber-800: #b45309;
19
+ --sv-amber-900: #92400e;
20
+ --sv-green-100: #ecfdf3;
21
+ --sv-green-200: #bbf7d0;
22
+ --sv-green-800: #167c4a;
23
+ --sv-green-900: #14532d;
24
+ --sv-red-100: #fef2f2;
25
+ --sv-red-200: #fecaca;
26
+ --sv-red-700: #b91c1c;
27
+ --sv-red-800: #991b1b;
28
+ --sv-red-900: #7f1d1d;
29
+ --sv-blue-100: #eff6ff;
30
+ --sv-blue-200: #dbeafe;
31
+ --sv-blue-800: #1d4ed8;
32
+ --sv-blue-900: #1e3a8a;
33
+ --sv-black: #000000;
34
+ --sv-grey-50: #fafafa;
35
+ --sv-grey-100: #f4f4f5;
36
+ --sv-grey-200: #e4e4e7;
37
+ --sv-grey-300: #d4d4d8;
38
+ --sv-grey-400: #a1a1aa;
39
+ --sv-grey-500: #71717a;
40
+ --sv-grey-600: #52525b;
41
+ --sv-grey-700: #3f3f46;
42
+ --sv-grey-800: #27272a;
43
+ --sv-grey-900: #18181b;
44
+ --sv-grey-950: #09090b;
45
+
46
+ /* Spacing scale (4px base) */
47
+ --sv-space-1: 0.25rem;
48
+ --sv-space-2: 0.5rem;
49
+ --sv-space-3: 0.75rem;
50
+ --sv-space-4: 1rem;
51
+ --sv-space-5: 1.25rem;
52
+ --sv-space-6: 1.5rem;
53
+ --sv-space-8: 2rem;
54
+ --sv-space-10: 2.5rem;
55
+ --sv-space-12: 3rem;
56
+ --sv-space-16: 4rem;
57
+
58
+ /* Typography
59
+ Default pair: Hanken Grotesk (body) + JetBrains Mono (code/identifiers).
60
+ Operators supply the web font via <link> or instance CSS; the fallback
61
+ stack applies when the font is not loaded. */
62
+ --sv-font-family:
63
+ 'Hanken Grotesk', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial,
64
+ sans-serif;
65
+ --sv-font-family-mono:
66
+ 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
67
+ --sv-font-size-label: 0.6875rem; /* 11px — all-caps section labels */
68
+ --sv-font-size-xs: 0.75rem; /* 12px — mono identifiers */
69
+ --sv-font-size-caption: 0.8125rem; /* 13px — secondary / supporting copy */
70
+ --sv-font-size-sm: 0.875rem; /* 14px — body copy */
71
+ --sv-font-size-md: 1rem; /* 16px */
72
+ --sv-font-size-lg: 1.125rem; /* 18px */
73
+ --sv-font-size-xl: 1.25rem; /* 20px */
74
+ --sv-font-size-2xl: 1.5rem; /* 24px */
75
+ --sv-font-weight-regular: 400;
76
+ --sv-font-weight-medium: 500;
77
+ --sv-font-weight-semibold: 600;
78
+ --sv-font-weight-bold: 700;
79
+
80
+ /* Icon sizes — scale tokens used directly by the Icon component */
81
+ --sv-icon-size-sm: 1rem; /* 16px — inline with body text */
82
+ --sv-icon-size-md: 1.25rem; /* 20px — standard affordance */
83
+ --sv-icon-size-lg: 1.5rem; /* 24px — prominent / standalone */
84
+
85
+ /* Border radii (v3.1 spec values) */
86
+ --sv-radius-sm: 0.375rem; /* 6px — badge, tag */
87
+ --sv-radius-md: 0.5rem; /* 8px — button, input */
88
+ --sv-radius-lg: 0.6875rem; /* 11px — sidebar icon, card */
89
+ --sv-radius-xl: 0.75rem; /* 12px — card, panel */
90
+ --sv-radius-2xl: 0.875rem; /* 14px — popover */
91
+ --sv-radius-3xl: 1.25rem; /* 20px — bottom sheet (Drawer top corners) */
92
+ --sv-radius-full: 9999px; /* pill / avatar */
93
+
94
+ /* Touch targets — minimum hit-area dimension for interactive controls.
95
+ 44px follows the WCAG 2.5.5 / Apple HIG / Material guideline for reliable
96
+ touch without a pointing device. Applied to icon-only controls on mobile
97
+ (avatar, footer button, Drawer nav items). */
98
+ --sv-touch-target-min: 44px;
99
+ }