panelui-web 0.5.0 → 0.7.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.
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Switch — on or off, for a setting that takes effect the moment it changes.
3
+ *
4
+ * ```tsx
5
+ * <Switch label="Dark mode" defaultChecked />
6
+ *
7
+ * <Label>
8
+ * <Label.Text>Email me a receipt</Label.Text>
9
+ * <Label.Action><Switch /></Label.Action>
10
+ * </Label>
11
+ * ```
12
+ *
13
+ * ## It moves like a thing with weight
14
+ *
15
+ * The colour does not fade in. It sweeps along the track behind the thumb,
16
+ * so the track fills from the side the thumb left and reads as the thumb's
17
+ * doing. While it is pressed, the thumb stretches towards where it is going,
18
+ * so a press that has not yet let go already says which way it will flip.
19
+ *
20
+ * ## While a change is saved
21
+ *
22
+ * A setting saved to a server is not on until the server says so. `pending`
23
+ * puts a turning ring in the thumb and stops the switch being pressed again,
24
+ * so the switch can show the new state at once and still be honest that it
25
+ * has not landed yet.
26
+ */
27
+ import { Switch as BaseSwitch } from '@base-ui/react/switch';
28
+ import type { CSSProperties } from 'react';
29
+ export type SwitchSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
30
+ export type SwitchColor = 'primary' | 'success' | 'info' | 'destructive';
31
+ export interface SwitchProps extends Omit<BaseSwitch.Root.Props, 'className' | 'color'> {
32
+ /** Default `md`. */
33
+ size?: SwitchSize;
34
+ /** The colour it fills with when on. `primary` by default; pick another for what it means. */
35
+ color?: SwitchColor;
36
+ /**
37
+ * What a screen reader calls it, when there is no visible label tied to it.
38
+ * A `Label` wrapped round it, or pointing at its `id`, is better when there is room.
39
+ */
40
+ label?: string;
41
+ /** A change is being saved: a ring turns in the thumb, and it cannot be pressed again until it is done. */
42
+ pending?: boolean;
43
+ className?: string;
44
+ style?: CSSProperties;
45
+ }
46
+ /** A switch. Takes `checked`/`onCheckedChange` or `defaultChecked`, and `name` for a form. */
47
+ declare function Switch({ size, color, label, pending, className, style, readOnly, ...props }: SwitchProps): import("react").JSX.Element;
48
+ declare namespace Switch {
49
+ var displayName: string;
50
+ }
51
+ export { Switch };
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Switch — on or off, for a setting that takes effect the moment it changes.
4
+ *
5
+ * ```tsx
6
+ * <Switch label="Dark mode" defaultChecked />
7
+ *
8
+ * <Label>
9
+ * <Label.Text>Email me a receipt</Label.Text>
10
+ * <Label.Action><Switch /></Label.Action>
11
+ * </Label>
12
+ * ```
13
+ *
14
+ * ## It moves like a thing with weight
15
+ *
16
+ * The colour does not fade in. It sweeps along the track behind the thumb,
17
+ * so the track fills from the side the thumb left and reads as the thumb's
18
+ * doing. While it is pressed, the thumb stretches towards where it is going,
19
+ * so a press that has not yet let go already says which way it will flip.
20
+ *
21
+ * ## While a change is saved
22
+ *
23
+ * A setting saved to a server is not on until the server says so. `pending`
24
+ * puts a turning ring in the thumb and stops the switch being pressed again,
25
+ * so the switch can show the new state at once and still be honest that it
26
+ * has not landed yet.
27
+ */
28
+ import { Switch as BaseSwitch } from '@base-ui/react/switch';
29
+ import { tv } from 'tailwind-variants';
30
+ /** Height and width of the track. The thumb is the height less 2px of padding on each side. */
31
+ const SIZE = {
32
+ xs: ['1rem', '1.75rem'],
33
+ sm: ['1.25rem', '2.125rem'],
34
+ md: ['1.5rem', '2.625rem'],
35
+ lg: ['1.75rem', '3.125rem'],
36
+ xl: ['2rem', '3.625rem'],
37
+ };
38
+ const SPRING = 'ease-[cubic-bezier(0.3,1.35,0.45,1)]';
39
+ const switchVariants = tv({
40
+ slots: {
41
+ root: [
42
+ 'group/switch relative inline-flex h-(--switch-h) w-(--switch-w) shrink-0 cursor-pointer items-center rounded-full p-0.5 outline-none',
43
+ 'bg-input transition-[background-color,box-shadow] duration-200 dark:bg-input/80',
44
+ 'hover:not-data-disabled:bg-[color-mix(in_oklab,var(--input),var(--foreground)_8%)]',
45
+ 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
46
+ 'data-disabled:cursor-not-allowed data-disabled:opacity-50 aria-busy:cursor-progress',
47
+ // The fill: the whole track in the switch's colour, uncovered from the
48
+ // thumb's starting side as it travels.
49
+ "before:absolute before:inset-0 before:rounded-[inherit] before:bg-(--switch-color) before:content-['']",
50
+ 'before:[clip-path:inset(0_100%_0_0_round_999px)] before:transition-[clip-path] before:duration-300 before:ease-[cubic-bezier(0.3,1.35,0.45,1)]',
51
+ 'rtl:before:[clip-path:inset(0_0_0_100%_round_999px)]',
52
+ 'data-checked:before:[clip-path:inset(0_0_0_0_round_999px)]',
53
+ 'motion-reduce:before:transition-none',
54
+ ],
55
+ thumb: [
56
+ 'relative z-10 flex size-[calc(var(--switch-h)-4px)] items-center justify-center rounded-full bg-white',
57
+ // On, the thumb takes the colour that reads on the fill: dark on a light primary, white on the rest.
58
+ 'transition-colors data-checked:bg-(--switch-thumb)',
59
+ 'shadow-[0_1px_2px_rgb(0_0_0/0.18),0_2px_6px_-1px_rgb(0_0_0/0.12)]',
60
+ `transition-[translate,width] duration-300 ${SPRING} motion-reduce:transition-none`,
61
+ // On: across by the track's width less its height, which is the room left.
62
+ 'data-checked:translate-x-[calc(var(--switch-w)-var(--switch-h))] rtl:data-checked:-translate-x-[calc(var(--switch-w)-var(--switch-h))]',
63
+ // Pressed: a fifth longer, towards where it is going. When on, it grows back the way it came.
64
+ 'group-active/switch:not-data-disabled:w-[calc((var(--switch-h)-4px)*1.22)]',
65
+ 'group-active/switch:data-checked:not-data-disabled:translate-x-[calc(var(--switch-w)-var(--switch-h)-(var(--switch-h)-4px)*0.22)]',
66
+ 'rtl:group-active/switch:data-checked:not-data-disabled:-translate-x-[calc(var(--switch-w)-var(--switch-h)-(var(--switch-h)-4px)*0.22)]',
67
+ 'group-aria-busy/switch:w-[calc(var(--switch-h)-4px)]',
68
+ ],
69
+ spinner: 'size-[62%] animate-spin text-(--switch-color) group-not-data-checked/switch:text-muted-foreground motion-reduce:animate-none',
70
+ },
71
+ variants: {
72
+ color: {
73
+ primary: { root: '[--switch-color:var(--primary)] [--switch-thumb:var(--primary-foreground)]' },
74
+ success: { root: '[--switch-color:var(--success)] [--switch-thumb:white]' },
75
+ info: { root: '[--switch-color:var(--info)] [--switch-thumb:white]' },
76
+ destructive: { root: '[--switch-color:var(--destructive)] [--switch-thumb:white]' },
77
+ },
78
+ },
79
+ defaultVariants: { color: 'primary' },
80
+ });
81
+ /** A switch. Takes `checked`/`onCheckedChange` or `defaultChecked`, and `name` for a form. */
82
+ function Switch({ size = 'md', color, label, pending = false, className, style, readOnly, ...props }) {
83
+ const slots = switchVariants({ color });
84
+ const [height, width] = SIZE[size];
85
+ return (_jsx(BaseSwitch.Root, { "data-slot": "switch", "data-size": size, "aria-label": label, "aria-busy": pending || undefined, readOnly: pending || readOnly, className: slots.root({ className }), style: { ['--switch-h']: height, ['--switch-w']: width, ...style }, ...props, children: _jsx(BaseSwitch.Thumb, { "data-slot": "switch-thumb", className: slots.thumb(), children: pending ? (_jsxs("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", className: slots.spinner(), fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeOpacity: 0.2, strokeWidth: 3.5 }), _jsx("path", { d: "M21 12a9 9 0 0 0-9-9", stroke: "currentColor", strokeWidth: 3.5, strokeLinecap: "round" })] })) : null }) }));
86
+ }
87
+ Switch.displayName = 'Switch';
88
+ export { Switch };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Tabs — a few views of one thing, one at a time, chosen from a row of tabs.
3
+ *
4
+ * ```tsx
5
+ * <Tabs defaultValue="overview">
6
+ * <Tabs.List>
7
+ * <Tabs.Trigger value="overview">Overview</Tabs.Trigger>
8
+ * <Tabs.Trigger value="activity">
9
+ * Activity <Tabs.Badge>12</Tabs.Badge>
10
+ * </Tabs.Trigger>
11
+ * </Tabs.List>
12
+ * <Tabs.Content value="overview">…</Tabs.Content>
13
+ * <Tabs.Content value="activity">…</Tabs.Content>
14
+ * </Tabs>
15
+ * ```
16
+ *
17
+ * ## Three weights
18
+ *
19
+ * `segmented` sets the tabs in a track with the chosen one raised out of it:
20
+ * a control for switching what a panel shows. `underline` is lighter, a line
21
+ * under the chosen tab, for the sections of a page. `pills` fills the chosen
22
+ * tab with the primary colour, for a filter that should be seen from across
23
+ * the screen.
24
+ *
25
+ * ## It moves the way the hand did
26
+ *
27
+ * The marker slides to the new tab. The underline stretches as it goes, its
28
+ * leading end arriving first and the trailing end catching up, so a long jump
29
+ * reads as one movement and not as a line teleporting. The new panel slides
30
+ * in from the side the tab was on, so going right looks like going right.
31
+ *
32
+ * ## A row that does not fit scrolls
33
+ *
34
+ * When the tabs are wider than the space for them, the row scrolls sideways
35
+ * and fades at the end that has more, rather than wrapping onto a second line
36
+ * or shrinking the labels.
37
+ */
38
+ import { Tabs as BaseTabs } from '@base-ui/react/tabs';
39
+ import { type ComponentProps } from 'react';
40
+ export type TabsVariant = 'segmented' | 'underline' | 'pills';
41
+ export interface TabsProps extends Omit<BaseTabs.Root.Props, 'className'> {
42
+ /** How the tabs are drawn. Default `segmented`. */
43
+ variant?: TabsVariant;
44
+ className?: string;
45
+ }
46
+ /**
47
+ * Holds which tab is chosen: `defaultValue`, or `value` with `onValueChange`.
48
+ * `orientation="vertical"` puts the tabs in a column beside the content.
49
+ */
50
+ declare function TabsRoot({ variant, className, ...props }: TabsProps): import("react").JSX.Element;
51
+ declare namespace TabsRoot {
52
+ var displayName: string;
53
+ }
54
+ export interface TabsListProps extends Omit<BaseTabs.List.Props, 'className'> {
55
+ className?: string;
56
+ }
57
+ /** The row of tabs, with the marker under the chosen one. */
58
+ declare function TabsList({ className, children, ...props }: TabsListProps): import("react").JSX.Element;
59
+ declare namespace TabsList {
60
+ var displayName: string;
61
+ }
62
+ export interface TabsTriggerProps extends Omit<BaseTabs.Tab.Props, 'className'> {
63
+ className?: string;
64
+ }
65
+ /**
66
+ * One tab. Its `value` names the `Tabs.Content` it shows. An icon and a
67
+ * `Tabs.Badge` can sit beside its label.
68
+ */
69
+ declare function TabsTrigger({ className, ...props }: TabsTriggerProps): import("react").JSX.Element;
70
+ declare namespace TabsTrigger {
71
+ var displayName: string;
72
+ }
73
+ export interface TabsBadgeProps extends ComponentProps<'span'> {
74
+ }
75
+ /** A count beside a tab's label: unread, open, waiting. */
76
+ declare function TabsBadge({ className, ...props }: TabsBadgeProps): import("react").JSX.Element;
77
+ declare namespace TabsBadge {
78
+ var displayName: string;
79
+ }
80
+ export interface TabsContentProps extends Omit<BaseTabs.Panel.Props, 'className'> {
81
+ className?: string;
82
+ }
83
+ /** What one tab shows. Only the chosen one is in the page unless `keepMounted` is set. */
84
+ declare function TabsContent({ className, ...props }: TabsContentProps): import("react").JSX.Element;
85
+ declare namespace TabsContent {
86
+ var displayName: string;
87
+ }
88
+ export declare const Tabs: typeof TabsRoot & {
89
+ List: typeof TabsList;
90
+ Trigger: typeof TabsTrigger;
91
+ Badge: typeof TabsBadge;
92
+ Content: typeof TabsContent;
93
+ };
94
+ export { TabsList, TabsTrigger, TabsBadge, TabsContent };
@@ -0,0 +1,196 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Tabs — a few views of one thing, one at a time, chosen from a row of tabs.
5
+ *
6
+ * ```tsx
7
+ * <Tabs defaultValue="overview">
8
+ * <Tabs.List>
9
+ * <Tabs.Trigger value="overview">Overview</Tabs.Trigger>
10
+ * <Tabs.Trigger value="activity">
11
+ * Activity <Tabs.Badge>12</Tabs.Badge>
12
+ * </Tabs.Trigger>
13
+ * </Tabs.List>
14
+ * <Tabs.Content value="overview">…</Tabs.Content>
15
+ * <Tabs.Content value="activity">…</Tabs.Content>
16
+ * </Tabs>
17
+ * ```
18
+ *
19
+ * ## Three weights
20
+ *
21
+ * `segmented` sets the tabs in a track with the chosen one raised out of it:
22
+ * a control for switching what a panel shows. `underline` is lighter, a line
23
+ * under the chosen tab, for the sections of a page. `pills` fills the chosen
24
+ * tab with the primary colour, for a filter that should be seen from across
25
+ * the screen.
26
+ *
27
+ * ## It moves the way the hand did
28
+ *
29
+ * The marker slides to the new tab. The underline stretches as it goes, its
30
+ * leading end arriving first and the trailing end catching up, so a long jump
31
+ * reads as one movement and not as a line teleporting. The new panel slides
32
+ * in from the side the tab was on, so going right looks like going right.
33
+ *
34
+ * ## A row that does not fit scrolls
35
+ *
36
+ * When the tabs are wider than the space for them, the row scrolls sideways
37
+ * and fades at the end that has more, rather than wrapping onto a second line
38
+ * or shrinking the labels.
39
+ */
40
+ import { Tabs as BaseTabs } from '@base-ui/react/tabs';
41
+ import { createContext, useContext, useEffect, useRef } from 'react';
42
+ import { tv } from 'tailwind-variants';
43
+ /** One curve for the marker and the panel, so they move as one thing. */
44
+ const EASE = 'ease-[cubic-bezier(0.3,0.7,0.1,1)]';
45
+ const tabsVariants = tv({
46
+ slots: {
47
+ root: 'group/tabs flex flex-col gap-4 data-[orientation=vertical]:flex-row',
48
+ list: [
49
+ 'relative z-0 flex shrink-0 items-center',
50
+ 'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch',
51
+ // Scrolls rather than wraps, with no bar of its own; the fade says there is more.
52
+ 'data-[orientation=horizontal]:max-w-full data-[orientation=horizontal]:overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
53
+ 'data-overflow-start:[--fade-start:3rem] data-overflow-end:[--fade-end:3rem]',
54
+ '[mask-image:linear-gradient(to_right,transparent,#000_var(--fade-start,0px),#000_calc(100%-var(--fade-end,0px)),transparent)]',
55
+ ],
56
+ trigger: [
57
+ 'relative z-10 inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium outline-none select-none',
58
+ 'text-muted-foreground transition-colors duration-200 hover:text-foreground data-active:text-foreground',
59
+ 'data-disabled:pointer-events-none data-disabled:opacity-50',
60
+ 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',
61
+ '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-4',
62
+ 'group-data-[orientation=vertical]/tabs:justify-start',
63
+ ],
64
+ indicator: 'absolute -z-10',
65
+ badge: [
66
+ 'inline-flex h-5 min-w-5 items-center justify-center rounded-full px-1.5 text-xs font-medium tabular-nums',
67
+ 'bg-foreground/[0.07] text-muted-foreground transition-colors duration-200',
68
+ 'in-data-active:bg-foreground/10 in-data-active:text-foreground',
69
+ ],
70
+ content: [
71
+ 'min-w-0 flex-1 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
72
+ // The new panel arrives from the side its tab was on. The old one goes at once.
73
+ `transition-[opacity,translate] duration-300 ${EASE} motion-reduce:transition-none`,
74
+ 'data-starting-style:opacity-0',
75
+ 'data-[activation-direction=right]:data-starting-style:translate-x-3 data-[activation-direction=left]:data-starting-style:-translate-x-3',
76
+ 'data-[activation-direction=down]:data-starting-style:translate-y-2 data-[activation-direction=up]:data-starting-style:-translate-y-2',
77
+ 'data-ending-style:hidden',
78
+ ],
79
+ },
80
+ variants: {
81
+ variant: {
82
+ segmented: {
83
+ list: 'w-fit gap-0.5 rounded-xl bg-muted p-1',
84
+ trigger: 'h-8 rounded-lg px-3',
85
+ indicator: [
86
+ 'top-(--active-tab-top) left-(--active-tab-left) h-(--active-tab-height) w-(--active-tab-width) rounded-lg',
87
+ 'bg-background shadow-sm ring-1 ring-foreground/[0.06] dark:bg-input dark:ring-foreground/10',
88
+ `transition-[left,top,width,height] duration-300 ${EASE} motion-reduce:transition-none`,
89
+ ],
90
+ },
91
+ underline: {
92
+ list: [
93
+ 'gap-1 data-[orientation=horizontal]:w-full data-[orientation=horizontal]:shadow-[inset_0_-1px_0_var(--border)]',
94
+ 'data-[orientation=vertical]:shadow-[inset_-1px_0_0_var(--border)]',
95
+ ],
96
+ trigger: [
97
+ 'h-10 px-3',
98
+ 'group-data-[orientation=vertical]/tabs:h-9 group-data-[orientation=vertical]/tabs:pe-5',
99
+ // The hover fill sits inside the row, clear of the line.
100
+ "before:absolute before:inset-x-0.5 before:inset-y-1.5 before:-z-10 before:rounded-md before:transition-colors before:content-[''] hover:before:bg-muted/70",
101
+ ],
102
+ indicator: [
103
+ 'bg-foreground',
104
+ // The two ends move separately: the one going first is quick and the
105
+ // other follows, so the line stretches on the way and settles.
106
+ 'data-[orientation=horizontal]:bottom-0 data-[orientation=horizontal]:h-0.5 data-[orientation=horizontal]:rounded-t-full',
107
+ 'data-[orientation=horizontal]:left-(--active-tab-left) data-[orientation=horizontal]:right-(--active-tab-right)',
108
+ 'data-[orientation=vertical]:right-0 data-[orientation=vertical]:w-0.5 data-[orientation=vertical]:rounded-s-full',
109
+ 'data-[orientation=vertical]:top-(--active-tab-top) data-[orientation=vertical]:bottom-(--active-tab-bottom)',
110
+ `transition-[left,right,top,bottom] ${EASE} motion-reduce:transition-none`,
111
+ '[transition-duration:300ms]',
112
+ 'data-[activation-direction=right]:[transition-duration:420ms,200ms] data-[activation-direction=left]:[transition-duration:200ms,420ms]',
113
+ 'data-[activation-direction=down]:[transition-duration:0ms,0ms,420ms,200ms] data-[activation-direction=up]:[transition-duration:0ms,0ms,200ms,420ms]',
114
+ ],
115
+ },
116
+ pills: {
117
+ list: 'w-fit gap-1',
118
+ trigger: 'h-8 rounded-full px-3.5 hover:bg-muted data-active:text-primary-foreground data-active:hover:bg-transparent',
119
+ badge: 'in-data-active:bg-primary-foreground/20 in-data-active:text-primary-foreground',
120
+ indicator: [
121
+ 'top-(--active-tab-top) left-(--active-tab-left) h-(--active-tab-height) w-(--active-tab-width) rounded-full bg-primary',
122
+ `transition-[left,top,width,height] duration-300 ${EASE} motion-reduce:transition-none`,
123
+ ],
124
+ },
125
+ },
126
+ },
127
+ compoundVariants: [
128
+ // A vertical segmented list is a column of full-width rows.
129
+ { variant: 'segmented', className: { list: 'data-[orientation=vertical]:w-48' } },
130
+ { variant: 'pills', className: { list: 'data-[orientation=vertical]:w-48' } },
131
+ ],
132
+ defaultVariants: { variant: 'segmented' },
133
+ });
134
+ /**
135
+ * Holds which tab is chosen: `defaultValue`, or `value` with `onValueChange`.
136
+ * `orientation="vertical"` puts the tabs in a column beside the content.
137
+ */
138
+ function TabsRoot({ variant = 'segmented', className, ...props }) {
139
+ return (_jsx(VariantContext.Provider, { value: variant, children: _jsx(BaseTabs.Root, { "data-slot": "tabs", "data-variant": variant, className: tabsVariants({ variant }).root({ className }), ...props }) }));
140
+ }
141
+ TabsRoot.displayName = 'Tabs';
142
+ const VariantContext = createContext('segmented');
143
+ /** The row of tabs, with the marker under the chosen one. */
144
+ function TabsList({ className, children, ...props }) {
145
+ const ref = useRef(null);
146
+ const slots = tabsVariants({ variant: useContext(VariantContext) });
147
+ // Marks the ends that have more to scroll to, for the fade.
148
+ useEffect(() => {
149
+ const list = ref.current;
150
+ if (!list)
151
+ return;
152
+ const read = () => {
153
+ const start = list.scrollLeft > 1;
154
+ const end = list.scrollLeft + list.clientWidth < list.scrollWidth - 1;
155
+ list.toggleAttribute('data-overflow-start', start);
156
+ list.toggleAttribute('data-overflow-end', end);
157
+ };
158
+ read();
159
+ list.addEventListener('scroll', read, { passive: true });
160
+ const observer = new ResizeObserver(read);
161
+ observer.observe(list);
162
+ return () => {
163
+ list.removeEventListener('scroll', read);
164
+ observer.disconnect();
165
+ };
166
+ }, []);
167
+ return (_jsxs(BaseTabs.List, { ref: ref, "data-slot": "tabs-list", className: slots.list({ className }), ...props, children: [children, _jsx(BaseTabs.Indicator, { "data-slot": "tabs-indicator", className: slots.indicator(), renderBeforeHydration: true })] }));
168
+ }
169
+ TabsList.displayName = 'Tabs.List';
170
+ /**
171
+ * One tab. Its `value` names the `Tabs.Content` it shows. An icon and a
172
+ * `Tabs.Badge` can sit beside its label.
173
+ */
174
+ function TabsTrigger({ className, ...props }) {
175
+ const slots = tabsVariants({ variant: useContext(VariantContext) });
176
+ return _jsx(BaseTabs.Tab, { "data-slot": "tabs-trigger", className: slots.trigger({ className }), ...props });
177
+ }
178
+ TabsTrigger.displayName = 'Tabs.Trigger';
179
+ /** A count beside a tab's label: unread, open, waiting. */
180
+ function TabsBadge({ className, ...props }) {
181
+ const slots = tabsVariants({ variant: useContext(VariantContext) });
182
+ return _jsx("span", { "data-slot": "tabs-badge", className: slots.badge({ className }), ...props });
183
+ }
184
+ TabsBadge.displayName = 'Tabs.Badge';
185
+ /** What one tab shows. Only the chosen one is in the page unless `keepMounted` is set. */
186
+ function TabsContent({ className, ...props }) {
187
+ return _jsx(BaseTabs.Panel, { "data-slot": "tabs-content", className: tabsVariants().content({ className }), ...props });
188
+ }
189
+ TabsContent.displayName = 'Tabs.Content';
190
+ export const Tabs = Object.assign(TabsRoot, {
191
+ List: TabsList,
192
+ Trigger: TabsTrigger,
193
+ Badge: TabsBadge,
194
+ Content: TabsContent,
195
+ });
196
+ export { TabsList, TabsTrigger, TabsBadge, TabsContent };
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { Planet, PlanetGlobe, PlanetMarker, PlanetControls, PlanetList, PlanetLi
4
4
  export { Feedback, FeedbackTrigger, FeedbackContent, FeedbackPanel, FeedbackTitle, FeedbackClose, FeedbackField, FeedbackDescription, FeedbackMessage, FeedbackRating, FeedbackFooter, FeedbackCancel, FeedbackSubmit, type FeedbackProps, type FeedbackTriggerProps, type FeedbackContentProps, type FeedbackPanelProps, type FeedbackTitleProps, type FeedbackCloseProps, type FeedbackFieldProps, type FeedbackDescriptionProps, type FeedbackMessageProps, type FeedbackRatingProps, type FeedbackFooterProps, type FeedbackActionProps, type FeedbackSubmitProps, } from './components/feedback/index.js';
5
5
  export { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter, type CardProps, type CardHeaderProps, type CardTitleProps, type CardDescriptionProps, type CardActionProps, type CardContentProps, type CardFooterProps, } from './components/card/index.js';
6
6
  export { Frame, FrameHeader, FrameTitle, FrameDescription, FrameAction, FramePanel, FrameRow, FrameMedia, FrameContent, FrameActions, FrameSection, FrameFooter, type FrameProps, type FrameVariant, type FrameHeaderProps, type FrameTitleProps, type FrameDescriptionProps, type FrameActionProps, type FramePanelProps, type FrameRowProps, type FrameMediaProps, type FrameContentProps, type FrameActionsProps, type FrameSectionProps, type FrameFooterProps, } from './components/frame/index.js';
7
- export { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter, SheetClose, SheetStage, type SheetProps, type SheetSide, type SheetTriggerProps, type SheetContentProps, type SheetHeaderProps, type SheetTitleProps, type SheetDescriptionProps, type SheetBodyProps, type SheetFooterProps, type SheetCloseProps, type SheetStageProps, } from './components/sheet/index.js';
7
+ export { Sheet, SheetTrigger, SheetNext, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter, SheetClose, SheetStage, type SheetProps, type SheetSide, type SheetTriggerProps, type SheetNextProps, type SheetContentProps, type SheetHeaderProps, type SheetTitleProps, type SheetDescriptionProps, type SheetBodyProps, type SheetFooterProps, type SheetCloseProps, type SheetStageProps, } from './components/sheet/index.js';
8
8
  export { DayGrid, DayGridLegend, DayGridWeekdays, DayGridCaption, DayGridTitle, DayGridDescription, type DayGridProps, type DayGridLegendProps, type DayGridWeekdaysProps, type DayGridCaptionProps, type DayGridTitleProps, type DayGridDescriptionProps, type DayGridColor, type DayCell, type DayLevel, } from './components/day-grid/index.js';
9
9
  export { RangeMeter, RangeMeterLabel, RangeMeterScale, type RangeMeterProps, type RangeMeterLabelProps, type RangeMeterScaleProps, type RangeMeterColor, } from './components/range-meter/index.js';
10
10
  export { BarPicker, type BarPickerProps, type BarPickerBar, type BarPickerColor, } from './components/bar-picker/index.js';
@@ -18,6 +18,12 @@ export { NotFound, NotFoundCode, NotFoundTitle, NotFoundDescription, NotFoundAct
18
18
  export { Button, buttonVariants, type ButtonProps, type ButtonVariant, type ButtonSize } from './components/button/index.js';
19
19
  export { Input, InputGroup, InputAddon, type InputProps, type InputGroupProps, type InputAddonProps, type InputSize } from './components/input/index.js';
20
20
  export { Textarea, type TextareaProps } from './components/textarea/index.js';
21
+ export { Switch, type SwitchProps, type SwitchSize, type SwitchColor } from './components/switch/index.js';
22
+ export { Label, LabelText, LabelHint, LabelAction, type LabelProps, type LabelTextProps, type LabelHintProps, type LabelActionProps, } from './components/label/index.js';
21
23
  export { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SelectGroup, SelectGroupLabel, SelectSeparator, type SelectProps, type SelectTriggerProps, type SelectValueProps, type SelectContentProps, type SelectItemProps, type SelectGroupProps, type SelectGroupLabelProps, type SelectSeparatorProps, } from './components/select/index.js';
22
24
  export { Prompt, PromptBanner, PromptBannerAction, PromptField, PromptAttachments, PromptTextarea, PromptFooter, PromptTools, PromptTool, PromptAttach, PromptMenu, PromptAttachItem, PromptModel, PromptSubmit, PromptStatus, PromptTasks, PromptTask, PromptCommands, PromptRecorder, PromptContext, PromptContextItem, PromptHint, type PromptProps, type PromptState, type PromptMessage, type PromptAttachment, type PromptRejectReason, type PromptBannerProps, type PromptBannerActionProps, type PromptFieldProps, type PromptAttachmentsProps, type PromptTextareaProps, type PromptFooterProps, type PromptToolsProps, type PromptToolProps, type PromptAttachProps, type PromptMenuProps, type PromptAttachItemProps, type PromptModelProps, type PromptModelItem, type PromptSubmitProps, type PromptStatusProps, type PromptTasksProps, type PromptTaskProps, type PromptTaskStatus, type PromptCommandsProps, type PromptCommandItem, type PromptRecorderProps, type PromptContextProps, type PromptContextItemProps, type PromptHintProps, } from './components/prompt/index.js';
23
25
  export { Menu, MenuTrigger, MenuContent, MenuItem, MenuCheckboxItem, MenuRadioGroup, MenuRadioItem, MenuSub, MenuSubTrigger, MenuSubContent, MenuGroup, MenuGroupLabel, MenuSeparator, MenuDescription, MenuShortcut, MenuBadge, type MenuProps, type MenuTriggerProps, type MenuContentProps, type MenuItemProps, type MenuCheckboxItemProps, type MenuRadioGroupProps, type MenuRadioItemProps, type MenuSubProps, type MenuSubTriggerProps, type MenuSubContentProps, type MenuGroupProps, type MenuGroupLabelProps, type MenuSeparatorProps, type MenuDescriptionProps, type MenuShortcutProps, type MenuBadgeProps, } from './components/menu/index.js';
26
+ export { Avatar, AvatarBadge, AvatarGroup, type AvatarProps, type AvatarBadgeProps, type AvatarGroupProps, type AvatarSize, type AvatarShape, type AvatarColor, type AvatarStatus, } from './components/avatar/index.js';
27
+ export { Tabs, TabsList, TabsTrigger, TabsBadge, TabsContent, type TabsProps, type TabsVariant, type TabsListProps, type TabsTriggerProps, type TabsBadgeProps, type TabsContentProps, } from './components/tabs/index.js';
28
+ export { Message, MessageGroup, MessageAvatar, MessageContent, MessageHeader, MessageBubble, MessageBubbleContent, MessageFooter, MessageActions, MessageAction, MessageBranch, MessageStatus, MessageAttachments, MessageAttachment, type MessageFrom, type MessageProps, type MessageGroupProps, type MessageAvatarProps, type MessageContentProps, type MessageHeaderProps, type MessageBubbleProps, type MessageBubbleContentProps, type MessageFooterProps, type MessageActionsProps, type MessageActionProps, type MessageBranchProps, type MessageStatusProps, type MessageAttachmentsProps, type MessageAttachmentProps, } from './components/message/index.js';
29
+ export { Soundwave, SoundwaveCenter, useAudioLevel, useMicrophone, type SoundwaveProps, type SoundwaveCenterProps, type SoundwaveVariant, type SoundwaveState, type SoundwaveColor, type SoundwaveSource, type AudioLevelOptions, type UseMicrophoneOptions, type MicrophoneControls, type MicrophoneStatus, } from './components/soundwave/index.js';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ export { Planet, PlanetGlobe, PlanetMarker, PlanetControls, PlanetList, PlanetLi
4
4
  export { Feedback, FeedbackTrigger, FeedbackContent, FeedbackPanel, FeedbackTitle, FeedbackClose, FeedbackField, FeedbackDescription, FeedbackMessage, FeedbackRating, FeedbackFooter, FeedbackCancel, FeedbackSubmit, } from './components/feedback/index.js';
5
5
  export { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter, } from './components/card/index.js';
6
6
  export { Frame, FrameHeader, FrameTitle, FrameDescription, FrameAction, FramePanel, FrameRow, FrameMedia, FrameContent, FrameActions, FrameSection, FrameFooter, } from './components/frame/index.js';
7
- export { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter, SheetClose, SheetStage, } from './components/sheet/index.js';
7
+ export { Sheet, SheetTrigger, SheetNext, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter, SheetClose, SheetStage, } from './components/sheet/index.js';
8
8
  export { DayGrid, DayGridLegend, DayGridWeekdays, DayGridCaption, DayGridTitle, DayGridDescription, } from './components/day-grid/index.js';
9
9
  export { RangeMeter, RangeMeterLabel, RangeMeterScale, } from './components/range-meter/index.js';
10
10
  export { BarPicker, } from './components/bar-picker/index.js';
@@ -18,6 +18,12 @@ export { NotFound, NotFoundCode, NotFoundTitle, NotFoundDescription, NotFoundAct
18
18
  export { Button, buttonVariants } from './components/button/index.js';
19
19
  export { Input, InputGroup, InputAddon } from './components/input/index.js';
20
20
  export { Textarea } from './components/textarea/index.js';
21
+ export { Switch } from './components/switch/index.js';
22
+ export { Label, LabelText, LabelHint, LabelAction, } from './components/label/index.js';
21
23
  export { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SelectGroup, SelectGroupLabel, SelectSeparator, } from './components/select/index.js';
22
24
  export { Prompt, PromptBanner, PromptBannerAction, PromptField, PromptAttachments, PromptTextarea, PromptFooter, PromptTools, PromptTool, PromptAttach, PromptMenu, PromptAttachItem, PromptModel, PromptSubmit, PromptStatus, PromptTasks, PromptTask, PromptCommands, PromptRecorder, PromptContext, PromptContextItem, PromptHint, } from './components/prompt/index.js';
23
25
  export { Menu, MenuTrigger, MenuContent, MenuItem, MenuCheckboxItem, MenuRadioGroup, MenuRadioItem, MenuSub, MenuSubTrigger, MenuSubContent, MenuGroup, MenuGroupLabel, MenuSeparator, MenuDescription, MenuShortcut, MenuBadge, } from './components/menu/index.js';
26
+ export { Avatar, AvatarBadge, AvatarGroup, } from './components/avatar/index.js';
27
+ export { Tabs, TabsList, TabsTrigger, TabsBadge, TabsContent, } from './components/tabs/index.js';
28
+ export { Message, MessageGroup, MessageAvatar, MessageContent, MessageHeader, MessageBubble, MessageBubbleContent, MessageFooter, MessageActions, MessageAction, MessageBranch, MessageStatus, MessageAttachments, MessageAttachment, } from './components/message/index.js';
29
+ export { Soundwave, SoundwaveCenter, useAudioLevel, useMicrophone, } from './components/soundwave/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panelui-web",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "PanelUI for the web: animated, data-rich React components styled with Tailwind CSS on shadcn tokens.",
5
5
  "type": "module",
6
6
  "sideEffects": false,