@womp/kookie-ui 0.10.0 → 0.11.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/components.css +132 -26
- package/dist/cjs/components/app-bar.d.ts +49 -0
- package/dist/cjs/components/app-bar.d.ts.map +1 -0
- package/dist/cjs/components/app-bar.js +2 -0
- package/dist/cjs/components/app-bar.js.map +7 -0
- package/dist/cjs/components/index.d.ts +2 -1
- package/dist/cjs/components/index.d.ts.map +1 -1
- package/dist/cjs/components/index.js +5 -5
- package/dist/cjs/components/index.js.map +4 -4
- package/dist/cjs/components/toolbar.d.ts +88 -36
- package/dist/cjs/components/toolbar.d.ts.map +1 -1
- package/dist/cjs/components/toolbar.js +4 -1
- package/dist/cjs/components/toolbar.js.map +4 -4
- package/dist/cjs/components/toolbar.props.d.ts +28 -0
- package/dist/cjs/components/toolbar.props.d.ts.map +1 -0
- package/dist/cjs/components/toolbar.props.js +2 -0
- package/dist/cjs/components/toolbar.props.js.map +7 -0
- package/dist/cjs/index.js +5 -5
- package/dist/cjs/index.js.map +4 -4
- package/dist/esm/{chunk-73QGEY2I.js → chunk-3R4YLW4A.js} +2 -2
- package/dist/esm/{chunk-ZZLZGHZQ.js → chunk-4LDVSTXI.js} +2 -2
- package/dist/esm/chunk-54JFIP5S.js +2 -0
- package/dist/esm/chunk-54JFIP5S.js.map +7 -0
- package/dist/esm/{chunk-X3JM2565.js → chunk-6G3MPL4A.js} +2 -2
- package/dist/esm/{chunk-DSJY5RI3.js → chunk-7JJT42J2.js} +2 -2
- package/dist/esm/chunk-C7EVYSWK.js +1 -0
- package/dist/esm/{chunk-ERY5TH2M.js → chunk-CYU6BLZ5.js} +2 -2
- package/dist/esm/{chunk-25LBWKEV.js → chunk-D6PHTHF2.js} +2 -2
- package/dist/esm/{chunk-QK5RBHKV.js → chunk-ENLFKWYV.js} +2 -2
- package/dist/esm/{chunk-4XGGX2V2.js → chunk-ISOLUTZF.js} +2 -2
- package/dist/esm/{chunk-LXWPEDPZ.js → chunk-IYCPYN4Z.js} +2 -2
- package/dist/esm/{chunk-RJP5QUXO.js → chunk-L5PID6BU.js} +2 -2
- package/dist/esm/{chunk-BW5CO4PZ.js → chunk-METRW4HG.js} +2 -2
- package/dist/esm/{chunk-PYHEBG5I.js → chunk-MJOXEUBT.js} +2 -2
- package/dist/esm/{chunk-4D2OAD6I.js → chunk-OIUCV5HK.js} +2 -2
- package/dist/esm/{chunk-65GAANJD.js → chunk-UYCPDGWA.js} +2 -2
- package/dist/esm/chunk-XLMTTSRO.js +2 -0
- package/dist/esm/chunk-XLMTTSRO.js.map +7 -0
- package/dist/esm/{chunk-QWVU2TW4.js → chunk-ZK7A2MZZ.js} +2 -2
- package/dist/esm/chunk-ZUOK3KFY.js +2 -0
- package/dist/esm/chunk-ZUOK3KFY.js.map +7 -0
- package/dist/esm/components/_internal/base-button.js +1 -1
- package/dist/esm/components/alert-dialog.js +1 -1
- package/dist/esm/components/app-bar.d.ts +49 -0
- package/dist/esm/components/app-bar.d.ts.map +1 -0
- package/dist/esm/components/app-bar.js +2 -0
- package/dist/esm/components/app-bar.js.map +7 -0
- package/dist/esm/components/button.js +1 -1
- package/dist/esm/components/chatbar.js +1 -1
- package/dist/esm/components/checkbox-cards.js +1 -1
- package/dist/esm/components/dialog.js +1 -1
- package/dist/esm/components/icon-button.js +1 -1
- package/dist/esm/components/index.d.ts +2 -1
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +1 -1
- package/dist/esm/components/message-scroller.js +1 -1
- package/dist/esm/components/notice.js +1 -1
- package/dist/esm/components/sheet.js +1 -1
- package/dist/esm/components/shell.js +1 -1
- package/dist/esm/components/theme-panel.js +1 -1
- package/dist/esm/components/toggle-button.js +1 -1
- package/dist/esm/components/toggle-icon-button.js +1 -1
- package/dist/esm/components/toolbar.d.ts +88 -36
- package/dist/esm/components/toolbar.d.ts.map +1 -1
- package/dist/esm/components/toolbar.js +1 -1
- package/dist/esm/components/toolbar.props.d.ts +28 -0
- package/dist/esm/components/toolbar.props.d.ts.map +1 -0
- package/dist/esm/components/toolbar.props.js +2 -0
- package/dist/esm/components/toolbar.props.js.map +7 -0
- package/dist/esm/components/user-card.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/props/index.js +1 -1
- package/package.json +1 -1
- package/src/components/app-bar.css +204 -0
- package/src/components/app-bar.tsx +256 -0
- package/src/components/index.css +2 -0
- package/src/components/index.tsx +13 -1
- package/src/components/toolbar.css +87 -160
- package/src/components/toolbar.props.tsx +27 -0
- package/src/components/toolbar.tsx +259 -193
- package/src/styles/tokens/color.css +19 -0
- package/styles.css +146 -26
- package/tokens/base.css +14 -0
- package/tokens.css +14 -0
- package/dist/esm/chunk-47LMOIW3.js +0 -2
- package/dist/esm/chunk-47LMOIW3.js.map +0 -7
- package/dist/esm/chunk-JKS2YXMS.js +0 -1
- /package/dist/esm/{chunk-73QGEY2I.js.map → chunk-3R4YLW4A.js.map} +0 -0
- /package/dist/esm/{chunk-ZZLZGHZQ.js.map → chunk-4LDVSTXI.js.map} +0 -0
- /package/dist/esm/{chunk-X3JM2565.js.map → chunk-6G3MPL4A.js.map} +0 -0
- /package/dist/esm/{chunk-DSJY5RI3.js.map → chunk-7JJT42J2.js.map} +0 -0
- /package/dist/esm/{chunk-JKS2YXMS.js.map → chunk-C7EVYSWK.js.map} +0 -0
- /package/dist/esm/{chunk-ERY5TH2M.js.map → chunk-CYU6BLZ5.js.map} +0 -0
- /package/dist/esm/{chunk-25LBWKEV.js.map → chunk-D6PHTHF2.js.map} +0 -0
- /package/dist/esm/{chunk-QK5RBHKV.js.map → chunk-ENLFKWYV.js.map} +0 -0
- /package/dist/esm/{chunk-4XGGX2V2.js.map → chunk-ISOLUTZF.js.map} +0 -0
- /package/dist/esm/{chunk-LXWPEDPZ.js.map → chunk-IYCPYN4Z.js.map} +0 -0
- /package/dist/esm/{chunk-RJP5QUXO.js.map → chunk-L5PID6BU.js.map} +0 -0
- /package/dist/esm/{chunk-BW5CO4PZ.js.map → chunk-METRW4HG.js.map} +0 -0
- /package/dist/esm/{chunk-PYHEBG5I.js.map → chunk-MJOXEUBT.js.map} +0 -0
- /package/dist/esm/{chunk-4D2OAD6I.js.map → chunk-OIUCV5HK.js.map} +0 -0
- /package/dist/esm/{chunk-65GAANJD.js.map → chunk-UYCPDGWA.js.map} +0 -0
- /package/dist/esm/{chunk-QWVU2TW4.js.map → chunk-ZK7A2MZZ.js.map} +0 -0
|
@@ -1,211 +1,272 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
1
3
|
import * as React from 'react';
|
|
2
4
|
import classNames from 'classnames';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type
|
|
16
|
-
type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
5
|
+
import { Toolbar as ToolbarPrimitive } from 'radix-ui';
|
|
6
|
+
|
|
7
|
+
import { toolbarRootPropDefs } from './toolbar.props.js';
|
|
8
|
+
import { Button } from './button.js';
|
|
9
|
+
import { IconButton } from './icon-button.js';
|
|
10
|
+
import { Text } from './text.js';
|
|
11
|
+
import { extractProps } from '../helpers/extract-props.js';
|
|
12
|
+
import { marginPropDefs } from '../props/margin.props.js';
|
|
13
|
+
|
|
14
|
+
import type { ButtonProps } from './button.js';
|
|
15
|
+
import type { TextProps } from './text.js';
|
|
16
|
+
import type { MarginProps } from '../props/margin.props.js';
|
|
17
|
+
import type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';
|
|
18
|
+
import type { GetPropDefTypes } from '../props/prop-def.js';
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* Toolbar takes Kookie UI v2's contract (v2: components/toolbar), built on Radix instead of
|
|
22
|
+
* Base UI. A toolbar is a row of controls with ONE tab stop: `role="toolbar"`, and the arrow
|
|
23
|
+
* keys move focus between its controls. That keyboard is the reason it is a component.
|
|
24
|
+
*
|
|
25
|
+
* Its `size` reaches every control inside it that does not state its own. The row itself paints
|
|
26
|
+
* nothing; a `ToolbarGroup` draws a quiet well around controls that belong together, and a
|
|
27
|
+
* `ToolbarSeparator` draws a gray hairline between clusters. Use a `Flex` to cluster controls
|
|
28
|
+
* without a well: the row spaces the clusters with `space-between`.
|
|
29
|
+
*
|
|
30
|
+
* The band anchored to a pane's edge (Left / Center / Right / Title) that this name used to
|
|
31
|
+
* mean is `AppBar` since 0.11.0.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
type ToolbarSize = NonNullable<GetPropDefTypes<typeof toolbarRootPropDefs>['size']>;
|
|
35
|
+
type ToolbarOrientation = NonNullable<GetPropDefTypes<typeof toolbarRootPropDefs>['orientation']>;
|
|
36
|
+
|
|
37
|
+
interface ToolbarContextValue {
|
|
38
|
+
size: ToolbarSize;
|
|
39
|
+
orientation: ToolbarOrientation;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
const
|
|
39
|
-
(props, forwardedRef) => {
|
|
40
|
-
const {
|
|
41
|
-
anchor = 'top',
|
|
42
|
-
floating = false,
|
|
43
|
-
offset = '2',
|
|
44
|
-
size = '1',
|
|
45
|
-
variant = 'ghost',
|
|
46
|
-
material,
|
|
47
|
-
className,
|
|
48
|
-
style,
|
|
49
|
-
children,
|
|
50
|
-
...restProps
|
|
51
|
-
} = props;
|
|
52
|
-
|
|
53
|
-
const isHorizontal = anchor === 'top' || anchor === 'bottom';
|
|
54
|
-
const internalRef = React.useRef<HTMLDivElement>(null);
|
|
55
|
-
|
|
56
|
-
// Merge refs
|
|
57
|
-
const mergedRef = React.useCallback(
|
|
58
|
-
(node: HTMLDivElement | null) => {
|
|
59
|
-
(internalRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
60
|
-
if (typeof forwardedRef === 'function') {
|
|
61
|
-
forwardedRef(node);
|
|
62
|
-
} else if (forwardedRef) {
|
|
63
|
-
forwardedRef.current = node;
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
[forwardedRef],
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
// Expose height/width as CSS variable on parent element
|
|
70
|
-
React.useEffect(() => {
|
|
71
|
-
const element = internalRef.current;
|
|
72
|
-
if (!element) return;
|
|
42
|
+
const ToolbarContext = React.createContext<ToolbarContextValue | null>(null);
|
|
73
43
|
|
|
74
|
-
|
|
75
|
-
|
|
44
|
+
/** Set by a `ToolbarGroup`: its children rest quiet, and `disabled` turns them all off. */
|
|
45
|
+
const ToolbarGroupContext = React.createContext<{ disabled: boolean } | null>(null);
|
|
76
46
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
dimension += margin * 2;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (isHorizontal) {
|
|
88
|
-
parent.style.setProperty('--rt-toolbar-height', `${dimension}px`);
|
|
89
|
-
} else {
|
|
90
|
-
parent.style.setProperty('--rt-toolbar-width', `${dimension}px`);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
47
|
+
function useToolbarContext(consumer: string): ToolbarContextValue {
|
|
48
|
+
const context = React.useContext(ToolbarContext);
|
|
49
|
+
if (!context) {
|
|
50
|
+
throw new Error(`${consumer} must be rendered inside a Toolbar.`);
|
|
51
|
+
}
|
|
52
|
+
return context;
|
|
53
|
+
}
|
|
93
54
|
|
|
94
|
-
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// Toolbar (root)
|
|
57
|
+
// ============================================================================
|
|
95
58
|
|
|
96
|
-
|
|
97
|
-
|
|
59
|
+
type ToolbarOwnProps = GetPropDefTypes<typeof toolbarRootPropDefs>;
|
|
60
|
+
|
|
61
|
+
interface ToolbarProps
|
|
62
|
+
extends ComponentPropsWithout<typeof ToolbarPrimitive.Root, RemovedProps | 'orientation'>,
|
|
63
|
+
ToolbarOwnProps,
|
|
64
|
+
MarginProps {}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* A row of controls with one keyboard tab stop. The arrow keys move focus between the controls.
|
|
68
|
+
*
|
|
69
|
+
* Give it an `aria-label` (or `aria-labelledby`) that says what the controls act on.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* <Toolbar aria-label="Formatting">
|
|
74
|
+
* <ToolbarGroup>
|
|
75
|
+
* <ToolbarButton iconOnly aria-label="Bold" aria-pressed={bold} onClick={toggleBold}>
|
|
76
|
+
* <HugeiconsIcon icon={TextBoldIcon} strokeWidth={1.75} />
|
|
77
|
+
* </ToolbarButton>
|
|
78
|
+
* </ToolbarGroup>
|
|
79
|
+
* <ToolbarSeparator />
|
|
80
|
+
* <ToolbarButton>Share</ToolbarButton>
|
|
81
|
+
* </Toolbar>
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
const ToolbarRoot = React.forwardRef<HTMLDivElement, ToolbarProps>((props, forwardedRef) => {
|
|
85
|
+
const size: ToolbarSize = props.size ?? toolbarRootPropDefs.size.default;
|
|
86
|
+
const orientation: ToolbarOrientation = props.orientation ?? toolbarRootPropDefs.orientation.default;
|
|
87
|
+
const { className, orientation: _orientation, children, ...rootProps } = extractProps(
|
|
88
|
+
props,
|
|
89
|
+
toolbarRootPropDefs,
|
|
90
|
+
marginPropDefs,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const context = React.useMemo(() => ({ size, orientation }), [size, orientation]);
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<ToolbarPrimitive.Root
|
|
97
|
+
{...rootProps}
|
|
98
|
+
ref={forwardedRef}
|
|
99
|
+
orientation={orientation}
|
|
100
|
+
className={classNames('rt-Toolbar', className)}
|
|
101
|
+
>
|
|
102
|
+
<ToolbarContext.Provider value={context}>{children}</ToolbarContext.Provider>
|
|
103
|
+
</ToolbarPrimitive.Root>
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
ToolbarRoot.displayName = 'Toolbar';
|
|
98
107
|
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// ToolbarGroup
|
|
110
|
+
// ============================================================================
|
|
101
111
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
112
|
+
interface ToolbarGroupProps extends ComponentPropsWithout<'div', RemovedProps> {
|
|
113
|
+
/** Turns every control in the group off at once. */
|
|
114
|
+
disabled?: boolean;
|
|
115
|
+
}
|
|
105
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Controls that belong together, drawn as one quiet well that stands level with a button
|
|
119
|
+
* beside it. Buttons inside it rest as `ghost` unless they state a `variant`.
|
|
120
|
+
* To cluster controls without a well, use a `Flex`.
|
|
121
|
+
*/
|
|
122
|
+
const ToolbarGroup = React.forwardRef<HTMLDivElement, ToolbarGroupProps>(
|
|
123
|
+
({ className, disabled = false, children, ...props }, forwardedRef) => {
|
|
124
|
+
const { orientation } = useToolbarContext('ToolbarGroup');
|
|
125
|
+
const group = React.useMemo(() => ({ disabled }), [disabled]);
|
|
106
126
|
return (
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
className={classNames('rt-Toolbar', className)}
|
|
115
|
-
style={computedStyle}
|
|
116
|
-
{...restProps}
|
|
127
|
+
<div
|
|
128
|
+
role="group"
|
|
129
|
+
data-orientation={orientation}
|
|
130
|
+
data-disabled={disabled || undefined}
|
|
131
|
+
{...props}
|
|
132
|
+
ref={forwardedRef}
|
|
133
|
+
className={classNames('rt-ToolbarGroup', className)}
|
|
117
134
|
>
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
</div>
|
|
121
|
-
</Card>
|
|
135
|
+
<ToolbarGroupContext.Provider value={group}>{children}</ToolbarGroupContext.Provider>
|
|
136
|
+
</div>
|
|
122
137
|
);
|
|
123
138
|
},
|
|
124
139
|
);
|
|
125
|
-
|
|
140
|
+
ToolbarGroup.displayName = 'Toolbar.Group';
|
|
126
141
|
|
|
127
142
|
// ============================================================================
|
|
128
|
-
//
|
|
143
|
+
// ToolbarButton
|
|
129
144
|
// ============================================================================
|
|
130
145
|
|
|
131
|
-
type
|
|
132
|
-
type ToolbarSectionProps = FlexProps;
|
|
146
|
+
type ToolbarButtonBaseProps = Omit<ButtonProps, 'as' | 'asChild'>;
|
|
133
147
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
align={align}
|
|
139
|
-
gap={gap}
|
|
140
|
-
className={classNames('rt-ToolbarSection', 'rt-ToolbarLeft', className)}
|
|
141
|
-
{...props}
|
|
142
|
-
>
|
|
143
|
-
{children}
|
|
144
|
-
</Flex>
|
|
145
|
-
),
|
|
146
|
-
);
|
|
147
|
-
ToolbarLeft.displayName = 'Toolbar.Left';
|
|
148
|
+
/** A labelled button: takes every `Button` prop. */
|
|
149
|
+
type ToolbarTextButtonProps = ToolbarButtonBaseProps & {
|
|
150
|
+
iconOnly?: false;
|
|
151
|
+
};
|
|
148
152
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
/** An icon-only button: renders an `IconButton`, and the type requires an `aria-label`. */
|
|
154
|
+
type ToolbarIconButtonProps = Omit<ToolbarButtonBaseProps, 'aria-label' | 'aria-labelledby' | 'overrideStyles'> & {
|
|
155
|
+
iconOnly: true;
|
|
156
|
+
/** The control's accessible name. An icon has no words of its own, so this is required. */
|
|
157
|
+
'aria-label': string;
|
|
158
|
+
};
|
|
152
159
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
);
|
|
167
|
-
|
|
160
|
+
type ToolbarButtonProps = ToolbarTextButtonProps | ToolbarIconButtonProps;
|
|
161
|
+
|
|
162
|
+
function isPressed(value: React.AriaAttributes['aria-pressed']) {
|
|
163
|
+
return value === true || value === 'true';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* A `Button` that joins the toolbar's keyboard navigation, so a row of them is one tab stop.
|
|
168
|
+
*
|
|
169
|
+
* Set `iconOnly` (with an `aria-label`) for a symbol-only control. Set `aria-pressed` for a
|
|
170
|
+
* control that toggles; a pressed button wears Button's pressed look.
|
|
171
|
+
*
|
|
172
|
+
* It takes the toolbar's `size`, and rests as a gray `soft` button (gray `ghost` inside a
|
|
173
|
+
* `ToolbarGroup`). A stated `size`, `variant` or `color` wins; a stated `variant` without a
|
|
174
|
+
* `color` takes Button's own default colour. It throws outside a `Toolbar`.
|
|
175
|
+
*/
|
|
176
|
+
const ToolbarButton = React.forwardRef<HTMLButtonElement, ToolbarButtonProps>((props, forwardedRef) => {
|
|
177
|
+
const toolbar = useToolbarContext('ToolbarButton');
|
|
178
|
+
const group = React.useContext(ToolbarGroupContext);
|
|
179
|
+
const { iconOnly, size, variant, color, disabled, ...rest } = props;
|
|
180
|
+
|
|
181
|
+
const pressed = isPressed(props['aria-pressed']);
|
|
182
|
+
const stateProps =
|
|
183
|
+
'data-state' in props || props['aria-pressed'] === undefined ? {} : { 'data-state': pressed ? 'on' : 'off' };
|
|
184
|
+
|
|
185
|
+
const shared = {
|
|
186
|
+
size: size ?? toolbar.size,
|
|
187
|
+
variant: variant ?? (group ? 'ghost' : 'soft'),
|
|
188
|
+
// The gray rest is a pair with the default variant: a caller who states a variant gets
|
|
189
|
+
// Button's own colour for it unless they state a colour too.
|
|
190
|
+
color: color ?? (variant ? undefined : 'gray'),
|
|
191
|
+
...stateProps,
|
|
192
|
+
} as const;
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<ToolbarPrimitive.Button asChild ref={forwardedRef} disabled={disabled || group?.disabled || undefined}>
|
|
196
|
+
{iconOnly ? (
|
|
197
|
+
<IconButton {...(rest as Omit<ToolbarIconButtonProps, 'iconOnly'>)} {...shared} />
|
|
198
|
+
) : (
|
|
199
|
+
<Button {...(rest as Omit<ToolbarTextButtonProps, 'iconOnly'>)} {...shared} />
|
|
200
|
+
)}
|
|
201
|
+
</ToolbarPrimitive.Button>
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
ToolbarButton.displayName = 'Toolbar.Button';
|
|
168
205
|
|
|
169
206
|
// ============================================================================
|
|
170
|
-
//
|
|
207
|
+
// ToolbarSeparator
|
|
171
208
|
// ============================================================================
|
|
172
209
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
210
|
+
type ToolbarSeparatorProps = ComponentPropsWithout<typeof ToolbarPrimitive.Separator, RemovedProps | 'orientation'>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* A gray hairline between two clusters, announced as a separator. Its direction is always
|
|
214
|
+
* opposite to the toolbar's.
|
|
215
|
+
*/
|
|
216
|
+
const ToolbarSeparator = React.forwardRef<HTMLDivElement, ToolbarSeparatorProps>(
|
|
217
|
+
({ className, ...props }, forwardedRef) => {
|
|
218
|
+
useToolbarContext('ToolbarSeparator');
|
|
219
|
+
return (
|
|
220
|
+
<ToolbarPrimitive.Separator
|
|
221
|
+
{...props}
|
|
222
|
+
ref={forwardedRef}
|
|
223
|
+
className={classNames('rt-ToolbarSeparator', className)}
|
|
224
|
+
/>
|
|
225
|
+
);
|
|
226
|
+
},
|
|
186
227
|
);
|
|
187
|
-
|
|
228
|
+
ToolbarSeparator.displayName = 'Toolbar.Separator';
|
|
188
229
|
|
|
189
230
|
// ============================================================================
|
|
190
|
-
//
|
|
231
|
+
// ToolbarTitle
|
|
191
232
|
// ============================================================================
|
|
192
233
|
|
|
193
|
-
|
|
194
|
-
|
|
234
|
+
/** The title's text step: one step above the label of a button at the same size. */
|
|
235
|
+
const TITLE_SIZE = { '1': '2', '2': '3', '3': '4', '4': '5' } as const satisfies Record<ToolbarSize, TextProps['size']>;
|
|
195
236
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
237
|
+
interface ToolbarTitleProps {
|
|
238
|
+
/** The title text. With none, the title renders nothing. */
|
|
239
|
+
children?: React.ReactNode;
|
|
240
|
+
className?: string;
|
|
241
|
+
style?: React.CSSProperties;
|
|
242
|
+
/** The id of the title, so that the toolbar's `aria-labelledby` can point at it. */
|
|
243
|
+
id?: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* What the row is about, at its leading edge. One line: it truncates rather than wrapping.
|
|
248
|
+
* Its text step follows the toolbar's `size`, and it takes more air from the controls beside it
|
|
249
|
+
* than they take from each other.
|
|
250
|
+
*/
|
|
251
|
+
const ToolbarTitle = React.forwardRef<HTMLSpanElement, ToolbarTitleProps>(
|
|
252
|
+
({ className, children, style, id }, forwardedRef) => {
|
|
253
|
+
const { size } = useToolbarContext('ToolbarTitle');
|
|
254
|
+
if (children === undefined || children === null || children === false) return null;
|
|
255
|
+
return (
|
|
256
|
+
<Text
|
|
257
|
+
ref={forwardedRef}
|
|
258
|
+
as="span"
|
|
259
|
+
size={TITLE_SIZE[size]}
|
|
260
|
+
weight="medium"
|
|
261
|
+
truncate
|
|
262
|
+
id={id}
|
|
263
|
+
style={style}
|
|
264
|
+
className={classNames('rt-ToolbarTitle', className)}
|
|
265
|
+
>
|
|
266
|
+
{children}
|
|
267
|
+
</Text>
|
|
268
|
+
);
|
|
269
|
+
},
|
|
209
270
|
);
|
|
210
271
|
ToolbarTitle.displayName = 'Toolbar.Title';
|
|
211
272
|
|
|
@@ -213,30 +274,35 @@ ToolbarTitle.displayName = 'Toolbar.Title';
|
|
|
213
274
|
// Exports
|
|
214
275
|
// ============================================================================
|
|
215
276
|
|
|
216
|
-
const Toolbar = ToolbarRoot
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
Toolbar.Left = ToolbarLeft;
|
|
224
|
-
Toolbar.Center = ToolbarCenter;
|
|
225
|
-
Toolbar.Right = ToolbarRight;
|
|
226
|
-
Toolbar.Title = ToolbarTitle;
|
|
277
|
+
const Toolbar = Object.assign(ToolbarRoot, {
|
|
278
|
+
Root: ToolbarRoot,
|
|
279
|
+
Group: ToolbarGroup,
|
|
280
|
+
Button: ToolbarButton,
|
|
281
|
+
Separator: ToolbarSeparator,
|
|
282
|
+
Title: ToolbarTitle,
|
|
283
|
+
});
|
|
227
284
|
|
|
228
285
|
export {
|
|
229
286
|
Toolbar,
|
|
287
|
+
ToolbarGroup,
|
|
288
|
+
ToolbarButton,
|
|
289
|
+
ToolbarSeparator,
|
|
290
|
+
ToolbarTitle,
|
|
230
291
|
ToolbarRoot as Root,
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
292
|
+
ToolbarGroup as Group,
|
|
293
|
+
ToolbarButton as Button,
|
|
294
|
+
ToolbarSeparator as Separator,
|
|
234
295
|
ToolbarTitle as Title,
|
|
235
296
|
};
|
|
236
297
|
export type {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
298
|
+
ToolbarProps,
|
|
299
|
+
ToolbarGroupProps,
|
|
300
|
+
ToolbarButtonProps,
|
|
301
|
+
ToolbarSeparatorProps,
|
|
302
|
+
ToolbarTitleProps,
|
|
303
|
+
ToolbarProps as RootProps,
|
|
304
|
+
ToolbarGroupProps as GroupProps,
|
|
305
|
+
ToolbarButtonProps as ButtonProps,
|
|
306
|
+
ToolbarSeparatorProps as SeparatorProps,
|
|
241
307
|
ToolbarTitleProps as TitleProps,
|
|
242
308
|
};
|
|
@@ -17,6 +17,25 @@
|
|
|
17
17
|
--color-dialog-solid: white;
|
|
18
18
|
--color-dialog-translucent: rgba(255, 255, 255, var(--dialog-opacity));
|
|
19
19
|
|
|
20
|
+
/*
|
|
21
|
+
* v2's names for the page, its text and its neutral scale, so code written against either
|
|
22
|
+
* system reads the same tokens. Aliases only: the values stay v1's and follow the appearance.
|
|
23
|
+
*/
|
|
24
|
+
--color-page: var(--color-background);
|
|
25
|
+
--color-text: var(--gray-12);
|
|
26
|
+
--neutral-1: var(--gray-1);
|
|
27
|
+
--neutral-2: var(--gray-2);
|
|
28
|
+
--neutral-3: var(--gray-3);
|
|
29
|
+
--neutral-4: var(--gray-4);
|
|
30
|
+
--neutral-5: var(--gray-5);
|
|
31
|
+
--neutral-6: var(--gray-6);
|
|
32
|
+
--neutral-7: var(--gray-7);
|
|
33
|
+
--neutral-8: var(--gray-8);
|
|
34
|
+
--neutral-9: var(--gray-9);
|
|
35
|
+
--neutral-10: var(--gray-10);
|
|
36
|
+
--neutral-11: var(--gray-11);
|
|
37
|
+
--neutral-12: var(--gray-12);
|
|
38
|
+
|
|
20
39
|
/* Material system defaults (solid) - controls color-mix blending for component backgrounds */
|
|
21
40
|
--material-blend: 100%;
|
|
22
41
|
--material-alpha: 0;
|