panelui-web 0.8.0 → 0.9.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.
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ButtonGroup — related actions held together in one control.
|
|
3
|
+
*
|
|
4
|
+
* ```tsx
|
|
5
|
+
* <ButtonGroup aria-label="History">
|
|
6
|
+
* <Button variant="outline">Undo</Button>
|
|
7
|
+
* <Button variant="outline">Redo</Button>
|
|
8
|
+
* </ButtonGroup>
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* ## A track, like the segmented Tabs
|
|
12
|
+
*
|
|
13
|
+
* The group is drawn the way the segmented `Tabs` are: a muted track with
|
|
14
|
+
* rounded corners, and the buttons inside it at the radius one step smaller,
|
|
15
|
+
* so every corner follows the track's. Outline and ghost buttons lie flat in
|
|
16
|
+
* the track with muted labels; the one under the pointer rises out of it the
|
|
17
|
+
* way the chosen tab does, and the short dividers on either side of it fade.
|
|
18
|
+
* A field or a filled button keeps its own surface, so it reads as raised
|
|
19
|
+
* from the start.
|
|
20
|
+
*
|
|
21
|
+
* It does this with child selectors rather than props, so any `Button`,
|
|
22
|
+
* `Input`, `Menu.Trigger` or `ButtonGroup.Text` placed directly inside takes
|
|
23
|
+
* part without being told to.
|
|
24
|
+
*
|
|
25
|
+
* ## Split buttons
|
|
26
|
+
*
|
|
27
|
+
* A group with a `ButtonGroup.Separator` in it is a split button instead: no
|
|
28
|
+
* track, and its filled halves joined edge to edge, with the separator
|
|
29
|
+
* carrying their fill across the seam.
|
|
30
|
+
*
|
|
31
|
+
* ## Groups of groups
|
|
32
|
+
*
|
|
33
|
+
* A group whose children are groups spaces them apart, which is how a
|
|
34
|
+
* toolbar is built: one track per kind of action.
|
|
35
|
+
*/
|
|
36
|
+
import type { ComponentProps } from 'react';
|
|
37
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
38
|
+
export declare const buttonGroupVariants: import("tailwind-variants").TVReturnType<{
|
|
39
|
+
orientation: {
|
|
40
|
+
horizontal: {
|
|
41
|
+
root: string[];
|
|
42
|
+
separator: string;
|
|
43
|
+
};
|
|
44
|
+
vertical: {
|
|
45
|
+
root: string[];
|
|
46
|
+
separator: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/** Matches the heights of `Button` and `Input` at the same size. */
|
|
50
|
+
size: {
|
|
51
|
+
sm: {
|
|
52
|
+
text: string;
|
|
53
|
+
};
|
|
54
|
+
md: {
|
|
55
|
+
text: string;
|
|
56
|
+
};
|
|
57
|
+
lg: {
|
|
58
|
+
text: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}, {
|
|
62
|
+
root: string[];
|
|
63
|
+
separator: string[];
|
|
64
|
+
text: string[];
|
|
65
|
+
}, undefined, {
|
|
66
|
+
orientation: {
|
|
67
|
+
horizontal: {
|
|
68
|
+
root: string[];
|
|
69
|
+
separator: string;
|
|
70
|
+
};
|
|
71
|
+
vertical: {
|
|
72
|
+
root: string[];
|
|
73
|
+
separator: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
/** Matches the heights of `Button` and `Input` at the same size. */
|
|
77
|
+
size: {
|
|
78
|
+
sm: {
|
|
79
|
+
text: string;
|
|
80
|
+
};
|
|
81
|
+
md: {
|
|
82
|
+
text: string;
|
|
83
|
+
};
|
|
84
|
+
lg: {
|
|
85
|
+
text: string;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
}, {
|
|
89
|
+
root: string[];
|
|
90
|
+
separator: string[];
|
|
91
|
+
text: string[];
|
|
92
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
93
|
+
orientation: {
|
|
94
|
+
horizontal: {
|
|
95
|
+
root: string[];
|
|
96
|
+
separator: string;
|
|
97
|
+
};
|
|
98
|
+
vertical: {
|
|
99
|
+
root: string[];
|
|
100
|
+
separator: string;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
/** Matches the heights of `Button` and `Input` at the same size. */
|
|
104
|
+
size: {
|
|
105
|
+
sm: {
|
|
106
|
+
text: string;
|
|
107
|
+
};
|
|
108
|
+
md: {
|
|
109
|
+
text: string;
|
|
110
|
+
};
|
|
111
|
+
lg: {
|
|
112
|
+
text: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
}, {
|
|
116
|
+
root: string[];
|
|
117
|
+
separator: string[];
|
|
118
|
+
text: string[];
|
|
119
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
120
|
+
export type ButtonGroupOrientation = NonNullable<VariantProps<typeof buttonGroupVariants>['orientation']>;
|
|
121
|
+
export type ButtonGroupTextSize = NonNullable<VariantProps<typeof buttonGroupVariants>['size']>;
|
|
122
|
+
export interface ButtonGroupProps extends ComponentProps<'div'> {
|
|
123
|
+
/** Lay the children out in a row or a column. Default `horizontal`. */
|
|
124
|
+
orientation?: ButtonGroupOrientation;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The group. It is a `role="group"`, so give it an `aria-label` that names
|
|
128
|
+
* what its actions have in common.
|
|
129
|
+
*/
|
|
130
|
+
declare function ButtonGroupRoot({ orientation, className, ...props }: ButtonGroupProps): import("react").JSX.Element;
|
|
131
|
+
declare namespace ButtonGroupRoot {
|
|
132
|
+
var displayName: string;
|
|
133
|
+
}
|
|
134
|
+
export interface ButtonGroupSeparatorProps extends ComponentProps<'span'> {
|
|
135
|
+
/**
|
|
136
|
+
* Which way the line runs. It follows the group: a row of buttons is divided
|
|
137
|
+
* by upright lines, a column by flat ones. Default `vertical`, for a row.
|
|
138
|
+
*/
|
|
139
|
+
orientation?: 'vertical' | 'horizontal';
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The divider of a split button. A group with one in it drops its track and
|
|
143
|
+
* joins its children edge to edge. Before a primary, secondary or destructive
|
|
144
|
+
* button the separator takes that button's fill, so the two halves read as
|
|
145
|
+
* one, and draws a short line in the button's text colour. It is decorative
|
|
146
|
+
* and hidden from assistive technology.
|
|
147
|
+
*/
|
|
148
|
+
declare function ButtonGroupSeparator({ orientation, className, ...props }: ButtonGroupSeparatorProps): import("react").JSX.Element;
|
|
149
|
+
declare namespace ButtonGroupSeparator {
|
|
150
|
+
var displayName: string;
|
|
151
|
+
}
|
|
152
|
+
export interface ButtonGroupTextProps extends ComponentProps<'div'> {
|
|
153
|
+
/** The height, matching the buttons and fields beside it. Default `md`. */
|
|
154
|
+
size?: ButtonGroupTextSize;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* A cell that is read rather than pressed: a prefix such as `https://`, a unit,
|
|
158
|
+
* or the value a pair of buttons changes.
|
|
159
|
+
*/
|
|
160
|
+
declare function ButtonGroupText({ size, className, ...props }: ButtonGroupTextProps): import("react").JSX.Element;
|
|
161
|
+
declare namespace ButtonGroupText {
|
|
162
|
+
var displayName: string;
|
|
163
|
+
}
|
|
164
|
+
export declare const ButtonGroup: typeof ButtonGroupRoot & {
|
|
165
|
+
Separator: typeof ButtonGroupSeparator;
|
|
166
|
+
Text: typeof ButtonGroupText;
|
|
167
|
+
};
|
|
168
|
+
export { ButtonGroupSeparator, ButtonGroupText };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { tv } from 'tailwind-variants';
|
|
3
|
+
/*
|
|
4
|
+
* Which of the three a group is depends on what it holds, so the rules below
|
|
5
|
+
* are scoped by selector rather than by prop:
|
|
6
|
+
*
|
|
7
|
+
* track &:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))
|
|
8
|
+
* split &:has(>[data-slot=button-group-separator])
|
|
9
|
+
*
|
|
10
|
+
* Tailwind reads class names whole, so each selector is written out in full
|
|
11
|
+
* in every class that uses it.
|
|
12
|
+
*/
|
|
13
|
+
export const buttonGroupVariants = tv({
|
|
14
|
+
slots: {
|
|
15
|
+
root: [
|
|
16
|
+
'flex w-fit items-stretch',
|
|
17
|
+
// A focused child draws its ring over its neighbours, not under them.
|
|
18
|
+
'*:focus-visible:relative *:focus-visible:z-10',
|
|
19
|
+
// A field takes the room the buttons leave.
|
|
20
|
+
'[&>[data-slot=input]]:min-w-0 [&>[data-slot=input]]:flex-1',
|
|
21
|
+
// The track, in the segmented Tabs' colour and radius. Its children
|
|
22
|
+
// take the radius one step down, which is the track's less its padding.
|
|
23
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))]:gap-1 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))]:rounded-xl [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))]:bg-muted [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))]:p-1',
|
|
24
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*]:relative [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*]:rounded-lg',
|
|
25
|
+
// Outline and ghost buttons lie flat, with muted labels, and rise out
|
|
26
|
+
// of the track under the pointer like the chosen tab.
|
|
27
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost])]:border-transparent [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost])]:bg-transparent [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost])]:text-muted-foreground [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost])]:shadow-none',
|
|
28
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost]):hover:not(:disabled)]:bg-background [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost]):hover:not(:disabled)]:text-foreground [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost]):hover:not(:disabled)]:shadow-sm',
|
|
29
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost]):hover:not(:disabled)]:inset-ring [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost]):hover:not(:disabled)]:inset-ring-foreground/[0.06]',
|
|
30
|
+
'dark:[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost]):hover:not(:disabled)]:bg-input dark:[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>:is([data-variant=outline],[data-variant=ghost]):hover:not(:disabled)]:inset-ring-foreground/10',
|
|
31
|
+
// Short dividers in the gaps, drawn by the second child of each pair so
|
|
32
|
+
// the first never gets one. None beside a field, which has its own
|
|
33
|
+
// edge, and none beside the child under the pointer.
|
|
34
|
+
"[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:pointer-events-none [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:absolute [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:bg-foreground/10 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:transition-opacity [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:duration-150 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:content-['']",
|
|
35
|
+
'[&>[data-slot=input]+*]:before:hidden [&>*+[data-slot=input]]:before:hidden',
|
|
36
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*:hover:not(:disabled)]:before:opacity-0 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*:hover:not(:disabled)+*]:before:opacity-0',
|
|
37
|
+
// Groups inside a group are spaced, one track each.
|
|
38
|
+
'has-[>[data-slot=button-group]]:gap-2',
|
|
39
|
+
],
|
|
40
|
+
separator: [
|
|
41
|
+
'relative shrink-0 self-stretch bg-border',
|
|
42
|
+
// Between filled buttons the separator carries their fill across the
|
|
43
|
+
// seam, and a short line in their text colour divides it.
|
|
44
|
+
"before:absolute before:content-['']",
|
|
45
|
+
'has-[+[data-variant=default]]:bg-primary has-[+[data-variant=default]]:before:bg-primary-foreground/25',
|
|
46
|
+
'has-[+[data-variant=secondary]]:bg-secondary has-[+[data-variant=secondary]]:before:bg-secondary-foreground/15',
|
|
47
|
+
'has-[+[data-variant=destructive]]:bg-destructive has-[+[data-variant=destructive]]:before:bg-white/30',
|
|
48
|
+
],
|
|
49
|
+
text: [
|
|
50
|
+
'relative flex shrink-0 items-center gap-2 whitespace-nowrap font-medium text-muted-foreground',
|
|
51
|
+
'[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-4',
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
variants: {
|
|
55
|
+
orientation: {
|
|
56
|
+
horizontal: {
|
|
57
|
+
root: [
|
|
58
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:inset-y-2 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:-left-0.5 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:w-px',
|
|
59
|
+
// A split button's halves meet edge to edge.
|
|
60
|
+
'[&:has(>[data-slot=button-group-separator])>*:not(:first-child)]:rounded-l-none [&:has(>[data-slot=button-group-separator])>*:not(:last-child)]:rounded-r-none',
|
|
61
|
+
],
|
|
62
|
+
separator: 'w-px before:inset-y-2 before:inset-x-0',
|
|
63
|
+
},
|
|
64
|
+
vertical: {
|
|
65
|
+
root: [
|
|
66
|
+
'flex-col',
|
|
67
|
+
'[&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:inset-x-2 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:-top-0.5 [&:not(:has(>[data-slot=button-group-separator],>[data-slot=button-group]))>*+*]:before:h-px',
|
|
68
|
+
'[&:has(>[data-slot=button-group-separator])>*:not(:first-child)]:rounded-t-none [&:has(>[data-slot=button-group-separator])>*:not(:last-child)]:rounded-b-none',
|
|
69
|
+
],
|
|
70
|
+
separator: 'h-px before:inset-x-2 before:inset-y-0',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
/** Matches the heights of `Button` and `Input` at the same size. */
|
|
74
|
+
size: {
|
|
75
|
+
sm: { text: 'h-8 px-2.5 text-[0.8125rem]' },
|
|
76
|
+
md: { text: 'h-9 px-3 text-sm' },
|
|
77
|
+
lg: { text: 'h-11 px-3.5 text-[0.9375rem]' },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
defaultVariants: { orientation: 'horizontal', size: 'md' },
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* The group. It is a `role="group"`, so give it an `aria-label` that names
|
|
84
|
+
* what its actions have in common.
|
|
85
|
+
*/
|
|
86
|
+
function ButtonGroupRoot({ orientation = 'horizontal', className, ...props }) {
|
|
87
|
+
return (_jsx("div", { role: "group", "data-slot": "button-group", "data-orientation": orientation, className: buttonGroupVariants({ orientation }).root({ className }), ...props }));
|
|
88
|
+
}
|
|
89
|
+
ButtonGroupRoot.displayName = 'ButtonGroup';
|
|
90
|
+
/**
|
|
91
|
+
* The divider of a split button. A group with one in it drops its track and
|
|
92
|
+
* joins its children edge to edge. Before a primary, secondary or destructive
|
|
93
|
+
* button the separator takes that button's fill, so the two halves read as
|
|
94
|
+
* one, and draws a short line in the button's text colour. It is decorative
|
|
95
|
+
* and hidden from assistive technology.
|
|
96
|
+
*/
|
|
97
|
+
function ButtonGroupSeparator({ orientation = 'vertical', className, ...props }) {
|
|
98
|
+
const slots = buttonGroupVariants({
|
|
99
|
+
orientation: orientation === 'vertical' ? 'horizontal' : 'vertical',
|
|
100
|
+
});
|
|
101
|
+
return (_jsx("span", { "aria-hidden": "true", "data-slot": "button-group-separator", "data-orientation": orientation, className: slots.separator({ className }), ...props }));
|
|
102
|
+
}
|
|
103
|
+
ButtonGroupSeparator.displayName = 'ButtonGroup.Separator';
|
|
104
|
+
/**
|
|
105
|
+
* A cell that is read rather than pressed: a prefix such as `https://`, a unit,
|
|
106
|
+
* or the value a pair of buttons changes.
|
|
107
|
+
*/
|
|
108
|
+
function ButtonGroupText({ size, className, ...props }) {
|
|
109
|
+
return (_jsx("div", { "data-slot": "button-group-text", className: buttonGroupVariants({ size }).text({ className }), ...props }));
|
|
110
|
+
}
|
|
111
|
+
ButtonGroupText.displayName = 'ButtonGroup.Text';
|
|
112
|
+
export const ButtonGroup = Object.assign(ButtonGroupRoot, {
|
|
113
|
+
Separator: ButtonGroupSeparator,
|
|
114
|
+
Text: ButtonGroupText,
|
|
115
|
+
});
|
|
116
|
+
export { ButtonGroupSeparator, ButtonGroupText };
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export { Stat, StatContent, StatLabel, StatDescription, StatValue, StatUnit, Sta
|
|
|
16
16
|
export { CommandDock, CommandDockTrigger, CommandDockPanel, CommandDockInput, CommandDockResults, CommandDockRow, CommandDockRowTitle, CommandDockRowMeta, CommandDockStatus, type CommandDockProps, type CommandDockTriggerProps, type CommandDockPanelProps, type CommandDockInputProps, type CommandDockResultsProps, type CommandDockRowProps, type CommandDockRowTitleProps, type CommandDockRowMetaProps, type CommandDockStatusProps, } from './components/command-dock/index.js';
|
|
17
17
|
export { NotFound, NotFoundCode, NotFoundTitle, NotFoundDescription, NotFoundActions, type NotFoundProps, type NotFoundCodeProps, type NotFoundTitleProps, type NotFoundDescriptionProps, type NotFoundActionsProps, type NotFoundEffect, type NotFoundColor, } from './components/not-found/index.js';
|
|
18
18
|
export { Button, buttonVariants, type ButtonProps, type ButtonVariant, type ButtonSize } from './components/button/index.js';
|
|
19
|
+
export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants, type ButtonGroupProps, type ButtonGroupOrientation, type ButtonGroupSeparatorProps, type ButtonGroupTextProps, type ButtonGroupTextSize, } from './components/button-group/index.js';
|
|
19
20
|
export { Input, InputGroup, InputAddon, type InputProps, type InputGroupProps, type InputAddonProps, type InputSize } from './components/input/index.js';
|
|
20
21
|
export { Textarea, type TextareaProps } from './components/textarea/index.js';
|
|
21
22
|
export { Switch, type SwitchProps, type SwitchSize, type SwitchColor } from './components/switch/index.js';
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { Stat, StatContent, StatLabel, StatDescription, StatValue, StatUnit, Sta
|
|
|
16
16
|
export { CommandDock, CommandDockTrigger, CommandDockPanel, CommandDockInput, CommandDockResults, CommandDockRow, CommandDockRowTitle, CommandDockRowMeta, CommandDockStatus, } from './components/command-dock/index.js';
|
|
17
17
|
export { NotFound, NotFoundCode, NotFoundTitle, NotFoundDescription, NotFoundActions, } from './components/not-found/index.js';
|
|
18
18
|
export { Button, buttonVariants } from './components/button/index.js';
|
|
19
|
+
export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants, } from './components/button-group/index.js';
|
|
19
20
|
export { Input, InputGroup, InputAddon } from './components/input/index.js';
|
|
20
21
|
export { Textarea } from './components/textarea/index.js';
|
|
21
22
|
export { Switch } from './components/switch/index.js';
|