@fragments-sdk/ui 0.11.1 → 0.13.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/README.md +15 -0
- package/dist/assets/ui.css +25 -18
- package/dist/blocks/AccountSettings.block.d.ts +1 -1
- package/dist/blocks/ActivityFeed.block.d.ts +1 -1
- package/dist/blocks/ActivityFeedSkeleton.block.d.ts +1 -1
- package/dist/blocks/BlogEditor.block.d.ts +1 -1
- package/dist/blocks/ChatInterface.block.d.ts +1 -1
- package/dist/blocks/ChatMessages.block.d.ts +1 -1
- package/dist/blocks/CheckoutForm.block.d.ts +1 -1
- package/dist/blocks/CommandPalette.block.d.ts +1 -1
- package/dist/blocks/ContactForm.block.d.ts +1 -1
- package/dist/blocks/DashboardLayout.block.d.ts +1 -1
- package/dist/blocks/DashboardPage.block.d.ts +1 -1
- package/dist/blocks/DashboardSkeleton.block.d.ts +1 -1
- package/dist/blocks/DataTable.block.d.ts +1 -1
- package/dist/blocks/EmptyState.block.d.ts +1 -1
- package/dist/blocks/FAQSection.block.d.ts +1 -1
- package/dist/blocks/FeatureGrid.block.d.ts +1 -1
- package/dist/blocks/HeroSection.block.d.ts +1 -1
- package/dist/blocks/LoginForm.block.d.ts +1 -1
- package/dist/blocks/NavigationHeader.block.d.ts +1 -1
- package/dist/blocks/PaginatedTable.block.d.ts +1 -1
- package/dist/blocks/PricingComparison.block.d.ts +1 -1
- package/dist/blocks/ProductCard.block.d.ts +1 -1
- package/dist/blocks/RegistrationForm.block.d.ts +1 -1
- package/dist/blocks/SettingsDrawer.block.d.ts +1 -1
- package/dist/blocks/SettingsPanel.block.d.ts +1 -1
- package/dist/blocks/ShoppingCart.block.d.ts +1 -1
- package/dist/blocks/StatsCard.block.d.ts +1 -1
- package/dist/blocks/StatsCardSkeleton.block.d.ts +1 -1
- package/dist/blocks/TableSkeleton.block.d.ts +1 -1
- package/dist/blocks/ThinkingStates.block.d.ts +1 -1
- package/dist/codeblock.cjs +7 -1
- package/dist/codeblock.cjs.map +1 -1
- package/dist/codeblock.js +7 -1
- package/dist/codeblock.js.map +1 -1
- package/dist/components/Accordion/index.cjs +11 -4
- package/dist/components/Accordion/index.cjs.map +1 -1
- package/dist/components/Accordion/index.d.ts +3 -3
- package/dist/components/Accordion/index.d.ts.map +1 -1
- package/dist/components/Accordion/index.js +11 -4
- package/dist/components/Accordion/index.js.map +1 -1
- package/dist/components/Alert/index.cjs.map +1 -1
- package/dist/components/Alert/index.d.ts +7 -0
- package/dist/components/Alert/index.d.ts.map +1 -1
- package/dist/components/Alert/index.js.map +1 -1
- package/dist/components/Avatar/index.cjs.map +1 -1
- package/dist/components/Avatar/index.d.ts +4 -0
- package/dist/components/Avatar/index.d.ts.map +1 -1
- package/dist/components/Avatar/index.js.map +1 -1
- package/dist/components/Badge/index.cjs.map +1 -1
- package/dist/components/Badge/index.d.ts +12 -0
- package/dist/components/Badge/index.d.ts.map +1 -1
- package/dist/components/Badge/index.js.map +1 -1
- package/dist/components/Button/index.cjs +9 -1
- package/dist/components/Button/index.cjs.map +1 -1
- package/dist/components/Button/index.d.ts +14 -1
- package/dist/components/Button/index.d.ts.map +1 -1
- package/dist/components/Button/index.js +9 -1
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Card/index.cjs +2 -1
- package/dist/components/Card/index.cjs.map +1 -1
- package/dist/components/Card/index.d.ts +12 -2
- package/dist/components/Card/index.d.ts.map +1 -1
- package/dist/components/Card/index.js +2 -1
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/Checkbox/index.cjs.map +1 -1
- package/dist/components/Checkbox/index.d.ts +6 -1
- package/dist/components/Checkbox/index.d.ts.map +1 -1
- package/dist/components/Checkbox/index.js.map +1 -1
- package/dist/components/Chip/index.cjs +2 -1
- package/dist/components/Chip/index.cjs.map +1 -1
- package/dist/components/Chip/index.d.ts +10 -3
- package/dist/components/Chip/index.d.ts.map +1 -1
- package/dist/components/Chip/index.js +2 -1
- package/dist/components/Chip/index.js.map +1 -1
- package/dist/components/CodeBlock/index.d.ts +1 -1
- package/dist/components/CodeBlock/index.d.ts.map +1 -1
- package/dist/components/Collapsible/index.cjs +45 -10
- package/dist/components/Collapsible/index.cjs.map +1 -1
- package/dist/components/Collapsible/index.d.ts +6 -12
- package/dist/components/Collapsible/index.d.ts.map +1 -1
- package/dist/components/Collapsible/index.js +45 -10
- package/dist/components/Collapsible/index.js.map +1 -1
- package/dist/components/Combobox/index.cjs +18 -9
- package/dist/components/Combobox/index.cjs.map +1 -1
- package/dist/components/Combobox/index.d.ts +8 -12
- package/dist/components/Combobox/index.d.ts.map +1 -1
- package/dist/components/Combobox/index.js +18 -9
- package/dist/components/Combobox/index.js.map +1 -1
- package/dist/components/Command/index.cjs +54 -21
- package/dist/components/Command/index.cjs.map +1 -1
- package/dist/components/Command/index.d.ts +2 -2
- package/dist/components/Command/index.d.ts.map +1 -1
- package/dist/components/Command/index.js +54 -21
- package/dist/components/Command/index.js.map +1 -1
- package/dist/components/DataTable/index.cjs +13 -1
- package/dist/components/DataTable/index.cjs.map +1 -1
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DataTable/index.js +13 -1
- package/dist/components/DataTable/index.js.map +1 -1
- package/dist/components/DatePicker/index.d.ts +2 -3
- package/dist/components/DatePicker/index.d.ts.map +1 -1
- package/dist/components/Dialog/index.cjs +12 -9
- package/dist/components/Dialog/index.cjs.map +1 -1
- package/dist/components/Dialog/index.d.ts +20 -12
- package/dist/components/Dialog/index.d.ts.map +1 -1
- package/dist/components/Dialog/index.js +12 -9
- package/dist/components/Dialog/index.js.map +1 -1
- package/dist/components/Drawer/index.cjs +12 -9
- package/dist/components/Drawer/index.cjs.map +1 -1
- package/dist/components/Drawer/index.d.ts +22 -12
- package/dist/components/Drawer/index.d.ts.map +1 -1
- package/dist/components/Drawer/index.js +12 -9
- package/dist/components/Drawer/index.js.map +1 -1
- package/dist/components/Grid/index.cjs +4 -1
- package/dist/components/Grid/index.cjs.map +1 -1
- package/dist/components/Grid/index.d.ts +6 -2
- package/dist/components/Grid/index.d.ts.map +1 -1
- package/dist/components/Grid/index.js +4 -1
- package/dist/components/Grid/index.js.map +1 -1
- package/dist/components/Input/index.cjs.map +1 -1
- package/dist/components/Input/index.d.ts +15 -1
- package/dist/components/Input/index.d.ts.map +1 -1
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/Menu/index.cjs +30 -16
- package/dist/components/Menu/index.cjs.map +1 -1
- package/dist/components/Menu/index.d.ts +17 -25
- package/dist/components/Menu/index.d.ts.map +1 -1
- package/dist/components/Menu/index.js +30 -16
- package/dist/components/Menu/index.js.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenuContext.cjs.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenuContext.d.ts +1 -0
- package/dist/components/NavigationMenu/NavigationMenuContext.d.ts.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenuContext.js.map +1 -1
- package/dist/components/NavigationMenu/index.cjs +43 -11
- package/dist/components/NavigationMenu/index.cjs.map +1 -1
- package/dist/components/NavigationMenu/index.d.ts.map +1 -1
- package/dist/components/NavigationMenu/index.js +43 -11
- package/dist/components/NavigationMenu/index.js.map +1 -1
- package/dist/components/NavigationMenu/useNavigationMenu.cjs +2 -0
- package/dist/components/NavigationMenu/useNavigationMenu.cjs.map +1 -1
- package/dist/components/NavigationMenu/useNavigationMenu.d.ts +1 -0
- package/dist/components/NavigationMenu/useNavigationMenu.d.ts.map +1 -1
- package/dist/components/NavigationMenu/useNavigationMenu.js +2 -0
- package/dist/components/NavigationMenu/useNavigationMenu.js.map +1 -1
- package/dist/components/Popover/index.cjs +11 -10
- package/dist/components/Popover/index.cjs.map +1 -1
- package/dist/components/Popover/index.d.ts +17 -12
- package/dist/components/Popover/index.d.ts.map +1 -1
- package/dist/components/Popover/index.js +11 -10
- package/dist/components/Popover/index.js.map +1 -1
- package/dist/components/RadioGroup/index.cjs.map +1 -1
- package/dist/components/RadioGroup/index.d.ts +4 -0
- package/dist/components/RadioGroup/index.d.ts.map +1 -1
- package/dist/components/RadioGroup/index.js.map +1 -1
- package/dist/components/Select/index.cjs +7 -6
- package/dist/components/Select/index.cjs.map +1 -1
- package/dist/components/Select/index.d.ts +20 -9
- package/dist/components/Select/index.d.ts.map +1 -1
- package/dist/components/Select/index.js +7 -6
- package/dist/components/Select/index.js.map +1 -1
- package/dist/components/Sidebar/index.cjs +71 -24
- package/dist/components/Sidebar/index.cjs.map +1 -1
- package/dist/components/Sidebar/index.d.ts +21 -33
- package/dist/components/Sidebar/index.d.ts.map +1 -1
- package/dist/components/Sidebar/index.js +71 -24
- package/dist/components/Sidebar/index.js.map +1 -1
- package/dist/components/Slider/index.cjs +3 -1
- package/dist/components/Slider/index.cjs.map +1 -1
- package/dist/components/Slider/index.d.ts +10 -0
- package/dist/components/Slider/index.d.ts.map +1 -1
- package/dist/components/Slider/index.js +3 -1
- package/dist/components/Slider/index.js.map +1 -1
- package/dist/components/Stack/index.cjs +6 -0
- package/dist/components/Stack/index.cjs.map +1 -1
- package/dist/components/Stack/index.d.ts +12 -6
- package/dist/components/Stack/index.d.ts.map +1 -1
- package/dist/components/Stack/index.js +6 -0
- package/dist/components/Stack/index.js.map +1 -1
- package/dist/components/Tabs/index.cjs.map +1 -1
- package/dist/components/Tabs/index.d.ts +13 -1
- package/dist/components/Tabs/index.d.ts.map +1 -1
- package/dist/components/Tabs/index.js.map +1 -1
- package/dist/components/Text/Text.module.scss.cjs +44 -32
- package/dist/components/Text/Text.module.scss.cjs.map +1 -1
- package/dist/components/Text/Text.module.scss.js +44 -32
- package/dist/components/Text/Text.module.scss.js.map +1 -1
- package/dist/components/Text/index.cjs.map +1 -1
- package/dist/components/Text/index.d.ts +18 -3
- package/dist/components/Text/index.d.ts.map +1 -1
- package/dist/components/Text/index.js.map +1 -1
- package/dist/components/Theme/index.cjs.map +1 -1
- package/dist/components/Theme/index.d.ts +12 -0
- package/dist/components/Theme/index.d.ts.map +1 -1
- package/dist/components/Theme/index.js.map +1 -1
- package/dist/components/Toggle/index.cjs +2 -1
- package/dist/components/Toggle/index.cjs.map +1 -1
- package/dist/components/Toggle/index.d.ts +9 -0
- package/dist/components/Toggle/index.d.ts.map +1 -1
- package/dist/components/Toggle/index.js +2 -1
- package/dist/components/Toggle/index.js.map +1 -1
- package/dist/components/ToggleGroup/index.cjs +4 -1
- package/dist/components/ToggleGroup/index.cjs.map +1 -1
- package/dist/components/ToggleGroup/index.d.ts +13 -4
- package/dist/components/ToggleGroup/index.d.ts.map +1 -1
- package/dist/components/ToggleGroup/index.js +4 -1
- package/dist/components/ToggleGroup/index.js.map +1 -1
- package/dist/components/Tooltip/index.cjs +20 -10
- package/dist/components/Tooltip/index.cjs.map +1 -1
- package/dist/components/Tooltip/index.d.ts +5 -1
- package/dist/components/Tooltip/index.d.ts.map +1 -1
- package/dist/components/Tooltip/index.js +20 -10
- package/dist/components/Tooltip/index.js.map +1 -1
- package/dist/datepicker.cjs +24 -10
- package/dist/datepicker.cjs.map +1 -1
- package/dist/datepicker.js +24 -10
- package/dist/datepicker.js.map +1 -1
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/css-warning.cjs +18 -0
- package/dist/utils/css-warning.cjs.map +1 -0
- package/dist/utils/css-warning.d.ts +2 -0
- package/dist/utils/css-warning.d.ts.map +1 -0
- package/dist/utils/css-warning.js +18 -0
- package/dist/utils/css-warning.js.map +1 -0
- package/fragments.json +1 -1
- package/package.json +2 -2
- package/src/components/Accordion/Accordion.test.tsx +33 -0
- package/src/components/Accordion/index.tsx +10 -3
- package/src/components/Alert/index.tsx +7 -0
- package/src/components/Avatar/index.tsx +4 -0
- package/src/components/Badge/Badge.fragment.tsx +10 -2
- package/src/components/Badge/index.tsx +12 -0
- package/src/components/Button/Button.fragment.tsx +12 -2
- package/src/components/Button/Button.test.tsx +16 -0
- package/src/components/Button/index.tsx +27 -2
- package/src/components/Card/Card.fragment.tsx +14 -2
- package/src/components/Card/Card.test.tsx +5 -0
- package/src/components/Card/index.tsx +15 -2
- package/src/components/Checkbox/index.tsx +6 -1
- package/src/components/Chip/Chip.fragment.tsx +12 -2
- package/src/components/Chip/Chip.test.tsx +5 -0
- package/src/components/Chip/index.tsx +14 -4
- package/src/components/CodeBlock/index.tsx +13 -2
- package/src/components/Collapsible/Collapsible.test.tsx +41 -0
- package/src/components/Collapsible/index.tsx +53 -16
- package/src/components/Combobox/Combobox.test.tsx +55 -0
- package/src/components/Combobox/index.tsx +23 -17
- package/src/components/Command/Command.test.tsx +93 -0
- package/src/components/Command/index.tsx +61 -18
- package/src/components/DataTable/DataTable.test.tsx +11 -2
- package/src/components/DataTable/index.tsx +22 -2
- package/src/components/DatePicker/DatePicker.test.tsx +79 -0
- package/src/components/DatePicker/index.tsx +29 -14
- package/src/components/Dialog/Dialog.test.tsx +23 -0
- package/src/components/Dialog/index.tsx +27 -16
- package/src/components/Drawer/Drawer.test.tsx +27 -0
- package/src/components/Drawer/index.tsx +29 -16
- package/src/components/Grid/Grid.fragment.tsx +14 -2
- package/src/components/Grid/Grid.test.tsx +6 -0
- package/src/components/Grid/index.tsx +12 -3
- package/src/components/Input/index.tsx +15 -1
- package/src/components/Menu/index.tsx +35 -30
- package/src/components/NavigationMenu/NavigationMenu.fragment.tsx +1 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +40 -4
- package/src/components/NavigationMenu/NavigationMenuContext.ts +3 -0
- package/src/components/NavigationMenu/index.tsx +49 -13
- package/src/components/NavigationMenu/useNavigationMenu.ts +4 -0
- package/src/components/Popover/Popover.test.tsx +23 -0
- package/src/components/Popover/index.tsx +24 -18
- package/src/components/RadioGroup/index.tsx +4 -0
- package/src/components/Select/Select.test.tsx +41 -0
- package/src/components/Select/index.tsx +24 -12
- package/src/components/Sidebar/Sidebar.test.tsx +83 -4
- package/src/components/Sidebar/index.tsx +87 -45
- package/src/components/Slider/Slider.fragment.tsx +5 -1
- package/src/components/Slider/Slider.test.tsx +6 -0
- package/src/components/Slider/index.tsx +13 -1
- package/src/components/Stack/Stack.fragment.tsx +22 -2
- package/src/components/Stack/Stack.test.tsx +6 -0
- package/src/components/Stack/index.tsx +20 -6
- package/src/components/Tabs/index.tsx +13 -1
- package/src/components/Text/Text.fragment.tsx +10 -8
- package/src/components/Text/Text.module.scss +8 -2
- package/src/components/Text/Text.test.tsx +15 -0
- package/src/components/Text/index.tsx +18 -3
- package/src/components/Theme/index.tsx +12 -0
- package/src/components/Toggle/Toggle.fragment.tsx +5 -1
- package/src/components/Toggle/Toggle.test.tsx +19 -0
- package/src/components/Toggle/index.tsx +11 -1
- package/src/components/ToggleGroup/ToggleGroup.fragment.tsx +5 -2
- package/src/components/ToggleGroup/ToggleGroup.test.tsx +20 -0
- package/src/components/ToggleGroup/index.tsx +15 -4
- package/src/components/Tooltip/Tooltip.test.tsx +17 -0
- package/src/components/Tooltip/index.tsx +58 -34
- package/src/index.ts +6 -0
- package/src/tokens/_seeds.scss +5 -3
- package/src/tokens/_variables.scss +2 -0
- package/src/utils/css-warning.ts +29 -0
|
@@ -2,7 +2,9 @@ import * as React from 'react';
|
|
|
2
2
|
import styles from './Stack.module.scss';
|
|
3
3
|
|
|
4
4
|
type Direction = 'row' | 'column';
|
|
5
|
-
type
|
|
5
|
+
type GapToken = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
6
|
+
/** Gap accepts string tokens or numbers (1-8) mapping to the spacing scale */
|
|
7
|
+
type Gap = GapToken | number;
|
|
6
8
|
|
|
7
9
|
/** Responsive value — either a single value or per-breakpoint overrides */
|
|
8
10
|
export interface ResponsiveDirection {
|
|
@@ -21,17 +23,21 @@ export interface ResponsiveDirection {
|
|
|
21
23
|
/** Responsive gap value */
|
|
22
24
|
export interface ResponsiveGap {
|
|
23
25
|
/** Default (mobile-first) */
|
|
24
|
-
base?:
|
|
26
|
+
base?: GapToken;
|
|
25
27
|
/** ≥640px */
|
|
26
|
-
sm?:
|
|
28
|
+
sm?: GapToken;
|
|
27
29
|
/** ≥768px */
|
|
28
|
-
md?:
|
|
30
|
+
md?: GapToken;
|
|
29
31
|
/** ≥1024px */
|
|
30
|
-
lg?:
|
|
32
|
+
lg?: GapToken;
|
|
31
33
|
/** ≥1280px */
|
|
32
|
-
xl?:
|
|
34
|
+
xl?: GapToken;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Flexbox layout component for vertical or horizontal stacking with consistent spacing.
|
|
39
|
+
* @see https://usefragments.com/components/stack
|
|
40
|
+
*/
|
|
35
41
|
export interface StackProps {
|
|
36
42
|
children: React.ReactNode;
|
|
37
43
|
/**
|
|
@@ -70,6 +76,10 @@ function isResponsiveGap(gap: StackProps['gap']): gap is ResponsiveGap {
|
|
|
70
76
|
return typeof gap === 'object' && gap !== null;
|
|
71
77
|
}
|
|
72
78
|
|
|
79
|
+
function isNumericGap(gap: StackProps['gap']): gap is number {
|
|
80
|
+
return typeof gap === 'number';
|
|
81
|
+
}
|
|
82
|
+
|
|
73
83
|
const StackRoot = React.forwardRef<HTMLElement, StackProps>(
|
|
74
84
|
function Stack(
|
|
75
85
|
{
|
|
@@ -114,6 +124,10 @@ const StackRoot = React.forwardRef<HTMLElement, StackProps>(
|
|
|
114
124
|
if (gap.lg && gap.lg !== 'none') gapVars['--fui-stack-gap-lg'] = `var(--fui-space-${gapToSpace(gap.lg)})`;
|
|
115
125
|
if (gap.xl && gap.xl !== 'none') gapVars['--fui-stack-gap-xl'] = `var(--fui-space-${gapToSpace(gap.xl)})`;
|
|
116
126
|
inlineStyle = { ...inlineStyle, ...gapVars } as React.CSSProperties;
|
|
127
|
+
} else if (isNumericGap(gap)) {
|
|
128
|
+
// Numeric gap: maps to space scale tokens (e.g. gap={2} → var(--fui-space-2))
|
|
129
|
+
gapClass = false;
|
|
130
|
+
inlineStyle = { ...inlineStyle, gap: `var(--fui-space-${gap})` } as React.CSSProperties;
|
|
117
131
|
} else {
|
|
118
132
|
gapClass = gap !== 'none' && styles[`gap-${gap}`];
|
|
119
133
|
}
|
|
@@ -8,18 +8,30 @@ import styles from './Tabs.module.scss';
|
|
|
8
8
|
// Types
|
|
9
9
|
// ============================================
|
|
10
10
|
|
|
11
|
-
export type TabValue = string
|
|
11
|
+
export type TabValue = string;
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Tabbed navigation for switching between content panels.
|
|
15
|
+
* @see https://usefragments.com/components/tabs
|
|
16
|
+
*/
|
|
13
17
|
export interface TabsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'defaultValue'> {
|
|
14
18
|
children: React.ReactNode;
|
|
19
|
+
/** Default active tab value (uncontrolled) */
|
|
15
20
|
defaultValue?: TabValue;
|
|
21
|
+
/** Controlled active tab value */
|
|
16
22
|
value?: TabValue;
|
|
23
|
+
/** Called when the active tab changes */
|
|
17
24
|
onValueChange?: (value: TabValue) => void;
|
|
25
|
+
/** Tab layout direction.
|
|
26
|
+
* @default "horizontal" */
|
|
18
27
|
orientation?: 'horizontal' | 'vertical';
|
|
19
28
|
}
|
|
20
29
|
|
|
21
30
|
export interface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
22
31
|
children: React.ReactNode;
|
|
32
|
+
/** Tab list visual style.
|
|
33
|
+
* @default "underline"
|
|
34
|
+
* @see https://usefragments.com/components/tabs#variants */
|
|
23
35
|
variant?: 'underline' | 'pills';
|
|
24
36
|
}
|
|
25
37
|
|
|
@@ -53,18 +53,18 @@ export default defineFragment({
|
|
|
53
53
|
},
|
|
54
54
|
size: {
|
|
55
55
|
type: 'enum',
|
|
56
|
-
description: 'Font size',
|
|
57
|
-
values: ['2xs', 'xs', 'sm', 'base', 'lg', 'xl', '2xl'],
|
|
56
|
+
description: 'Font size (md is an alias for base)',
|
|
57
|
+
values: ['2xs', 'xs', 'sm', 'base', 'md', 'lg', 'xl', '2xl'],
|
|
58
58
|
},
|
|
59
59
|
weight: {
|
|
60
60
|
type: 'enum',
|
|
61
61
|
description: 'Font weight',
|
|
62
|
-
values: ['normal', 'medium', 'semibold'],
|
|
62
|
+
values: ['normal', 'medium', 'semibold', 'bold'],
|
|
63
63
|
},
|
|
64
64
|
color: {
|
|
65
65
|
type: 'enum',
|
|
66
|
-
description: 'Text color',
|
|
67
|
-
values: ['primary', 'secondary', 'tertiary'],
|
|
66
|
+
description: 'Text color (muted is an alias for tertiary)',
|
|
67
|
+
values: ['primary', 'secondary', 'tertiary', 'muted'],
|
|
68
68
|
},
|
|
69
69
|
font: {
|
|
70
70
|
type: 'enum',
|
|
@@ -91,9 +91,9 @@ export default defineFragment({
|
|
|
91
91
|
contract: {
|
|
92
92
|
propsSummary: [
|
|
93
93
|
'as: string - HTML element',
|
|
94
|
-
'size: 2xs|xs|sm|base|lg|xl|2xl - font size',
|
|
95
|
-
'weight: normal|medium|semibold - font weight',
|
|
96
|
-
'color: primary|secondary|tertiary - text color',
|
|
94
|
+
'size: 2xs|xs|sm|base|md|lg|xl|2xl - font size (md = base)',
|
|
95
|
+
'weight: normal|medium|semibold|bold - font weight',
|
|
96
|
+
'color: primary|secondary|tertiary|muted - text color (muted = tertiary)',
|
|
97
97
|
'font: sans|mono - font family',
|
|
98
98
|
'truncate: boolean - enable truncation',
|
|
99
99
|
'lineClamp: number - max lines',
|
|
@@ -130,6 +130,7 @@ export default defineFragment({
|
|
|
130
130
|
<Text weight="normal">Normal weight</Text>
|
|
131
131
|
<Text weight="medium">Medium weight</Text>
|
|
132
132
|
<Text weight="semibold">Semibold weight</Text>
|
|
133
|
+
<Text weight="bold">Bold weight</Text>
|
|
133
134
|
</div>
|
|
134
135
|
),
|
|
135
136
|
},
|
|
@@ -141,6 +142,7 @@ export default defineFragment({
|
|
|
141
142
|
<Text color="primary">Primary color (default)</Text>
|
|
142
143
|
<Text color="secondary">Secondary color</Text>
|
|
143
144
|
<Text color="tertiary">Tertiary color</Text>
|
|
145
|
+
<Text color="muted">Muted color (alias for tertiary)</Text>
|
|
144
146
|
</div>
|
|
145
147
|
),
|
|
146
148
|
},
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
font-size: var(--fui-font-size-sm, $fui-font-size-sm);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
.size-base
|
|
28
|
+
.size-base,
|
|
29
|
+
.size-md {
|
|
29
30
|
font-size: var(--fui-font-size-base, $fui-font-size-base);
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -54,6 +55,10 @@
|
|
|
54
55
|
font-weight: var(--fui-font-weight-semibold, $fui-font-weight-semibold);
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
.weight-bold {
|
|
59
|
+
font-weight: var(--fui-font-weight-bold, $fui-font-weight-bold);
|
|
60
|
+
}
|
|
61
|
+
|
|
57
62
|
// Text colors
|
|
58
63
|
.color-primary {
|
|
59
64
|
color: var(--fui-text-primary, $fui-text-primary);
|
|
@@ -63,7 +68,8 @@
|
|
|
63
68
|
color: var(--fui-text-secondary, $fui-text-secondary);
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
.color-tertiary
|
|
71
|
+
.color-tertiary,
|
|
72
|
+
.color-muted {
|
|
67
73
|
color: var(--fui-text-tertiary, $fui-text-tertiary);
|
|
68
74
|
}
|
|
69
75
|
|
|
@@ -22,6 +22,21 @@ describe('Text', () => {
|
|
|
22
22
|
expect(el).toHaveClass('color-secondary');
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
it('applies bold weight class', () => {
|
|
26
|
+
render(<Text weight="bold">Bold text</Text>);
|
|
27
|
+
expect(screen.getByText('Bold text')).toHaveClass('weight-bold');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('applies muted color class (alias for tertiary)', () => {
|
|
31
|
+
render(<Text color="muted">Muted text</Text>);
|
|
32
|
+
expect(screen.getByText('Muted text')).toHaveClass('color-muted');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('applies md size class (alias for base)', () => {
|
|
36
|
+
render(<Text size="md">Medium text</Text>);
|
|
37
|
+
expect(screen.getByText('Medium text')).toHaveClass('size-md');
|
|
38
|
+
});
|
|
39
|
+
|
|
25
40
|
it('applies section-label variant class', () => {
|
|
26
41
|
render(<Text variant="section-label">Label</Text>);
|
|
27
42
|
expect(screen.getByText('Label')).toHaveClass('variant-section-label');
|
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styles from './Text.module.scss';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Typography component for rendering text with consistent styling.
|
|
6
|
+
* @see https://usefragments.com/components/text
|
|
7
|
+
*/
|
|
4
8
|
export interface TextProps extends Omit<React.HTMLAttributes<HTMLElement>, 'color'> {
|
|
5
9
|
children: React.ReactNode;
|
|
10
|
+
/** HTML element to render.
|
|
11
|
+
* @default "span" */
|
|
6
12
|
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'label' | 'div' | 'strong' | 'em' | 'small' | 'mark' | 'del' | 'ins' | 'sub' | 'sup' | 'time' | 'address' | 'blockquote' | 'cite' | 'code' | 'abbr';
|
|
13
|
+
/** Preset text variant */
|
|
7
14
|
variant?: 'section-label';
|
|
8
|
-
size
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
/** Font size. `"md"` is an alias for `"base"`.
|
|
16
|
+
* @see https://usefragments.com/components/text#sizes */
|
|
17
|
+
size?: '2xs' | 'xs' | 'sm' | 'base' | 'md' | 'lg' | 'xl' | '2xl';
|
|
18
|
+
/** Font weight.
|
|
19
|
+
* @default "normal" */
|
|
20
|
+
weight?: 'normal' | 'medium' | 'semibold' | 'bold';
|
|
21
|
+
/** Text color. `"muted"` is an alias for `"tertiary"`.
|
|
22
|
+
* @default "primary" */
|
|
23
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'muted';
|
|
24
|
+
/** Font family.
|
|
25
|
+
* @default "sans" */
|
|
11
26
|
font?: 'sans' | 'mono';
|
|
12
27
|
/** Truncate text with ellipsis when it overflows */
|
|
13
28
|
truncate?: boolean;
|
|
@@ -368,8 +368,20 @@ export { ThemeProvider, ThemeToggle, useTheme };
|
|
|
368
368
|
// configureTheme — JS-only seed configuration
|
|
369
369
|
// ============================================
|
|
370
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Neutral palette for surfaces, text, and borders.
|
|
373
|
+
* - `stone`: Cool gray (balanced, professional) — default
|
|
374
|
+
* - `ice`: Cool blue-tinted grays (crisp, technical)
|
|
375
|
+
* - `earth`: Warm brown-tinted grays (natural, grounded)
|
|
376
|
+
* - `sand`: Warm tan-tinted grays (organic, approachable)
|
|
377
|
+
* - `fire`: Warm red-tinted grays (bold, energetic)
|
|
378
|
+
*
|
|
379
|
+
* Preview palettes at https://usefragments.com/themes
|
|
380
|
+
*/
|
|
371
381
|
export type NeutralPalette = 'stone' | 'ice' | 'earth' | 'sand' | 'fire';
|
|
382
|
+
/** Spacing density: `compact` (tight), `default` (balanced), `relaxed` (spacious) */
|
|
372
383
|
export type DensityPreset = 'compact' | 'default' | 'relaxed';
|
|
384
|
+
/** Border radius style: `sharp` (0), `subtle` (2px), `default` (4px), `rounded` (8px), `pill` (9999px) */
|
|
373
385
|
export type RadiusStyle = 'sharp' | 'subtle' | 'default' | 'rounded' | 'pill';
|
|
374
386
|
|
|
375
387
|
export interface ConfigureThemeOptions {
|
|
@@ -58,6 +58,10 @@ export default defineFragment({
|
|
|
58
58
|
type: 'function',
|
|
59
59
|
description: 'Callback with new checked state: (checked: boolean) => void',
|
|
60
60
|
},
|
|
61
|
+
onCheckedChange: {
|
|
62
|
+
type: 'function',
|
|
63
|
+
description: 'Alias for onChange (Radix convention): (checked: boolean) => void',
|
|
64
|
+
},
|
|
61
65
|
label: {
|
|
62
66
|
type: 'string',
|
|
63
67
|
description: 'Visible label text',
|
|
@@ -87,7 +91,7 @@ export default defineFragment({
|
|
|
87
91
|
contract: {
|
|
88
92
|
propsSummary: [
|
|
89
93
|
'checked: boolean - on/off state',
|
|
90
|
-
'onChange: (checked) => void - state change handler',
|
|
94
|
+
'onChange: (checked) => void - state change handler (or onCheckedChange)',
|
|
91
95
|
'label: string - visible label text',
|
|
92
96
|
'description: string - helper text below label',
|
|
93
97
|
'disabled: boolean - non-interactive state',
|
|
@@ -42,6 +42,25 @@ describe('Switch', () => {
|
|
|
42
42
|
expect(handleChange.mock.calls[0][0]).toBe(true);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
+
it('calls onCheckedChange alias when toggled', async () => {
|
|
46
|
+
const handleChange = vi.fn();
|
|
47
|
+
const user = userEvent.setup();
|
|
48
|
+
render(<Switch aria-label="Dark mode" onCheckedChange={handleChange} />);
|
|
49
|
+
await user.click(screen.getByRole('switch'));
|
|
50
|
+
expect(handleChange).toHaveBeenCalled();
|
|
51
|
+
expect(handleChange.mock.calls[0][0]).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('prefers onChange over onCheckedChange when both provided', async () => {
|
|
55
|
+
const onChange = vi.fn();
|
|
56
|
+
const onCheckedChange = vi.fn();
|
|
57
|
+
const user = userEvent.setup();
|
|
58
|
+
render(<Switch aria-label="Test" onChange={onChange} onCheckedChange={onCheckedChange} />);
|
|
59
|
+
await user.click(screen.getByRole('switch'));
|
|
60
|
+
expect(onChange).toHaveBeenCalled();
|
|
61
|
+
expect(onCheckedChange).not.toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
|
|
45
64
|
it('has no accessibility violations', async () => {
|
|
46
65
|
const { container } = render(<Switch aria-label="Accessible switch" />);
|
|
47
66
|
await expectNoA11yViolations(container);
|
|
@@ -4,10 +4,19 @@ import * as React from 'react';
|
|
|
4
4
|
import { Switch as BaseSwitch } from '@base-ui/react/switch';
|
|
5
5
|
import styles from './Toggle.module.scss';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Binary on/off switch for settings and preferences.
|
|
9
|
+
* @see https://usefragments.com/components/switch
|
|
10
|
+
*/
|
|
7
11
|
export interface SwitchProps {
|
|
12
|
+
/** Whether the switch is on */
|
|
8
13
|
checked?: boolean;
|
|
14
|
+
/** Default checked state (uncontrolled) */
|
|
9
15
|
defaultChecked?: boolean;
|
|
16
|
+
/** Called when the switch is toggled */
|
|
10
17
|
onChange?: (checked: boolean) => void;
|
|
18
|
+
/** Alias for onChange (Radix convention) */
|
|
19
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
11
20
|
label?: string;
|
|
12
21
|
description?: string;
|
|
13
22
|
disabled?: boolean;
|
|
@@ -28,6 +37,7 @@ const SwitchRoot = React.forwardRef<HTMLButtonElement, SwitchProps>(
|
|
|
28
37
|
checked,
|
|
29
38
|
defaultChecked,
|
|
30
39
|
onChange,
|
|
40
|
+
onCheckedChange,
|
|
31
41
|
label,
|
|
32
42
|
description,
|
|
33
43
|
disabled = false,
|
|
@@ -73,7 +83,7 @@ const SwitchRoot = React.forwardRef<HTMLButtonElement, SwitchProps>(
|
|
|
73
83
|
id={id}
|
|
74
84
|
checked={checked}
|
|
75
85
|
defaultChecked={defaultChecked}
|
|
76
|
-
onCheckedChange={onChange}
|
|
86
|
+
onCheckedChange={onChange ?? onCheckedChange}
|
|
77
87
|
disabled={disabled}
|
|
78
88
|
name={name}
|
|
79
89
|
className={rootClasses}
|
|
@@ -157,7 +157,10 @@ export default defineFragment({
|
|
|
157
157
|
onChange: {
|
|
158
158
|
type: "function",
|
|
159
159
|
description: "Called with new value when selection changes",
|
|
160
|
-
|
|
160
|
+
},
|
|
161
|
+
onValueChange: {
|
|
162
|
+
type: "function",
|
|
163
|
+
description: "Alias for onChange (Radix convention): (value: string) => void",
|
|
161
164
|
},
|
|
162
165
|
children: {
|
|
163
166
|
type: "node",
|
|
@@ -197,7 +200,7 @@ export default defineFragment({
|
|
|
197
200
|
contract: {
|
|
198
201
|
propsSummary: [
|
|
199
202
|
"value: string - selected value (required)",
|
|
200
|
-
"onChange: (value: string) => void - change handler (
|
|
203
|
+
"onChange: (value: string) => void - change handler (or onValueChange)",
|
|
201
204
|
"children: ToggleGroup.Item[] - toggle items",
|
|
202
205
|
"variant: default|pills|outline - visual style",
|
|
203
206
|
"size: sm|md - size variant",
|
|
@@ -83,6 +83,26 @@ describe('ToggleGroup', () => {
|
|
|
83
83
|
expect(optionB).toHaveAttribute('tabindex', '-1');
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
it('calls onValueChange alias when an item is clicked', async () => {
|
|
87
|
+
const user = userEvent.setup();
|
|
88
|
+
const onValueChange = vi.fn();
|
|
89
|
+
renderToggleGroup({ onChange: undefined, onValueChange });
|
|
90
|
+
|
|
91
|
+
await user.click(screen.getByRole('radio', { name: /option b/i }));
|
|
92
|
+
expect(onValueChange).toHaveBeenCalledWith('b');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('prefers onChange over onValueChange when both provided', async () => {
|
|
96
|
+
const user = userEvent.setup();
|
|
97
|
+
const onChange = vi.fn();
|
|
98
|
+
const onValueChange = vi.fn();
|
|
99
|
+
renderToggleGroup({ onChange, onValueChange });
|
|
100
|
+
|
|
101
|
+
await user.click(screen.getByRole('radio', { name: /option b/i }));
|
|
102
|
+
expect(onChange).toHaveBeenCalledWith('b');
|
|
103
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
86
106
|
it('has no accessibility violations', async () => {
|
|
87
107
|
const { container } = renderToggleGroup();
|
|
88
108
|
await expectNoA11yViolations(container);
|
|
@@ -7,16 +7,25 @@ import styles from './ToggleGroup.module.scss';
|
|
|
7
7
|
// Types
|
|
8
8
|
// ============================================
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* A group of toggle buttons where only one can be selected at a time.
|
|
12
|
+
* @see https://usefragments.com/components/togglegroup
|
|
13
|
+
*/
|
|
10
14
|
export interface ToggleGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
11
15
|
/** Current selected value */
|
|
12
16
|
value: string;
|
|
13
17
|
/** Callback when selection changes */
|
|
14
|
-
onChange
|
|
18
|
+
onChange?: (value: string) => void;
|
|
19
|
+
/** Alias for onChange (Radix convention) */
|
|
20
|
+
onValueChange?: (value: string) => void;
|
|
15
21
|
/** Toggle items */
|
|
16
22
|
children: React.ReactNode;
|
|
17
|
-
/** Visual variant
|
|
23
|
+
/** Visual variant.
|
|
24
|
+
* @default "default"
|
|
25
|
+
* @see https://usefragments.com/components/togglegroup#variants */
|
|
18
26
|
variant?: 'default' | 'pills' | 'outline';
|
|
19
|
-
/** Size
|
|
27
|
+
/** Size.
|
|
28
|
+
* @default "md" */
|
|
20
29
|
size?: 'sm' | 'md' | 'lg';
|
|
21
30
|
/** Gap between items (for pills/outline variants) */
|
|
22
31
|
gap?: 'none' | 'xs' | 'sm';
|
|
@@ -63,6 +72,7 @@ function useToggleGroupContext() {
|
|
|
63
72
|
function ToggleGroupRoot({
|
|
64
73
|
value,
|
|
65
74
|
onChange,
|
|
75
|
+
onValueChange,
|
|
66
76
|
children,
|
|
67
77
|
variant = 'default',
|
|
68
78
|
size = 'md',
|
|
@@ -70,6 +80,7 @@ function ToggleGroupRoot({
|
|
|
70
80
|
className,
|
|
71
81
|
...htmlProps
|
|
72
82
|
}: ToggleGroupProps) {
|
|
83
|
+
const resolvedOnChange = onChange ?? onValueChange ?? (() => {});
|
|
73
84
|
const classes = [
|
|
74
85
|
styles.group,
|
|
75
86
|
styles[variant],
|
|
@@ -91,7 +102,7 @@ function ToggleGroupRoot({
|
|
|
91
102
|
|
|
92
103
|
const contextValue: ToggleGroupContextValue = {
|
|
93
104
|
value,
|
|
94
|
-
onChange,
|
|
105
|
+
onChange: resolvedOnChange,
|
|
95
106
|
variant,
|
|
96
107
|
size,
|
|
97
108
|
hasFocusableSelection,
|
|
@@ -91,6 +91,23 @@ describe('Tooltip', () => {
|
|
|
91
91
|
});
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
+
it('respects shared Tooltip.Provider delay settings', async () => {
|
|
95
|
+
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
|
|
96
|
+
render(
|
|
97
|
+
<Tooltip.Provider delay={0}>
|
|
98
|
+
<Tooltip content="Provider tooltip">
|
|
99
|
+
<button>Provider Trigger</button>
|
|
100
|
+
</Tooltip>
|
|
101
|
+
</Tooltip.Provider>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
await user.hover(screen.getByRole('button', { name: /provider trigger/i }));
|
|
105
|
+
|
|
106
|
+
await waitFor(() => {
|
|
107
|
+
expect(screen.getByText('Provider tooltip')).toBeInTheDocument();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
94
111
|
it('has no accessibility violations when open', async () => {
|
|
95
112
|
const { container } = render(
|
|
96
113
|
<Tooltip content="Accessible tooltip" open={true} delay={0}>
|
|
@@ -46,12 +46,18 @@ export interface TooltipProviderProps {
|
|
|
46
46
|
closeDelay?: number;
|
|
47
47
|
/** Timeout for instant open when moving between tooltips (ms) */
|
|
48
48
|
timeout?: number;
|
|
49
|
+
/** Alias for `delay` (Radix convention) */
|
|
50
|
+
delayDuration?: number;
|
|
51
|
+
/** Alias for `timeout` (Radix convention) */
|
|
52
|
+
skipDelayDuration?: number;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
// ============================================
|
|
52
56
|
// Components
|
|
53
57
|
// ============================================
|
|
54
58
|
|
|
59
|
+
const TooltipProviderContext = React.createContext(false);
|
|
60
|
+
|
|
55
61
|
/**
|
|
56
62
|
* Tooltip - Shows contextual information on hover/focus
|
|
57
63
|
*
|
|
@@ -68,8 +74,8 @@ function TooltipRoot({
|
|
|
68
74
|
side = 'top',
|
|
69
75
|
align = 'center',
|
|
70
76
|
sideOffset = 6,
|
|
71
|
-
delay
|
|
72
|
-
closeDelay
|
|
77
|
+
delay,
|
|
78
|
+
closeDelay,
|
|
73
79
|
disabled = false,
|
|
74
80
|
arrow = true,
|
|
75
81
|
open,
|
|
@@ -78,6 +84,7 @@ function TooltipRoot({
|
|
|
78
84
|
className,
|
|
79
85
|
...htmlProps
|
|
80
86
|
}: TooltipProps) {
|
|
87
|
+
const hasExternalProvider = React.useContext(TooltipProviderContext);
|
|
81
88
|
const renderTrigger = React.useCallback(
|
|
82
89
|
(triggerProps: React.HTMLAttributes<HTMLElement> & { ref?: React.Ref<HTMLElement> }) => {
|
|
83
90
|
const childProps = children.props as Record<string, unknown>;
|
|
@@ -106,30 +113,39 @@ function TooltipRoot({
|
|
|
106
113
|
return children;
|
|
107
114
|
}
|
|
108
115
|
|
|
109
|
-
|
|
110
|
-
<BaseTooltip.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<BaseTooltip.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
</BaseTooltip.Root>
|
|
131
|
-
</BaseTooltip.Provider>
|
|
116
|
+
const tooltipNode = (
|
|
117
|
+
<BaseTooltip.Root
|
|
118
|
+
open={open}
|
|
119
|
+
defaultOpen={defaultOpen}
|
|
120
|
+
onOpenChange={onOpenChange}
|
|
121
|
+
>
|
|
122
|
+
<BaseTooltip.Trigger render={renderTrigger} />
|
|
123
|
+
<BaseTooltip.Portal>
|
|
124
|
+
<BaseTooltip.Positioner
|
|
125
|
+
side={side}
|
|
126
|
+
align={align}
|
|
127
|
+
sideOffset={sideOffset}
|
|
128
|
+
className={styles.positioner}
|
|
129
|
+
>
|
|
130
|
+
<BaseTooltip.Popup {...htmlProps} className={[styles.popup, className].filter(Boolean).join(' ')}>
|
|
131
|
+
{content}
|
|
132
|
+
{arrow && <BaseTooltip.Arrow className={styles.arrow} />}
|
|
133
|
+
</BaseTooltip.Popup>
|
|
134
|
+
</BaseTooltip.Positioner>
|
|
135
|
+
</BaseTooltip.Portal>
|
|
136
|
+
</BaseTooltip.Root>
|
|
132
137
|
);
|
|
138
|
+
|
|
139
|
+
// Only create a local provider when no shared provider exists, or when a local delay override is requested.
|
|
140
|
+
if (!hasExternalProvider || delay !== undefined || closeDelay !== undefined) {
|
|
141
|
+
return (
|
|
142
|
+
<BaseTooltip.Provider delay={delay ?? 400} closeDelay={closeDelay ?? 0}>
|
|
143
|
+
{tooltipNode}
|
|
144
|
+
</BaseTooltip.Provider>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return tooltipNode;
|
|
133
149
|
}
|
|
134
150
|
|
|
135
151
|
/**
|
|
@@ -145,18 +161,26 @@ function TooltipRoot({
|
|
|
145
161
|
*/
|
|
146
162
|
export function TooltipProvider({
|
|
147
163
|
children,
|
|
148
|
-
delay
|
|
164
|
+
delay,
|
|
149
165
|
closeDelay = 0,
|
|
150
|
-
timeout
|
|
166
|
+
timeout,
|
|
167
|
+
delayDuration,
|
|
168
|
+
skipDelayDuration,
|
|
151
169
|
}: TooltipProviderProps) {
|
|
170
|
+
// Resolve Radix-compatible aliases
|
|
171
|
+
const resolvedDelay = delay ?? delayDuration ?? 400;
|
|
172
|
+
const resolvedTimeout = timeout ?? skipDelayDuration ?? 400;
|
|
173
|
+
|
|
152
174
|
return (
|
|
153
|
-
<
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
175
|
+
<TooltipProviderContext.Provider value={true}>
|
|
176
|
+
<BaseTooltip.Provider
|
|
177
|
+
delay={resolvedDelay}
|
|
178
|
+
closeDelay={closeDelay}
|
|
179
|
+
timeout={resolvedTimeout}
|
|
180
|
+
>
|
|
181
|
+
{children}
|
|
182
|
+
</BaseTooltip.Provider>
|
|
183
|
+
</TooltipProviderContext.Provider>
|
|
160
184
|
);
|
|
161
185
|
}
|
|
162
186
|
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
// This ensures --fui-* variables are available when using any component
|
|
3
3
|
import './styles/globals.scss';
|
|
4
4
|
|
|
5
|
+
// Runtime CSS detection — warns if component styles aren't loaded
|
|
6
|
+
import { checkCssLoaded } from './utils/css-warning';
|
|
7
|
+
if (typeof window !== 'undefined') {
|
|
8
|
+
checkCssLoaded();
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
// Core Components
|
|
6
12
|
export { Button, type ButtonProps } from './components/Button';
|
|
7
13
|
export { Input, type InputProps } from './components/Input';
|
package/src/tokens/_seeds.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use 'sass:list';
|
|
2
|
+
|
|
1
3
|
// ============================================
|
|
2
4
|
// @fragments-sdk/ui Design Token Seeds
|
|
3
5
|
// ============================================
|
|
@@ -44,17 +46,17 @@ $fui-radius-style: "default" !default;
|
|
|
44
46
|
// Fail fast at compile time if invalid seed values are provided.
|
|
45
47
|
|
|
46
48
|
$_valid-neutrals: "stone", "ice", "earth", "sand", "fire";
|
|
47
|
-
@if not index($_valid-neutrals, $fui-neutral) {
|
|
49
|
+
@if not list.index($_valid-neutrals, $fui-neutral) {
|
|
48
50
|
@error "Invalid $fui-neutral: '#{$fui-neutral}'. Must be one of: #{$_valid-neutrals}";
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
$_valid-densities: "compact", "default", "relaxed";
|
|
52
|
-
@if not index($_valid-densities, $fui-density) {
|
|
54
|
+
@if not list.index($_valid-densities, $fui-density) {
|
|
53
55
|
@error "Invalid $fui-density: '#{$fui-density}'. Must be one of: #{$_valid-densities}";
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
$_valid-radii: "sharp", "subtle", "default", "rounded", "pill";
|
|
57
|
-
@if not index($_valid-radii, $fui-radius-style) {
|
|
59
|
+
@if not list.index($_valid-radii, $fui-radius-style) {
|
|
58
60
|
@error "Invalid $fui-radius-style: '#{$fui-radius-style}'. Must be one of: #{$_valid-radii}";
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -68,6 +68,7 @@ $fui-font-size-2xl: 2.143rem !default; // 30px
|
|
|
68
68
|
$fui-font-weight-normal: 400 !default;
|
|
69
69
|
$fui-font-weight-medium: 500 !default;
|
|
70
70
|
$fui-font-weight-semibold: 600 !default;
|
|
71
|
+
$fui-font-weight-bold: 700 !default;
|
|
71
72
|
|
|
72
73
|
$fui-line-height-tight: 1.25 !default;
|
|
73
74
|
$fui-line-height-normal: 1.5 !default;
|
|
@@ -436,6 +437,7 @@ $fui-dark-hero-gradient-color: rgba(120, 119, 198, 0.25) !default;
|
|
|
436
437
|
--fui-font-weight-normal: #{$fui-font-weight-normal};
|
|
437
438
|
--fui-font-weight-medium: #{$fui-font-weight-medium};
|
|
438
439
|
--fui-font-weight-semibold: #{$fui-font-weight-semibold};
|
|
440
|
+
--fui-font-weight-bold: #{$fui-font-weight-bold};
|
|
439
441
|
--fui-line-height-tight: #{$fui-line-height-tight};
|
|
440
442
|
--fui-line-height-normal: #{$fui-line-height-normal};
|
|
441
443
|
--fui-line-height-relaxed: #{$fui-line-height-relaxed};
|