@shadow-js/ui 0.0.0-stage → 1.0.1
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/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +598 -2
- package/dist/cli.mjs +2281 -0
- package/dist/dev/cli/schema.d.ts +71 -0
- package/dist/dev/index.d.ts +6 -0
- package/dist/dev/index.js +5 -0
- package/dist/dev/locales/ar.d.ts +139 -0
- package/dist/dev/locales/ar.js +127 -0
- package/dist/dev/locales/ar.js.map +1 -0
- package/dist/dev/locales/en.d.ts +139 -0
- package/dist/dev/locales/en.js +127 -0
- package/dist/dev/locales/en.js.map +1 -0
- package/dist/dev/registry/utils/utils.d.ts +27 -0
- package/dist/dev/registry/utils/utils.js +26 -0
- package/dist/dev/registry/utils/utils.js.map +1 -0
- package/dist/dev/theme/theme-logic.d.ts +185 -0
- package/dist/dev/theme/theme-logic.js +183 -0
- package/dist/dev/theme/theme-logic.js.map +1 -0
- package/dist/dev/theme/theme-provider.d.ts +88 -0
- package/dist/dev/theme/theme-provider.js +149 -0
- package/dist/dev/theme/theme-provider.js.map +1 -0
- package/dist/prod/index.js +1 -0
- package/dist/prod/locales/ar.js +2 -0
- package/dist/prod/locales/ar.js.map +1 -0
- package/dist/prod/locales/en.js +2 -0
- package/dist/prod/locales/en.js.map +1 -0
- package/dist/prod/registry/utils/utils.js +2 -0
- package/dist/prod/registry/utils/utils.js.map +1 -0
- package/dist/prod/theme/theme-logic.js +2 -0
- package/dist/prod/theme/theme-logic.js.map +1 -0
- package/dist/prod/theme/theme-provider.js +2 -0
- package/dist/prod/theme/theme-provider.js.map +1 -0
- package/package.json +102 -4
- package/registry/accordion/accordion.tsx +210 -0
- package/registry/accordion/item.json +4 -0
- package/registry/alert/alert.tsx +200 -0
- package/registry/alert/item.json +4 -0
- package/registry/alert-dialog/alert-dialog.tsx +530 -0
- package/registry/alert-dialog/item.json +4 -0
- package/registry/aspect-ratio/aspect-ratio.tsx +71 -0
- package/registry/aspect-ratio/item.json +4 -0
- package/registry/attachment/attachment.tsx +459 -0
- package/registry/attachment/item.json +4 -0
- package/registry/avatar/avatar.tsx +385 -0
- package/registry/avatar/item.json +4 -0
- package/registry/badge/badge.tsx +108 -0
- package/registry/badge/item.json +4 -0
- package/registry/breadcrumb/breadcrumb.tsx +354 -0
- package/registry/breadcrumb/item.json +4 -0
- package/registry/bubble/bubble.tsx +260 -0
- package/registry/bubble/item.json +4 -0
- package/registry/button/button.tsx +125 -0
- package/registry/button/item.json +4 -0
- package/registry/button-group/button-group.tsx +189 -0
- package/registry/button-group/item.json +4 -0
- package/registry/calendar/calendar.tsx +348 -0
- package/registry/calendar/item.json +4 -0
- package/registry/card/card.tsx +311 -0
- package/registry/card/item.json +4 -0
- package/registry/carousel/carousel.tsx +851 -0
- package/registry/carousel/item.json +4 -0
- package/registry/chart/chart.tsx +1956 -0
- package/registry/chart/item.json +4 -0
- package/registry/chart-scale/chart-scale.ts +670 -0
- package/registry/chart-scale/item.json +5 -0
- package/registry/checkbox/checkbox.tsx +79 -0
- package/registry/checkbox/item.json +4 -0
- package/registry/code-block/code-block.tsx +470 -0
- package/registry/code-block/item.json +4 -0
- package/registry/collapsible/collapsible.tsx +117 -0
- package/registry/collapsible/item.json +4 -0
- package/registry/combobox/combobox.tsx +977 -0
- package/registry/combobox/item.json +4 -0
- package/registry/command/command.tsx +757 -0
- package/registry/command/item.json +4 -0
- package/registry/context-menu/context-menu.tsx +697 -0
- package/registry/context-menu/item.json +4 -0
- package/registry/data-table/data-table.tsx +437 -0
- package/registry/data-table/item.json +4 -0
- package/registry/date-picker/date-picker.tsx +349 -0
- package/registry/date-picker/item.json +4 -0
- package/registry/dialog/dialog.tsx +412 -0
- package/registry/dialog/item.json +4 -0
- package/registry/direction/direction.tsx +88 -0
- package/registry/direction/item.json +4 -0
- package/registry/drawer/drawer.tsx +787 -0
- package/registry/drawer/item.json +4 -0
- package/registry/dropdown-menu/dropdown-menu.tsx +692 -0
- package/registry/dropdown-menu/item.json +4 -0
- package/registry/empty/empty.tsx +240 -0
- package/registry/empty/item.json +4 -0
- package/registry/field/field.tsx +624 -0
- package/registry/field/item.json +4 -0
- package/registry/form/form.tsx +1112 -0
- package/registry/form/item.json +4 -0
- package/registry/hover-card/hover-card.tsx +144 -0
- package/registry/hover-card/item.json +4 -0
- package/registry/icons/icons.tsx +1691 -0
- package/registry/icons/item.json +4 -0
- package/registry/input/input.tsx +43 -0
- package/registry/input/item.json +4 -0
- package/registry/input-group/input-group.tsx +315 -0
- package/registry/input-group/item.json +4 -0
- package/registry/input-otp/input-otp.tsx +329 -0
- package/registry/input-otp/item.json +4 -0
- package/registry/item/item.json +4 -0
- package/registry/item/item.tsx +439 -0
- package/registry/kbd/item.json +4 -0
- package/registry/kbd/kbd.tsx +65 -0
- package/registry/label/item.json +4 -0
- package/registry/label/label.tsx +60 -0
- package/registry/marker/item.json +4 -0
- package/registry/marker/marker.tsx +175 -0
- package/registry/menubar/item.json +4 -0
- package/registry/menubar/menubar.tsx +694 -0
- package/registry/message/item.json +4 -0
- package/registry/message/message.tsx +280 -0
- package/registry/message-scroller/item.json +4 -0
- package/registry/message-scroller/message-scroller.tsx +262 -0
- package/registry/native-select/item.json +4 -0
- package/registry/native-select/native-select.tsx +113 -0
- package/registry/navigation-menu/item.json +4 -0
- package/registry/navigation-menu/navigation-menu.tsx +362 -0
- package/registry/pagination/item.json +4 -0
- package/registry/pagination/pagination.tsx +460 -0
- package/registry/password-input/item.json +5 -0
- package/registry/password-input/password-input.tsx +494 -0
- package/registry/popover/item.json +4 -0
- package/registry/popover/popover.tsx +284 -0
- package/registry/progress/item.json +4 -0
- package/registry/progress/progress.tsx +190 -0
- package/registry/questionnaire/item.json +4 -0
- package/registry/questionnaire/questionnaire.tsx +569 -0
- package/registry/radio-group/item.json +4 -0
- package/registry/radio-group/radio-group.tsx +101 -0
- package/registry/resizable/item.json +4 -0
- package/registry/resizable/resizable.tsx +455 -0
- package/registry/scroll-area/item.json +4 -0
- package/registry/scroll-area/scroll-area.tsx +149 -0
- package/registry/select/item.json +4 -0
- package/registry/select/select.tsx +571 -0
- package/registry/separator/item.json +4 -0
- package/registry/separator/separator.tsx +52 -0
- package/registry/sheet/item.json +4 -0
- package/registry/sheet/sheet.tsx +476 -0
- package/registry/sidebar/item.json +4 -0
- package/registry/sidebar/sidebar.tsx +1870 -0
- package/registry/skeleton/item.json +4 -0
- package/registry/skeleton/skeleton.tsx +47 -0
- package/registry/slider/item.json +4 -0
- package/registry/slider/slider.tsx +149 -0
- package/registry/spinner/item.json +4 -0
- package/registry/spinner/spinner.tsx +51 -0
- package/registry/switch/item.json +4 -0
- package/registry/switch/switch.tsx +93 -0
- package/registry/table/item.json +4 -0
- package/registry/table/table.tsx +373 -0
- package/registry/tabs/item.json +4 -0
- package/registry/tabs/tabs.tsx +209 -0
- package/registry/textarea/item.json +4 -0
- package/registry/textarea/textarea.tsx +51 -0
- package/registry/toast/item.json +4 -0
- package/registry/toast/toast.tsx +949 -0
- package/registry/toggle/item.json +4 -0
- package/registry/toggle/toggle.tsx +110 -0
- package/registry/toggle-group/item.json +4 -0
- package/registry/toggle-group/toggle-group.tsx +189 -0
- package/registry/tooltip/item.json +4 -0
- package/registry/tooltip/tooltip.tsx +169 -0
- package/registry/trace/item.json +4 -0
- package/registry/trace/trace.tsx +356 -0
- package/registry/ui-strings/item.json +5 -0
- package/registry/ui-strings/ui-strings.tsx +454 -0
- package/registry/use-highlighted-code/item.json +5 -0
- package/registry/use-highlighted-code/use-highlighted-code.tsx +145 -0
- package/registry/use-mobile/item.json +5 -0
- package/registry/use-mobile/use-mobile.ts +46 -0
- package/registry/utils/item.json +5 -0
- package/registry/utils/utils.ts +38 -0
- package/registry.json +3274 -0
- package/styles/animations.css +321 -0
- package/styles/theme-core.css +55 -0
- package/styles/theme.css +12 -0
- package/styles/themes/gray.css +69 -0
- package/styles/themes/neutral.css +69 -0
- package/styles/themes/slate.css +69 -0
- package/styles/themes/stone.css +69 -0
- package/styles/themes/zinc.css +69 -0
- package/styles/typeset.css +251 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { splitProps } from "@shadow-js/core";
|
|
2
|
+
import {
|
|
3
|
+
NavigationMenu as NavigationMenuPrimitive,
|
|
4
|
+
type NavigationMenuProps as NavigationMenuPrimitiveProps,
|
|
5
|
+
} from "@shadow-js/primitives";
|
|
6
|
+
import type { ComponentProps, JSX } from "@shadow-js/web";
|
|
7
|
+
import { cva } from "class-variance-authority";
|
|
8
|
+
import { ChevronDownIcon } from "@/components/ui/icons";
|
|
9
|
+
import { cn } from "@/lib/utils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The classes of a trigger, for a plain link or a button that should look like a top-level item of
|
|
13
|
+
* a {@link NavigationMenu}.
|
|
14
|
+
*
|
|
15
|
+
* @param props Optional `class` (or `className`) to add to the classes.
|
|
16
|
+
* @returns The class string.
|
|
17
|
+
* @example
|
|
18
|
+
* import { navigationMenuTriggerStyle } from "@/components/ui/navigation-menu";
|
|
19
|
+
*
|
|
20
|
+
* <a href="/about" class={navigationMenuTriggerStyle()}>About</a>
|
|
21
|
+
* @since 1.0.0
|
|
22
|
+
* @see {@link NavigationMenu}
|
|
23
|
+
*/
|
|
24
|
+
const navigationMenuTriggerStyle = cva(
|
|
25
|
+
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[state=open]:bg-accent/50 data-[state=open]:text-accent-foreground motion-reduce:transition-none focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-transparent",
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Props of {@link NavigationMenu}: the `nav` attributes plus `value`, `defaultValue`,
|
|
30
|
+
* `onValueChange`, `delayDuration`, `orientation` and `dir`, which are the primitive's.
|
|
31
|
+
* @since 1.0.0
|
|
32
|
+
* @see {@link NavigationMenu}
|
|
33
|
+
*/
|
|
34
|
+
export type NavigationMenuProps = NavigationMenuPrimitiveProps;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The site navigation with flyouts. Each trigger opens its content on click, on a pointer rest
|
|
38
|
+
* (after `delayDuration`), or with ArrowDown, which moves focus into the content. Escape closes the
|
|
39
|
+
* open item and returns focus to its trigger, and a press outside closes it.
|
|
40
|
+
*
|
|
41
|
+
* Keyboard and ARIA: a `nav` element. Name it with `aria-label` (for example `aria-label="Main"`)
|
|
42
|
+
* when the page has more than one navigation. Each trigger has `aria-expanded`, and `aria-controls`
|
|
43
|
+
* while its content is open; the content is labeled by its trigger. Left and Right move between the
|
|
44
|
+
* triggers (Up and Down when vertical); Home and End go to the first and last.
|
|
45
|
+
*
|
|
46
|
+
* @param props See {@link NavigationMenuProps}. `class` adds to the menu's classes.
|
|
47
|
+
* @returns The `nav` element with the items inside.
|
|
48
|
+
* @example
|
|
49
|
+
* import {
|
|
50
|
+
* NavigationMenu,
|
|
51
|
+
* NavigationMenuContent,
|
|
52
|
+
* NavigationMenuItem,
|
|
53
|
+
* NavigationMenuLink,
|
|
54
|
+
* NavigationMenuList,
|
|
55
|
+
* NavigationMenuTrigger,
|
|
56
|
+
* } from "@/components/ui/navigation-menu";
|
|
57
|
+
*
|
|
58
|
+
* <NavigationMenu aria-label="Main">
|
|
59
|
+
* <NavigationMenuList>
|
|
60
|
+
* <NavigationMenuItem value="docs">
|
|
61
|
+
* <NavigationMenuTrigger>Docs</NavigationMenuTrigger>
|
|
62
|
+
* <NavigationMenuContent>
|
|
63
|
+
* <NavigationMenuLink href="/docs/start">Get started</NavigationMenuLink>
|
|
64
|
+
* </NavigationMenuContent>
|
|
65
|
+
* </NavigationMenuItem>
|
|
66
|
+
* </NavigationMenuList>
|
|
67
|
+
* </NavigationMenu>
|
|
68
|
+
* @since 1.0.0
|
|
69
|
+
* @see {@link NavigationMenuItem}
|
|
70
|
+
*/
|
|
71
|
+
function NavigationMenu(props: NavigationMenuProps): JSX.Element {
|
|
72
|
+
const [local, rest] = splitProps(
|
|
73
|
+
props as NavigationMenuProps & { readonly class?: unknown; readonly children?: unknown },
|
|
74
|
+
["class", "children"],
|
|
75
|
+
);
|
|
76
|
+
return (
|
|
77
|
+
<NavigationMenuPrimitive
|
|
78
|
+
data-slot="navigation-menu"
|
|
79
|
+
class={cn(
|
|
80
|
+
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
|
|
81
|
+
local.class as string | undefined,
|
|
82
|
+
)}
|
|
83
|
+
{...rest}
|
|
84
|
+
>
|
|
85
|
+
{local.children as JSX.Element}
|
|
86
|
+
<div data-slot="navigation-menu-viewport-position" class="absolute start-0 top-full" />
|
|
87
|
+
</NavigationMenuPrimitive>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The row of top-level items of a {@link NavigationMenu}: a `ul`.
|
|
93
|
+
*
|
|
94
|
+
* Keyboard and ARIA: a plain list with no role of its own. The triggers inside it are the tab
|
|
95
|
+
* stops, one at a time, and carry the keys.
|
|
96
|
+
*
|
|
97
|
+
* @param props The `ul` attributes. `class` adds to the classes.
|
|
98
|
+
* @returns The `ul` element.
|
|
99
|
+
* @throws Error when rendered outside a {@link NavigationMenu}.
|
|
100
|
+
* @example
|
|
101
|
+
* import { NavigationMenuItem, NavigationMenuList } from "@/components/ui/navigation-menu";
|
|
102
|
+
*
|
|
103
|
+
* <NavigationMenuList>
|
|
104
|
+
* <NavigationMenuItem value="about">...</NavigationMenuItem>
|
|
105
|
+
* </NavigationMenuList>
|
|
106
|
+
* @since 1.0.0
|
|
107
|
+
* @see {@link NavigationMenu}
|
|
108
|
+
*/
|
|
109
|
+
function NavigationMenuList(props: ComponentProps<"ul">): JSX.Element {
|
|
110
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
111
|
+
return (
|
|
112
|
+
<NavigationMenuPrimitive.List
|
|
113
|
+
data-slot="navigation-menu-list"
|
|
114
|
+
class={cn("group flex flex-1 list-none items-center justify-center gap-1", local.class)}
|
|
115
|
+
{...rest}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* One item of the list: a trigger and its content, linked through `value`. Use it as the container
|
|
122
|
+
* of a {@link NavigationMenuTrigger} and a {@link NavigationMenuContent}.
|
|
123
|
+
*
|
|
124
|
+
* Keyboard and ARIA: an `li` with no role of its own. The trigger and the content are linked
|
|
125
|
+
* through `value`, which builds their ids.
|
|
126
|
+
*
|
|
127
|
+
* shadcn/ui differences: `value` is required here, because it links the trigger to the content. The
|
|
128
|
+
* shadcn examples render `NavigationMenuItem` without one.
|
|
129
|
+
*
|
|
130
|
+
* @param props The `li` attributes, plus `value` (the name of the item). `class` adds to the classes.
|
|
131
|
+
* @returns The `li` element.
|
|
132
|
+
* @throws Error when rendered outside a {@link NavigationMenu}.
|
|
133
|
+
* @example
|
|
134
|
+
* import {
|
|
135
|
+
* NavigationMenuContent,
|
|
136
|
+
* NavigationMenuItem,
|
|
137
|
+
* NavigationMenuLink,
|
|
138
|
+
* NavigationMenuList,
|
|
139
|
+
* NavigationMenuTrigger,
|
|
140
|
+
* } from "@/components/ui/navigation-menu";
|
|
141
|
+
*
|
|
142
|
+
* <NavigationMenuList>
|
|
143
|
+
* <NavigationMenuItem value="products">
|
|
144
|
+
* <NavigationMenuTrigger>Products</NavigationMenuTrigger>
|
|
145
|
+
* <NavigationMenuContent>
|
|
146
|
+
* <NavigationMenuLink href="/products/tools">Tools</NavigationMenuLink>
|
|
147
|
+
* </NavigationMenuContent>
|
|
148
|
+
* </NavigationMenuItem>
|
|
149
|
+
* </NavigationMenuList>
|
|
150
|
+
* @since 1.0.0
|
|
151
|
+
* @see {@link NavigationMenuTrigger}
|
|
152
|
+
*/
|
|
153
|
+
function NavigationMenuItem(props: ComponentProps<"li"> & { readonly value: string }): JSX.Element {
|
|
154
|
+
const [local, rest] = splitProps(
|
|
155
|
+
props as ComponentProps<"li"> & { readonly value: string; readonly class?: unknown },
|
|
156
|
+
["class", "value"],
|
|
157
|
+
);
|
|
158
|
+
return (
|
|
159
|
+
<NavigationMenuPrimitive.Item
|
|
160
|
+
data-slot="navigation-menu-item"
|
|
161
|
+
value={local.value}
|
|
162
|
+
// Not positioned: a flyout is placed against the menu (the nearest positioned ancestor), so it
|
|
163
|
+
// hangs below the bar instead of over its own trigger.
|
|
164
|
+
class={cn(local.class as string | undefined)}
|
|
165
|
+
{...rest}
|
|
166
|
+
/>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The button that opens an item's content, with a chevron that turns while the content is open.
|
|
172
|
+
*
|
|
173
|
+
* Keyboard and ARIA: a button with `aria-expanded`, and `aria-controls` while its content is open.
|
|
174
|
+
* Enter and Space toggle the content; ArrowDown opens it and moves focus into it; Left and Right move
|
|
175
|
+
* to the neighboring trigger; Home and End go to the first and last. The chevron is decorative and
|
|
176
|
+
* hidden from assistive technology. Its name is its text.
|
|
177
|
+
*
|
|
178
|
+
* @param props The `button` attributes. `class` adds to the classes; `children` is the label.
|
|
179
|
+
* @returns The trigger button.
|
|
180
|
+
* @throws Error when rendered outside a {@link NavigationMenu} or its {@link NavigationMenuItem}.
|
|
181
|
+
* @example
|
|
182
|
+
* import { NavigationMenuItem, NavigationMenuTrigger } from "@/components/ui/navigation-menu";
|
|
183
|
+
*
|
|
184
|
+
* <NavigationMenuItem value="products">
|
|
185
|
+
* <NavigationMenuTrigger>Products</NavigationMenuTrigger>
|
|
186
|
+
* </NavigationMenuItem>
|
|
187
|
+
* @since 1.0.0
|
|
188
|
+
* @see {@link NavigationMenuContent}
|
|
189
|
+
*/
|
|
190
|
+
function NavigationMenuTrigger(props: ComponentProps<"button">): JSX.Element {
|
|
191
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
192
|
+
return (
|
|
193
|
+
<NavigationMenuPrimitive.Trigger
|
|
194
|
+
data-slot="navigation-menu-trigger"
|
|
195
|
+
class={cn(navigationMenuTriggerStyle(), "group", local.class)}
|
|
196
|
+
{...rest}
|
|
197
|
+
>
|
|
198
|
+
{local.children}
|
|
199
|
+
<ChevronDownIcon
|
|
200
|
+
aria-hidden="true"
|
|
201
|
+
class="relative top-px ms-1 size-3 transition duration-300 group-data-[state=open]:rotate-180 motion-reduce:transition-none"
|
|
202
|
+
/>
|
|
203
|
+
</NavigationMenuPrimitive.Trigger>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The flyout of an item. It is mounted only while its item is open; once it closes, it is removed
|
|
209
|
+
* after any exit animation has ended.
|
|
210
|
+
*
|
|
211
|
+
* Keyboard and ARIA: it is labeled by its trigger (`aria-labelledby`). Escape, which closes the
|
|
212
|
+
* item, is handled by the menu, so it works from inside the content too.
|
|
213
|
+
*
|
|
214
|
+
* @param props The `div` attributes. `class` adds to the classes; `children` are the links.
|
|
215
|
+
* @returns The flyout `div`, or nothing while the item is closed.
|
|
216
|
+
* @throws Error when rendered outside a {@link NavigationMenu} or its {@link NavigationMenuItem}.
|
|
217
|
+
* @example
|
|
218
|
+
* import { NavigationMenuContent, NavigationMenuLink } from "@/components/ui/navigation-menu";
|
|
219
|
+
*
|
|
220
|
+
* <NavigationMenuContent>
|
|
221
|
+
* <NavigationMenuLink href="/products/tools">Tools</NavigationMenuLink>
|
|
222
|
+
* </NavigationMenuContent>
|
|
223
|
+
* @since 1.0.0
|
|
224
|
+
* @see {@link NavigationMenuTrigger}
|
|
225
|
+
*/
|
|
226
|
+
function NavigationMenuContent(props: ComponentProps<"div">): JSX.Element {
|
|
227
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
228
|
+
return (
|
|
229
|
+
<NavigationMenuPrimitive.Content
|
|
230
|
+
data-slot="navigation-menu-content"
|
|
231
|
+
class={cn(
|
|
232
|
+
"start-0 w-full rounded-md border bg-popover p-2 pe-2.5 text-popover-foreground shadow md:absolute md:top-full md:mt-2 md:w-auto data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 motion-reduce:animate-none",
|
|
233
|
+
local.class,
|
|
234
|
+
)}
|
|
235
|
+
{...rest}
|
|
236
|
+
>
|
|
237
|
+
{local.children}
|
|
238
|
+
</NavigationMenuPrimitive.Content>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* A link in the navigation: a link inside a content, or a plain link as a top-level item. Following
|
|
244
|
+
* the link closes the menu. `active` marks the page the user is on.
|
|
245
|
+
*
|
|
246
|
+
* Keyboard and ARIA: a native link, so Enter follows it. `active` sets `aria-current="page"`. The
|
|
247
|
+
* link adds no other ARIA attribute; its name is its text.
|
|
248
|
+
*
|
|
249
|
+
* @param props The `a` attributes, plus `active`. `class` adds to the classes.
|
|
250
|
+
* @returns The `a` element.
|
|
251
|
+
* @throws Error when rendered outside a {@link NavigationMenu}.
|
|
252
|
+
* @example
|
|
253
|
+
* import { NavigationMenuLink } from "@/components/ui/navigation-menu";
|
|
254
|
+
*
|
|
255
|
+
* <NavigationMenuLink href="/docs" active>Docs</NavigationMenuLink>
|
|
256
|
+
* @since 1.0.0
|
|
257
|
+
* @see {@link NavigationMenuContent}
|
|
258
|
+
*/
|
|
259
|
+
function NavigationMenuLink(
|
|
260
|
+
props: ComponentProps<"a"> & { readonly active?: boolean | undefined },
|
|
261
|
+
): JSX.Element {
|
|
262
|
+
const [local, rest] = splitProps(
|
|
263
|
+
props as ComponentProps<"a"> & {
|
|
264
|
+
readonly active?: boolean | undefined;
|
|
265
|
+
readonly class?: unknown;
|
|
266
|
+
},
|
|
267
|
+
["class", "active"],
|
|
268
|
+
);
|
|
269
|
+
return (
|
|
270
|
+
<NavigationMenuPrimitive.Link
|
|
271
|
+
data-slot="navigation-menu-link"
|
|
272
|
+
active={local.active === true}
|
|
273
|
+
class={cn(
|
|
274
|
+
"flex flex-col gap-1 rounded-sm p-2 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[current=page]:font-medium [&_svg:not([class*='size-'])]:size-4 focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-transparent",
|
|
275
|
+
local.class as string | undefined,
|
|
276
|
+
)}
|
|
277
|
+
{...rest}
|
|
278
|
+
/>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* The shared panel that hosts the open item's content, so the flyout resizes between items. Render it
|
|
284
|
+
* once after the list. While it is rendered, every {@link NavigationMenuContent} renders inside it;
|
|
285
|
+
* give the content `md:static md:mt-0 md:border-0 md:shadow-none` classes (or your own) to drop the
|
|
286
|
+
* floating look it has on its own. Its size follows the open content through the CSS variables
|
|
287
|
+
* `--primitives-navigation-menu-viewport-width` and `--primitives-navigation-menu-viewport-height`.
|
|
288
|
+
*
|
|
289
|
+
* Keyboard and ARIA: none of its own; the content keeps its labeling. In RTL the panel starts at the
|
|
290
|
+
* right edge of the menu.
|
|
291
|
+
*
|
|
292
|
+
* @param props The `div` attributes. `class` adds to the classes of the panel.
|
|
293
|
+
* @returns The wrapper `div` that holds the panel.
|
|
294
|
+
* @throws Error when rendered outside a {@link NavigationMenu}.
|
|
295
|
+
* @example
|
|
296
|
+
* import { NavigationMenuViewport } from "@/components/ui/navigation-menu";
|
|
297
|
+
*
|
|
298
|
+
* <NavigationMenuViewport />
|
|
299
|
+
* @since 1.0.0
|
|
300
|
+
* @see {@link NavigationMenuContent}
|
|
301
|
+
*/
|
|
302
|
+
function NavigationMenuViewport(props: ComponentProps<"div">): JSX.Element {
|
|
303
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
304
|
+
return (
|
|
305
|
+
<div class="absolute start-0 top-full isolate z-50 flex justify-center">
|
|
306
|
+
<NavigationMenuPrimitive.Viewport
|
|
307
|
+
data-slot="navigation-menu-viewport"
|
|
308
|
+
class={cn(
|
|
309
|
+
"relative mt-1.5 h-[var(--primitives-navigation-menu-viewport-height)] w-full origin-top overflow-hidden rounded-md border bg-popover text-popover-foreground shadow md:w-[var(--primitives-navigation-menu-viewport-width)] data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:zoom-in-90 motion-reduce:animate-none",
|
|
310
|
+
local.class,
|
|
311
|
+
)}
|
|
312
|
+
{...rest}
|
|
313
|
+
/>
|
|
314
|
+
</div>
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* A marker that follows the open item's trigger: an arrow under the active item. Render it inside
|
|
320
|
+
* the {@link NavigationMenuList}, which is positioned. It places itself with the CSS variables
|
|
321
|
+
* `--primitives-navigation-menu-indicator-position` and `--primitives-navigation-menu-indicator-size`,
|
|
322
|
+
* counted from the start edge, so it follows the trigger in RTL as well.
|
|
323
|
+
*
|
|
324
|
+
* Keyboard and ARIA: decorative, hidden from assistive technology.
|
|
325
|
+
*
|
|
326
|
+
* @param props The `div` attributes. `class` adds to the classes.
|
|
327
|
+
* @returns The `div` element with the arrow inside.
|
|
328
|
+
* @throws Error when rendered outside a {@link NavigationMenu}.
|
|
329
|
+
* @example
|
|
330
|
+
* import { NavigationMenuIndicator } from "@/components/ui/navigation-menu";
|
|
331
|
+
*
|
|
332
|
+
* <NavigationMenuIndicator />
|
|
333
|
+
* @since 1.0.0
|
|
334
|
+
* @see {@link NavigationMenuTrigger}
|
|
335
|
+
*/
|
|
336
|
+
function NavigationMenuIndicator(props: ComponentProps<"div">): JSX.Element {
|
|
337
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
338
|
+
return (
|
|
339
|
+
<NavigationMenuPrimitive.Indicator
|
|
340
|
+
data-slot="navigation-menu-indicator"
|
|
341
|
+
class={cn(
|
|
342
|
+
"absolute start-[var(--primitives-navigation-menu-indicator-position)] top-full z-[1] flex h-1.5 w-[var(--primitives-navigation-menu-indicator-size)] items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in motion-reduce:animate-none",
|
|
343
|
+
local.class,
|
|
344
|
+
)}
|
|
345
|
+
{...rest}
|
|
346
|
+
>
|
|
347
|
+
<div class="relative top-[60%] size-2 rotate-45 rounded-ss-sm bg-border shadow-md" />
|
|
348
|
+
</NavigationMenuPrimitive.Indicator>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export {
|
|
353
|
+
NavigationMenu,
|
|
354
|
+
NavigationMenuContent,
|
|
355
|
+
NavigationMenuIndicator,
|
|
356
|
+
NavigationMenuItem,
|
|
357
|
+
NavigationMenuLink,
|
|
358
|
+
NavigationMenuList,
|
|
359
|
+
NavigationMenuTrigger,
|
|
360
|
+
NavigationMenuViewport,
|
|
361
|
+
navigationMenuTriggerStyle,
|
|
362
|
+
};
|