@fragments-sdk/ui 0.17.1 → 0.19.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/assets/ui.css +2700 -3256
- package/dist/chart.cjs +0 -1
- package/dist/chart.js +0 -1
- package/dist/codeblock.cjs +0 -1
- package/dist/codeblock.js +0 -1
- package/dist/colorpicker.cjs +0 -1
- package/dist/colorpicker.js +0 -1
- package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
- package/dist/components/Accordion/Accordion.module.scss.js +8 -8
- package/dist/components/Alert/Alert.module.scss.cjs +12 -12
- package/dist/components/Alert/Alert.module.scss.js +12 -12
- package/dist/components/AppShell/AppShell.module.scss.cjs +12 -12
- package/dist/components/AppShell/AppShell.module.scss.js +12 -12
- package/dist/components/Avatar/Avatar.module.scss.cjs +13 -13
- package/dist/components/Avatar/Avatar.module.scss.js +13 -13
- package/dist/components/Badge/Badge.module.scss.cjs +13 -13
- package/dist/components/Badge/Badge.module.scss.js +13 -13
- package/dist/components/BentoGrid/BentoGrid.module.scss.cjs +14 -14
- package/dist/components/BentoGrid/BentoGrid.module.scss.js +14 -14
- package/dist/components/Box/Box.module.scss.cjs +152 -152
- package/dist/components/Box/Box.module.scss.js +152 -152
- package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.cjs +8 -8
- package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.js +8 -8
- package/dist/components/Button/Button.module.scss.cjs +12 -12
- package/dist/components/Button/Button.module.scss.js +12 -12
- package/dist/components/Card/Card.module.scss.cjs +14 -14
- package/dist/components/Card/Card.module.scss.js +14 -14
- package/dist/components/Chart/Chart.module.scss.cjs +15 -15
- package/dist/components/Chart/Chart.module.scss.js +15 -15
- package/dist/components/Chart/index.d.ts +0 -1
- package/dist/components/Chart/index.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.module.scss.cjs +10 -10
- package/dist/components/Checkbox/Checkbox.module.scss.js +10 -10
- package/dist/components/Chip/Chip.module.scss.cjs +15 -15
- package/dist/components/Chip/Chip.module.scss.js +15 -15
- package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +21 -21
- package/dist/components/CodeBlock/CodeBlock.module.scss.js +21 -21
- package/dist/components/CodeBlock/index.d.ts +0 -1
- package/dist/components/CodeBlock/index.d.ts.map +1 -1
- package/dist/components/Collapsible/Collapsible.module.scss.cjs +10 -10
- package/dist/components/Collapsible/Collapsible.module.scss.js +10 -10
- package/dist/components/ColorPicker/ColorPicker.module.scss.cjs +14 -14
- package/dist/components/ColorPicker/ColorPicker.module.scss.js +14 -14
- package/dist/components/ColorPicker/index.d.ts +0 -1
- package/dist/components/ColorPicker/index.d.ts.map +1 -1
- package/dist/components/Combobox/Combobox.module.scss.cjs +23 -23
- package/dist/components/Combobox/Combobox.module.scss.js +23 -23
- package/dist/components/Combobox/index.cjs +13 -10
- package/dist/components/Combobox/index.d.ts.map +1 -1
- package/dist/components/Combobox/index.js +13 -10
- package/dist/components/Command/Command.module.scss.cjs +11 -11
- package/dist/components/Command/Command.module.scss.js +11 -11
- package/dist/components/ConversationList/ConversationList.module.scss.cjs +10 -10
- package/dist/components/ConversationList/ConversationList.module.scss.js +10 -10
- package/dist/components/DataTable/DataTable.module.scss.cjs +26 -26
- package/dist/components/DataTable/DataTable.module.scss.js +26 -26
- package/dist/components/DataTable/index.cjs +0 -1
- package/dist/components/DataTable/index.d.ts +0 -1
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DataTable/index.js +0 -1
- package/dist/components/DatePicker/DatePicker.module.scss.cjs +31 -31
- package/dist/components/DatePicker/DatePicker.module.scss.js +31 -31
- package/dist/components/DatePicker/index.d.ts +0 -1
- package/dist/components/DatePicker/index.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.module.scss.cjs +14 -14
- package/dist/components/Dialog/Dialog.module.scss.js +14 -14
- package/dist/components/Drawer/Drawer.module.scss.cjs +33 -27
- package/dist/components/Drawer/Drawer.module.scss.js +34 -28
- package/dist/components/Drawer/index.cjs +36 -14
- package/dist/components/Drawer/index.d.ts +21 -3
- package/dist/components/Drawer/index.d.ts.map +1 -1
- package/dist/components/Drawer/index.js +36 -14
- package/dist/components/Editor/Editor.module.scss.cjs +17 -17
- package/dist/components/Editor/Editor.module.scss.js +17 -17
- package/dist/components/EmptyState/EmptyState.module.scss.cjs +8 -8
- package/dist/components/EmptyState/EmptyState.module.scss.js +8 -8
- package/dist/components/Field/Field.module.scss.cjs +4 -4
- package/dist/components/Field/Field.module.scss.js +4 -4
- package/dist/components/Fieldset/Fieldset.module.scss.cjs +3 -3
- package/dist/components/Fieldset/Fieldset.module.scss.js +3 -3
- package/dist/components/Header/Header.module.scss.cjs +28 -28
- package/dist/components/Header/Header.module.scss.js +28 -28
- package/dist/components/Icon/Icon.module.scss.cjs +8 -8
- package/dist/components/Icon/Icon.module.scss.js +8 -8
- package/dist/components/Image/Image.module.scss.cjs +27 -27
- package/dist/components/Image/Image.module.scss.js +27 -27
- package/dist/components/Input/Input.module.scss.cjs +19 -19
- package/dist/components/Input/Input.module.scss.js +19 -19
- package/dist/components/Link/Link.module.scss.cjs +10 -10
- package/dist/components/Link/Link.module.scss.js +10 -10
- package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
- package/dist/components/Listbox/Listbox.module.scss.js +8 -8
- package/dist/components/Loading/Loading.module.scss.cjs +30 -30
- package/dist/components/Loading/Loading.module.scss.js +30 -30
- package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
- package/dist/components/Markdown/Markdown.module.scss.js +1 -1
- package/dist/components/Markdown/index.d.ts +0 -1
- package/dist/components/Markdown/index.d.ts.map +1 -1
- package/dist/components/Menu/Menu.module.scss.cjs +16 -13
- package/dist/components/Menu/Menu.module.scss.js +17 -14
- package/dist/components/Menu/index.cjs +1 -1
- package/dist/components/Menu/index.d.ts.map +1 -1
- package/dist/components/Menu/index.js +1 -1
- package/dist/components/Message/Message.module.scss.cjs +18 -18
- package/dist/components/Message/Message.module.scss.js +18 -18
- package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +28 -28
- package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +28 -28
- package/dist/components/Pagination/Pagination.module.scss.cjs +7 -7
- package/dist/components/Pagination/Pagination.module.scss.js +7 -7
- package/dist/components/Popover/Popover.module.scss.cjs +10 -10
- package/dist/components/Popover/Popover.module.scss.js +10 -10
- package/dist/components/Progress/Progress.module.scss.cjs +25 -25
- package/dist/components/Progress/Progress.module.scss.js +25 -25
- package/dist/components/Prompt/Prompt.module.scss.cjs +26 -14
- package/dist/components/Prompt/Prompt.module.scss.js +26 -14
- package/dist/components/Prompt/index.cjs +16 -0
- package/dist/components/Prompt/index.d.ts +17 -1
- package/dist/components/Prompt/index.d.ts.map +1 -1
- package/dist/components/Prompt/index.js +16 -0
- package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +16 -16
- package/dist/components/RadioGroup/RadioGroup.module.scss.js +16 -16
- package/dist/components/ScrollArea/ScrollArea.module.scss.cjs +10 -10
- package/dist/components/ScrollArea/ScrollArea.module.scss.js +10 -10
- package/dist/components/Select/Select.module.scss.cjs +17 -17
- package/dist/components/Select/Select.module.scss.js +17 -17
- package/dist/components/Select/index.cjs +20 -20
- package/dist/components/Select/index.d.ts.map +1 -1
- package/dist/components/Select/index.js +20 -20
- package/dist/components/Separator/Separator.module.scss.cjs +10 -10
- package/dist/components/Separator/Separator.module.scss.js +10 -10
- package/dist/components/Sidebar/Sidebar.module.scss.cjs +42 -42
- package/dist/components/Sidebar/Sidebar.module.scss.js +42 -42
- package/dist/components/Slider/Slider.module.scss.cjs +12 -12
- package/dist/components/Slider/Slider.module.scss.js +12 -12
- package/dist/components/Slider/index.cjs +23 -21
- package/dist/components/Slider/index.js +23 -21
- package/dist/components/Stack/Stack.module.scss.cjs +35 -35
- package/dist/components/Stack/Stack.module.scss.js +35 -35
- package/dist/components/Table/Table.module.scss.cjs +16 -16
- package/dist/components/Table/Table.module.scss.js +16 -16
- package/dist/components/Table/index.d.ts +0 -1
- package/dist/components/Table/index.d.ts.map +1 -1
- package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +7 -7
- package/dist/components/TableOfContents/TableOfContents.module.scss.js +7 -7
- package/dist/components/Tabs/Tabs.module.scss.cjs +9 -9
- package/dist/components/Tabs/Tabs.module.scss.js +9 -9
- package/dist/components/Text/Text.module.scss.cjs +38 -38
- package/dist/components/Text/Text.module.scss.js +38 -38
- package/dist/components/Textarea/Textarea.module.scss.cjs +23 -23
- package/dist/components/Textarea/Textarea.module.scss.js +23 -23
- package/dist/components/Theme/ThemeToggle.module.scss.cjs +6 -6
- package/dist/components/Theme/ThemeToggle.module.scss.js +6 -6
- package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.cjs +22 -22
- package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.js +22 -22
- package/dist/components/Toast/Toast.module.scss.cjs +20 -20
- package/dist/components/Toast/Toast.module.scss.js +20 -20
- package/dist/components/Toggle/Toggle.module.scss.cjs +13 -13
- package/dist/components/Toggle/Toggle.module.scss.js +13 -13
- package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
- package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
- package/dist/components/Tooltip/Tooltip.module.scss.cjs +3 -3
- package/dist/components/Tooltip/Tooltip.module.scss.js +3 -3
- package/dist/components/Tooltip/index.cjs +4 -3
- package/dist/components/Tooltip/index.d.ts +4 -1
- package/dist/components/Tooltip/index.d.ts.map +1 -1
- package/dist/components/Tooltip/index.js +4 -3
- package/dist/datepicker.cjs +0 -1
- package/dist/datepicker.js +0 -1
- package/dist/index.cjs +0 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/markdown.cjs +0 -1
- package/dist/markdown.js +0 -1
- package/dist/table.cjs +0 -1
- package/dist/table.js +0 -1
- package/dist/utils/seed-derivation.cjs +29 -0
- package/dist/utils/seed-derivation.d.ts +1 -1
- package/dist/utils/seed-derivation.d.ts.map +1 -1
- package/dist/utils/seed-derivation.js +29 -0
- package/fragments.json +1 -1
- package/package.json +18 -14
- package/src/components/Accordion/Accordion.contract.json +169 -0
- package/src/components/Alert/Alert.contract.json +157 -0
- package/src/components/AppShell/AppShell.contract.json +155 -0
- package/src/components/Avatar/Avatar.contract.json +189 -0
- package/src/components/Badge/Badge.contract.json +187 -0
- package/src/components/BentoGrid/BentoGrid.contract.json +135 -0
- package/src/components/Box/Box.contract.json +423 -0
- package/src/components/Breadcrumbs/Breadcrumbs.contract.json +143 -0
- package/src/components/Button/Button.contract.json +205 -0
- package/src/components/Button/Button.module.scss +24 -1
- package/src/components/ButtonGroup/ButtonGroup.contract.json +140 -0
- package/src/components/Card/Card.contract.json +185 -0
- package/src/components/Card/Card.module.scss +5 -1
- package/src/components/Chart/Chart.contract.json +129 -0
- package/src/components/Chart/index.tsx +0 -1
- package/src/components/Checkbox/Checkbox.contract.json +246 -0
- package/src/components/Chip/Chip.contract.json +212 -0
- package/src/components/Chip/Chip.module.scss +4 -4
- package/src/components/CodeBlock/CodeBlock.contract.json +388 -0
- package/src/components/CodeBlock/index.tsx +0 -1
- package/src/components/Collapsible/Collapsible.contract.json +154 -0
- package/src/components/ColorPicker/ColorPicker.contract.json +212 -0
- package/src/components/ColorPicker/index.tsx +0 -1
- package/src/components/Combobox/Combobox.contract.json +297 -0
- package/src/components/Combobox/index.tsx +7 -8
- package/src/components/Command/Command.contract.json +165 -0
- package/src/components/Command/Command.module.scss +22 -9
- package/src/components/ConversationList/ConversationList.contract.json +151 -0
- package/src/components/DataTable/DataTable.contract.json +302 -0
- package/src/components/DataTable/index.tsx +0 -2
- package/src/components/DatePicker/DatePicker.contract.json +288 -0
- package/src/components/DatePicker/index.tsx +0 -2
- package/src/components/Dialog/Dialog.contract.json +159 -0
- package/src/components/Drawer/Drawer.contract.json +161 -0
- package/src/components/Drawer/Drawer.module.scss +45 -5
- package/src/components/Drawer/index.tsx +66 -23
- package/src/components/Editor/Editor.contract.json +263 -0
- package/src/components/EmptyState/EmptyState.contract.json +133 -0
- package/src/components/Field/Field.contract.json +157 -0
- package/src/components/Fieldset/Fieldset.contract.json +117 -0
- package/src/components/Form/Form.contract.json +145 -0
- package/src/components/Grid/Grid.contract.json +195 -0
- package/src/components/Header/Header.contract.json +196 -0
- package/src/components/Icon/Icon.contract.json +194 -0
- package/src/components/Image/Image.contract.json +209 -0
- package/src/components/Input/Input.contract.json +344 -0
- package/src/components/Input/Input.module.scss +16 -6
- package/src/components/Link/Link.contract.json +180 -0
- package/src/components/List/List.contract.json +154 -0
- package/src/components/Listbox/Listbox.contract.json +158 -0
- package/src/components/Loading/Loading.contract.json +167 -0
- package/src/components/Markdown/Markdown.contract.json +127 -0
- package/src/components/Markdown/Markdown.module.scss +0 -3
- package/src/components/Markdown/index.tsx +0 -1
- package/src/components/Menu/Menu.contract.json +177 -0
- package/src/components/Menu/Menu.module.scss +6 -0
- package/src/components/Menu/index.tsx +3 -1
- package/src/components/Message/Message.contract.json +183 -0
- package/src/components/Message/Message.module.scss +2 -2
- package/src/components/NavigationMenu/NavigationMenu.contract.json +203 -0
- package/src/components/NavigationMenu/NavigationMenu.module.scss +18 -23
- package/src/components/Pagination/Pagination.contract.json +163 -0
- package/src/components/Pagination/Pagination.module.scss +1 -1
- package/src/components/Popover/Popover.contract.json +163 -0
- package/src/components/Progress/Progress.contract.json +176 -0
- package/src/components/Prompt/Prompt.contract.json +211 -0
- package/src/components/Prompt/Prompt.module.scss +117 -3
- package/src/components/Prompt/index.tsx +40 -0
- package/src/components/RadioGroup/RadioGroup.contract.json +226 -0
- package/src/components/ScrollArea/ScrollArea.contract.json +131 -0
- package/src/components/Select/Select.contract.json +269 -0
- package/src/components/Select/index.tsx +20 -25
- package/src/components/Separator/Separator.contract.json +143 -0
- package/src/components/Sidebar/Sidebar.contract.json +258 -0
- package/src/components/Sidebar/Sidebar.module.scss +1 -1
- package/src/components/Skeleton/Skeleton.contract.json +166 -0
- package/src/components/Slider/Slider.contract.json +248 -0
- package/src/components/Slider/index.tsx +10 -10
- package/src/components/Stack/Stack.contract.json +220 -0
- package/src/components/Table/Table.contract.json +171 -0
- package/src/components/Table/index.tsx +0 -2
- package/src/components/TableOfContents/TableOfContents.contract.json +145 -0
- package/src/components/TableOfContents/TableOfContents.module.scss +19 -15
- package/src/components/Tabs/Tabs.contract.json +159 -0
- package/src/components/Text/Text.contract.json +239 -0
- package/src/components/Textarea/Textarea.contract.json +308 -0
- package/src/components/Theme/Theme.contract.json +152 -0
- package/src/components/ThinkingIndicator/ThinkingIndicator.contract.json +165 -0
- package/src/components/Toast/Toast.contract.json +181 -0
- package/src/components/Toggle/Toggle.contract.json +231 -0
- package/src/components/Toggle/Toggle.module.scss +3 -3
- package/src/components/ToggleGroup/ToggleGroup.contract.json +206 -0
- package/src/components/Tooltip/Tooltip.contract.json +214 -0
- package/src/components/Tooltip/index.tsx +7 -3
- package/src/components/VisuallyHidden/VisuallyHidden.contract.json +116 -0
- package/src/index.ts +8 -3
- package/src/styles/globals.scss +6 -1
- package/src/tokens/_computed.scss +3 -1
- package/src/tokens/_density.scss +4 -4
- package/src/tokens/_derive.scss +52 -56
- package/src/tokens/_palettes.scss +20 -1
- package/src/tokens/_seeds.scss +2 -2
- package/src/tokens/_variables.scss +45 -29
- package/src/utils/seed-derivation.ts +23 -1
|
@@ -36,6 +36,9 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
36
36
|
defaultOpen?: boolean;
|
|
37
37
|
/** Callback when open state changes */
|
|
38
38
|
onOpenChange?: (open: boolean) => void;
|
|
39
|
+
/** Whether clicking the trigger closes the tooltip.
|
|
40
|
+
* @default false */
|
|
41
|
+
closeOnClick?: boolean;
|
|
39
42
|
/** Explicit props for the tooltip popup element (preferred over top-level HTMLAttributes for clarity) */
|
|
40
43
|
contentProps?: React.HTMLAttributes<HTMLDivElement>;
|
|
41
44
|
}
|
|
@@ -83,6 +86,7 @@ function TooltipRoot({
|
|
|
83
86
|
open,
|
|
84
87
|
defaultOpen,
|
|
85
88
|
onOpenChange,
|
|
89
|
+
closeOnClick = false,
|
|
86
90
|
contentProps,
|
|
87
91
|
className,
|
|
88
92
|
style,
|
|
@@ -113,8 +117,8 @@ function TooltipRoot({
|
|
|
113
117
|
[children],
|
|
114
118
|
);
|
|
115
119
|
|
|
116
|
-
if (disabled) {
|
|
117
|
-
return children;
|
|
120
|
+
if (disabled || !children) {
|
|
121
|
+
return children ?? null;
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
const {
|
|
@@ -129,7 +133,7 @@ function TooltipRoot({
|
|
|
129
133
|
defaultOpen={defaultOpen}
|
|
130
134
|
onOpenChange={onOpenChange}
|
|
131
135
|
>
|
|
132
|
-
<BaseTooltip.Trigger render={renderTrigger} />
|
|
136
|
+
<BaseTooltip.Trigger closeOnClick={closeOnClick} render={renderTrigger} />
|
|
133
137
|
<BaseTooltip.Portal>
|
|
134
138
|
<BaseTooltip.Positioner
|
|
135
139
|
side={side}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "VisuallyHidden",
|
|
4
|
+
"description": "Hides content visually while keeping it accessible to screen readers. Essential for accessible icon-only buttons and supplementary text.",
|
|
5
|
+
"category": "navigation",
|
|
6
|
+
"tags": [
|
|
7
|
+
"accessibility",
|
|
8
|
+
"a11y",
|
|
9
|
+
"screen-reader",
|
|
10
|
+
"hidden",
|
|
11
|
+
"sr-only"
|
|
12
|
+
],
|
|
13
|
+
"status": "stable",
|
|
14
|
+
"sourcePath": "src/components/VisuallyHidden/index.tsx",
|
|
15
|
+
"exportName": "VisuallyHidden",
|
|
16
|
+
"propsSummary": [
|
|
17
|
+
"children: node (required)",
|
|
18
|
+
"as: span|div (default: span)"
|
|
19
|
+
],
|
|
20
|
+
"props": {
|
|
21
|
+
"children": {
|
|
22
|
+
"type": "node",
|
|
23
|
+
"description": "Content to hide visually",
|
|
24
|
+
"required": true
|
|
25
|
+
},
|
|
26
|
+
"as": {
|
|
27
|
+
"type": "enum",
|
|
28
|
+
"description": "HTML element to render",
|
|
29
|
+
"default": "span",
|
|
30
|
+
"required": false,
|
|
31
|
+
"values": [
|
|
32
|
+
"span",
|
|
33
|
+
"div"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"usage": {
|
|
38
|
+
"when": [
|
|
39
|
+
"Providing accessible labels for icon-only buttons",
|
|
40
|
+
"Adding context that screen readers need but sighted users don't",
|
|
41
|
+
"Hiding decorative content while providing text alternatives",
|
|
42
|
+
"Skip links for keyboard navigation"
|
|
43
|
+
],
|
|
44
|
+
"whenNot": [
|
|
45
|
+
"Hiding content from everyone (use display: none or conditional render)",
|
|
46
|
+
"Content that should be visible on focus (use focus-visible styles)",
|
|
47
|
+
"Temporarily hidden content (use proper ARIA attributes)",
|
|
48
|
+
"Lazy-loaded content (use suspense or loading states)"
|
|
49
|
+
],
|
|
50
|
+
"guidelines": [
|
|
51
|
+
"Always use with icon-only interactive elements",
|
|
52
|
+
"Keep hidden text concise but descriptive",
|
|
53
|
+
"Test with screen readers to verify announcements",
|
|
54
|
+
"Don't overuse; visible text is often better",
|
|
55
|
+
"VisuallyHidden forwards DOM props and className to the rendered element"
|
|
56
|
+
],
|
|
57
|
+
"accessibility": [
|
|
58
|
+
"Content is announced by screen readers",
|
|
59
|
+
"Content is focusable if interactive elements are inside",
|
|
60
|
+
"Essential for WCAG 2.1 compliance with icon-only controls",
|
|
61
|
+
"Must convey equivalent information to visual content"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"examples": [
|
|
65
|
+
{
|
|
66
|
+
"name": "Icon Button Label",
|
|
67
|
+
"description": "Accessible label for icon-only button",
|
|
68
|
+
"code": "<button style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '40px',\n height: '40px',\n border: '1px solid var(--fui-border-default)',\n borderRadius: '8px',\n background: 'var(--fui-color-surface-primary)',\n cursor: 'pointer'\n}}>\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <VisuallyHidden>Search</VisuallyHidden>\n</button>"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "Supplementary Text",
|
|
72
|
+
"description": "Additional context for screen readers",
|
|
73
|
+
"code": "<a href=\"#\" style={{ color: 'var(--fui-color-accent)' }}>\n Read more\n <VisuallyHidden> about our accessibility features</VisuallyHidden>\n</a>"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "Skip Link",
|
|
77
|
+
"description": "Navigation aid that becomes visible on focus",
|
|
78
|
+
"code": "<div>\n <VisuallyHidden as=\"div\">\n <a\n href=\"#main-content\"\n style={{\n position: 'absolute',\n padding: '8px 16px',\n background: 'var(--fui-color-accent)',\n color: 'white'\n }}\n >\n Skip to main content\n </a>\n </VisuallyHidden>\n <p style={{ color: 'var(--fui-color-text-tertiary)', fontSize: '14px' }}>\n (Screen reader only: \"Skip to main content\" link)\n </p>\n</div>"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"relations": [
|
|
82
|
+
{
|
|
83
|
+
"component": "Button",
|
|
84
|
+
"relationship": "child",
|
|
85
|
+
"note": "Use inside icon-only buttons for accessible labels"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"component": "Icon",
|
|
89
|
+
"relationship": "sibling",
|
|
90
|
+
"note": "Pair with icons to provide text alternatives"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"contract": {
|
|
94
|
+
"propsSummary": [
|
|
95
|
+
"children: ReactNode - hidden text (required)",
|
|
96
|
+
"as: span|div - HTML element",
|
|
97
|
+
"Forwards standard DOM props (id, aria-*, data-*, className, handlers)"
|
|
98
|
+
],
|
|
99
|
+
"a11yRules": [
|
|
100
|
+
"A11Y_SR_ONLY",
|
|
101
|
+
"A11Y_ICON_LABEL"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
"ai": {
|
|
105
|
+
"compositionPattern": "compound",
|
|
106
|
+
"subComponents": [
|
|
107
|
+
"Root"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"provenance": {
|
|
111
|
+
"source": "migrated",
|
|
112
|
+
"verified": false,
|
|
113
|
+
"frameworkSupport": "native",
|
|
114
|
+
"extractedAt": "2026-03-13T23:19:06.625Z"
|
|
115
|
+
}
|
|
116
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
|
|
1
|
+
// CSS variables and base styles are NOT auto-imported here.
|
|
2
|
+
// Consumers must import styles separately with seed configuration:
|
|
3
|
+
// @use '@fragments-sdk/ui/styles' with ($fui-brand: ..., $fui-neutral: ...);
|
|
4
|
+
// Bundling globals.scss here would compile with default seeds and
|
|
5
|
+
// override any consumer-configured palette.
|
|
4
6
|
|
|
5
7
|
// Runtime CSS detection — warns if component styles aren't loaded
|
|
6
8
|
import { checkCssLoaded } from './utils/css-warning';
|
|
@@ -404,6 +406,8 @@ export {
|
|
|
404
406
|
type PromptVariant,
|
|
405
407
|
type PromptTextareaProps,
|
|
406
408
|
type PromptToolbarProps,
|
|
409
|
+
type PromptTabsProps,
|
|
410
|
+
type PromptTabProps,
|
|
407
411
|
type PromptActionsProps,
|
|
408
412
|
type PromptInfoProps,
|
|
409
413
|
type PromptActionButtonProps,
|
|
@@ -591,6 +595,7 @@ export {
|
|
|
591
595
|
type DrawerBodyProps,
|
|
592
596
|
type DrawerFooterProps,
|
|
593
597
|
type DrawerCloseProps,
|
|
598
|
+
type DrawerSwipeAreaProps,
|
|
594
599
|
} from './components/Drawer';
|
|
595
600
|
|
|
596
601
|
// Pagination
|
package/src/styles/globals.scss
CHANGED
|
@@ -83,13 +83,18 @@ $fui-info: #3b82f6 !default;
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// Base Element Resets
|
|
86
|
-
:where(
|
|
86
|
+
// Use real specificity (not :where()) for font-size so it overrides
|
|
87
|
+
// the browser default 16px. This makes 1rem = 14px throughout.
|
|
88
|
+
html {
|
|
89
|
+
font-size: #{$fui-base-font-size};
|
|
87
90
|
scroll-behavior: smooth;
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
:where(body) {
|
|
91
94
|
margin: 0;
|
|
95
|
+
font-size: inherit;
|
|
92
96
|
font-family: var(--fui-font-sans, Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
|
|
97
|
+
line-height: var(--fui-line-height-normal, $fui-line-height-normal);
|
|
93
98
|
background-color: var(--fui-bg-primary, #ffffff);
|
|
94
99
|
color: var(--fui-text-primary, #171717);
|
|
95
100
|
-webkit-font-smoothing: antialiased;
|
|
@@ -86,6 +86,7 @@ $computed-sidebar-item-height: density.px-to-rem($_density, map.get($_density, s
|
|
|
86
86
|
|
|
87
87
|
// Accent colors (from brand seed)
|
|
88
88
|
$computed-color-accent: seeds.$fui-brand;
|
|
89
|
+
$computed-color-on-accent: derive.contrast-color(seeds.$fui-brand);
|
|
89
90
|
$computed-color-accent-hover: derive.derive-accent-hover(seeds.$fui-brand, false);
|
|
90
91
|
$computed-color-accent-active: derive.derive-accent-active(seeds.$fui-brand, false);
|
|
91
92
|
|
|
@@ -153,8 +154,9 @@ $computed-backdrop: derive.derive-backdrop(false);
|
|
|
153
154
|
// Computed: Colors - Dark Mode
|
|
154
155
|
// --------------------------------------------
|
|
155
156
|
|
|
156
|
-
// Accent colors
|
|
157
|
+
// Accent colors — dark brands lightened for visibility; on-accent handles text contrast
|
|
157
158
|
$computed-dark-color-accent: derive.derive-dark-accent(seeds.$fui-brand);
|
|
159
|
+
$computed-dark-color-on-accent: derive.contrast-color($computed-dark-color-accent);
|
|
158
160
|
$computed-dark-color-accent-hover: derive.derive-accent-hover($computed-dark-color-accent, true);
|
|
159
161
|
$computed-dark-color-accent-active: derive.derive-accent-active($computed-dark-color-accent, true);
|
|
160
162
|
|
package/src/tokens/_density.scss
CHANGED
|
@@ -59,8 +59,8 @@ $density-default: (
|
|
|
59
59
|
// Input height
|
|
60
60
|
input-height: 40px,
|
|
61
61
|
// ~6 units
|
|
62
|
-
input-height-sm:
|
|
63
|
-
// 4 units
|
|
62
|
+
input-height-sm: 32px,
|
|
63
|
+
// ~4.5 units
|
|
64
64
|
input-height-lg: 44px,
|
|
65
65
|
// ~6 units
|
|
66
66
|
// Touch targets (baseline)
|
|
@@ -70,8 +70,8 @@ $density-default: (
|
|
|
70
70
|
touch-lg: 44px,
|
|
71
71
|
// WCAG AAA recommended
|
|
72
72
|
// Sidebar navigation
|
|
73
|
-
sidebar-item-height:
|
|
74
|
-
// 5 units
|
|
73
|
+
sidebar-item-height: 36px,
|
|
74
|
+
// ~5 units
|
|
75
75
|
);
|
|
76
76
|
|
|
77
77
|
$density-relaxed: (
|
package/src/tokens/_derive.scss
CHANGED
|
@@ -20,14 +20,8 @@
|
|
|
20
20
|
/// @param {Color} $color - Color to check
|
|
21
21
|
/// @return {Boolean} True if dark
|
|
22
22
|
@function is-dark-color($color) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
$b: math.div(color.channel($color, 'blue', $space: rgb), 255);
|
|
26
|
-
|
|
27
|
-
// Relative luminance formula (simplified)
|
|
28
|
-
$luminance: 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
|
|
29
|
-
|
|
30
|
-
@return $luminance < 0.5;
|
|
23
|
+
// oklch lightness is perceptually uniform (0-1 range)
|
|
24
|
+
@return color.channel($color, 'lightness', $space: oklch) < 0.5;
|
|
31
25
|
}
|
|
32
26
|
|
|
33
27
|
/// Get appropriate contrast color (black or white)
|
|
@@ -52,22 +46,22 @@
|
|
|
52
46
|
/// @param {Boolean} $is-dark - Whether in dark mode
|
|
53
47
|
/// @return {Color} Hover state color
|
|
54
48
|
@function derive-accent-hover($base, $is-dark: false) {
|
|
55
|
-
$l: color.channel($base, 'lightness', $space:
|
|
49
|
+
$l: color.channel($base, 'lightness', $space: oklch);
|
|
56
50
|
|
|
57
51
|
@if $is-dark {
|
|
58
|
-
@if $l > 85
|
|
52
|
+
@if $l > 0.85 {
|
|
59
53
|
// Very light accent on dark bg: darken for visible hover
|
|
60
|
-
@return color.
|
|
54
|
+
@return color.adjust($base, $lightness: -0.05, $space: oklch);
|
|
61
55
|
}
|
|
62
56
|
// Standard dark mode: lighten for hover
|
|
63
|
-
@return color.
|
|
57
|
+
@return color.adjust($base, $lightness: 0.04, $space: oklch);
|
|
64
58
|
} @else {
|
|
65
|
-
@if $l < 15
|
|
59
|
+
@if $l < 0.15 {
|
|
66
60
|
// Very dark accent on light bg: lighten for visible hover
|
|
67
|
-
@return color.
|
|
61
|
+
@return color.adjust($base, $lightness: 0.09, $space: oklch);
|
|
68
62
|
}
|
|
69
63
|
// Standard light mode: darken for hover
|
|
70
|
-
@return color.
|
|
64
|
+
@return color.adjust($base, $lightness: -0.05, $space: oklch);
|
|
71
65
|
}
|
|
72
66
|
}
|
|
73
67
|
|
|
@@ -78,38 +72,36 @@
|
|
|
78
72
|
/// @param {Boolean} $is-dark - Whether in dark mode
|
|
79
73
|
/// @return {Color} Active state color
|
|
80
74
|
@function derive-accent-active($base, $is-dark: false) {
|
|
81
|
-
$l: color.channel($base, 'lightness', $space:
|
|
75
|
+
$l: color.channel($base, 'lightness', $space: oklch);
|
|
82
76
|
|
|
83
77
|
@if $is-dark {
|
|
84
|
-
@if $l > 85
|
|
78
|
+
@if $l > 0.85 {
|
|
85
79
|
// Very light accent on dark bg: darken more for active
|
|
86
|
-
@return color.
|
|
80
|
+
@return color.adjust($base, $lightness: -0.08, $space: oklch);
|
|
87
81
|
}
|
|
88
82
|
// Standard dark mode: lighten more for active
|
|
89
|
-
@return color.
|
|
83
|
+
@return color.adjust($base, $lightness: 0.07, $space: oklch);
|
|
90
84
|
} @else {
|
|
91
|
-
@if $l < 15
|
|
85
|
+
@if $l < 0.15 {
|
|
92
86
|
// Very dark accent on light bg: lighten more for active
|
|
93
|
-
@return color.
|
|
87
|
+
@return color.adjust($base, $lightness: 0.14, $space: oklch);
|
|
94
88
|
}
|
|
95
89
|
// Standard light mode: darken more for active
|
|
96
|
-
@return color.
|
|
90
|
+
@return color.adjust($base, $lightness: -0.09, $space: oklch);
|
|
97
91
|
}
|
|
98
92
|
}
|
|
99
93
|
|
|
100
94
|
/// Derive a light variant of accent for dark mode
|
|
101
|
-
///
|
|
95
|
+
/// Lightens dark brand colors so the accent stands out on dark backgrounds.
|
|
96
|
+
/// Clamps lightness to 0.45–0.85 and chroma to 0.12 to keep it muted.
|
|
102
97
|
/// @param {Color} $brand - Brand color
|
|
103
98
|
/// @return {Color} Lightened accent for dark mode
|
|
104
99
|
@function derive-dark-accent($brand) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// If brand is already light, use it as-is or slightly adjust
|
|
111
|
-
@return color.scale($brand, $lightness: 10%);
|
|
112
|
-
}
|
|
100
|
+
$l: color.channel($brand, 'lightness', $space: oklch);
|
|
101
|
+
$c: color.channel($brand, 'chroma', $space: oklch);
|
|
102
|
+
$clamped-l: math.max(0.45, math.min($l, 0.85));
|
|
103
|
+
$clamped-c: math.min($c, 0.12);
|
|
104
|
+
@return oklch($clamped-l $clamped-c color.channel($brand, 'hue', $space: oklch));
|
|
113
105
|
}
|
|
114
106
|
|
|
115
107
|
// --------------------------------------------
|
|
@@ -129,9 +121,9 @@
|
|
|
129
121
|
@for $i from 1 through 40 {
|
|
130
122
|
@if wcag-contrast($adjusted, $bg) < $target {
|
|
131
123
|
@if $is-dark {
|
|
132
|
-
$adjusted: color.adjust($adjusted, $lightness: 2
|
|
124
|
+
$adjusted: color.adjust($adjusted, $lightness: 2%, $space: oklch);
|
|
133
125
|
} @else {
|
|
134
|
-
$adjusted: color.adjust($adjusted, $lightness: -2
|
|
126
|
+
$adjusted: color.adjust($adjusted, $lightness: -2%, $space: oklch);
|
|
135
127
|
}
|
|
136
128
|
}
|
|
137
129
|
}
|
|
@@ -202,19 +194,23 @@
|
|
|
202
194
|
/// @return {Map} Text token values
|
|
203
195
|
@function derive-text($palette, $is-dark: false, $palette-name: 'stone') {
|
|
204
196
|
@if $is-dark {
|
|
205
|
-
// Dark mode:
|
|
197
|
+
// Dark mode: neutral white text on all palettes.
|
|
198
|
+
// Palette-tinted text (e.g. green-on-green-dark) looks muddy and reduces
|
|
199
|
+
// readability. Every major dark theme (Linear, Vercel, Stripe, GitHub)
|
|
200
|
+
// uses neutral white text regardless of background tint.
|
|
206
201
|
@return (
|
|
207
|
-
primary:
|
|
208
|
-
secondary:
|
|
209
|
-
|
|
210
|
-
// against palette[950] backgrounds (pure palette[500] gives ~4.1:1)
|
|
211
|
-
tertiary: color.mix(get-shade($palette, 500), get-shade($palette, 400), 10%),
|
|
202
|
+
primary: #ffffff,
|
|
203
|
+
secondary: rgba(255, 255, 255, 0.6),
|
|
204
|
+
tertiary: rgba(255, 255, 255, 0.4),
|
|
212
205
|
inverse: get-shade($palette, 900) // Text on light accents
|
|
213
206
|
);
|
|
214
207
|
}
|
|
215
208
|
|
|
216
209
|
// Light mode background — stone uses white, colorful palettes use palette[50]
|
|
217
|
-
$bg:
|
|
210
|
+
$bg: #ffffff;
|
|
211
|
+
@if $palette-name != 'stone' {
|
|
212
|
+
$bg: get-shade($palette, 50);
|
|
213
|
+
}
|
|
218
214
|
|
|
219
215
|
@return (
|
|
220
216
|
primary: get-shade($palette, 900), // Main text (high contrast)
|
|
@@ -236,16 +232,16 @@
|
|
|
236
232
|
/// @return {Map} Border token values
|
|
237
233
|
@function derive-borders($palette, $is-dark: false) {
|
|
238
234
|
@if $is-dark {
|
|
239
|
-
// Dark mode:
|
|
235
|
+
// Dark mode: subtle white-alpha borders
|
|
240
236
|
@return (
|
|
241
237
|
default: rgba(255, 255, 255, 0.08),
|
|
242
|
-
strong: rgba(255, 255, 255, 0.
|
|
238
|
+
strong: rgba(255, 255, 255, 0.15)
|
|
243
239
|
);
|
|
244
240
|
} @else {
|
|
245
|
-
// Light mode:
|
|
241
|
+
// Light mode: reduced opacity (ChatGPT --border-light ~5%)
|
|
246
242
|
@return (
|
|
247
|
-
default: rgba(0, 0, 0, 0.
|
|
248
|
-
strong: rgba(0, 0, 0, 0.
|
|
243
|
+
default: rgba(0, 0, 0, 0.05),
|
|
244
|
+
strong: rgba(0, 0, 0, 0.10)
|
|
249
245
|
);
|
|
250
246
|
}
|
|
251
247
|
}
|
|
@@ -259,18 +255,18 @@
|
|
|
259
255
|
/// @return {Map} Shadow token values
|
|
260
256
|
@function derive-shadows($is-dark: false) {
|
|
261
257
|
@if $is-dark {
|
|
262
|
-
// Dark mode:
|
|
258
|
+
// Dark mode: near-zero shadows (Linear uses borders, not shadows)
|
|
263
259
|
@return (
|
|
264
|
-
sm: (0 1px 2px 0 rgba(0, 0, 0, 0.
|
|
265
|
-
md: (0 2px 4px -1px rgba(0, 0, 0, 0.
|
|
266
|
-
lg: (0 8px 12px -3px rgba(0, 0, 0, 0.
|
|
260
|
+
sm: (0 1px 2px 0 rgba(0, 0, 0, 0.15)),
|
|
261
|
+
md: (0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 1px 3px -2px rgba(0, 0, 0, 0.15)),
|
|
262
|
+
lg: (0 8px 12px -3px rgba(0, 0, 0, 0.25), 0 3px 5px -4px rgba(0, 0, 0, 0.18))
|
|
267
263
|
);
|
|
268
264
|
} @else {
|
|
269
|
-
// Light mode:
|
|
265
|
+
// Light mode: flatter aesthetic (Linear/ChatGPT near-zero shadows)
|
|
270
266
|
@return (
|
|
271
|
-
sm: (0 1px 2px 0 rgba(0, 0, 0, 0.
|
|
272
|
-
md: (0 2px 4px -1px rgba(0, 0, 0, 0.
|
|
273
|
-
lg: (0 8px 12px -3px rgba(0, 0, 0, 0.
|
|
267
|
+
sm: (0 1px 2px 0 rgba(0, 0, 0, 0.02)),
|
|
268
|
+
md: (0 2px 4px -1px rgba(0, 0, 0, 0.04), 0 1px 3px -2px rgba(0, 0, 0, 0.03)),
|
|
269
|
+
lg: (0 8px 12px -3px rgba(0, 0, 0, 0.06), 0 3px 5px -4px rgba(0, 0, 0, 0.04))
|
|
274
270
|
);
|
|
275
271
|
}
|
|
276
272
|
}
|
|
@@ -321,7 +317,7 @@
|
|
|
321
317
|
/// @param {Color} $color - The semantic color
|
|
322
318
|
/// @return {Color} Hover state color
|
|
323
319
|
@function derive-semantic-hover($color) {
|
|
324
|
-
@return color.
|
|
320
|
+
@return color.adjust($color, $lightness: -0.05, $space: oklch);
|
|
325
321
|
}
|
|
326
322
|
|
|
327
323
|
// --------------------------------------------
|
|
@@ -421,9 +417,9 @@
|
|
|
421
417
|
@for $i from 1 through 40 {
|
|
422
418
|
@if wcag-contrast($adjusted, $bg) < $target {
|
|
423
419
|
@if $is-dark {
|
|
424
|
-
$adjusted: color.adjust($adjusted, $lightness: 2
|
|
420
|
+
$adjusted: color.adjust($adjusted, $lightness: 2%, $space: oklch);
|
|
425
421
|
} @else {
|
|
426
|
-
$adjusted: color.adjust($adjusted, $lightness: -2
|
|
422
|
+
$adjusted: color.adjust($adjusted, $lightness: -2%, $space: oklch);
|
|
427
423
|
}
|
|
428
424
|
}
|
|
429
425
|
}
|
|
@@ -83,6 +83,24 @@ $palette-earth: (
|
|
|
83
83
|
950: #0a0f08 // Very dark green-gray for dark mode bg
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
+
// --------------------------------------------
|
|
87
|
+
// Fragments - Rich saturated green tones
|
|
88
|
+
// The Fragments brand palette — deep forest greens
|
|
89
|
+
// --------------------------------------------
|
|
90
|
+
$palette-fragments: (
|
|
91
|
+
50: #f0f7f3,
|
|
92
|
+
100: #dceee3,
|
|
93
|
+
200: #b8ddc6,
|
|
94
|
+
300: #88c5a0,
|
|
95
|
+
400: #5aaa7a,
|
|
96
|
+
500: #3d8f60,
|
|
97
|
+
600: #2d7049,
|
|
98
|
+
700: #235536,
|
|
99
|
+
800: #1a3025, // Dark card surface
|
|
100
|
+
900: #142318, // Dark surface
|
|
101
|
+
950: #0d1f17 // Darkest bg
|
|
102
|
+
);
|
|
103
|
+
|
|
86
104
|
// --------------------------------------------
|
|
87
105
|
// Fire - Warm red/orange tones
|
|
88
106
|
// Energy, passion feel
|
|
@@ -110,6 +128,7 @@ $palettes: (
|
|
|
110
128
|
"sand": $palette-sand,
|
|
111
129
|
"earth": $palette-earth,
|
|
112
130
|
"fire": $palette-fire,
|
|
131
|
+
"fragments": $palette-fragments,
|
|
113
132
|
"wind": $palette-stone // Legacy alias — "wind" was renamed to "stone"
|
|
114
133
|
);
|
|
115
134
|
|
|
@@ -118,7 +137,7 @@ $palettes: (
|
|
|
118
137
|
// --------------------------------------------
|
|
119
138
|
|
|
120
139
|
/// Get a palette map by name
|
|
121
|
-
/// @param {String} $name - Palette name (stone, ice, sand, earth, fire)
|
|
140
|
+
/// @param {String} $name - Palette name (stone, ice, sand, earth, fire, fragments)
|
|
122
141
|
/// @return {Map} The palette map with shades 50-950
|
|
123
142
|
@function get-palette($name) {
|
|
124
143
|
@if not map.has-key($palettes, $name) {
|
package/src/tokens/_seeds.scss
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
$fui-brand: #18181b !default;
|
|
27
27
|
|
|
28
28
|
/// Neutral palette name for surfaces, text, and borders
|
|
29
|
-
/// Options: "stone" | "ice" | "earth" | "sand" | "fire"
|
|
29
|
+
/// Options: "stone" | "ice" | "earth" | "sand" | "fire" | "fragments"
|
|
30
30
|
/// @type String
|
|
31
31
|
$fui-neutral: "stone" !default;
|
|
32
32
|
|
|
@@ -45,7 +45,7 @@ $fui-radius-style: "default" !default;
|
|
|
45
45
|
// --------------------------------------------
|
|
46
46
|
// Fail fast at compile time if invalid seed values are provided.
|
|
47
47
|
|
|
48
|
-
$_valid-neutrals: "stone", "ice", "earth", "sand", "fire";
|
|
48
|
+
$_valid-neutrals: "stone", "ice", "earth", "sand", "fire", "fragments";
|
|
49
49
|
@if not list.index($_valid-neutrals, $fui-neutral) {
|
|
50
50
|
@error "Invalid $fui-neutral: '#{$fui-neutral}'. Must be one of: #{$_valid-neutrals}";
|
|
51
51
|
}
|