@usefragments/ui 1.0.2 → 1.2.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 +16 -16
- package/dist/assets/fragments-wordmark.cjs +30 -0
- package/dist/assets/fragments-wordmark.d.ts +13 -0
- package/dist/assets/fragments-wordmark.d.ts.map +1 -0
- package/dist/assets/fragments-wordmark.js +30 -0
- package/dist/assets/ui.css +3234 -3116
- package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
- package/dist/components/Accordion/Accordion.module.scss.js +8 -8
- package/dist/components/Accordion/index.cjs +22 -10
- package/dist/components/Accordion/index.d.ts.map +1 -1
- package/dist/components/Accordion/index.js +22 -10
- package/dist/components/Alert/Alert.module.scss.cjs +13 -13
- package/dist/components/Alert/Alert.module.scss.js +13 -13
- package/dist/components/AppShell/AppShell.module.scss.cjs +22 -10
- package/dist/components/AppShell/AppShell.module.scss.js +22 -10
- package/dist/components/AppShell/index.cjs +1 -1
- package/dist/components/AppShell/index.js +1 -1
- 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 +16 -16
- package/dist/components/Badge/Badge.module.scss.js +16 -16
- 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 +13 -13
- package/dist/components/Button/Button.module.scss.js +13 -13
- package/dist/components/Card/Card.module.scss.cjs +17 -17
- package/dist/components/Card/Card.module.scss.js +17 -17
- package/dist/components/Card/index.d.ts +3 -3
- package/dist/components/Card/index.d.ts.map +1 -1
- package/dist/components/Chart/Chart.module.scss.cjs +15 -15
- package/dist/components/Chart/Chart.module.scss.js +15 -15
- package/dist/components/Checkbox/Checkbox.module.scss.cjs +11 -11
- package/dist/components/Checkbox/Checkbox.module.scss.js +11 -11
- 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/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/Combobox/Combobox.module.scss.cjs +23 -23
- package/dist/components/Combobox/Combobox.module.scss.js +23 -23
- package/dist/components/Combobox/index.cjs +106 -9
- package/dist/components/Combobox/index.d.ts.map +1 -1
- package/dist/components/Combobox/index.js +106 -9
- 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 +37 -34
- package/dist/components/DataTable/DataTable.module.scss.js +37 -34
- package/dist/components/DataTable/index.d.ts +3 -1
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DatePicker/DatePicker.module.scss.cjs +33 -33
- package/dist/components/DatePicker/DatePicker.module.scss.js +33 -33
- package/dist/components/DatePicker/index.d.ts +1 -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 +28 -28
- package/dist/components/Drawer/Drawer.module.scss.js +28 -28
- package/dist/components/Drawer/index.cjs +20 -3
- package/dist/components/Drawer/index.d.ts.map +1 -1
- package/dist/components/Drawer/index.js +20 -3
- 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/Field/index.cjs +10 -9
- package/dist/components/Field/index.d.ts +7 -7
- package/dist/components/Field/index.d.ts.map +1 -1
- package/dist/components/Field/index.js +10 -9
- 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 +44 -29
- package/dist/components/Header/Header.module.scss.js +44 -29
- package/dist/components/Header/index.cjs +56 -3
- package/dist/components/Header/index.d.ts +25 -3
- package/dist/components/Header/index.d.ts.map +1 -1
- package/dist/components/Header/index.js +56 -3
- package/dist/components/Icon/Icon.module.scss.cjs +8 -8
- package/dist/components/Icon/Icon.module.scss.js +8 -8
- package/dist/components/IconButton/IconButton.module.scss.cjs +8 -8
- package/dist/components/IconButton/IconButton.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/List/List.module.scss.cjs +19 -19
- package/dist/components/List/List.module.scss.js +19 -19
- 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/Main/Main.module.scss.cjs +26 -0
- package/dist/components/Main/Main.module.scss.js +26 -0
- package/dist/components/Main/index.cjs +128 -0
- package/dist/components/Main/index.d.ts +22 -0
- package/dist/components/Main/index.d.ts.map +1 -0
- package/dist/components/Main/index.js +111 -0
- package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
- package/dist/components/Markdown/Markdown.module.scss.js +1 -1
- package/dist/components/Menu/Menu.module.scss.cjs +14 -14
- package/dist/components/Menu/Menu.module.scss.js +14 -14
- 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/Popover/index.cjs +27 -2
- package/dist/components/Popover/index.d.ts.map +1 -1
- package/dist/components/Popover/index.js +27 -2
- 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 +18 -18
- package/dist/components/Prompt/Prompt.module.scss.js +18 -18
- package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +17 -17
- package/dist/components/RadioGroup/RadioGroup.module.scss.js +17 -17
- package/dist/components/RadioGroup/index.cjs +2 -0
- package/dist/components/RadioGroup/index.d.ts +2 -0
- package/dist/components/RadioGroup/index.d.ts.map +1 -1
- package/dist/components/RadioGroup/index.js +2 -0
- 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/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/Skeleton/Skeleton.module.scss.cjs +38 -38
- package/dist/components/Skeleton/Skeleton.module.scss.js +38 -38
- package/dist/components/Slider/Slider.module.scss.cjs +12 -12
- package/dist/components/Slider/Slider.module.scss.js +12 -12
- package/dist/components/Table/Table.module.scss.cjs +19 -19
- package/dist/components/Table/Table.module.scss.js +19 -19
- package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +15 -15
- package/dist/components/TableOfContents/TableOfContents.module.scss.js +15 -15
- package/dist/components/TableOfContents/index.cjs +22 -42
- package/dist/components/TableOfContents/index.d.ts +3 -3
- package/dist/components/TableOfContents/index.d.ts.map +1 -1
- package/dist/components/TableOfContents/index.js +22 -42
- package/dist/components/Tabs/Tabs.module.scss.cjs +12 -12
- package/dist/components/Tabs/Tabs.module.scss.js +12 -12
- package/dist/components/Text/Text.module.scss.cjs +51 -51
- package/dist/components/Text/Text.module.scss.js +51 -51
- 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 +13 -13
- package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.js +13 -13
- package/dist/components/Toast/Toast.module.scss.cjs +21 -21
- package/dist/components/Toast/Toast.module.scss.js +21 -21
- 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/data-table.cjs +58 -41
- package/dist/data-table.js +59 -41
- package/dist/datepicker.cjs +32 -72
- package/dist/datepicker.js +32 -72
- package/dist/index.cjs +89 -85
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/fragments.json +1 -1
- package/package.json +9 -8
- package/src/assets/fragments-wordmark.tsx +47 -0
- package/src/components/Accordion/index.tsx +13 -3
- package/src/components/Alert/Alert.module.scss +15 -2
- package/src/components/AppShell/AppShell.module.scss +73 -15
- package/src/components/AppShell/index.tsx +1 -1
- package/src/components/Button/Button.module.scss +19 -20
- package/src/components/Card/Card.module.scss +3 -3
- package/src/components/Card/index.tsx +3 -3
- package/src/components/Checkbox/Checkbox.contract.json +5 -24
- package/src/components/Checkbox/Checkbox.module.scss +4 -2
- package/src/components/Chip/Chip.contract.json +11 -28
- package/src/components/Chip/Chip.module.scss +21 -45
- package/src/components/CodeBlock/CodeBlock.module.scss +2 -7
- package/src/components/Combobox/Combobox.contract.json +6 -24
- package/src/components/Combobox/Combobox.module.scss +3 -2
- package/src/components/Combobox/index.tsx +132 -6
- package/src/components/DataTable/DataTable.contract.json +16 -23
- package/src/components/DataTable/DataTable.module.scss +31 -8
- package/src/components/DataTable/index.tsx +25 -4
- package/src/components/DatePicker/index.tsx +32 -84
- package/src/components/Drawer/index.tsx +38 -12
- package/src/components/Field/index.tsx +35 -35
- package/src/components/Header/Header.contract.json +41 -1
- package/src/components/Header/Header.module.scss +40 -0
- package/src/components/Header/index.tsx +88 -2
- package/src/components/IconButton/IconButton.contract.json +120 -0
- package/src/components/Listbox/Listbox.module.scss +5 -4
- package/src/components/Main/Main.contract.json +79 -0
- package/src/components/Main/Main.module.scss +31 -0
- package/src/components/Main/index.tsx +124 -0
- package/src/components/Menu/Menu.module.scss +8 -10
- package/src/components/Popover/index.tsx +34 -2
- package/src/components/RadioGroup/RadioGroup.contract.json +13 -27
- package/src/components/RadioGroup/index.tsx +4 -0
- package/src/components/Select/Select.module.scss +13 -12
- package/src/components/Table/Table.module.scss +22 -5
- package/src/components/TableOfContents/TableOfContents.contract.json +6 -16
- package/src/components/TableOfContents/TableOfContents.module.scss +20 -14
- package/src/components/TableOfContents/index.tsx +27 -38
- package/src/components/Toast/Toast.module.scss +15 -2
- package/src/components/ToggleGroup/ToggleGroup.module.scss +4 -1
- package/src/index.ts +4 -0
- package/src/styles/globals.scss +13 -10
- package/src/tokens/_component-properties.scss +26 -0
- package/src/tokens/_computed.scss +22 -4
- package/src/tokens/_derive.scss +55 -6
- package/src/tokens/_palettes.scss +24 -0
- package/src/tokens/_seeds.scss +20 -12
- package/src/tokens/_variables.scss +110 -63
- package/dist/components/Cloud/DashboardLayoutPrototypes.shared.d.ts +0 -33
- package/dist/components/Cloud/DashboardLayoutPrototypes.shared.d.ts.map +0 -1
- package/dist/components/Cloud/DashboardLayoutPrototypes.shell.d.ts +0 -11
- package/dist/components/Cloud/DashboardLayoutPrototypes.shell.d.ts.map +0 -1
- package/dist/components/Cloud/PullRequestsPrototypes.content.d.ts +0 -5
- package/dist/components/Cloud/PullRequestsPrototypes.content.d.ts.map +0 -1
- package/dist/components/Cloud/PullRequestsPrototypes.detail-panels.d.ts +0 -4
- package/dist/components/Cloud/PullRequestsPrototypes.detail-panels.d.ts.map +0 -1
- package/dist/components/Cloud/PullRequestsPrototypes.detail.d.ts +0 -3
- package/dist/components/Cloud/PullRequestsPrototypes.detail.d.ts.map +0 -1
- package/dist/components/Cloud/PullRequestsPrototypes.id-data.d.ts +0 -86
- package/dist/components/Cloud/PullRequestsPrototypes.id-data.d.ts.map +0 -1
- package/dist/components/Cloud/PullRequestsPrototypes.id-page.d.ts +0 -2
- package/dist/components/Cloud/PullRequestsPrototypes.id-page.d.ts.map +0 -1
- package/src/components/Accordion/Accordion.stories.tsx +0 -106
- package/src/components/Alert/Alert.stories.tsx +0 -119
- package/src/components/AppShell/AppShell.stories.tsx +0 -156
- package/src/components/Avatar/Avatar.stories.tsx +0 -74
- package/src/components/Badge/Badge.stories.tsx +0 -92
- package/src/components/BentoGrid/BentoGrid.stories.tsx +0 -98
- package/src/components/Box/Box.stories.tsx +0 -150
- package/src/components/Breadcrumbs/Breadcrumbs.stories.tsx +0 -87
- package/src/components/Button/Button.stories.tsx +0 -103
- package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -97
- package/src/components/Card/Card.stories.tsx +0 -144
- package/src/components/Chart/Chart.stories.tsx +0 -119
- package/src/components/Checkbox/Checkbox.stories.tsx +0 -68
- package/src/components/Chip/Chip.stories.tsx +0 -70
- package/src/components/Cloud/CloudGovernanceShell.module.scss +0 -88
- package/src/components/Cloud/CloudGovernanceShell.stories.tsx +0 -446
- package/src/components/Cloud/ControlSizing.module.scss +0 -49
- package/src/components/Cloud/ControlSizing.stories.tsx +0 -238
- package/src/components/Cloud/DashboardLayoutPrototypes.module.scss +0 -462
- package/src/components/Cloud/DashboardLayoutPrototypes.shared.tsx +0 -375
- package/src/components/Cloud/DashboardLayoutPrototypes.shell.tsx +0 -147
- package/src/components/Cloud/DashboardLayoutPrototypes.stories.tsx +0 -328
- package/src/components/Cloud/PullRequestsPrototypes.content.tsx +0 -283
- package/src/components/Cloud/PullRequestsPrototypes.detail-panels.tsx +0 -381
- package/src/components/Cloud/PullRequestsPrototypes.detail.tsx +0 -204
- package/src/components/Cloud/PullRequestsPrototypes.id-data.ts +0 -395
- package/src/components/Cloud/PullRequestsPrototypes.id-page.tsx +0 -349
- package/src/components/Cloud/PullRequestsPrototypes.stories.tsx +0 -81
- package/src/components/CodeBlock/CodeBlock.stories.tsx +0 -147
- package/src/components/Collapsible/Collapsible.stories.tsx +0 -94
- package/src/components/ColorPicker/ColorPicker.stories.tsx +0 -74
- package/src/components/Combobox/Combobox.stories.tsx +0 -133
- package/src/components/Command/Command.stories.tsx +0 -102
- package/src/components/ConversationList/ConversationList.stories.tsx +0 -93
- package/src/components/DataTable/DataTable.stories.tsx +0 -129
- package/src/components/DatePicker/DatePicker.stories.tsx +0 -129
- package/src/components/Dialog/Dialog.stories.tsx +0 -154
- package/src/components/Drawer/Drawer.stories.tsx +0 -144
- package/src/components/Editor/Editor.stories.tsx +0 -99
- package/src/components/EmptyState/EmptyState.stories.tsx +0 -97
- package/src/components/Field/Field.stories.tsx +0 -109
- package/src/components/Fieldset/Fieldset.stories.tsx +0 -116
- package/src/components/Form/Form.stories.tsx +0 -142
- package/src/components/Grid/Grid.stories.tsx +0 -125
- package/src/components/Header/Header.stories.tsx +0 -133
- package/src/components/Icon/Icon.stories.tsx +0 -80
- package/src/components/IconButton/IconButton.stories.tsx +0 -78
- package/src/components/Image/Image.stories.tsx +0 -109
- package/src/components/Input/Input.stories.tsx +0 -104
- package/src/components/Link/Link.stories.tsx +0 -67
- package/src/components/List/List.stories.tsx +0 -95
- package/src/components/Listbox/Listbox.stories.tsx +0 -81
- package/src/components/Loading/Loading.stories.tsx +0 -69
- package/src/components/Markdown/Markdown.stories.tsx +0 -75
- package/src/components/Menu/Menu.stories.tsx +0 -113
- package/src/components/Message/Message.stories.tsx +0 -85
- package/src/components/NavigationMenu/NavigationMenu.stories.tsx +0 -161
- package/src/components/Pagination/Pagination.stories.tsx +0 -81
- package/src/components/Popover/Popover.stories.tsx +0 -152
- package/src/components/Progress/Progress.stories.tsx +0 -64
- package/src/components/Prompt/Prompt.stories.tsx +0 -93
- package/src/components/RadioGroup/RadioGroup.stories.tsx +0 -107
- package/src/components/ScrollArea/ScrollArea.stories.tsx +0 -97
- package/src/components/Select/Select.stories.tsx +0 -127
- package/src/components/Separator/Separator.stories.tsx +0 -84
- package/src/components/Sidebar/Sidebar.stories.tsx +0 -122
- package/src/components/Skeleton/Skeleton.stories.tsx +0 -80
- package/src/components/Slider/Slider.stories.tsx +0 -73
- package/src/components/Stack/Stack.stories.tsx +0 -73
- package/src/components/Switch/Switch.stories.tsx +0 -59
- package/src/components/Table/Table.stories.tsx +0 -219
- package/src/components/TableOfContents/TableOfContents.stories.tsx +0 -120
- package/src/components/Tabs/Tabs.stories.tsx +0 -136
- package/src/components/Text/Text.stories.tsx +0 -133
- package/src/components/Textarea/Textarea.stories.tsx +0 -107
- package/src/components/Theme/Theme.stories.tsx +0 -95
- package/src/components/ThinkingIndicator/ThinkingIndicator.stories.tsx +0 -85
- package/src/components/Toast/Toast.stories.tsx +0 -91
- package/src/components/ToggleGroup/ToggleGroup.stories.tsx +0 -114
- package/src/components/Tooltip/Tooltip.stories.tsx +0 -95
- package/src/components/VisuallyHidden/VisuallyHidden.stories.tsx +0 -78
|
@@ -25,12 +25,26 @@ export type HeaderIconSlot =
|
|
|
25
25
|
|
|
26
26
|
export type HeaderIcons = Partial<Record<HeaderIconRenderState['slot'], HeaderIconSlot>>;
|
|
27
27
|
|
|
28
|
+
export type HeaderNavAlign = 'start' | 'center';
|
|
29
|
+
export type HeaderContainer = 'full' | 'page';
|
|
30
|
+
|
|
31
|
+
export interface HeaderElevatedOnScrollOptions {
|
|
32
|
+
/** Scroll offset before the elevated surface is applied */
|
|
33
|
+
threshold?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
export interface HeaderProps extends React.HTMLAttributes<HTMLElement> {
|
|
29
37
|
children: React.ReactNode;
|
|
30
38
|
/** Header height (default: '56px') */
|
|
31
39
|
height?: string;
|
|
32
40
|
/** Position behavior */
|
|
33
41
|
position?: 'static' | 'fixed' | 'sticky';
|
|
42
|
+
/** Apply the elevated header surface after scroll */
|
|
43
|
+
elevatedOnScroll?: boolean | HeaderElevatedOnScrollOptions;
|
|
44
|
+
/** Navigation alignment inside the header */
|
|
45
|
+
navAlign?: HeaderNavAlign;
|
|
46
|
+
/** Header content width */
|
|
47
|
+
container?: HeaderContainer;
|
|
34
48
|
/** Optional icon overrides for internal header controls (mobile trigger + nav menu chevron) */
|
|
35
49
|
icons?: HeaderIcons;
|
|
36
50
|
}
|
|
@@ -39,6 +53,8 @@ export interface HeaderBrandProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
39
53
|
children: React.ReactNode;
|
|
40
54
|
/** Link destination */
|
|
41
55
|
href?: string;
|
|
56
|
+
/** Render as child element (polymorphic) */
|
|
57
|
+
asChild?: boolean;
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
export interface HeaderNavProps extends React.HTMLAttributes<HTMLElement> {
|
|
@@ -101,6 +117,10 @@ export interface HeaderMobileNavProps {
|
|
|
101
117
|
className?: string;
|
|
102
118
|
}
|
|
103
119
|
|
|
120
|
+
export interface HeaderMobileNavActionsProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
121
|
+
children: React.ReactNode;
|
|
122
|
+
}
|
|
123
|
+
|
|
104
124
|
// ============================================
|
|
105
125
|
// Internal Context
|
|
106
126
|
// ============================================
|
|
@@ -175,17 +195,37 @@ function HeaderRoot({
|
|
|
175
195
|
children,
|
|
176
196
|
height = '56px',
|
|
177
197
|
position = 'static',
|
|
198
|
+
elevatedOnScroll = false,
|
|
199
|
+
navAlign = 'start',
|
|
200
|
+
container = 'full',
|
|
178
201
|
icons,
|
|
179
202
|
className,
|
|
180
203
|
style: styleProp,
|
|
181
204
|
...htmlProps
|
|
182
205
|
}: HeaderProps) {
|
|
183
206
|
const [mobileOpen, setMobileOpen] = React.useState(false);
|
|
207
|
+
const [scrolled, setScrolled] = React.useState(false);
|
|
208
|
+
const shouldElevateOnScroll = Boolean(elevatedOnScroll);
|
|
209
|
+
const scrollThreshold =
|
|
210
|
+
typeof elevatedOnScroll === 'object' ? (elevatedOnScroll.threshold ?? 16) : 16;
|
|
211
|
+
|
|
212
|
+
React.useEffect(() => {
|
|
213
|
+
if (!shouldElevateOnScroll) return;
|
|
214
|
+
|
|
215
|
+
const updateScrolled = () => setScrolled(window.scrollY > scrollThreshold);
|
|
216
|
+
updateScrolled();
|
|
217
|
+
window.addEventListener('scroll', updateScrolled, { passive: true });
|
|
218
|
+
return () => window.removeEventListener('scroll', updateScrolled);
|
|
219
|
+
}, [scrollThreshold, shouldElevateOnScroll]);
|
|
184
220
|
|
|
185
221
|
const classes = [
|
|
186
222
|
styles.header,
|
|
187
223
|
position === 'fixed' && styles.fixed,
|
|
188
224
|
position === 'sticky' && styles.sticky,
|
|
225
|
+
shouldElevateOnScroll && styles.elevatedOnScroll,
|
|
226
|
+
shouldElevateOnScroll && scrolled && styles.scrolled,
|
|
227
|
+
navAlign === 'center' && styles.navCentered,
|
|
228
|
+
container === 'page' && styles.containerPage,
|
|
189
229
|
className,
|
|
190
230
|
].filter(Boolean).join(' ');
|
|
191
231
|
|
|
@@ -202,7 +242,13 @@ function HeaderRoot({
|
|
|
202
242
|
return (
|
|
203
243
|
<HeaderContext.Provider value={contextValue}>
|
|
204
244
|
<HeaderIconContext.Provider value={icons}>
|
|
205
|
-
<header
|
|
245
|
+
<header
|
|
246
|
+
{...htmlProps}
|
|
247
|
+
className={classes}
|
|
248
|
+
style={style}
|
|
249
|
+
data-position={position}
|
|
250
|
+
data-scrolled={shouldElevateOnScroll ? scrolled : undefined}
|
|
251
|
+
>
|
|
206
252
|
<div className={styles.container}>
|
|
207
253
|
{children}
|
|
208
254
|
</div>
|
|
@@ -215,9 +261,30 @@ function HeaderRoot({
|
|
|
215
261
|
/**
|
|
216
262
|
* Header.Brand - Logo/brand slot
|
|
217
263
|
*/
|
|
218
|
-
function HeaderBrand({
|
|
264
|
+
function HeaderBrand({
|
|
265
|
+
children,
|
|
266
|
+
href,
|
|
267
|
+
asChild = false,
|
|
268
|
+
className,
|
|
269
|
+
...htmlProps
|
|
270
|
+
}: HeaderBrandProps) {
|
|
219
271
|
const classes = [styles.brand, className].filter(Boolean).join(' ');
|
|
220
272
|
|
|
273
|
+
if (asChild && React.isValidElement(children)) {
|
|
274
|
+
const childProps = children.props as {
|
|
275
|
+
className?: string;
|
|
276
|
+
onClick?: React.MouseEventHandler<HTMLElement>;
|
|
277
|
+
};
|
|
278
|
+
const { onClick, ...restHtmlProps } = htmlProps as React.HTMLAttributes<HTMLElement>;
|
|
279
|
+
|
|
280
|
+
return React.cloneElement(children, {
|
|
281
|
+
...restHtmlProps,
|
|
282
|
+
...(href ? { href } : {}),
|
|
283
|
+
className: [classes, childProps.className].filter(Boolean).join(' '),
|
|
284
|
+
onClick: onClick ? composeEventHandlers(childProps.onClick, onClick) : childProps.onClick,
|
|
285
|
+
} as React.HTMLAttributes<HTMLElement>);
|
|
286
|
+
}
|
|
287
|
+
|
|
221
288
|
if (href) {
|
|
222
289
|
return (
|
|
223
290
|
<a {...htmlProps} href={href} className={classes}>
|
|
@@ -604,6 +671,23 @@ function HeaderMobileNavLink({
|
|
|
604
671
|
);
|
|
605
672
|
}
|
|
606
673
|
|
|
674
|
+
/**
|
|
675
|
+
* Header.MobileNavActions - Action row inside the mobile drawer
|
|
676
|
+
*/
|
|
677
|
+
function HeaderMobileNavActions({
|
|
678
|
+
children,
|
|
679
|
+
className,
|
|
680
|
+
...htmlProps
|
|
681
|
+
}: HeaderMobileNavActionsProps) {
|
|
682
|
+
const classes = [styles.mobileNavActions, className].filter(Boolean).join(' ');
|
|
683
|
+
|
|
684
|
+
return (
|
|
685
|
+
<div {...htmlProps} className={classes}>
|
|
686
|
+
{children}
|
|
687
|
+
</div>
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
|
|
607
691
|
/**
|
|
608
692
|
* Header.SkipLink - Skip to main content link (accessibility)
|
|
609
693
|
*/
|
|
@@ -641,6 +725,7 @@ export const Header = Object.assign(HeaderRoot, {
|
|
|
641
725
|
SkipLink: HeaderSkipLink,
|
|
642
726
|
MobileNav: HeaderMobileNav,
|
|
643
727
|
MobileNavLink: HeaderMobileNavLink,
|
|
728
|
+
MobileNavActions: HeaderMobileNavActions,
|
|
644
729
|
});
|
|
645
730
|
|
|
646
731
|
export {
|
|
@@ -657,4 +742,5 @@ export {
|
|
|
657
742
|
HeaderSkipLink,
|
|
658
743
|
HeaderMobileNav,
|
|
659
744
|
HeaderMobileNavLink,
|
|
745
|
+
HeaderMobileNavActions,
|
|
660
746
|
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "IconButton",
|
|
4
|
+
"description": "Compact square button for icon-only actions in dense toolbars, top bars, and row controls.",
|
|
5
|
+
"category": "forms",
|
|
6
|
+
"tags": ["action", "button", "icon", "toolbar", "interactive"],
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"sourcePath": "src/components/IconButton/index.tsx",
|
|
9
|
+
"exportName": "IconButton",
|
|
10
|
+
"propsSummary": [
|
|
11
|
+
"children: node (required)",
|
|
12
|
+
"variant: ghost|subtle|outlined (default: ghost)",
|
|
13
|
+
"size: sm|md|lg (default: md)",
|
|
14
|
+
"pressed: boolean",
|
|
15
|
+
"aria-label: string",
|
|
16
|
+
"aria-labelledby: string"
|
|
17
|
+
],
|
|
18
|
+
"props": {
|
|
19
|
+
"children": {
|
|
20
|
+
"type": "node",
|
|
21
|
+
"description": "Icon element rendered inside the button",
|
|
22
|
+
"required": true
|
|
23
|
+
},
|
|
24
|
+
"variant": {
|
|
25
|
+
"type": "enum",
|
|
26
|
+
"description": "Visual treatment for the icon-only action",
|
|
27
|
+
"default": "ghost",
|
|
28
|
+
"required": false,
|
|
29
|
+
"values": ["ghost", "subtle", "outlined"]
|
|
30
|
+
},
|
|
31
|
+
"size": {
|
|
32
|
+
"type": "enum",
|
|
33
|
+
"description": "Control size aligned with adjacent fields and toolbar actions",
|
|
34
|
+
"default": "md",
|
|
35
|
+
"required": false,
|
|
36
|
+
"values": ["sm", "md", "lg"]
|
|
37
|
+
},
|
|
38
|
+
"pressed": {
|
|
39
|
+
"type": "boolean",
|
|
40
|
+
"description": "Marks a toggle-style action as pressed and sets aria-pressed",
|
|
41
|
+
"required": false
|
|
42
|
+
},
|
|
43
|
+
"aria-label": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"description": "Accessible action name when no labelled-by relationship is available",
|
|
46
|
+
"required": false
|
|
47
|
+
},
|
|
48
|
+
"aria-labelledby": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"description": "ID reference for an external accessible action label",
|
|
51
|
+
"required": false
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"usage": {
|
|
55
|
+
"when": [
|
|
56
|
+
"Compact icon-only actions in toolbars or top bars",
|
|
57
|
+
"Row actions where a text button would be too wide",
|
|
58
|
+
"Toggle-style icon actions with a visible pressed state"
|
|
59
|
+
],
|
|
60
|
+
"whenNot": [
|
|
61
|
+
"The action needs a visible text label (use Button)",
|
|
62
|
+
"The control changes a persistent boolean setting (use Switch)",
|
|
63
|
+
"The icon is decorative and not interactive (use Icon)"
|
|
64
|
+
],
|
|
65
|
+
"guidelines": [
|
|
66
|
+
"Always provide aria-label or aria-labelledby",
|
|
67
|
+
"Use ghost for ordinary toolbar actions and outlined when more separation is needed",
|
|
68
|
+
"Use pressed only when the button represents a persistent toggle state"
|
|
69
|
+
],
|
|
70
|
+
"accessibility": [
|
|
71
|
+
"Every icon-only button must have an accessible name",
|
|
72
|
+
"The accessible name should describe the action, not the icon",
|
|
73
|
+
"Pressed state must be exposed with aria-pressed"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"examples": [
|
|
77
|
+
{
|
|
78
|
+
"name": "Toolbar action",
|
|
79
|
+
"description": "A named icon-only toolbar action",
|
|
80
|
+
"code": "<IconButton aria-label=\"Add item\">\n <PlusIcon aria-hidden />\n</IconButton>"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "Pressed state",
|
|
84
|
+
"description": "A toggle-style action with its state exposed",
|
|
85
|
+
"code": "import { PushPin as PinIcon } from '@phosphor-icons/react';\n\n<IconButton aria-label=\"Pin item\" pressed>\n <PinIcon aria-hidden />\n</IconButton>"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"relations": [
|
|
89
|
+
{
|
|
90
|
+
"component": "Button",
|
|
91
|
+
"relationship": "sibling",
|
|
92
|
+
"note": "Use Button when the action should have a visible text label or broader layout variants"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"component": "Icon",
|
|
96
|
+
"relationship": "complementary",
|
|
97
|
+
"note": "Icon supplies the visual glyph rendered inside IconButton"
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"contract": {
|
|
101
|
+
"propsSummary": [
|
|
102
|
+
"children: ReactNode - icon element (required)",
|
|
103
|
+
"variant: ghost|subtle|outlined - visual treatment",
|
|
104
|
+
"size: sm|md|lg - square control size",
|
|
105
|
+
"pressed: boolean - toggle state exposed with aria-pressed",
|
|
106
|
+
"aria-label or aria-labelledby - required accessible name"
|
|
107
|
+
],
|
|
108
|
+
"a11yRules": ["A11Y_BTN_LABEL", "A11Y_BTN_FOCUS", "A11Y_TARGET_SIZE_MIN"]
|
|
109
|
+
},
|
|
110
|
+
"ai": {
|
|
111
|
+
"compositionPattern": "compound",
|
|
112
|
+
"subComponents": ["Root"]
|
|
113
|
+
},
|
|
114
|
+
"provenance": {
|
|
115
|
+
"source": "migrated",
|
|
116
|
+
"verified": false,
|
|
117
|
+
"frameworkSupport": "native",
|
|
118
|
+
"extractedAt": "2026-07-14T00:00:00.000Z"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
@use
|
|
2
|
-
@use
|
|
1
|
+
@use "../../tokens/variables" as *;
|
|
2
|
+
@use "../../tokens/mixins" as *;
|
|
3
3
|
|
|
4
4
|
// ============================================
|
|
5
5
|
// Listbox container
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
@include popup-container;
|
|
11
11
|
|
|
12
12
|
// Item height derived from text-base font + vertical padding (matches Select/Combobox)
|
|
13
|
-
--
|
|
13
|
+
--_listbox-item-h: calc(
|
|
14
14
|
var(--fui-font-size-sm, #{$fui-font-size-sm}) *
|
|
15
15
|
var(--fui-line-height-normal, #{$fui-line-height-normal}) +
|
|
16
16
|
var(--fui-space-2, #{$fui-space-2}) * 2
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
min-width: 12rem;
|
|
20
20
|
// Show N items + half-peek scroll hint (default 4.5 items)
|
|
21
21
|
max-height: calc(
|
|
22
|
-
var(--
|
|
22
|
+
var(--_listbox-item-h) * var(--fui-select-max-items, 4.5) +
|
|
23
|
+
var(--fui-space-1, #{$fui-space-1}) * 2
|
|
23
24
|
);
|
|
24
25
|
overflow-y: auto;
|
|
25
26
|
border-color: var(--fui-form-group-border, $fui-border);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "Main",
|
|
4
|
+
"description": "Canonical page composition owning gutter, measure, and vertical rhythm.",
|
|
5
|
+
"category": "layout",
|
|
6
|
+
"tags": ["main", "page", "layout", "compound"],
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"sourcePath": "src/components/Main/index.tsx",
|
|
9
|
+
"exportName": "Main",
|
|
10
|
+
"propsSummary": [
|
|
11
|
+
"children: node (required)",
|
|
12
|
+
"measure: full|narrow (default: full)",
|
|
13
|
+
"as: semantic element (default: main)"
|
|
14
|
+
],
|
|
15
|
+
"props": {
|
|
16
|
+
"children": {
|
|
17
|
+
"type": "node",
|
|
18
|
+
"description": "Page regions composed from Main.Header, Main.Description, Main.Content, and Main.Footer",
|
|
19
|
+
"required": true
|
|
20
|
+
},
|
|
21
|
+
"measure": {
|
|
22
|
+
"type": "enum",
|
|
23
|
+
"description": "Maximum width applied to the page composition",
|
|
24
|
+
"default": "full",
|
|
25
|
+
"required": false,
|
|
26
|
+
"values": ["full", "narrow"]
|
|
27
|
+
},
|
|
28
|
+
"as": {
|
|
29
|
+
"type": "enum",
|
|
30
|
+
"description": "Semantic HTML element rendered by the root",
|
|
31
|
+
"default": "main",
|
|
32
|
+
"required": false,
|
|
33
|
+
"values": [
|
|
34
|
+
"div",
|
|
35
|
+
"section",
|
|
36
|
+
"nav",
|
|
37
|
+
"article",
|
|
38
|
+
"aside",
|
|
39
|
+
"header",
|
|
40
|
+
"footer",
|
|
41
|
+
"main",
|
|
42
|
+
"ul",
|
|
43
|
+
"ol"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"usage": {
|
|
48
|
+
"when": ["Composing a page header, description, content, and footer"],
|
|
49
|
+
"whenNot": ["Application shell navigation (use AppShell)"],
|
|
50
|
+
"guidelines": [
|
|
51
|
+
"Use one Main gutter owner per page",
|
|
52
|
+
"Compose page regions with Main.Header, Main.Description, Main.Content, and Main.Footer"
|
|
53
|
+
],
|
|
54
|
+
"accessibility": [
|
|
55
|
+
"Use the default main element unless an existing shell already owns the main landmark"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"examples": [
|
|
59
|
+
{
|
|
60
|
+
"name": "Full Measure",
|
|
61
|
+
"description": "Page composition that uses the full available canvas",
|
|
62
|
+
"code": "<Main measure=\"full\">\n <Main.Header>Page statement</Main.Header>\n <Main.Description>Supporting page context.</Main.Description>\n <Main.Content>Page content</Main.Content>\n <Main.Footer>Page actions</Main.Footer>\n</Main>"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "Narrow Measure",
|
|
66
|
+
"description": "Readable page composition constrained to the canonical 800px measure",
|
|
67
|
+
"code": "<Main measure=\"narrow\">\n <Main.Header>Settings</Main.Header>\n <Main.Description>Manage the workspace contract.</Main.Description>\n <Main.Content>Settings content</Main.Content>\n <Main.Footer>Save changes</Main.Footer>\n</Main>"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"ai": {
|
|
71
|
+
"compositionPattern": "compound",
|
|
72
|
+
"subComponents": ["Header", "Description", "Content", "Footer"]
|
|
73
|
+
},
|
|
74
|
+
"provenance": {
|
|
75
|
+
"source": "manual",
|
|
76
|
+
"verified": true,
|
|
77
|
+
"frameworkSupport": "native"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@use "../../tokens/variables" as *;
|
|
2
|
+
|
|
3
|
+
$fui-main-measure-narrow: 57.143rem !default;
|
|
4
|
+
|
|
5
|
+
.root {
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
width: 100%;
|
|
8
|
+
min-width: 0;
|
|
9
|
+
min-height: 100%;
|
|
10
|
+
margin-inline: auto;
|
|
11
|
+
padding: var(--fui-space-3, $fui-space-3);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.full {
|
|
15
|
+
max-width: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.narrow {
|
|
19
|
+
max-width: $fui-main-measure-narrow;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.header,
|
|
23
|
+
.description,
|
|
24
|
+
.content,
|
|
25
|
+
.footer {
|
|
26
|
+
min-width: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.description {
|
|
30
|
+
max-width: 68ch;
|
|
31
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Stack, type StackProps } from "../Stack";
|
|
3
|
+
import styles from "./Main.module.scss";
|
|
4
|
+
|
|
5
|
+
export type MainMeasure = "full" | "narrow";
|
|
6
|
+
|
|
7
|
+
export interface MainProps extends Omit<StackProps, "as" | "children" | "direction" | "gap"> {
|
|
8
|
+
as?: StackProps["as"];
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
/** Maximum readable width for the page content. */
|
|
11
|
+
measure?: MainMeasure;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type MainRegionProps = StackProps;
|
|
15
|
+
|
|
16
|
+
function joinClasses(...classes: Array<string | false | undefined>) {
|
|
17
|
+
return classes.filter(Boolean).join(" ");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const MainRoot = React.forwardRef<HTMLElement, MainProps>(function MainRoot(
|
|
21
|
+
{ as = "main", children, className, measure = "full", ...htmlProps },
|
|
22
|
+
ref
|
|
23
|
+
) {
|
|
24
|
+
return (
|
|
25
|
+
<Stack
|
|
26
|
+
{...htmlProps}
|
|
27
|
+
ref={ref}
|
|
28
|
+
as={as}
|
|
29
|
+
direction="column"
|
|
30
|
+
gap="lg"
|
|
31
|
+
className={joinClasses(
|
|
32
|
+
styles.root,
|
|
33
|
+
measure === "narrow" ? styles.narrow : styles.full,
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
36
|
+
data-main-measure={measure}
|
|
37
|
+
>
|
|
38
|
+
{children}
|
|
39
|
+
</Stack>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
function MainHeader({
|
|
44
|
+
as = "header",
|
|
45
|
+
direction = "column",
|
|
46
|
+
gap = "sm",
|
|
47
|
+
className,
|
|
48
|
+
...props
|
|
49
|
+
}: MainRegionProps) {
|
|
50
|
+
return (
|
|
51
|
+
<Stack
|
|
52
|
+
{...props}
|
|
53
|
+
as={as}
|
|
54
|
+
direction={direction}
|
|
55
|
+
gap={gap}
|
|
56
|
+
className={joinClasses(styles.header, className)}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function MainDescription({
|
|
62
|
+
as = "div",
|
|
63
|
+
direction = "column",
|
|
64
|
+
gap = "xs",
|
|
65
|
+
className,
|
|
66
|
+
...props
|
|
67
|
+
}: MainRegionProps) {
|
|
68
|
+
return (
|
|
69
|
+
<Stack
|
|
70
|
+
{...props}
|
|
71
|
+
as={as}
|
|
72
|
+
direction={direction}
|
|
73
|
+
gap={gap}
|
|
74
|
+
className={joinClasses(styles.description, className)}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function MainContent({
|
|
80
|
+
as = "div",
|
|
81
|
+
direction = "column",
|
|
82
|
+
gap = "lg",
|
|
83
|
+
className,
|
|
84
|
+
...props
|
|
85
|
+
}: MainRegionProps) {
|
|
86
|
+
return (
|
|
87
|
+
<Stack
|
|
88
|
+
{...props}
|
|
89
|
+
as={as}
|
|
90
|
+
direction={direction}
|
|
91
|
+
gap={gap}
|
|
92
|
+
className={joinClasses(styles.content, className)}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function MainFooter({
|
|
98
|
+
as = "footer",
|
|
99
|
+
direction = "row",
|
|
100
|
+
gap = "sm",
|
|
101
|
+
justify = "end",
|
|
102
|
+
wrap = true,
|
|
103
|
+
className,
|
|
104
|
+
...props
|
|
105
|
+
}: MainRegionProps) {
|
|
106
|
+
return (
|
|
107
|
+
<Stack
|
|
108
|
+
{...props}
|
|
109
|
+
as={as}
|
|
110
|
+
direction={direction}
|
|
111
|
+
gap={gap}
|
|
112
|
+
justify={justify}
|
|
113
|
+
wrap={wrap}
|
|
114
|
+
className={joinClasses(styles.footer, className)}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const Main = Object.assign(MainRoot, {
|
|
120
|
+
Header: MainHeader,
|
|
121
|
+
Description: MainDescription,
|
|
122
|
+
Content: MainContent,
|
|
123
|
+
Footer: MainFooter,
|
|
124
|
+
});
|
|
@@ -8,6 +8,7 @@ $fui-arrow-size: 10px !default;
|
|
|
8
8
|
.positioner {
|
|
9
9
|
z-index: 52;
|
|
10
10
|
outline: none;
|
|
11
|
+
pointer-events: auto;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
// Popup container
|
|
@@ -19,23 +20,21 @@ $fui-arrow-size: 10px !default;
|
|
|
19
20
|
margin: 0;
|
|
20
21
|
min-width: 12rem;
|
|
21
22
|
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
// Menus must be fully hit-testable as soon as they open. A fade/scale
|
|
24
|
+
// entrance can let fast clicks pass through to page links under the portal.
|
|
25
|
+
opacity: 1;
|
|
26
|
+
transform: none;
|
|
25
27
|
transform-origin: var(--transform-origin);
|
|
26
|
-
transition:
|
|
27
|
-
opacity var(--fui-transition-fast, $fui-transition-fast),
|
|
28
|
-
transform var(--fui-transition-fast, $fui-transition-fast);
|
|
29
28
|
|
|
30
29
|
&[data-open] {
|
|
31
30
|
opacity: 1;
|
|
32
|
-
transform:
|
|
31
|
+
transform: none;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
&[data-starting-style],
|
|
36
35
|
&[data-ending-style] {
|
|
37
|
-
opacity:
|
|
38
|
-
transform:
|
|
36
|
+
opacity: 1;
|
|
37
|
+
transform: none;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
@@ -204,7 +203,6 @@ $fui-arrow-size: 10px !default;
|
|
|
204
203
|
|
|
205
204
|
@media (prefers-reduced-motion: reduce) {
|
|
206
205
|
.popup {
|
|
207
|
-
transition: none;
|
|
208
206
|
transform: none;
|
|
209
207
|
|
|
210
208
|
&[data-starting-style],
|
|
@@ -110,6 +110,28 @@ function CloseIcon() {
|
|
|
110
110
|
);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// ============================================
|
|
114
|
+
// Helpers
|
|
115
|
+
// ============================================
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Base UI's button-like triggers default `nativeButton` to `true`. When an
|
|
119
|
+
* `asChild` trigger renders something other than a native `<button>` (an
|
|
120
|
+
* anchor, or a component rendered `as="a"`), that default is wrong and Base UI
|
|
121
|
+
* warns that native button semantics were removed. Resolve the correct value
|
|
122
|
+
* from the child so the trigger stays honest and the warning goes away.
|
|
123
|
+
*/
|
|
124
|
+
function resolveNativeButton(child: React.ReactElement): boolean {
|
|
125
|
+
const type = child.type;
|
|
126
|
+
// Intrinsic elements: only `<button>` is a native button.
|
|
127
|
+
if (typeof type === 'string') return type === 'button';
|
|
128
|
+
// Custom components render a native `<button>` by default; treat anchors
|
|
129
|
+
// (via `as="a"` or an `href`) as non-native.
|
|
130
|
+
const props = (child.props ?? {}) as Record<string, unknown>;
|
|
131
|
+
if (props.as === 'a' || props.href != null) return false;
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
113
135
|
// ============================================
|
|
114
136
|
// Components
|
|
115
137
|
// ============================================
|
|
@@ -139,7 +161,12 @@ function PopoverTrigger({ children, asChild, className, ...htmlProps }: PopoverT
|
|
|
139
161
|
throw new Error('Popover.Trigger with asChild requires a single valid React element child.');
|
|
140
162
|
}
|
|
141
163
|
return (
|
|
142
|
-
<BasePopover.Trigger
|
|
164
|
+
<BasePopover.Trigger
|
|
165
|
+
{...htmlProps}
|
|
166
|
+
nativeButton={resolveNativeButton(children as React.ReactElement)}
|
|
167
|
+
className={className}
|
|
168
|
+
render={children as React.ReactElement}
|
|
169
|
+
>
|
|
143
170
|
{null}
|
|
144
171
|
</BasePopover.Trigger>
|
|
145
172
|
);
|
|
@@ -240,7 +267,12 @@ function PopoverClose({ children, asChild, className, ...htmlProps }: PopoverClo
|
|
|
240
267
|
throw new Error('Popover.Close with asChild requires a single valid React element child.');
|
|
241
268
|
}
|
|
242
269
|
return (
|
|
243
|
-
<BasePopover.Close
|
|
270
|
+
<BasePopover.Close
|
|
271
|
+
{...htmlProps}
|
|
272
|
+
nativeButton={resolveNativeButton(children as React.ReactElement)}
|
|
273
|
+
className={className}
|
|
274
|
+
render={children as React.ReactElement}
|
|
275
|
+
>
|
|
244
276
|
{null}
|
|
245
277
|
</BasePopover.Close>
|
|
246
278
|
);
|