@syscore/ui-library 1.27.3 → 2.0.0-beta-publish-workflow-beta.2
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/client/App.tsx +0 -2
- package/client/assets/alert/icon-clear.svg +4 -0
- package/client/assets/alert/icon-done.svg +3 -0
- package/client/assets/avatar-identity/photo.png +0 -0
- package/client/assets/avatar-identity/placeholder-icon.svg +8 -0
- package/client/assets/breadcrumb/icon-ellipsis.svg +5 -0
- package/client/assets/breadcrumb/icon-home.svg +3 -0
- package/client/assets/breadcrumb/icon-separator.svg +3 -0
- package/client/assets/button-v01/icon-back.svg +4 -0
- package/client/assets/button-v01/icon-check.svg +3 -0
- package/client/assets/button-v01/icon-close.svg +4 -0
- package/client/assets/button-v01/icon-delete.svg +3 -0
- package/client/assets/button-v01/icon-device.svg +3 -0
- package/client/assets/dropdown/icon-carrot-contract.svg +3 -0
- package/client/assets/dropdown/icon-carrot-expand.svg +3 -0
- package/client/assets/dropdown/icon-clear.svg +4 -0
- package/client/assets/dropdown/icon-enter.svg +3 -0
- package/client/components/icons/UtilityChangeType.tsx +21 -0
- package/client/components/ui/alert-dialog-panel.tsx +246 -0
- package/client/components/ui/alert-v02.tsx +214 -0
- package/client/components/ui/app-bar.tsx +299 -0
- package/client/components/ui/avatar-identity.tsx +122 -0
- package/client/components/ui/banner.tsx +108 -0
- package/client/components/ui/bottom-navigation.tsx +223 -0
- package/client/components/ui/breadcrumb-trail.tsx +170 -0
- package/client/components/ui/button-v01.tsx +238 -0
- package/client/components/ui/button.tsx +2 -0
- package/client/components/ui/card.tsx +108 -26
- package/client/components/ui/code-badge.tsx +62 -0
- package/client/components/ui/date-picker.tsx +188 -0
- package/client/components/ui/dropdown.tsx +448 -0
- package/client/components/ui/empty-state.tsx +197 -0
- package/client/components/ui/file-upload.tsx +214 -0
- package/client/components/ui/footer.tsx +179 -0
- package/client/components/ui/layout.tsx +1182 -0
- package/client/components/ui/pagination-v01.tsx +157 -0
- package/client/components/ui/password-field-v01.tsx +67 -0
- package/client/components/ui/search-field-v01.tsx +192 -0
- package/client/components/ui/section-heading.tsx +49 -0
- package/client/components/ui/sidebar.tsx +2 -3
- package/client/components/ui/standard-navigation.tsx +8 -2
- package/client/components/ui/stepper.tsx +148 -0
- package/client/components/ui/switch-v01.tsx +71 -0
- package/client/components/ui/system-bar.tsx +119 -0
- package/client/components/ui/table-v01.tsx +230 -0
- package/client/components/ui/tabs-v01.tsx +99 -0
- package/client/components/ui/tag-v02.tsx +113 -0
- package/client/components/ui/text-area-v01.tsx +33 -0
- package/client/components/ui/text-field-v01.tsx +108 -0
- package/client/components/ui/timeline.tsx +181 -0
- package/client/components/ui/toast-v01.tsx +206 -0
- package/client/components/ui/tooltip.tsx +264 -71
- package/client/global.css +9565 -4378
- package/client/storybook.css +125 -0
- package/client/ui/Accordion.stories.tsx +1 -1
- package/client/ui/AlertDialogPanel/AlertDialogPanel.stories.tsx +150 -0
- package/client/ui/AlertV02/AlertV02.stories.tsx +188 -0
- package/client/ui/AppBar/app-bar.stories.tsx +280 -0
- package/client/ui/AspectRatio.stories.tsx +1 -1
- package/client/ui/AvatarIdentity/AvatarIdentity.stories.tsx +77 -0
- package/client/ui/Banner/banner.stories.tsx +238 -0
- package/client/ui/BottomNavigation/bottom-navigation.stories.tsx +285 -0
- package/client/ui/BreadcrumbTrail/BreadcrumbTrail.stories.tsx +232 -0
- package/client/ui/Button.stories.tsx +1 -1
- package/client/ui/ButtonV01/ButtonV01.stories.tsx +417 -0
- package/client/ui/Calendar/Calendar.stories.tsx +1 -1
- package/client/ui/Card.stories.tsx +285 -168
- package/client/ui/Carousel/Carousel.stories.tsx +1 -1
- package/client/ui/Chart/Chart.stories.tsx +1 -1
- package/client/ui/Checkbox.stories.tsx +1 -1
- package/client/ui/Collapsible/Collapsible.stories.tsx +1 -1
- package/client/ui/Colors.stories.tsx +1 -1
- package/client/ui/Command/Command.stories.tsx +1 -1
- package/client/ui/ContextMenu/ContextMenu.stories.tsx +1 -1
- package/client/ui/DatePicker/DatePicker.stories.tsx +293 -0
- package/client/ui/Dialog.stories.tsx +1 -1
- package/client/ui/Drawer/Drawer.stories.tsx +1 -1
- package/client/ui/Dropdown/Dropdown.stories.tsx +205 -0
- package/client/ui/EmptyState/empty-state.stories.tsx +251 -0
- package/client/ui/FileUpload/FileUpload.stories.tsx +218 -0
- package/client/ui/Footer/footer.stories.tsx +194 -0
- package/client/ui/Form/Form.stories.tsx +1 -1
- package/client/ui/Hero.stories.tsx +1 -1
- package/client/ui/HoverCard/HoverCard.stories.tsx +1 -1
- package/client/ui/Icons.stories.tsx +1 -1
- package/client/ui/Input.stories.tsx +1 -1
- package/client/ui/InputOTP/InputOTP.stories.tsx +1 -1
- package/client/ui/Label.stories.tsx +1 -1
- package/client/ui/Layout/Center.stories.tsx +100 -0
- package/client/ui/Layout/Columns.stories.tsx +136 -0
- package/client/ui/Layout/Container.stories.tsx +104 -0
- package/client/ui/Layout/FormLayout.stories.tsx +144 -0
- package/client/ui/Layout/Grid.stories.tsx +158 -0
- package/client/ui/Layout/GridSpan.stories.tsx +75 -0
- package/client/ui/Layout/HStack.stories.tsx +128 -0
- package/client/ui/Layout/Layout.stories.tsx +287 -0
- package/client/ui/Layout/LayoutContent.stories.tsx +91 -0
- package/client/ui/Layout/LayoutFooter.stories.tsx +77 -0
- package/client/ui/Layout/LayoutHeader.stories.tsx +104 -0
- package/client/ui/Layout/LayoutPanel.stories.tsx +143 -0
- package/client/ui/Layout/Positioned.stories.tsx +113 -0
- package/client/ui/Layout/Section.stories.tsx +84 -0
- package/client/ui/Layout/ShowHide.stories.tsx +99 -0
- package/client/ui/Layout/Spacer.stories.tsx +149 -0
- package/client/ui/Layout/Stack.stories.tsx +69 -0
- package/client/ui/Layout/StackItem.stories.tsx +124 -0
- package/client/ui/Layout/VStack.stories.tsx +101 -0
- package/client/ui/Layout/controls.ts +33 -0
- package/client/ui/Layout/demo.tsx +37 -0
- package/client/ui/Menubar/Menubar.stories.tsx +1 -1
- package/client/ui/MobileNav.stories.tsx +1 -1
- package/client/ui/Navigation.stories.tsx +1 -1
- package/client/ui/NavigationMenu/NavigationMenu.stories.tsx +1 -1
- package/client/ui/PageHeader.stories.tsx +13 -13
- package/client/ui/Pagination/Pagination.stories.tsx +178 -98
- package/client/ui/Pagination/PaginationLegacy.stories.tsx +121 -0
- package/client/ui/Panel.stories.tsx +1 -1
- package/client/ui/Popover/Popover.stories.tsx +1 -1
- package/client/ui/Progress/Progress.stories.tsx +1 -1
- package/client/ui/RadioGroup/RadioGroup.stories.tsx +1 -1
- package/client/ui/Resizable/Resizable.stories.tsx +1 -1
- package/client/ui/ScrollArea/ScrollArea.stories.tsx +1 -1
- package/client/ui/SearchField/SearchField.stories.tsx +153 -0
- package/client/ui/{SearchField.stories.tsx → SearchField/SearchFieldLegacy.stories.tsx} +2 -2
- package/client/ui/SectionBadge.stories.tsx +1 -1
- package/client/ui/Select.stories.tsx +1 -1
- package/client/ui/Separator/Separator.stories.tsx +1 -1
- package/client/ui/Sheet/Sheet.stories.tsx +1 -1
- package/client/ui/Sidebar/Sidebar.stories.tsx +57 -8
- package/client/ui/Skeleton/Skeleton.stories.tsx +1 -1
- package/client/ui/Slider/Slider.stories.tsx +1 -1
- package/client/ui/StandardNavigation.stories.tsx +1 -1
- package/client/ui/Stepper/Stepper.stories.tsx +344 -0
- package/client/ui/Switch.stories.tsx +1 -1
- package/client/ui/SwitchV01/SwitchV01.stories.tsx +152 -0
- package/client/ui/SystemBar/system-bar.stories.tsx +179 -0
- package/client/ui/Table/TableV01.stories.tsx +256 -0
- package/client/ui/Tabs.stories.tsx +1 -1
- package/client/ui/TabsV01/TabsV01.stories.tsx +144 -0
- package/client/ui/Tag.stories.tsx +1 -1
- package/client/ui/TagV02/TagStatusV02.stories.tsx +132 -0
- package/client/ui/TagV02/TagV02.stories.tsx +142 -0
- package/client/ui/TextAreaV01/TextAreaV01.stories.tsx +146 -0
- package/client/ui/TextFieldV01/PasswordFieldV01.stories.tsx +161 -0
- package/client/ui/TextFieldV01/TextFieldV01.stories.tsx +160 -0
- package/client/ui/Textarea.stories.tsx +1 -1
- package/client/ui/Timeline/timeline.stories.tsx +404 -0
- package/client/ui/Toast/Toast.stories.tsx +1 -1
- package/client/ui/ToastV01/ToastV01.stories.tsx +201 -0
- package/client/ui/Toaster/Toaster.stories.tsx +1 -1
- package/client/ui/Toggle.stories.tsx +1 -1
- package/client/ui/Tooltip.stories.tsx +287 -114
- package/client/ui/Typography.stories.tsx +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +649 -13
- package/dist/index.es.js +4405 -653
- package/package.json +1 -1
- package/client/components/ui/badge.tsx +0 -33
- package/client/components/ui/sonner.tsx +0 -26
- package/client/components/ui/toggle-group.tsx +0 -76
- package/client/ui/Alert/Alert.stories.tsx +0 -82
- package/client/ui/AlertDialog/AlertDialog.stories.tsx +0 -106
- package/client/ui/Avatar/Avatar.stories.tsx +0 -94
- package/client/ui/Badge/Badge.stories.tsx +0 -60
- package/client/ui/Breadcrumb/Breadcrumb.stories.tsx +0 -97
- package/client/ui/DropdownMenu/DropdownMenu.stories.tsx +0 -139
- package/client/ui/Sonner/Sonner.stories.tsx +0 -48
- package/client/ui/Table/Table.stories.tsx +0 -135
- package/client/ui/ToggleGroup/ToggleGroup.stories.tsx +0 -88
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { ToastV01 } from "../../components/ui/toast-v01";
|
|
3
|
+
import samplePhoto from "../../assets/avatar-identity/photo.png";
|
|
4
|
+
|
|
5
|
+
const LOREM =
|
|
6
|
+
"Lorem ipsum dolor sit amet consectetur adipiscing elit. Sit amet consectetur adipiscing elit quisque faucibus ex. Adipiscing elit quisque faucibus ex sapien vitae pellentesque.";
|
|
7
|
+
|
|
8
|
+
const appearances = ["solid", "subtle", "outline"] as const;
|
|
9
|
+
const colors = ["default", "success", "error"] as const;
|
|
10
|
+
const sizes = ["large", "small"] as const;
|
|
11
|
+
const indicators = ["icon", "avatar"] as const;
|
|
12
|
+
|
|
13
|
+
const meta = {
|
|
14
|
+
title: "Components/Toast",
|
|
15
|
+
component: ToastV01,
|
|
16
|
+
tags: ["autodocs"],
|
|
17
|
+
parameters: {
|
|
18
|
+
layout: "centered",
|
|
19
|
+
docs: {
|
|
20
|
+
description: {
|
|
21
|
+
component: [
|
|
22
|
+
"Transient notification. Existing `Components/ToastLegacy` (Radix `Toast`) is unchanged.",
|
|
23
|
+
"",
|
|
24
|
+
"Stories are the semantic states: **Default**, **Success**, **Error**.",
|
|
25
|
+
"Use **Controls** for appearance (solid / subtle / outline), size, and indicator.",
|
|
26
|
+
"All Variants shows the full set of **36**.",
|
|
27
|
+
"",
|
|
28
|
+
"---",
|
|
29
|
+
"",
|
|
30
|
+
"## Import",
|
|
31
|
+
"",
|
|
32
|
+
"```tsx",
|
|
33
|
+
`import { ToastV01 } from "@syscore/ui-library"`,
|
|
34
|
+
"```",
|
|
35
|
+
"",
|
|
36
|
+
"## How to use",
|
|
37
|
+
"",
|
|
38
|
+
"Pick `color` for meaning. Use `variant`, `size`, and `indicator` for presentation.",
|
|
39
|
+
'A toast is announced to screen readers on appearance (`role="status"`), so keep the',
|
|
40
|
+
"copy short and put anything the user must act on behind Confirm.",
|
|
41
|
+
"",
|
|
42
|
+
"```tsx",
|
|
43
|
+
"const [visible, setVisible] = useState(true)",
|
|
44
|
+
"",
|
|
45
|
+
"visible ? (",
|
|
46
|
+
" <ToastV01",
|
|
47
|
+
` color="success"`,
|
|
48
|
+
` variant="solid"`,
|
|
49
|
+
` size="large"`,
|
|
50
|
+
` indicator="icon"`,
|
|
51
|
+
` title="Changes saved"`,
|
|
52
|
+
` description="Your updates are live for everyone on the project."`,
|
|
53
|
+
` confirmLabel="View"`,
|
|
54
|
+
` cancelLabel="Dismiss"`,
|
|
55
|
+
" onConfirm={handleView}",
|
|
56
|
+
" onCancel={() => setVisible(false)}",
|
|
57
|
+
" onDismiss={() => setVisible(false)}",
|
|
58
|
+
" />",
|
|
59
|
+
") : null",
|
|
60
|
+
"```",
|
|
61
|
+
"",
|
|
62
|
+
"| Situation | Use |",
|
|
63
|
+
"|-----------|-----|",
|
|
64
|
+
'| Neutral notice | `color="default"` |',
|
|
65
|
+
'| Completed action | `color="success"` |',
|
|
66
|
+
'| Failure / blocking problem | `color="error"` |',
|
|
67
|
+
'| Single line, one action | `size="small"` (heading + Confirm only) |',
|
|
68
|
+
'| Person-specific message | `indicator="avatar"` and `avatarSrc` |',
|
|
69
|
+
"",
|
|
70
|
+
"## Props",
|
|
71
|
+
"",
|
|
72
|
+
"| Prop | Values | Default | Effect |",
|
|
73
|
+
"|------|--------|---------|--------|",
|
|
74
|
+
'| `color` | `"default"` \\| `"success"` \\| `"error"` | `"default"` | Semantic state (stories) |',
|
|
75
|
+
'| `variant` | `"solid"` \\| `"subtle"` \\| `"outline"` | `"solid"` | Surface treatment |',
|
|
76
|
+
'| `size` | `"large"` \\| `"small"` | `"large"` | Stacked copy + two actions vs single row |',
|
|
77
|
+
'| `indicator` | `"icon"` \\| `"avatar"` | `"icon"` | Leading checkmark or 32px avatar |',
|
|
78
|
+
"| `action` | `boolean` | `true` | Confirm (and Cancel on large) |",
|
|
79
|
+
"| `title` | `ReactNode` | — | Heading |",
|
|
80
|
+
"| `description` | `ReactNode` | — | Body copy (large only) |",
|
|
81
|
+
'| `confirmLabel` | `ReactNode` | `"Confirm"` | Primary pill |',
|
|
82
|
+
'| `cancelLabel` | `ReactNode` | `"Cancel"` | Secondary pill (large only) |',
|
|
83
|
+
"| `onConfirm` / `onCancel` / `onDismiss` | `() => void` | — | Action and close handlers |",
|
|
84
|
+
].join("\n"),
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
argTypes: {
|
|
89
|
+
variant: {
|
|
90
|
+
name: "Appearance",
|
|
91
|
+
control: "select",
|
|
92
|
+
options: [...appearances],
|
|
93
|
+
},
|
|
94
|
+
size: { control: "select", options: [...sizes] },
|
|
95
|
+
indicator: { control: "select", options: [...indicators] },
|
|
96
|
+
action: { control: "boolean" },
|
|
97
|
+
title: { control: "text" },
|
|
98
|
+
description: { control: "text" },
|
|
99
|
+
confirmLabel: { control: "text" },
|
|
100
|
+
cancelLabel: { control: "text" },
|
|
101
|
+
avatarSrc: { control: "text" },
|
|
102
|
+
color: { table: { disable: true } },
|
|
103
|
+
},
|
|
104
|
+
args: {
|
|
105
|
+
variant: "solid",
|
|
106
|
+
size: "large",
|
|
107
|
+
indicator: "icon",
|
|
108
|
+
action: true,
|
|
109
|
+
title: "Alert Heading",
|
|
110
|
+
description: LOREM,
|
|
111
|
+
confirmLabel: "Confirm",
|
|
112
|
+
cancelLabel: "Cancel",
|
|
113
|
+
avatarSrc: samplePhoto,
|
|
114
|
+
},
|
|
115
|
+
} satisfies Meta<typeof ToastV01>;
|
|
116
|
+
|
|
117
|
+
export default meta;
|
|
118
|
+
type Story = StoryObj<typeof meta>;
|
|
119
|
+
|
|
120
|
+
export const Default: Story = {
|
|
121
|
+
args: { color: "default" },
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const Success: Story = {
|
|
125
|
+
args: { color: "success" },
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const Error: Story = {
|
|
129
|
+
args: { color: "error" },
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export const AllVariants: Story = {
|
|
133
|
+
name: "All Variants",
|
|
134
|
+
render: (args) => (
|
|
135
|
+
<div
|
|
136
|
+
style={{
|
|
137
|
+
display: "grid",
|
|
138
|
+
// minmax(0, 1fr) so the track can shrink below its max-content width.
|
|
139
|
+
gridTemplateColumns: "minmax(0, 1fr)",
|
|
140
|
+
justifyItems: "center",
|
|
141
|
+
gap: 40,
|
|
142
|
+
width: "100%",
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
{sizes.flatMap((size) =>
|
|
146
|
+
indicators.map((indicator) => (
|
|
147
|
+
<section
|
|
148
|
+
key={`${size}-${indicator}`}
|
|
149
|
+
style={{ width: "100%", maxWidth: 1112 }}
|
|
150
|
+
>
|
|
151
|
+
<h3
|
|
152
|
+
style={{
|
|
153
|
+
margin: "0 0 16px",
|
|
154
|
+
fontSize: 14,
|
|
155
|
+
fontWeight: 600,
|
|
156
|
+
textTransform: "uppercase",
|
|
157
|
+
letterSpacing: 0.5,
|
|
158
|
+
color: "#52545d",
|
|
159
|
+
textAlign: "center",
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
{size} · {indicator}
|
|
163
|
+
</h3>
|
|
164
|
+
<div
|
|
165
|
+
style={{
|
|
166
|
+
display: "grid",
|
|
167
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(360px, 1fr))",
|
|
168
|
+
maxWidth: 1112,
|
|
169
|
+
margin: "0 auto",
|
|
170
|
+
gap: 16,
|
|
171
|
+
justifyItems: "center",
|
|
172
|
+
}}
|
|
173
|
+
>
|
|
174
|
+
{appearances.flatMap((variant) =>
|
|
175
|
+
colors.map((color) => (
|
|
176
|
+
<ToastV01
|
|
177
|
+
key={`${size}-${indicator}-${variant}-${color}`}
|
|
178
|
+
{...args}
|
|
179
|
+
size={size}
|
|
180
|
+
indicator={indicator}
|
|
181
|
+
variant={variant}
|
|
182
|
+
color={color}
|
|
183
|
+
title="Alert Heading"
|
|
184
|
+
description={LOREM}
|
|
185
|
+
avatarSrc={samplePhoto}
|
|
186
|
+
/>
|
|
187
|
+
)),
|
|
188
|
+
)}
|
|
189
|
+
</div>
|
|
190
|
+
</section>
|
|
191
|
+
)),
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
),
|
|
195
|
+
argTypes: {
|
|
196
|
+
variant: { table: { disable: true } },
|
|
197
|
+
size: { table: { disable: true } },
|
|
198
|
+
indicator: { table: { disable: true } },
|
|
199
|
+
},
|
|
200
|
+
parameters: { layout: "padded" },
|
|
201
|
+
};
|
|
@@ -6,7 +6,7 @@ import { UtilityAccordion } from "../components/icons/UtilityAccordion";
|
|
|
6
6
|
import { UtilityText } from "../components/icons/UtilityText";
|
|
7
7
|
|
|
8
8
|
const meta = {
|
|
9
|
-
title: "
|
|
9
|
+
title: "Components/Toggle",
|
|
10
10
|
component: SegmentedControl,
|
|
11
11
|
tags: ["autodocs"],
|
|
12
12
|
parameters: {
|
|
@@ -1,139 +1,312 @@
|
|
|
1
|
+
import * as React from "react";
|
|
1
2
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
3
|
import {
|
|
3
4
|
Tooltip,
|
|
4
5
|
TooltipContent,
|
|
6
|
+
TooltipPanel,
|
|
5
7
|
TooltipTrigger,
|
|
6
8
|
} from "../components/ui/tooltip";
|
|
7
|
-
import { Separator } from "../components/ui/separator";
|
|
8
|
-
import { Button } from "../components/ui/button";
|
|
9
|
-
import { Text } from "../components/ui/typography";
|
|
10
9
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
component: Tooltip,
|
|
14
|
-
tags: ["autodocs"],
|
|
15
|
-
parameters: {
|
|
16
|
-
layout: "centered",
|
|
17
|
-
},
|
|
18
|
-
} satisfies Meta<typeof Tooltip>;
|
|
10
|
+
const tones = ["dark", "light"] as const;
|
|
11
|
+
const directions = ["top", "bottom", "left", "right"] as const;
|
|
19
12
|
|
|
20
|
-
|
|
13
|
+
// The panel is portaled, so centring it means boxing the trigger inside the
|
|
14
|
+
// group's footprint and insetting it by the panel's own alignOffset shift.
|
|
15
|
+
const PANEL_W = 400;
|
|
16
|
+
const PANEL_H = { vertical: 234, horizontal: 226 } as const;
|
|
17
|
+
const SIDE_OFFSET = 12;
|
|
18
|
+
const TRIGGER = { w: 65, h: 24 };
|
|
19
|
+
const MARKER_CENTRE = { inline: 54 + 5, block: 53 + 5 } as const;
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
const shift = {
|
|
22
|
+
inline: MARKER_CENTRE.inline - TRIGGER.w / 2,
|
|
23
|
+
block: MARKER_CENTRE.block - TRIGGER.h / 2,
|
|
24
|
+
};
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</div>
|
|
49
|
-
),
|
|
26
|
+
const group: Record<
|
|
27
|
+
(typeof directions)[number],
|
|
28
|
+
{ width: number; height: number; trigger: React.CSSProperties }
|
|
29
|
+
> = {
|
|
30
|
+
top: {
|
|
31
|
+
width: PANEL_W,
|
|
32
|
+
height: TRIGGER.h + SIDE_OFFSET + PANEL_H.vertical,
|
|
33
|
+
trigger: { left: shift.inline, top: 0 },
|
|
34
|
+
},
|
|
35
|
+
bottom: {
|
|
36
|
+
width: PANEL_W,
|
|
37
|
+
height: TRIGGER.h + SIDE_OFFSET + PANEL_H.vertical,
|
|
38
|
+
trigger: { left: shift.inline, bottom: 0 },
|
|
39
|
+
},
|
|
40
|
+
left: {
|
|
41
|
+
width: TRIGGER.w + SIDE_OFFSET + PANEL_W,
|
|
42
|
+
height: PANEL_H.horizontal,
|
|
43
|
+
trigger: { left: 0, top: shift.block },
|
|
44
|
+
},
|
|
45
|
+
right: {
|
|
46
|
+
width: TRIGGER.w + SIDE_OFFSET + PANEL_W,
|
|
47
|
+
height: PANEL_H.horizontal,
|
|
48
|
+
trigger: { right: 0, top: shift.block },
|
|
49
|
+
},
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<Tooltip trigger="click">
|
|
56
|
-
<TooltipTrigger>Click me</TooltipTrigger>
|
|
57
|
-
<TooltipContent className="w-[400px]">
|
|
58
|
-
<div className="space-y-3">
|
|
59
|
-
<Text as="h1" variant="body-base" className="text-white">
|
|
60
|
-
Click Tooltip
|
|
61
|
-
</Text>
|
|
62
|
-
<div className="space-y-1">
|
|
63
|
-
<Text as="p" variant="body-small" className="text-white/90">
|
|
64
|
-
This tooltip opens on click and closes when clicking outside.
|
|
65
|
-
</Text>
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
</TooltipContent>
|
|
69
|
-
</Tooltip>
|
|
70
|
-
</div>
|
|
71
|
-
),
|
|
52
|
+
type StoryArgs = React.ComponentProps<typeof TooltipContent> & {
|
|
53
|
+
/** `trigger` on the `Tooltip` root. */
|
|
54
|
+
trigger?: "hover" | "click";
|
|
72
55
|
};
|
|
73
56
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<Text as="p" variant="body-small">
|
|
81
|
-
<span className="font-semibold">Required</span> for certification
|
|
82
|
-
</Text>
|
|
83
|
-
</TooltipContent>
|
|
84
|
-
</Tooltip>
|
|
85
|
-
</div>
|
|
86
|
-
),
|
|
57
|
+
const copy = {
|
|
58
|
+
heading: "Heading",
|
|
59
|
+
body: "Body text",
|
|
60
|
+
conditionalText: "Conditional body text",
|
|
61
|
+
primaryLabel: "Label",
|
|
62
|
+
secondaryLabel: "Label",
|
|
87
63
|
};
|
|
88
64
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
65
|
+
const meta = {
|
|
66
|
+
title: "Components/Tooltip",
|
|
67
|
+
component: TooltipContent,
|
|
68
|
+
tags: ["autodocs"],
|
|
69
|
+
args: {
|
|
70
|
+
tone: "dark",
|
|
71
|
+
direction: "top",
|
|
72
|
+
trigger: "click",
|
|
73
|
+
...copy,
|
|
74
|
+
},
|
|
75
|
+
argTypes: {
|
|
76
|
+
direction: {
|
|
77
|
+
control: "inline-radio",
|
|
78
|
+
options: [...directions],
|
|
79
|
+
description:
|
|
80
|
+
"Which edge the marker sits on. That edge also carries the extra 8px of padding, and the panel opens on the opposite side so the marker points back at the trigger.",
|
|
81
|
+
table: { defaultValue: { summary: "top" } },
|
|
82
|
+
},
|
|
83
|
+
trigger: {
|
|
84
|
+
control: "inline-radio",
|
|
85
|
+
options: ["hover", "click"],
|
|
86
|
+
description:
|
|
87
|
+
"How the panel opens. `click` stays put until you click the trigger again, click outside, or press Escape. `hover` follows the pointer — better for short labels than for this panel.",
|
|
88
|
+
table: { defaultValue: { summary: "click" } },
|
|
89
|
+
},
|
|
90
|
+
heading: { control: "text", description: "Title line." },
|
|
91
|
+
body: {
|
|
92
|
+
control: "text",
|
|
93
|
+
description: "Supporting copy beneath the heading.",
|
|
94
|
+
},
|
|
95
|
+
conditionalText: {
|
|
96
|
+
control: "text",
|
|
97
|
+
description:
|
|
98
|
+
"Extra copy below the dashed divider. Clear it to drop both.",
|
|
99
|
+
},
|
|
100
|
+
primaryLabel: { control: "text", description: "Filled action pill." },
|
|
101
|
+
secondaryLabel: { control: "text", description: "Muted action pill." },
|
|
102
|
+
tone: { table: { disable: true } },
|
|
103
|
+
align: { table: { disable: true } },
|
|
104
|
+
sideOffset: { table: { disable: true } },
|
|
105
|
+
alignOffset: { table: { disable: true } },
|
|
106
|
+
children: { table: { disable: true } },
|
|
107
|
+
className: { table: { disable: true } },
|
|
108
|
+
asChild: { table: { disable: true } },
|
|
109
|
+
},
|
|
110
|
+
parameters: {
|
|
111
|
+
layout: "padded",
|
|
112
|
+
docs: {
|
|
113
|
+
description: {
|
|
114
|
+
component: [
|
|
115
|
+
"Tooltip panel: a 400px card with a heading, supporting copy, a dashed",
|
|
116
|
+
"divider, conditional copy, and up to two action pills. A half-ellipse",
|
|
117
|
+
"marker sits flush with the edge that faces the trigger.",
|
|
118
|
+
"",
|
|
119
|
+
"Stories are the two tones: **Dark** and **Light** — click the trigger to",
|
|
120
|
+
"open one. Use **Controls** for `direction`, `trigger`, and the copy.",
|
|
121
|
+
"All Variants shows the full set of **8**.",
|
|
122
|
+
"",
|
|
123
|
+
"---",
|
|
124
|
+
"",
|
|
125
|
+
"## Import",
|
|
126
|
+
"",
|
|
127
|
+
"```tsx",
|
|
128
|
+
`import { Tooltip, TooltipTrigger, TooltipContent } from "@syscore/ui-library"`,
|
|
129
|
+
"```",
|
|
130
|
+
"",
|
|
131
|
+
"## How to use",
|
|
132
|
+
"",
|
|
133
|
+
"Pass the copy as props — `heading`, `body`, `conditionalText` — rather than",
|
|
134
|
+
"children, so the 32px rhythm and cap-height trim stay exact. Supplying",
|
|
135
|
+
"`conditionalText` adds the dashed divider above it.",
|
|
136
|
+
"",
|
|
137
|
+
"```tsx",
|
|
138
|
+
"<Tooltip>",
|
|
139
|
+
" <TooltipTrigger>Details</TooltipTrigger>",
|
|
140
|
+
" <TooltipContent",
|
|
141
|
+
` direction="top"`,
|
|
142
|
+
` tone="dark"`,
|
|
143
|
+
` heading="Heading"`,
|
|
144
|
+
` body="Body text"`,
|
|
145
|
+
` conditionalText="Conditional body text"`,
|
|
146
|
+
` primaryLabel="Label"`,
|
|
147
|
+
` secondaryLabel="Label"`,
|
|
148
|
+
" onPrimaryAction={handleConfirm}",
|
|
149
|
+
" onSecondaryAction={handleDismiss}",
|
|
150
|
+
" />",
|
|
151
|
+
"</Tooltip>",
|
|
152
|
+
"```",
|
|
153
|
+
"",
|
|
154
|
+
"`trigger` defaults to `click`: the panel opens on click and stays until you",
|
|
155
|
+
"click the trigger again, click outside, or press Escape. That suits a surface",
|
|
156
|
+
"this size with two action pills, and it is the only mode that works on touch,",
|
|
157
|
+
"where there is no hover at all.",
|
|
158
|
+
"",
|
|
159
|
+
'`trigger="hover"` fits short labels instead. Content stays hoverable in that',
|
|
160
|
+
"mode, so pills are still reachable, but the panel closes as soon as the",
|
|
161
|
+
"pointer leaves.",
|
|
162
|
+
"",
|
|
163
|
+
"## Placement",
|
|
164
|
+
"",
|
|
165
|
+
"`direction` names the edge the marker sits on. That edge takes the extra 8px",
|
|
166
|
+
"of padding, and the panel opens on the opposite side so the marker points",
|
|
167
|
+
"back at the trigger:",
|
|
168
|
+
"",
|
|
169
|
+
"| `direction` | Marker edge | Extra padding | Panel opens |",
|
|
170
|
+
"|---|---|---|---|",
|
|
171
|
+
'| `"top"` | top | `padding-top` | below the trigger |',
|
|
172
|
+
'| `"bottom"` | bottom | `padding-bottom` | above the trigger |',
|
|
173
|
+
'| `"left"` | left | `padding-left` | right of the trigger |',
|
|
174
|
+
'| `"right"` | right | `padding-right` | left of the trigger |',
|
|
175
|
+
"",
|
|
176
|
+
"The marker keeps a fixed 54px offset from the leading edge and does not",
|
|
177
|
+
"follow the trigger — override `--tooltip-marker-inline` (top/bottom) or",
|
|
178
|
+
"`--tooltip-marker-block` (left/right) to move it.",
|
|
179
|
+
"",
|
|
180
|
+
"## Props",
|
|
181
|
+
"",
|
|
182
|
+
"| Prop | Values | Default | Effect |",
|
|
183
|
+
"|------|--------|---------|--------|",
|
|
184
|
+
'| `tone` | `"dark"` \\| `"light"` | `"dark"` | Colour scheme (stories) |',
|
|
185
|
+
'| `direction` | `"top"` \\| `"bottom"` \\| `"left"` \\| `"right"` | `"top"` | Marker edge; also sets the padding side and where the panel opens |',
|
|
186
|
+
"| `heading` | `ReactNode` | — | Title line (16px/21px, weight 500) |",
|
|
187
|
+
"| `body` | `ReactNode` | — | Supporting copy (16px/21px, weight 400) |",
|
|
188
|
+
"| `conditionalText` | `ReactNode` | — | Copy below the dashed divider; adds the divider |",
|
|
189
|
+
"| `primaryLabel` | `ReactNode` | — | Filled pill — cyan on dark, blue on light |",
|
|
190
|
+
"| `secondaryLabel` | `ReactNode` | — | Muted pill — grey on dark, outlined white on light |",
|
|
191
|
+
"| `onPrimaryAction` | `() => void` | — | Filled pill handler |",
|
|
192
|
+
"| `onSecondaryAction` | `() => void` | — | Muted pill handler |",
|
|
193
|
+
'| `trigger` (on `Tooltip`) | `"click"` \\| `"hover"` | `"click"` | How the panel opens |',
|
|
194
|
+
].join("\n"),
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
render: ({ trigger, ...args }) => (
|
|
199
|
+
<div
|
|
200
|
+
style={{
|
|
201
|
+
display: "flex",
|
|
202
|
+
height: 340,
|
|
203
|
+
alignItems: "center",
|
|
204
|
+
justifyContent: "center",
|
|
205
|
+
}}
|
|
206
|
+
>
|
|
207
|
+
<div
|
|
208
|
+
style={{
|
|
209
|
+
position: "relative",
|
|
210
|
+
width: group[args.direction ?? "top"].width,
|
|
211
|
+
height: group[args.direction ?? "top"].height,
|
|
212
|
+
}}
|
|
213
|
+
>
|
|
214
|
+
<div
|
|
215
|
+
style={{
|
|
216
|
+
position: "absolute",
|
|
217
|
+
...group[args.direction ?? "top"].trigger,
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
<Tooltip trigger={trigger}>
|
|
221
|
+
<TooltipTrigger className="tooltip-link-trigger">
|
|
222
|
+
{trigger === "click" ? "Click me" : "Hover me"}
|
|
223
|
+
</TooltipTrigger>
|
|
224
|
+
<TooltipContent {...args} />
|
|
225
|
+
</Tooltip>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
109
228
|
</div>
|
|
110
229
|
),
|
|
230
|
+
} satisfies Meta<StoryArgs>;
|
|
231
|
+
|
|
232
|
+
export default meta;
|
|
233
|
+
|
|
234
|
+
type Story = StoryObj<typeof meta>;
|
|
235
|
+
|
|
236
|
+
export const Dark: Story = {
|
|
237
|
+
args: { tone: "dark" },
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export const Light: Story = {
|
|
241
|
+
args: { tone: "light" },
|
|
111
242
|
};
|
|
112
243
|
|
|
113
|
-
export const
|
|
244
|
+
export const AllVariants: Story = {
|
|
245
|
+
name: "All Variants",
|
|
246
|
+
parameters: { layout: "padded", controls: { disable: true } },
|
|
247
|
+
argTypes: {
|
|
248
|
+
direction: { table: { disable: true } },
|
|
249
|
+
trigger: { table: { disable: true } },
|
|
250
|
+
},
|
|
114
251
|
render: () => (
|
|
115
|
-
<div
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
252
|
+
<div
|
|
253
|
+
style={{
|
|
254
|
+
display: "grid",
|
|
255
|
+
// minmax(0, 1fr) so the track can shrink below its max-content width.
|
|
256
|
+
gridTemplateColumns: "minmax(0, 1fr)",
|
|
257
|
+
justifyItems: "center",
|
|
258
|
+
gap: 40,
|
|
259
|
+
width: "100%",
|
|
260
|
+
}}
|
|
261
|
+
>
|
|
262
|
+
{tones.map((tone) => (
|
|
263
|
+
<section key={tone} style={{ width: "100%", maxWidth: 824 }}>
|
|
264
|
+
<h3
|
|
265
|
+
style={{
|
|
266
|
+
margin: "0 0 16px",
|
|
267
|
+
fontSize: 14,
|
|
268
|
+
fontWeight: 600,
|
|
269
|
+
textTransform: "uppercase",
|
|
270
|
+
letterSpacing: 0.5,
|
|
271
|
+
color: "#52545d",
|
|
272
|
+
textAlign: "center",
|
|
273
|
+
}}
|
|
274
|
+
>
|
|
275
|
+
{tone}
|
|
276
|
+
</h3>
|
|
277
|
+
<div
|
|
278
|
+
style={{
|
|
279
|
+
display: "grid",
|
|
280
|
+
// Capped at two tracks so the four directions land 2x2.
|
|
281
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(400px, 1fr))",
|
|
282
|
+
maxWidth: 824,
|
|
283
|
+
margin: "0 auto",
|
|
284
|
+
gap: 24,
|
|
285
|
+
alignItems: "start",
|
|
286
|
+
justifyItems: "center",
|
|
287
|
+
}}
|
|
288
|
+
>
|
|
289
|
+
{directions.map((direction) => (
|
|
290
|
+
<div key={direction}>
|
|
291
|
+
<p
|
|
292
|
+
style={{
|
|
293
|
+
margin: "0 0 8px",
|
|
294
|
+
fontSize: 11,
|
|
295
|
+
fontWeight: 600,
|
|
296
|
+
textTransform: "uppercase",
|
|
297
|
+
letterSpacing: 0.4,
|
|
298
|
+
color: "#71747d",
|
|
299
|
+
textAlign: "center",
|
|
300
|
+
}}
|
|
301
|
+
>
|
|
302
|
+
{direction}
|
|
303
|
+
</p>
|
|
304
|
+
<TooltipPanel tone={tone} direction={direction} {...copy} />
|
|
305
|
+
</div>
|
|
306
|
+
))}
|
|
126
307
|
</div>
|
|
127
|
-
</
|
|
128
|
-
|
|
129
|
-
<Tooltip>
|
|
130
|
-
<TooltipTrigger>Simple</TooltipTrigger>
|
|
131
|
-
<TooltipContent variant="simple">
|
|
132
|
-
<Text as="p" variant="body-base">
|
|
133
|
-
Required for certification
|
|
134
|
-
</Text>
|
|
135
|
-
</TooltipContent>
|
|
136
|
-
</Tooltip>
|
|
308
|
+
</section>
|
|
309
|
+
))}
|
|
137
310
|
</div>
|
|
138
311
|
),
|
|
139
312
|
};
|