@sovereignfs/ui 0.40.0 → 0.45.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.
- package/dist/Accordion.module.css +3 -0
- package/dist/Alert.module.css +62 -0
- package/dist/AspectRatio.module.css +15 -0
- package/dist/Badge.module.css +75 -9
- package/dist/BalanceChip.module.css +32 -0
- package/dist/Breadcrumb.module.css +49 -0
- package/dist/Button.module.css +12 -3
- package/dist/ButtonGroup.module.css +29 -0
- package/dist/Card.module.css +6 -0
- package/dist/Checkbox.module.css +3 -1
- package/dist/Collapsible.module.css +70 -0
- package/dist/Combobox.module.css +122 -0
- package/dist/Command.module.css +80 -0
- package/dist/ConfirmDialog.module.css +5 -1
- package/dist/DataTable.module.css +28 -0
- package/dist/DatePicker.module.css +6 -2
- package/dist/Dialog.module.css +3 -0
- package/dist/HoverCard.module.css +3 -0
- package/dist/Input.module.css +6 -1
- package/dist/Item.module.css +70 -0
- package/dist/Kbd.module.css +14 -0
- package/dist/Label.module.css +11 -0
- package/dist/Marker.module.css +33 -0
- package/dist/MemberMultiSelect.module.css +27 -0
- package/dist/Menu.module.css +8 -1
- package/dist/Message.module.css +99 -0
- package/dist/MessageScroller.module.css +54 -0
- package/dist/NavigationMenu.module.css +53 -0
- package/dist/Pagination.module.css +98 -0
- package/dist/Progress.module.css +20 -0
- package/dist/RadioGroup.module.css +88 -0
- package/dist/Resizable.module.css +70 -0
- package/dist/ScrollArea.module.css +20 -0
- package/dist/Select.module.css +7 -3
- package/dist/Slider.module.css +95 -0
- package/dist/Table.module.css +45 -0
- package/dist/Tabs.module.css +6 -1
- package/dist/Toggle.module.css +6 -1
- package/dist/Typography.module.css +47 -0
- package/dist/index.d.ts +698 -5
- package/dist/index.js +1938 -482
- package/dist/tokens/primitives.css +22 -8
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.module.css +3 -0
- package/src/components/Accordion/Accordion.stories.tsx +110 -0
- package/src/components/Accordion/Accordion.tsx +53 -0
- package/src/components/Accordion/__tests__/Accordion.test.tsx +61 -0
- package/src/components/Alert/Alert.module.css +62 -0
- package/src/components/Alert/Alert.stories.tsx +96 -0
- package/src/components/Alert/Alert.tsx +58 -0
- package/src/components/Alert/__tests__/Alert.test.tsx +75 -0
- package/src/components/AspectRatio/AspectRatio.module.css +15 -0
- package/src/components/AspectRatio/AspectRatio.stories.tsx +78 -0
- package/src/components/AspectRatio/AspectRatio.tsx +21 -0
- package/src/components/AspectRatio/__tests__/AspectRatio.test.tsx +27 -0
- package/src/components/Badge/Badge.module.css +75 -9
- package/src/components/Badge/Badge.stories.tsx +109 -1
- package/src/components/Badge/Badge.tsx +30 -2
- package/src/components/Badge/__tests__/Badge.test.tsx +26 -2
- package/src/components/BalanceChip/BalanceChip.module.css +32 -0
- package/src/components/BalanceChip/BalanceChip.stories.tsx +45 -0
- package/src/components/BalanceChip/BalanceChip.tsx +33 -0
- package/src/components/Breadcrumb/Breadcrumb.module.css +49 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +47 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +57 -0
- package/src/components/Breadcrumb/__tests__/Breadcrumb.test.tsx +52 -0
- package/src/components/Button/Button.module.css +12 -3
- package/src/components/Button/Button.stories.tsx +3 -2
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Button/__tests__/Button.test.tsx +10 -0
- package/src/components/ButtonGroup/ButtonGroup.module.css +29 -0
- package/src/components/ButtonGroup/ButtonGroup.stories.tsx +57 -0
- package/src/components/ButtonGroup/ButtonGroup.tsx +27 -0
- package/src/components/ButtonGroup/__tests__/ButtonGroup.test.tsx +29 -0
- package/src/components/Card/Card.module.css +6 -0
- package/src/components/Checkbox/Checkbox.module.css +3 -1
- package/src/components/Collapsible/Collapsible.module.css +70 -0
- package/src/components/Collapsible/Collapsible.stories.tsx +62 -0
- package/src/components/Collapsible/Collapsible.tsx +66 -0
- package/src/components/Collapsible/__tests__/Collapsible.test.tsx +71 -0
- package/src/components/Combobox/Combobox.module.css +122 -0
- package/src/components/Combobox/Combobox.stories.tsx +79 -0
- package/src/components/Combobox/Combobox.tsx +186 -0
- package/src/components/Combobox/__tests__/Combobox.test.tsx +158 -0
- package/src/components/Command/Command.module.css +80 -0
- package/src/components/Command/Command.stories.tsx +104 -0
- package/src/components/Command/Command.tsx +168 -0
- package/src/components/Command/__tests__/Command.test.tsx +162 -0
- package/src/components/ConfirmDialog/ConfirmDialog.module.css +5 -1
- package/src/components/ContextMenu/ContextMenu.stories.tsx +81 -0
- package/src/components/ContextMenu/ContextMenu.tsx +100 -0
- package/src/components/ContextMenu/__tests__/ContextMenu.test.tsx +87 -0
- package/src/components/CurrencyInput/CurrencyInput.stories.tsx +50 -0
- package/src/components/CurrencyInput/CurrencyInput.tsx +60 -0
- package/src/components/DataTable/DataTable.module.css +28 -0
- package/src/components/DataTable/DataTable.stories.tsx +74 -0
- package/src/components/DataTable/DataTable.tsx +154 -0
- package/src/components/DataTable/__tests__/DataTable.test.tsx +123 -0
- package/src/components/DatePicker/DatePicker.module.css +6 -2
- package/src/components/Dialog/Dialog.module.css +3 -0
- package/src/components/HoverCard/HoverCard.module.css +3 -0
- package/src/components/HoverCard/HoverCard.stories.tsx +66 -0
- package/src/components/HoverCard/HoverCard.tsx +111 -0
- package/src/components/HoverCard/__tests__/HoverCard.test.tsx +99 -0
- package/src/components/Icon/icons/circle-check.tsx +21 -0
- package/src/components/Icon/icons/circle-x.tsx +22 -0
- package/src/components/Icon/icons/index.ts +8 -0
- package/src/components/Input/Input.module.css +6 -1
- package/src/components/Item/Item.module.css +70 -0
- package/src/components/Item/Item.stories.tsx +62 -0
- package/src/components/Item/Item.tsx +54 -0
- package/src/components/Item/__tests__/Item.test.tsx +39 -0
- package/src/components/Kbd/Kbd.module.css +14 -0
- package/src/components/Kbd/Kbd.stories.tsx +32 -0
- package/src/components/Kbd/Kbd.tsx +12 -0
- package/src/components/Kbd/__tests__/Kbd.test.tsx +14 -0
- package/src/components/Label/Label.module.css +11 -0
- package/src/components/Label/Label.stories.tsx +40 -0
- package/src/components/Label/Label.tsx +24 -0
- package/src/components/Label/__tests__/Label.test.tsx +32 -0
- package/src/components/Marker/Marker.module.css +33 -0
- package/src/components/Marker/Marker.stories.tsx +39 -0
- package/src/components/Marker/Marker.tsx +34 -0
- package/src/components/Marker/__tests__/Marker.test.tsx +23 -0
- package/src/components/MemberMultiSelect/MemberMultiSelect.module.css +27 -0
- package/src/components/MemberMultiSelect/MemberMultiSelect.stories.tsx +74 -0
- package/src/components/MemberMultiSelect/MemberMultiSelect.tsx +67 -0
- package/src/components/Menu/Menu.module.css +8 -1
- package/src/components/Menu/Menu.tsx +30 -8
- package/src/components/Menubar/Menubar.stories.tsx +52 -0
- package/src/components/Menubar/Menubar.tsx +42 -0
- package/src/components/Menubar/__tests__/Menubar.test.tsx +45 -0
- package/src/components/Message/Message.module.css +99 -0
- package/src/components/Message/Message.stories.tsx +79 -0
- package/src/components/Message/Message.tsx +41 -0
- package/src/components/Message/__tests__/Message.test.tsx +46 -0
- package/src/components/MessageScroller/MessageScroller.module.css +54 -0
- package/src/components/MessageScroller/MessageScroller.stories.tsx +84 -0
- package/src/components/MessageScroller/MessageScroller.tsx +72 -0
- package/src/components/MessageScroller/__tests__/MessageScroller.test.tsx +105 -0
- package/src/components/NavigationMenu/NavigationMenu.module.css +53 -0
- package/src/components/NavigationMenu/NavigationMenu.stories.tsx +58 -0
- package/src/components/NavigationMenu/NavigationMenu.tsx +125 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.test.tsx +93 -0
- package/src/components/Pagination/Pagination.module.css +98 -0
- package/src/components/Pagination/Pagination.stories.tsx +49 -0
- package/src/components/Pagination/Pagination.tsx +87 -0
- package/src/components/Pagination/__tests__/Pagination.test.tsx +56 -0
- package/src/components/Progress/Progress.module.css +20 -0
- package/src/components/Progress/Progress.stories.tsx +40 -0
- package/src/components/Progress/Progress.tsx +35 -0
- package/src/components/Progress/__tests__/Progress.test.tsx +31 -0
- package/src/components/RadioGroup/RadioGroup.module.css +88 -0
- package/src/components/RadioGroup/RadioGroup.stories.tsx +69 -0
- package/src/components/RadioGroup/RadioGroup.tsx +99 -0
- package/src/components/RadioGroup/__tests__/RadioGroup.test.tsx +59 -0
- package/src/components/Resizable/Resizable.module.css +70 -0
- package/src/components/Resizable/Resizable.stories.tsx +82 -0
- package/src/components/Resizable/Resizable.tsx +313 -0
- package/src/components/Resizable/__tests__/Resizable.test.tsx +128 -0
- package/src/components/ScrollArea/ScrollArea.module.css +20 -0
- package/src/components/ScrollArea/ScrollArea.stories.tsx +57 -0
- package/src/components/ScrollArea/ScrollArea.tsx +27 -0
- package/src/components/ScrollArea/__tests__/ScrollArea.test.tsx +39 -0
- package/src/components/Select/Select.module.css +7 -3
- package/src/components/Slider/Slider.module.css +95 -0
- package/src/components/Slider/Slider.stories.tsx +64 -0
- package/src/components/Slider/Slider.tsx +77 -0
- package/src/components/Slider/__tests__/Slider.test.tsx +45 -0
- package/src/components/SplitMethodSelector/SplitMethodSelector.stories.tsx +33 -0
- package/src/components/SplitMethodSelector/SplitMethodSelector.tsx +43 -0
- package/src/components/Table/Table.module.css +45 -0
- package/src/components/Table/Table.stories.tsx +125 -0
- package/src/components/Table/Table.tsx +51 -0
- package/src/components/Table/__tests__/Table.test.tsx +50 -0
- package/src/components/Tabs/Tabs.module.css +6 -1
- package/src/components/Toggle/Toggle.module.css +6 -1
- package/src/components/Typography/Typography.module.css +47 -0
- package/src/components/Typography/Typography.stories.tsx +62 -0
- package/src/components/Typography/Typography.tsx +30 -0
- package/src/components/Typography/__tests__/Typography.test.tsx +34 -0
- package/src/index.ts +92 -1
- package/src/stories/DesignSystemOverview.stories.tsx +706 -2
- package/src/stories/MobilePatterns.stories.tsx +8 -2
- package/src/stories/TokenGallery.stories.tsx +112 -16
- package/src/tokens/primitives.css +22 -8
|
@@ -33,6 +33,44 @@ import { ToastProvider, useToast } from '../components/Toast/Toast';
|
|
|
33
33
|
import { Toggle } from '../components/Toggle/Toggle';
|
|
34
34
|
import { Tooltip } from '../components/Tooltip/Tooltip';
|
|
35
35
|
import { Checkbox } from '../components/Checkbox/Checkbox';
|
|
36
|
+
import { RadioGroup } from '../components/RadioGroup/RadioGroup';
|
|
37
|
+
import { Slider } from '../components/Slider/Slider';
|
|
38
|
+
import { Progress } from '../components/Progress/Progress';
|
|
39
|
+
import {
|
|
40
|
+
Table,
|
|
41
|
+
TableHead,
|
|
42
|
+
TableBody,
|
|
43
|
+
TableRow,
|
|
44
|
+
TableHeaderCell,
|
|
45
|
+
TableCell,
|
|
46
|
+
} from '../components/Table/Table';
|
|
47
|
+
import { Alert } from '../components/Alert/Alert';
|
|
48
|
+
import { Breadcrumb } from '../components/Breadcrumb/Breadcrumb';
|
|
49
|
+
import { Pagination } from '../components/Pagination/Pagination';
|
|
50
|
+
import { Kbd } from '../components/Kbd/Kbd';
|
|
51
|
+
import { Accordion } from '../components/Accordion/Accordion';
|
|
52
|
+
import { AspectRatio } from '../components/AspectRatio/AspectRatio';
|
|
53
|
+
import { ButtonGroup } from '../components/ButtonGroup/ButtonGroup';
|
|
54
|
+
import { Item } from '../components/Item/Item';
|
|
55
|
+
import { Label } from '../components/Label/Label';
|
|
56
|
+
import { ScrollArea } from '../components/ScrollArea/ScrollArea';
|
|
57
|
+
import { Typography } from '../components/Typography/Typography';
|
|
58
|
+
import { Marker } from '../components/Marker/Marker';
|
|
59
|
+
import { Message } from '../components/Message/Message';
|
|
60
|
+
import { MessageScroller } from '../components/MessageScroller/MessageScroller';
|
|
61
|
+
import { HoverCard } from '../components/HoverCard/HoverCard';
|
|
62
|
+
import { ContextMenu } from '../components/ContextMenu/ContextMenu';
|
|
63
|
+
import { Command } from '../components/Command/Command';
|
|
64
|
+
import {
|
|
65
|
+
ResizableHandle,
|
|
66
|
+
ResizablePanel,
|
|
67
|
+
ResizablePanelGroup,
|
|
68
|
+
} from '../components/Resizable/Resizable';
|
|
69
|
+
import { DataTable } from '../components/DataTable/DataTable';
|
|
70
|
+
import { Combobox } from '../components/Combobox/Combobox';
|
|
71
|
+
import { NavigationMenu } from '../components/NavigationMenu/NavigationMenu';
|
|
72
|
+
import { Menubar } from '../components/Menubar/Menubar';
|
|
73
|
+
import { Collapsible } from '../components/Collapsible/Collapsible';
|
|
36
74
|
import { DragHandleRow } from '../components/DragHandleRow/DragHandleRow';
|
|
37
75
|
import { FileDropzone } from '../components/FileDropzone/FileDropzone';
|
|
38
76
|
import { OverlayHeader } from '../components/OverlayHeader/OverlayHeader';
|
|
@@ -41,6 +79,16 @@ import { ConfirmDialog } from '../components/ConfirmDialog/ConfirmDialog';
|
|
|
41
79
|
import { Menu } from '../components/Menu/Menu';
|
|
42
80
|
import { Calendar } from '../components/Calendar/Calendar';
|
|
43
81
|
import { DatePicker } from '../components/DatePicker/DatePicker';
|
|
82
|
+
import { CurrencyInput } from '../components/CurrencyInput/CurrencyInput';
|
|
83
|
+
import { BalanceChip } from '../components/BalanceChip/BalanceChip';
|
|
84
|
+
import {
|
|
85
|
+
SplitMethodSelector,
|
|
86
|
+
type SplitMethod,
|
|
87
|
+
} from '../components/SplitMethodSelector/SplitMethodSelector';
|
|
88
|
+
import {
|
|
89
|
+
MemberMultiSelect,
|
|
90
|
+
type MemberMultiSelectOption,
|
|
91
|
+
} from '../components/MemberMultiSelect/MemberMultiSelect';
|
|
44
92
|
|
|
45
93
|
// ---------------------------------------------------------------------------
|
|
46
94
|
// Shared primitives
|
|
@@ -456,6 +504,64 @@ function TabsDemo() {
|
|
|
456
504
|
);
|
|
457
505
|
}
|
|
458
506
|
|
|
507
|
+
function CommandDemo() {
|
|
508
|
+
const [open, setOpen] = useState(false);
|
|
509
|
+
return (
|
|
510
|
+
<>
|
|
511
|
+
<Button size="sm" onClick={() => setOpen(true)}>
|
|
512
|
+
Open command palette
|
|
513
|
+
</Button>
|
|
514
|
+
<Command
|
|
515
|
+
open={open}
|
|
516
|
+
onClose={() => setOpen(false)}
|
|
517
|
+
aria-label="Command palette"
|
|
518
|
+
items={[
|
|
519
|
+
{
|
|
520
|
+
id: 'new',
|
|
521
|
+
label: 'New conversation',
|
|
522
|
+
group: 'Actions',
|
|
523
|
+
icon: 'plus',
|
|
524
|
+
onSelect: () => {},
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
id: 'export',
|
|
528
|
+
label: 'Export chat',
|
|
529
|
+
group: 'Actions',
|
|
530
|
+
icon: 'upload',
|
|
531
|
+
onSelect: () => {},
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
id: 'profile',
|
|
535
|
+
label: 'Go to profile',
|
|
536
|
+
group: 'Navigation',
|
|
537
|
+
icon: 'user',
|
|
538
|
+
onSelect: () => {},
|
|
539
|
+
},
|
|
540
|
+
]}
|
|
541
|
+
/>
|
|
542
|
+
</>
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function ComboboxDemo() {
|
|
547
|
+
const [value, setValue] = useState<string | null>(null);
|
|
548
|
+
return (
|
|
549
|
+
<div style={{ width: 240 }}>
|
|
550
|
+
<Combobox
|
|
551
|
+
options={[
|
|
552
|
+
{ value: 'tasks', label: 'sovereign-tasks' },
|
|
553
|
+
{ value: 'ledger', label: 'sovereign-ledger' },
|
|
554
|
+
{ value: 'shopper', label: 'sovereign-shopper' },
|
|
555
|
+
]}
|
|
556
|
+
value={value}
|
|
557
|
+
onChange={setValue}
|
|
558
|
+
placeholder="Select a plugin"
|
|
559
|
+
aria-label="Plugin"
|
|
560
|
+
/>
|
|
561
|
+
</div>
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
|
|
459
565
|
function DialogDemo() {
|
|
460
566
|
const [open, setOpen] = useState(false);
|
|
461
567
|
return (
|
|
@@ -756,6 +862,50 @@ function CheckableListRowDemo() {
|
|
|
756
862
|
);
|
|
757
863
|
}
|
|
758
864
|
|
|
865
|
+
function CurrencyInputDemo() {
|
|
866
|
+
const [cents, setCents] = useState<number | null>(4250);
|
|
867
|
+
return (
|
|
868
|
+
<CurrencyInput
|
|
869
|
+
valueCents={cents}
|
|
870
|
+
onValueChange={setCents}
|
|
871
|
+
placeholder="0.00"
|
|
872
|
+
aria-label="Amount"
|
|
873
|
+
/>
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
function SplitMethodSelectorDemo() {
|
|
878
|
+
const [value, setValue] = useState<SplitMethod>('equal');
|
|
879
|
+
return <SplitMethodSelector value={value} onChange={setValue} />;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const MEMBER_MULTI_SELECT_OPTIONS: MemberMultiSelectOption[] = [
|
|
883
|
+
{ id: '1', label: 'Priya' },
|
|
884
|
+
{ id: '2', label: 'Jamie (guest)' },
|
|
885
|
+
{ id: '3', label: 'Sam' },
|
|
886
|
+
];
|
|
887
|
+
|
|
888
|
+
function MemberMultiSelectDemo() {
|
|
889
|
+
const [selected, setSelected] = useState<Set<string>>(new Set(['1', '3']));
|
|
890
|
+
return (
|
|
891
|
+
<div style={{ width: '100%' }}>
|
|
892
|
+
<MemberMultiSelect
|
|
893
|
+
options={MEMBER_MULTI_SELECT_OPTIONS}
|
|
894
|
+
selectedIds={selected}
|
|
895
|
+
onToggle={(id, checked) => {
|
|
896
|
+
setSelected((prev) => {
|
|
897
|
+
const next = new Set(prev);
|
|
898
|
+
if (checked) next.add(id);
|
|
899
|
+
else next.delete(id);
|
|
900
|
+
return next;
|
|
901
|
+
});
|
|
902
|
+
}}
|
|
903
|
+
label="Split between"
|
|
904
|
+
/>
|
|
905
|
+
</div>
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
|
|
759
909
|
function FileDropzoneDemo() {
|
|
760
910
|
const [file, setFile] = useState<File | null>(null);
|
|
761
911
|
return (
|
|
@@ -1454,7 +1604,7 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1454
1604
|
<ComponentCard
|
|
1455
1605
|
name="Button"
|
|
1456
1606
|
importLine="import { Button } from '@sovereignfs/ui';"
|
|
1457
|
-
usage="Primary interactive control. Four variants: primary, secondary, ghost, destructive.
|
|
1607
|
+
usage="Primary interactive control. Four variants: primary, secondary, ghost, destructive. Three sizes: lg, md (default), sm. loading disables the button, sets aria-busy, and shows a spinner. 44px min-height under (pointer: coarse); hover behind (hover: hover)."
|
|
1458
1608
|
>
|
|
1459
1609
|
<Button>Primary</Button>
|
|
1460
1610
|
<Button variant="secondary">Secondary</Button>
|
|
@@ -1462,6 +1612,7 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1462
1612
|
<Button variant="destructive" size="sm">
|
|
1463
1613
|
Delete
|
|
1464
1614
|
</Button>
|
|
1615
|
+
<Button size="lg">Large</Button>
|
|
1465
1616
|
<Button loading>Saving…</Button>
|
|
1466
1617
|
</ComponentCard>
|
|
1467
1618
|
|
|
@@ -1469,7 +1620,7 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1469
1620
|
<ComponentCard
|
|
1470
1621
|
name="Badge"
|
|
1471
1622
|
importLine="import { Badge } from '@sovereignfs/ui';"
|
|
1472
|
-
usage="Compact label for roles (role), lifecycle states (status), and type/version tags (mono). RSC-safe."
|
|
1623
|
+
usage="Compact label for roles (role), lifecycle states (status), and type/version tags (mono). sm/md/lg sizes; ALL CAPS by default, or uppercase={false} for title case. RSC-safe."
|
|
1473
1624
|
>
|
|
1474
1625
|
<Badge variant="role">Admin</Badge>
|
|
1475
1626
|
<Badge variant="status" status="active">
|
|
@@ -1479,6 +1630,9 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1479
1630
|
Invited
|
|
1480
1631
|
</Badge>
|
|
1481
1632
|
<Badge variant="mono">v1.2.0</Badge>
|
|
1633
|
+
<Badge variant="role" size="lg" uppercase={false}>
|
|
1634
|
+
Owner
|
|
1635
|
+
</Badge>
|
|
1482
1636
|
</ComponentCard>
|
|
1483
1637
|
|
|
1484
1638
|
{/* StatusBadge */}
|
|
@@ -1493,6 +1647,17 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1493
1647
|
<StatusBadge status="pending-delete" />
|
|
1494
1648
|
</ComponentCard>
|
|
1495
1649
|
|
|
1650
|
+
{/* BalanceChip */}
|
|
1651
|
+
<ComponentCard
|
|
1652
|
+
name="BalanceChip"
|
|
1653
|
+
importLine="import { BalanceChip } from '@sovereignfs/ui';"
|
|
1654
|
+
usage="Inline net-balance indicator — green when owed to them, red when they owe, neutral when settled. Not tied to expense-splitting specifically."
|
|
1655
|
+
>
|
|
1656
|
+
<BalanceChip amountCents={2500} currency="USD" />
|
|
1657
|
+
<BalanceChip amountCents={-1350} currency="USD" />
|
|
1658
|
+
<BalanceChip amountCents={0} currency="USD" />
|
|
1659
|
+
</ComponentCard>
|
|
1660
|
+
|
|
1496
1661
|
{/* Input */}
|
|
1497
1662
|
<ComponentCard
|
|
1498
1663
|
name="Input"
|
|
@@ -1505,6 +1670,15 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1505
1670
|
</div>
|
|
1506
1671
|
</ComponentCard>
|
|
1507
1672
|
|
|
1673
|
+
{/* CurrencyInput */}
|
|
1674
|
+
<ComponentCard
|
|
1675
|
+
name="CurrencyInput"
|
|
1676
|
+
importLine="import { CurrencyInput } from '@sovereignfs/ui';"
|
|
1677
|
+
usage="Decimal amount entry that reports its value as integer cents. Preserves in-progress typing instead of reformatting on every keystroke."
|
|
1678
|
+
>
|
|
1679
|
+
<CurrencyInputDemo />
|
|
1680
|
+
</ComponentCard>
|
|
1681
|
+
|
|
1508
1682
|
{/* TagInput */}
|
|
1509
1683
|
<ComponentCard
|
|
1510
1684
|
name="TagInput"
|
|
@@ -1585,6 +1759,15 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1585
1759
|
<SegmentedDemo />
|
|
1586
1760
|
</ComponentCard>
|
|
1587
1761
|
|
|
1762
|
+
{/* SplitMethodSelector */}
|
|
1763
|
+
<ComponentCard
|
|
1764
|
+
name="SplitMethodSelector"
|
|
1765
|
+
importLine="import { SplitMethodSelector } from '@sovereignfs/ui';"
|
|
1766
|
+
usage="The four-way Equal/Amount/Percentage/Shares picker shared by any cost-splitting plugin. A thin SegmentedControl preset."
|
|
1767
|
+
>
|
|
1768
|
+
<SplitMethodSelectorDemo />
|
|
1769
|
+
</ComponentCard>
|
|
1770
|
+
|
|
1588
1771
|
{/* Tabs */}
|
|
1589
1772
|
<ComponentCard
|
|
1590
1773
|
name="Tabs"
|
|
@@ -1922,6 +2105,15 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1922
2105
|
<CheckableListRowDemo />
|
|
1923
2106
|
</ComponentCard>
|
|
1924
2107
|
|
|
2108
|
+
{/* MemberMultiSelect */}
|
|
2109
|
+
<ComponentCard
|
|
2110
|
+
name="MemberMultiSelect"
|
|
2111
|
+
importLine="import { MemberMultiSelect } from '@sovereignfs/ui';"
|
|
2112
|
+
usage="Checkbox list for picking any number of people from an already-resolved option set. Domain-agnostic about guest vs. instance-user options; pair with SuggestionInput for search + add."
|
|
2113
|
+
>
|
|
2114
|
+
<MemberMultiSelectDemo />
|
|
2115
|
+
</ComponentCard>
|
|
2116
|
+
|
|
1925
2117
|
{/* Checkbox */}
|
|
1926
2118
|
<ComponentCard
|
|
1927
2119
|
name="Checkbox"
|
|
@@ -1940,6 +2132,518 @@ font-weight: var(--sv-font-weight-bold); /* 700 */`}</Code>
|
|
|
1940
2132
|
})()}
|
|
1941
2133
|
</ComponentCard>
|
|
1942
2134
|
|
|
2135
|
+
{/* RadioGroup */}
|
|
2136
|
+
<ComponentCard
|
|
2137
|
+
name="RadioGroup"
|
|
2138
|
+
importLine="import { RadioGroup } from '@sovereignfs/ui';"
|
|
2139
|
+
usage="Single-select list of options. Renders real <input type=radio> elements sharing one name, so arrow-key navigation between options is native browser behavior, not hand-rolled."
|
|
2140
|
+
>
|
|
2141
|
+
{(() => {
|
|
2142
|
+
const [size, setSize] = useState('md');
|
|
2143
|
+
return (
|
|
2144
|
+
<RadioGroup
|
|
2145
|
+
items={[
|
|
2146
|
+
{ label: 'Small', value: 'sm' },
|
|
2147
|
+
{ label: 'Medium', value: 'md' },
|
|
2148
|
+
{ label: 'Large', value: 'lg' },
|
|
2149
|
+
]}
|
|
2150
|
+
value={size}
|
|
2151
|
+
onChange={setSize}
|
|
2152
|
+
aria-label="Size"
|
|
2153
|
+
/>
|
|
2154
|
+
);
|
|
2155
|
+
})()}
|
|
2156
|
+
</ComponentCard>
|
|
2157
|
+
|
|
2158
|
+
{/* Slider */}
|
|
2159
|
+
<ComponentCard
|
|
2160
|
+
name="Slider"
|
|
2161
|
+
importLine="import { Slider } from '@sovereignfs/ui';"
|
|
2162
|
+
usage="Single-thumb range input. A native <input type=range> under custom styling — arrow keys, Home/End, and touch-drag all come from the browser."
|
|
2163
|
+
>
|
|
2164
|
+
{(() => {
|
|
2165
|
+
const [value, setValue] = useState(50);
|
|
2166
|
+
return (
|
|
2167
|
+
<div style={{ width: 240 }}>
|
|
2168
|
+
<Slider value={value} onChange={setValue} min={0} max={100} label="Volume" />
|
|
2169
|
+
</div>
|
|
2170
|
+
);
|
|
2171
|
+
})()}
|
|
2172
|
+
</ComponentCard>
|
|
2173
|
+
|
|
2174
|
+
{/* Progress */}
|
|
2175
|
+
<ComponentCard
|
|
2176
|
+
name="Progress"
|
|
2177
|
+
importLine="import { Progress } from '@sovereignfs/ui';"
|
|
2178
|
+
usage="Determinate progress bar. role=progressbar with aria-valuenow/min/max so screen readers announce the current value."
|
|
2179
|
+
>
|
|
2180
|
+
<div style={{ width: 240 }}>
|
|
2181
|
+
<Progress value={65} label="Upload progress" />
|
|
2182
|
+
</div>
|
|
2183
|
+
</ComponentCard>
|
|
2184
|
+
|
|
2185
|
+
{/* Table */}
|
|
2186
|
+
<ComponentCard
|
|
2187
|
+
name="Table"
|
|
2188
|
+
importLine="import { Table, TableHead, TableBody, TableRow, TableHeaderCell, TableCell } from '@sovereignfs/ui';"
|
|
2189
|
+
usage="Thin, styled wrappers around the native table elements. Not a data grid — no sort/filter/virtualization. Scrolls horizontally (masked-edge fade) at any viewport size."
|
|
2190
|
+
>
|
|
2191
|
+
<Table>
|
|
2192
|
+
<TableHead>
|
|
2193
|
+
<TableRow>
|
|
2194
|
+
<TableHeaderCell>Plugin</TableHeaderCell>
|
|
2195
|
+
<TableHeaderCell>Status</TableHeaderCell>
|
|
2196
|
+
</TableRow>
|
|
2197
|
+
</TableHead>
|
|
2198
|
+
<TableBody>
|
|
2199
|
+
<TableRow>
|
|
2200
|
+
<TableCell>sovereign-tasks</TableCell>
|
|
2201
|
+
<TableCell>Active</TableCell>
|
|
2202
|
+
</TableRow>
|
|
2203
|
+
<TableRow>
|
|
2204
|
+
<TableCell>sovereign-shopper</TableCell>
|
|
2205
|
+
<TableCell>Disabled</TableCell>
|
|
2206
|
+
</TableRow>
|
|
2207
|
+
</TableBody>
|
|
2208
|
+
</Table>
|
|
2209
|
+
</ComponentCard>
|
|
2210
|
+
|
|
2211
|
+
{/* Alert */}
|
|
2212
|
+
<ComponentCard
|
|
2213
|
+
name="Alert"
|
|
2214
|
+
importLine="import { Alert } from '@sovereignfs/ui';"
|
|
2215
|
+
usage="Inline, non-dismissible banner. Distinct from Toast (transient) and SystemBanner (instance-wide) — for form-level errors or explaining an empty/blocked state. Leading icon defaults per variant; pass icon to override or icon={false} to suppress."
|
|
2216
|
+
>
|
|
2217
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
|
2218
|
+
<Alert variant="error" heading="Something went wrong">
|
|
2219
|
+
We couldn’t save your changes. Check your connection and try again.
|
|
2220
|
+
</Alert>
|
|
2221
|
+
<Alert variant="success">Invite sent.</Alert>
|
|
2222
|
+
<Alert variant="neutral">This project has no members yet.</Alert>
|
|
2223
|
+
</div>
|
|
2224
|
+
</ComponentCard>
|
|
2225
|
+
|
|
2226
|
+
{/* Breadcrumb */}
|
|
2227
|
+
<ComponentCard
|
|
2228
|
+
name="Breadcrumb"
|
|
2229
|
+
importLine="import { Breadcrumb } from '@sovereignfs/ui';"
|
|
2230
|
+
usage="Link trail. The last item (no href) renders as plain text with aria-current=page. Pass renderLink to keep navigation client-side inside overlay-shell plugins."
|
|
2231
|
+
>
|
|
2232
|
+
<Breadcrumb
|
|
2233
|
+
items={[
|
|
2234
|
+
{ label: 'Console', href: '/console' },
|
|
2235
|
+
{ label: 'Plugins', href: '/console/plugins' },
|
|
2236
|
+
{ label: 'sovereign-tasks' },
|
|
2237
|
+
]}
|
|
2238
|
+
/>
|
|
2239
|
+
</ComponentCard>
|
|
2240
|
+
|
|
2241
|
+
{/* Pagination */}
|
|
2242
|
+
<ComponentCard
|
|
2243
|
+
name="Pagination"
|
|
2244
|
+
importLine="import { Pagination } from '@sovereignfs/ui';"
|
|
2245
|
+
usage="Page-number / prev-next control. Shows first, last, and pages near the current one, with an ellipsis for gaps once the page count grows."
|
|
2246
|
+
>
|
|
2247
|
+
{(() => {
|
|
2248
|
+
const [page, setPage] = useState(4);
|
|
2249
|
+
return <Pagination page={page} totalPages={12} onChange={setPage} />;
|
|
2250
|
+
})()}
|
|
2251
|
+
</ComponentCard>
|
|
2252
|
+
|
|
2253
|
+
{/* Kbd */}
|
|
2254
|
+
<ComponentCard
|
|
2255
|
+
name="Kbd"
|
|
2256
|
+
importLine="import { Kbd } from '@sovereignfs/ui';"
|
|
2257
|
+
usage="Inline keyboard-key styling. Renders a real <kbd> element."
|
|
2258
|
+
>
|
|
2259
|
+
<span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
|
|
2260
|
+
<Kbd>Ctrl</Kbd>
|
|
2261
|
+
<span>+</span>
|
|
2262
|
+
<Kbd>K</Kbd>
|
|
2263
|
+
</span>
|
|
2264
|
+
</ComponentCard>
|
|
2265
|
+
|
|
2266
|
+
{/* Collapsible */}
|
|
2267
|
+
<ComponentCard
|
|
2268
|
+
name="Collapsible"
|
|
2269
|
+
importLine="import { Collapsible } from '@sovereignfs/ui';"
|
|
2270
|
+
usage="Single expand/collapse primitive. Independently useful (e.g. a 'show more' toggle), and composed internally by Accordion."
|
|
2271
|
+
>
|
|
2272
|
+
{(() => {
|
|
2273
|
+
const [open, setOpen] = useState(false);
|
|
2274
|
+
return (
|
|
2275
|
+
<Collapsible open={open} onOpenChange={setOpen} trigger="Advanced settings">
|
|
2276
|
+
These settings are rarely needed — change them only if you know what you're
|
|
2277
|
+
doing.
|
|
2278
|
+
</Collapsible>
|
|
2279
|
+
);
|
|
2280
|
+
})()}
|
|
2281
|
+
</ComponentCard>
|
|
2282
|
+
|
|
2283
|
+
{/* Accordion */}
|
|
2284
|
+
<ComponentCard
|
|
2285
|
+
name="Accordion"
|
|
2286
|
+
importLine="import { Accordion } from '@sovereignfs/ui';"
|
|
2287
|
+
usage="One or more Collapsible sections. type=single closes other sections when one opens; type=multiple allows any number open at once."
|
|
2288
|
+
>
|
|
2289
|
+
{(() => {
|
|
2290
|
+
const [openIds, setOpenIds] = useState<string[]>(['plugins']);
|
|
2291
|
+
return (
|
|
2292
|
+
<Accordion
|
|
2293
|
+
items={[
|
|
2294
|
+
{
|
|
2295
|
+
id: 'plugins',
|
|
2296
|
+
trigger: 'What plugins ship by default?',
|
|
2297
|
+
content:
|
|
2298
|
+
'Only the platform plugins (Console, Launcher, Account) plus Sovereign Tasks.',
|
|
2299
|
+
},
|
|
2300
|
+
{
|
|
2301
|
+
id: 'hosting',
|
|
2302
|
+
trigger: 'Can I self-host this?',
|
|
2303
|
+
content:
|
|
2304
|
+
'Yes — Sovereign is designed to be self-hosted via Docker Compose.',
|
|
2305
|
+
},
|
|
2306
|
+
]}
|
|
2307
|
+
type="single"
|
|
2308
|
+
openIds={openIds}
|
|
2309
|
+
onOpenIdsChange={setOpenIds}
|
|
2310
|
+
/>
|
|
2311
|
+
);
|
|
2312
|
+
})()}
|
|
2313
|
+
</ComponentCard>
|
|
2314
|
+
|
|
2315
|
+
{/* AspectRatio */}
|
|
2316
|
+
<ComponentCard
|
|
2317
|
+
name="AspectRatio"
|
|
2318
|
+
importLine="import { AspectRatio } from '@sovereignfs/ui';"
|
|
2319
|
+
usage="Constrains content (image, video, embed) to a fixed ratio."
|
|
2320
|
+
>
|
|
2321
|
+
<div style={{ width: 200 }}>
|
|
2322
|
+
<AspectRatio ratio={16 / 9}>
|
|
2323
|
+
<div
|
|
2324
|
+
style={{
|
|
2325
|
+
width: '100%',
|
|
2326
|
+
height: '100%',
|
|
2327
|
+
background: 'var(--sv-color-surface-sunken)',
|
|
2328
|
+
display: 'flex',
|
|
2329
|
+
alignItems: 'center',
|
|
2330
|
+
justifyContent: 'center',
|
|
2331
|
+
color: 'var(--sv-color-text-muted)',
|
|
2332
|
+
fontSize: 'var(--sv-font-size-xs)',
|
|
2333
|
+
}}
|
|
2334
|
+
>
|
|
2335
|
+
16:9
|
|
2336
|
+
</div>
|
|
2337
|
+
</AspectRatio>
|
|
2338
|
+
</div>
|
|
2339
|
+
</ComponentCard>
|
|
2340
|
+
|
|
2341
|
+
{/* ButtonGroup */}
|
|
2342
|
+
<ComponentCard
|
|
2343
|
+
name="ButtonGroup"
|
|
2344
|
+
importLine="import { ButtonGroup } from '@sovereignfs/ui';"
|
|
2345
|
+
usage="Visually joins adjacent Buttons into one control (shared border, connected corners)."
|
|
2346
|
+
>
|
|
2347
|
+
<ButtonGroup aria-label="View">
|
|
2348
|
+
<Button variant="secondary" size="sm">
|
|
2349
|
+
Day
|
|
2350
|
+
</Button>
|
|
2351
|
+
<Button variant="secondary" size="sm">
|
|
2352
|
+
Week
|
|
2353
|
+
</Button>
|
|
2354
|
+
<Button variant="secondary" size="sm">
|
|
2355
|
+
Month
|
|
2356
|
+
</Button>
|
|
2357
|
+
</ButtonGroup>
|
|
2358
|
+
</ComponentCard>
|
|
2359
|
+
|
|
2360
|
+
{/* Item */}
|
|
2361
|
+
<ComponentCard
|
|
2362
|
+
name="Item"
|
|
2363
|
+
importLine="import { Item } from '@sovereignfs/ui';"
|
|
2364
|
+
usage="Generic row primitive: leading slot, title + optional description, trailing slot. For settings rows and list rows that don't fit Menu's own item shape."
|
|
2365
|
+
>
|
|
2366
|
+
<Item
|
|
2367
|
+
title="Notifications"
|
|
2368
|
+
description="Manage email and push alerts"
|
|
2369
|
+
leading={<Icon name="bell" aria-hidden />}
|
|
2370
|
+
trailing={<Icon name="chevron-right" size="sm" aria-hidden />}
|
|
2371
|
+
onClick={() => {}}
|
|
2372
|
+
/>
|
|
2373
|
+
</ComponentCard>
|
|
2374
|
+
|
|
2375
|
+
{/* Label */}
|
|
2376
|
+
<ComponentCard
|
|
2377
|
+
name="Label"
|
|
2378
|
+
importLine="import { Label } from '@sovereignfs/ui';"
|
|
2379
|
+
usage="Standalone accessible form label, independent of FormField. Use FormField when a control needs hint/error text too."
|
|
2380
|
+
>
|
|
2381
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
|
2382
|
+
<Label htmlFor="label-demo-input">Email address</Label>
|
|
2383
|
+
<input
|
|
2384
|
+
id="label-demo-input"
|
|
2385
|
+
type="email"
|
|
2386
|
+
placeholder="you@example.com"
|
|
2387
|
+
style={{
|
|
2388
|
+
padding: 'var(--sv-space-2) var(--sv-space-3)',
|
|
2389
|
+
border: '1px solid var(--sv-color-border-strong)',
|
|
2390
|
+
borderRadius: 'var(--sv-radius-md)',
|
|
2391
|
+
fontFamily: 'var(--sv-font-family)',
|
|
2392
|
+
fontSize: 'var(--sv-font-size-sm)',
|
|
2393
|
+
}}
|
|
2394
|
+
/>
|
|
2395
|
+
</div>
|
|
2396
|
+
</ComponentCard>
|
|
2397
|
+
|
|
2398
|
+
{/* ScrollArea */}
|
|
2399
|
+
<ComponentCard
|
|
2400
|
+
name="ScrollArea"
|
|
2401
|
+
importLine="import { ScrollArea } from '@sovereignfs/ui';"
|
|
2402
|
+
usage="Styled scrollable container — thin, token-colored scrollbar instead of the OS default. Native overflow scrolling underneath."
|
|
2403
|
+
>
|
|
2404
|
+
<ScrollArea maxHeight={120}>
|
|
2405
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, padding: 4 }}>
|
|
2406
|
+
{Array.from({ length: 10 }, (_, i) => (
|
|
2407
|
+
<div key={i} style={{ fontSize: 13 }}>
|
|
2408
|
+
Row {i + 1}
|
|
2409
|
+
</div>
|
|
2410
|
+
))}
|
|
2411
|
+
</div>
|
|
2412
|
+
</ScrollArea>
|
|
2413
|
+
</ComponentCard>
|
|
2414
|
+
|
|
2415
|
+
{/* Typography */}
|
|
2416
|
+
<ComponentCard
|
|
2417
|
+
name="Typography"
|
|
2418
|
+
importLine="import { Typography } from '@sovereignfs/ui';"
|
|
2419
|
+
usage="Text bound to the design system's font-size/weight scale. Pass `as` to override the rendered tag while keeping the variant's visual style."
|
|
2420
|
+
>
|
|
2421
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
|
2422
|
+
<Typography variant="h3">Heading 3</Typography>
|
|
2423
|
+
<Typography variant="body">Body copy for descriptions.</Typography>
|
|
2424
|
+
<Typography variant="caption">Caption — secondary text.</Typography>
|
|
2425
|
+
</div>
|
|
2426
|
+
</ComponentCard>
|
|
2427
|
+
|
|
2428
|
+
{/* Marker */}
|
|
2429
|
+
<ComponentCard
|
|
2430
|
+
name="Marker"
|
|
2431
|
+
importLine="import { Marker } from '@sovereignfs/ui';"
|
|
2432
|
+
usage="Inline citation/reference marker — attributes part of an assistant answer to a source (Sovereign Harness 'source trace', RFC 0040)."
|
|
2433
|
+
>
|
|
2434
|
+
<p style={{ fontSize: 14, margin: 0 }}>
|
|
2435
|
+
Your next task is due Thursday
|
|
2436
|
+
<Marker index={1} label="Source: Tasks" onClick={() => {}} />.
|
|
2437
|
+
</p>
|
|
2438
|
+
</ComponentCard>
|
|
2439
|
+
|
|
2440
|
+
{/* Message */}
|
|
2441
|
+
<ComponentCard
|
|
2442
|
+
name="Message"
|
|
2443
|
+
importLine="import { Message } from '@sovereignfs/ui';"
|
|
2444
|
+
usage="A single chat turn for the Sovereign Harness assistant. role is user/assistant/tool, matching harness_messages (RFC 0040). Content is caller-controlled ReactNode."
|
|
2445
|
+
>
|
|
2446
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
|
2447
|
+
<Message sender="user">What's on my plate this week?</Message>
|
|
2448
|
+
<Message sender="assistant">You have 3 tasks due this week.</Message>
|
|
2449
|
+
</div>
|
|
2450
|
+
</ComponentCard>
|
|
2451
|
+
|
|
2452
|
+
{/* MessageScroller */}
|
|
2453
|
+
<ComponentCard
|
|
2454
|
+
name="MessageScroller"
|
|
2455
|
+
importLine="import { MessageScroller } from '@sovereignfs/ui';"
|
|
2456
|
+
usage="Auto-scrolling chat container. Scrolls to the newest message while the user is near the bottom; shows a 'New messages' button instead of yanking them down if they've scrolled up."
|
|
2457
|
+
>
|
|
2458
|
+
<div style={{ height: 160, border: '1px solid var(--sv-color-border)' }}>
|
|
2459
|
+
<MessageScroller>
|
|
2460
|
+
<Message sender="user">Hi there</Message>
|
|
2461
|
+
<Message sender="assistant">How can I help?</Message>
|
|
2462
|
+
</MessageScroller>
|
|
2463
|
+
</div>
|
|
2464
|
+
</ComponentCard>
|
|
2465
|
+
|
|
2466
|
+
{/* HoverCard */}
|
|
2467
|
+
<ComponentCard
|
|
2468
|
+
name="HoverCard"
|
|
2469
|
+
importLine="import { HoverCard } from '@sovereignfs/ui';"
|
|
2470
|
+
usage="Hover-triggered popover on desktop, tap-to-toggle on touch. Built on Popover for positioning — adds hover-intent timing and the touch fallback. Opens on keyboard focus too."
|
|
2471
|
+
>
|
|
2472
|
+
<HoverCard
|
|
2473
|
+
aria-label="User preview"
|
|
2474
|
+
trigger={
|
|
2475
|
+
<button
|
|
2476
|
+
type="button"
|
|
2477
|
+
style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer' }}
|
|
2478
|
+
>
|
|
2479
|
+
<Avatar name="Jane Smith" size="sm" />
|
|
2480
|
+
</button>
|
|
2481
|
+
}
|
|
2482
|
+
>
|
|
2483
|
+
<div style={{ padding: 'var(--sv-space-3)', fontSize: 14 }}>
|
|
2484
|
+
<div style={{ fontWeight: 600 }}>Jane Smith</div>
|
|
2485
|
+
<div style={{ color: 'var(--sv-color-text-muted)' }}>jane@example.com</div>
|
|
2486
|
+
</div>
|
|
2487
|
+
</HoverCard>
|
|
2488
|
+
</ComponentCard>
|
|
2489
|
+
|
|
2490
|
+
{/* ContextMenu */}
|
|
2491
|
+
<ComponentCard
|
|
2492
|
+
name="ContextMenu"
|
|
2493
|
+
importLine="import { ContextMenu } from '@sovereignfs/ui';"
|
|
2494
|
+
usage="Right-click menu on desktop, long-press on touch. Desktop positioning reuses Popover's collision detection anchored to the click point; touch opens the same items in a Drawer."
|
|
2495
|
+
>
|
|
2496
|
+
<ContextMenu
|
|
2497
|
+
aria-label="Row actions"
|
|
2498
|
+
items={[
|
|
2499
|
+
{ label: 'Rename', onSelect: () => {} },
|
|
2500
|
+
{ label: 'Duplicate', onSelect: () => {} },
|
|
2501
|
+
{ type: 'separator' },
|
|
2502
|
+
{ label: 'Delete', destructive: true, onSelect: () => {} },
|
|
2503
|
+
]}
|
|
2504
|
+
>
|
|
2505
|
+
<div
|
|
2506
|
+
style={{
|
|
2507
|
+
padding: 'var(--sv-space-4)',
|
|
2508
|
+
border: '1px dashed var(--sv-color-border-strong)',
|
|
2509
|
+
borderRadius: 'var(--sv-radius-md)',
|
|
2510
|
+
textAlign: 'center',
|
|
2511
|
+
fontSize: 14,
|
|
2512
|
+
color: 'var(--sv-color-text-muted)',
|
|
2513
|
+
}}
|
|
2514
|
+
>
|
|
2515
|
+
Right-click here
|
|
2516
|
+
</div>
|
|
2517
|
+
</ContextMenu>
|
|
2518
|
+
</ComponentCard>
|
|
2519
|
+
|
|
2520
|
+
{/* NavigationMenu */}
|
|
2521
|
+
<ComponentCard
|
|
2522
|
+
name="NavigationMenu"
|
|
2523
|
+
importLine="import { NavigationMenu } from '@sovereignfs/ui';"
|
|
2524
|
+
usage="Top-level nav bar where some items open a flyout panel. Desktop-oriented — a hover-triggered flyout bar has no mobile equivalent."
|
|
2525
|
+
>
|
|
2526
|
+
<NavigationMenu
|
|
2527
|
+
aria-label="Main"
|
|
2528
|
+
items={[
|
|
2529
|
+
{ label: 'Home', href: '/home' },
|
|
2530
|
+
{
|
|
2531
|
+
label: 'Products',
|
|
2532
|
+
content: (
|
|
2533
|
+
<div style={{ padding: 'var(--sv-space-3)', fontSize: 14 }}>
|
|
2534
|
+
Tasks · Ledger · Shopper
|
|
2535
|
+
</div>
|
|
2536
|
+
),
|
|
2537
|
+
},
|
|
2538
|
+
]}
|
|
2539
|
+
/>
|
|
2540
|
+
</ComponentCard>
|
|
2541
|
+
|
|
2542
|
+
{/* Menubar */}
|
|
2543
|
+
<ComponentCard
|
|
2544
|
+
name="Menubar"
|
|
2545
|
+
importLine="import { Menubar } from '@sovereignfs/ui';"
|
|
2546
|
+
usage="Desktop app-style menu bar (File/Edit/View...). A thin composition of NavigationMenu with MenuEntries as each item's flyout content."
|
|
2547
|
+
>
|
|
2548
|
+
<Menubar
|
|
2549
|
+
menus={[
|
|
2550
|
+
{
|
|
2551
|
+
label: 'File',
|
|
2552
|
+
items: [
|
|
2553
|
+
{ label: 'New conversation', onSelect: () => {} },
|
|
2554
|
+
{ label: 'Export', onSelect: () => {} },
|
|
2555
|
+
],
|
|
2556
|
+
},
|
|
2557
|
+
{
|
|
2558
|
+
label: 'Edit',
|
|
2559
|
+
items: [
|
|
2560
|
+
{ label: 'Undo', onSelect: () => {} },
|
|
2561
|
+
{ label: 'Redo', onSelect: () => {} },
|
|
2562
|
+
],
|
|
2563
|
+
},
|
|
2564
|
+
]}
|
|
2565
|
+
/>
|
|
2566
|
+
</ComponentCard>
|
|
2567
|
+
|
|
2568
|
+
{/* Command */}
|
|
2569
|
+
<ComponentCard
|
|
2570
|
+
name="Command"
|
|
2571
|
+
importLine="import { Command } from '@sovereignfs/ui';"
|
|
2572
|
+
usage="⌘K-style command palette. Opened via Dialog for the modal shell — adds the search input, substring filtering, and arrow-key/Enter selection. Controlled: consumer owns the open state."
|
|
2573
|
+
>
|
|
2574
|
+
<CommandDemo />
|
|
2575
|
+
</ComponentCard>
|
|
2576
|
+
|
|
2577
|
+
{/* Resizable */}
|
|
2578
|
+
<ComponentCard
|
|
2579
|
+
name="Resizable"
|
|
2580
|
+
importLine="import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '@sovereignfs/ui';"
|
|
2581
|
+
usage="A row or column of resizable panes. Each handle resizes only its two immediate neighbor panels. Desktop-oriented — panels render at their default sizes on touch."
|
|
2582
|
+
>
|
|
2583
|
+
<div style={{ width: '100%', height: 160 }}>
|
|
2584
|
+
<ResizablePanelGroup direction="horizontal">
|
|
2585
|
+
<ResizablePanel defaultSize={30} minSize={15} maxSize={50}>
|
|
2586
|
+
<div
|
|
2587
|
+
style={{
|
|
2588
|
+
display: 'flex',
|
|
2589
|
+
alignItems: 'center',
|
|
2590
|
+
justifyContent: 'center',
|
|
2591
|
+
height: '100%',
|
|
2592
|
+
fontSize: 14,
|
|
2593
|
+
color: 'var(--sv-color-text-muted)',
|
|
2594
|
+
}}
|
|
2595
|
+
>
|
|
2596
|
+
Sidebar
|
|
2597
|
+
</div>
|
|
2598
|
+
</ResizablePanel>
|
|
2599
|
+
<ResizableHandle aria-label="Resize sidebar" />
|
|
2600
|
+
<ResizablePanel defaultSize={70}>
|
|
2601
|
+
<div
|
|
2602
|
+
style={{
|
|
2603
|
+
display: 'flex',
|
|
2604
|
+
alignItems: 'center',
|
|
2605
|
+
justifyContent: 'center',
|
|
2606
|
+
height: '100%',
|
|
2607
|
+
fontSize: 14,
|
|
2608
|
+
color: 'var(--sv-color-text-muted)',
|
|
2609
|
+
}}
|
|
2610
|
+
>
|
|
2611
|
+
Content
|
|
2612
|
+
</div>
|
|
2613
|
+
</ResizablePanel>
|
|
2614
|
+
</ResizablePanelGroup>
|
|
2615
|
+
</div>
|
|
2616
|
+
</ComponentCard>
|
|
2617
|
+
|
|
2618
|
+
{/* DataTable */}
|
|
2619
|
+
<ComponentCard
|
|
2620
|
+
name="DataTable"
|
|
2621
|
+
importLine="import { DataTable } from '@sovereignfs/ui';"
|
|
2622
|
+
usage="Sortable table built on Table. Column-driven: pass columns + data instead of composing TableRow/TableCell by hand. Clicking a sortable header cycles ascending → descending → unsorted."
|
|
2623
|
+
>
|
|
2624
|
+
<DataTable
|
|
2625
|
+
columns={[
|
|
2626
|
+
{ key: 'name', header: 'Plugin', sortable: true },
|
|
2627
|
+
{ key: 'installs', header: 'Installs', sortable: true, align: 'end' },
|
|
2628
|
+
]}
|
|
2629
|
+
data={[
|
|
2630
|
+
{ id: 'tasks', name: 'sovereign-tasks', installs: 482 },
|
|
2631
|
+
{ id: 'ledger', name: 'sovereign-ledger', installs: 219 },
|
|
2632
|
+
{ id: 'shopper', name: 'sovereign-shopper', installs: 37 },
|
|
2633
|
+
]}
|
|
2634
|
+
getRowKey={(row) => row.id}
|
|
2635
|
+
/>
|
|
2636
|
+
</ComponentCard>
|
|
2637
|
+
|
|
2638
|
+
{/* Combobox */}
|
|
2639
|
+
<ComponentCard
|
|
2640
|
+
name="Combobox"
|
|
2641
|
+
importLine="import { Combobox } from '@sovereignfs/ui';"
|
|
2642
|
+
usage="A searchable single-select: Popover on desktop, a bottom-sheet Drawer on mobile. For a short fixed list where search adds no value, use Select's native <select> instead."
|
|
2643
|
+
>
|
|
2644
|
+
<ComboboxDemo />
|
|
2645
|
+
</ComponentCard>
|
|
2646
|
+
|
|
1943
2647
|
{/* DragHandleRow */}
|
|
1944
2648
|
<ComponentCard
|
|
1945
2649
|
name="DragHandleRow"
|