@zylem/ui 0.8.14 → 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.
- package/dist/chunk-YJVLOHJL.js +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.js +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.tsx +6 -1
- package/src/components/BuildLabel/BuildLabel.tsx +0 -1
- package/src/components/BuildLabel/mount-build-label.ts +0 -1
- package/src/components/Button/Button.css.ts +85 -66
- package/src/components/Button/Button.tsx +9 -3
- package/src/components/Callout/Callout.css.ts +1 -1
- package/src/components/Callout/Callout.tsx +1 -1
- package/src/components/Card/Card.css.ts +1 -0
- package/src/components/Card/Card.tsx +11 -2
- package/src/components/Checkbox/Checkbox.tsx +4 -2
- package/src/components/ColorPalette/ColorPalette.tsx +1 -1
- package/src/components/Console/Console.css.ts +1 -1
- package/src/components/Console/Console.tsx +3 -0
- package/src/components/Dialog/Dialog.css.ts +41 -17
- package/src/components/Dialog/Dialog.tsx +134 -53
- package/src/components/FrameStrip/FrameStrip.css.ts +1 -0
- package/src/components/FrameStrip/FrameStrip.tsx +2 -3
- package/src/components/ItemPicker/ItemPicker.tsx +46 -33
- package/src/components/MenuButton/MenuButton.css.ts +49 -46
- package/src/components/MenuButton/MenuButton.tsx +17 -5
- package/src/components/Menubar/Menubar.css.ts +1 -1
- package/src/components/Mixer/Knob.tsx +10 -3
- package/src/components/Mixer/Mixer.css.ts +21 -0
- package/src/components/Mixer/MixerStrip.tsx +29 -8
- package/src/components/NumberField/NumberField.css.ts +32 -26
- package/src/components/NumberField/NumberField.tsx +7 -2
- package/src/components/Panel/Panel.css.ts +1 -0
- package/src/components/Panel/Panel.tsx +9 -1
- package/src/components/PianoRoll/PianoRoll.tsx +1 -0
- package/src/components/Progress/Progress.css.ts +1 -1
- package/src/components/Progress/Progress.tsx +3 -0
- package/src/components/Property/Property.css.ts +13 -0
- package/src/components/Property/Property.tsx +3 -2
- package/src/components/SearchInput/SearchInput.tsx +1 -1
- package/src/components/Select/Select.css.ts +7 -1
- package/src/components/Select/Select.tsx +7 -2
- package/src/components/Sidebar/Sidebar.css.ts +1 -0
- package/src/components/Sidebar/Sidebar.tsx +23 -5
- package/src/components/Slider/Slider.css.ts +1 -1
- package/src/components/Slider/Slider.tsx +4 -2
- package/src/components/SpriteSizePicker/SpriteSizePicker.css.ts +2 -0
- package/src/components/Switch/Switch.tsx +3 -1
- package/src/components/Tabs/Tabs.css.ts +0 -5
- package/src/components/Tabs/Tabs.tsx +23 -12
- package/src/components/TextField/TextField.tsx +4 -0
- package/src/components/TimelineLanes/TimelineLanes.css.ts +7 -0
- package/src/components/TimelineLanes/TimelineLanes.tsx +52 -4
- package/src/components/TimelineLanes/lanes-math.ts +51 -0
- package/src/components/TimelineTrack/TimelineTrack.css.ts +3 -2
- package/src/components/TimelineTrack/TimelineTrack.tsx +16 -3
- package/src/components/TitleBar/TitleBar.css.ts +1 -0
- package/src/components/TitleBar/TitleBar.tsx +7 -1
- package/src/components/Toast/Toast.tsx +1 -2
- package/src/components/ToolButton/ToolButton.tsx +1 -1
- package/src/components/Toolbar/Toolbar.tsx +6 -1
- package/src/components/ToolbarButton/ToolbarButton.tsx +9 -2
- package/src/components/ToolboxButton/ToolboxButton.tsx +2 -1
- package/src/components/TrackHeader/TrackHeader.css.ts +21 -0
- package/src/components/TrackHeader/TrackHeader.tsx +37 -12
- package/src/components/TransportBar/TransportBar.css.ts +5 -0
- package/src/components/TransportBar/TransportBar.tsx +4 -1
- package/src/components/Waveform/Waveform.css.ts +10 -0
- package/src/components/Waveform/Waveform.tsx +59 -27
- package/src/components/WindowControls/WindowControls.css.ts +46 -63
- package/src/components/WindowControls/WindowControls.tsx +7 -6
- package/src/components/index.ts +1 -0
- package/src/components/shared/Heading.tsx +30 -0
- package/src/fonts.css +1 -1
- package/src/global/accordion.css.ts +9 -5
- package/src/global/common.css.ts +13 -0
- package/src/global/editor-base.css.ts +9 -0
- package/src/layers/LayerContext.tsx +2 -2
- package/src/sprinkles.css.ts +4 -1
- package/src/theme.css.ts +6 -0
- package/dist/chunk-V47CGFWX.js +0 -1
|
@@ -73,6 +73,7 @@ globalStyle('.zylem-knob-label', {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
globalStyle('.zylem-knob-value', {
|
|
76
|
+
fontFamily: vars.typography.fontFamilyMono,
|
|
76
77
|
fontSize: '10px',
|
|
77
78
|
fontVariantNumeric: 'tabular-nums',
|
|
78
79
|
color: vars.colors.text,
|
|
@@ -216,6 +217,7 @@ globalStyle('.zylem-mixer-meter-fill', {
|
|
|
216
217
|
});
|
|
217
218
|
|
|
218
219
|
globalStyle('.zylem-mixer-readout', {
|
|
220
|
+
fontFamily: vars.typography.fontFamilyMono,
|
|
219
221
|
fontSize: '10px',
|
|
220
222
|
fontVariantNumeric: 'tabular-nums',
|
|
221
223
|
color: vars.colors.textSecondary,
|
|
@@ -236,6 +238,25 @@ globalStyle('.zylem-mixer-name', {
|
|
|
236
238
|
textOverflow: 'ellipsis',
|
|
237
239
|
});
|
|
238
240
|
|
|
241
|
+
// A selectable strip's name is a button that still reads as the name.
|
|
242
|
+
globalStyle('button.zylem-mixer-name', {
|
|
243
|
+
appearance: 'none',
|
|
244
|
+
margin: 0,
|
|
245
|
+
padding: 0,
|
|
246
|
+
border: 0,
|
|
247
|
+
background: 'none',
|
|
248
|
+
color: 'inherit',
|
|
249
|
+
fontFamily: 'inherit',
|
|
250
|
+
lineHeight: 'inherit',
|
|
251
|
+
cursor: 'inherit',
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
globalStyle('button.zylem-mixer-name:focus-visible', {
|
|
255
|
+
outline: 'none',
|
|
256
|
+
borderRadius: '3px',
|
|
257
|
+
boxShadow: vars.effects.focusRing,
|
|
258
|
+
});
|
|
259
|
+
|
|
239
260
|
globalStyle('.zylem-mixer-strip[data-muted] .zylem-mixer-name', {
|
|
240
261
|
color: vars.colors.textSecondary,
|
|
241
262
|
});
|
|
@@ -26,6 +26,7 @@ export interface MixerStripProps {
|
|
|
26
26
|
/** Wider strip with a stronger label; for the master bus. */
|
|
27
27
|
master?: boolean;
|
|
28
28
|
selected?: boolean;
|
|
29
|
+
/** Pointer down anywhere on the strip; given, the name is also a button for the keyboard. */
|
|
29
30
|
onSelect?: () => void;
|
|
30
31
|
disabled?: boolean;
|
|
31
32
|
class?: string;
|
|
@@ -52,6 +53,7 @@ export function formatPan(value: number): string {
|
|
|
52
53
|
export function MixerStrip(props: MixerStripProps) {
|
|
53
54
|
const min = () => props.minVolume ?? -60;
|
|
54
55
|
const max = () => props.maxVolume ?? 6;
|
|
56
|
+
const volumeText = () => formatDb(clamp(props.volume, min(), max()), min());
|
|
55
57
|
|
|
56
58
|
return (
|
|
57
59
|
<div
|
|
@@ -61,6 +63,8 @@ export function MixerStrip(props: MixerStripProps) {
|
|
|
61
63
|
data-selected={props.selected ? '' : undefined}
|
|
62
64
|
data-disabled={props.disabled ? '' : undefined}
|
|
63
65
|
data-muted={props.muted ? '' : undefined}
|
|
66
|
+
role="group"
|
|
67
|
+
aria-label={props.name}
|
|
64
68
|
onPointerDown={() => props.onSelect?.()}
|
|
65
69
|
>
|
|
66
70
|
<Show when={props.pan !== undefined}>
|
|
@@ -91,14 +95,13 @@ export function MixerStrip(props: MixerStripProps) {
|
|
|
91
95
|
disabled={props.disabled}
|
|
92
96
|
onChange={(values) => props.onVolumeChange?.(values[0] ?? min())}
|
|
93
97
|
onChangeEnd={(values) => props.onVolumeCommit?.(values[0] ?? min())}
|
|
94
|
-
getValueLabel={(params) => formatDb(params.values[0] ?? min(), min())}
|
|
95
98
|
>
|
|
96
99
|
<KSlider.Label class="zylem-fader-sr">{`${props.name} volume`}</KSlider.Label>
|
|
97
100
|
<KSlider.Track class="zylem-fader-track">
|
|
98
101
|
<KSlider.Fill class="zylem-fader-fill" />
|
|
99
102
|
<span class="zylem-fader-zero" aria-hidden="true" />
|
|
100
|
-
<KSlider.Thumb class="zylem-fader-thumb">
|
|
101
|
-
<KSlider.Input class="zylem-fader-sr" />
|
|
103
|
+
<KSlider.Thumb class="zylem-fader-thumb" aria-valuetext={volumeText()}>
|
|
104
|
+
<KSlider.Input class="zylem-fader-sr" aria-valuetext={volumeText()} />
|
|
102
105
|
</KSlider.Thumb>
|
|
103
106
|
</KSlider.Track>
|
|
104
107
|
</KSlider.Root>
|
|
@@ -117,7 +120,7 @@ export function MixerStrip(props: MixerStripProps) {
|
|
|
117
120
|
class="zylem-track-toggle"
|
|
118
121
|
data-kind="mute"
|
|
119
122
|
aria-pressed={props.muted ? 'true' : 'false'}
|
|
120
|
-
aria-label=
|
|
123
|
+
aria-label="Mute"
|
|
121
124
|
title={props.muted ? 'Unmute' : 'Mute'}
|
|
122
125
|
disabled={props.disabled}
|
|
123
126
|
onPointerDown={(event) => event.stopPropagation()}
|
|
@@ -132,7 +135,7 @@ export function MixerStrip(props: MixerStripProps) {
|
|
|
132
135
|
class="zylem-track-toggle"
|
|
133
136
|
data-kind="solo"
|
|
134
137
|
aria-pressed={props.solo ? 'true' : 'false'}
|
|
135
|
-
aria-label=
|
|
138
|
+
aria-label="Solo"
|
|
136
139
|
title={props.solo ? 'Unsolo' : 'Solo'}
|
|
137
140
|
disabled={props.disabled}
|
|
138
141
|
onPointerDown={(event) => event.stopPropagation()}
|
|
@@ -142,9 +145,27 @@ export function MixerStrip(props: MixerStripProps) {
|
|
|
142
145
|
</button>
|
|
143
146
|
</Show>
|
|
144
147
|
</div>
|
|
145
|
-
<
|
|
146
|
-
{props.
|
|
147
|
-
|
|
148
|
+
<Show
|
|
149
|
+
when={props.onSelect}
|
|
150
|
+
fallback={
|
|
151
|
+
<span class="zylem-mixer-name" title={props.name}>
|
|
152
|
+
{props.name}
|
|
153
|
+
</span>
|
|
154
|
+
}
|
|
155
|
+
>
|
|
156
|
+
<button
|
|
157
|
+
type="button"
|
|
158
|
+
class="zylem-mixer-name"
|
|
159
|
+
aria-current={props.selected ? 'true' : undefined}
|
|
160
|
+
title={props.name}
|
|
161
|
+
onClick={(event) => {
|
|
162
|
+
// The pointer selected on pointer down; keys and assistive tech click without one.
|
|
163
|
+
if (event.detail === 0) props.onSelect?.();
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
{props.name}
|
|
167
|
+
</button>
|
|
168
|
+
</Show>
|
|
148
169
|
</div>
|
|
149
170
|
);
|
|
150
171
|
}
|
|
@@ -3,45 +3,51 @@ import { vars } from '../../theme.css';
|
|
|
3
3
|
import '../shared/field.css';
|
|
4
4
|
|
|
5
5
|
globalStyle('.zylem-numberfield-group', {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
display: 'inline-flex',
|
|
7
|
+
alignItems: 'stretch',
|
|
8
|
+
position: 'relative',
|
|
9
|
+
width: '100%',
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
globalStyle('.zylem-numberfield-input', {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
width: '100%',
|
|
14
|
+
height: '28px',
|
|
15
|
+
paddingRight: '26px',
|
|
16
|
+
fontFamily: vars.typography.fontFamilyMono,
|
|
17
|
+
fontVariantNumeric: 'tabular-nums',
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
globalStyle('.zylem-numberfield-stepper', {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
transition: `filter ${vars.motion.fast} ${vars.motion.easeOut}`,
|
|
21
|
+
position: 'absolute',
|
|
22
|
+
right: '3px',
|
|
23
|
+
width: '20px',
|
|
24
|
+
height: '9px',
|
|
25
|
+
display: 'flex',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
justifyContent: 'center',
|
|
28
|
+
cursor: 'pointer',
|
|
29
|
+
border: '0.5px solid rgba(150, 210, 255, 0.4)',
|
|
30
|
+
borderRadius: '4px',
|
|
31
|
+
background: vars.material.buttonGlass,
|
|
32
|
+
color: '#F4FAFF',
|
|
33
|
+
lineHeight: 1,
|
|
34
|
+
padding: 0,
|
|
35
|
+
transition: `filter ${vars.motion.fast} ${vars.motion.easeOut}`,
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
globalStyle('.zylem-numberfield-stepper:hover', {
|
|
39
|
-
|
|
39
|
+
filter: 'brightness(1.25)',
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
globalStyle('.zylem-numberfield-stepper:active', {
|
|
43
|
-
|
|
43
|
+
filter: 'brightness(0.85)',
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
globalStyle('.zylem-numberfield-stepper--up', { top: '3px' });
|
|
47
47
|
globalStyle('.zylem-numberfield-stepper--down', { bottom: '3px' });
|
|
48
|
+
|
|
49
|
+
globalStyle('.zylem-numberfield-stepper svg', {
|
|
50
|
+
width: '10px',
|
|
51
|
+
height: '8px',
|
|
52
|
+
stroke: 'currentColor',
|
|
53
|
+
});
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { NumberField as KNumberField } from '@kobalte/core';
|
|
2
|
+
import ChevronDown from 'lucide-solid/icons/chevron-down';
|
|
3
|
+
import ChevronUp from 'lucide-solid/icons/chevron-up';
|
|
2
4
|
import { Show } from 'solid-js';
|
|
3
5
|
|
|
4
6
|
export interface NumberFieldProps {
|
|
5
7
|
label?: string;
|
|
8
|
+
/** Accessible name when there is no visible `label`. */
|
|
9
|
+
'aria-label'?: string;
|
|
6
10
|
error?: string;
|
|
7
11
|
value?: number;
|
|
8
12
|
onChange?: (value: number) => void;
|
|
@@ -45,19 +49,20 @@ export function NumberField(props: NumberFieldProps) {
|
|
|
45
49
|
<div class="zylem-numberfield-group">
|
|
46
50
|
<KNumberField.Input
|
|
47
51
|
class="zylem-field zylem-numberfield-input"
|
|
52
|
+
aria-label={props['aria-label']}
|
|
48
53
|
placeholder={props.placeholder}
|
|
49
54
|
/>
|
|
50
55
|
<KNumberField.IncrementTrigger
|
|
51
56
|
class="zylem-numberfield-stepper zylem-numberfield-stepper--up"
|
|
52
57
|
aria-label="Increment"
|
|
53
58
|
>
|
|
54
|
-
|
|
59
|
+
<ChevronUp aria-hidden="true" />
|
|
55
60
|
</KNumberField.IncrementTrigger>
|
|
56
61
|
<KNumberField.DecrementTrigger
|
|
57
62
|
class="zylem-numberfield-stepper zylem-numberfield-stepper--down"
|
|
58
63
|
aria-label="Decrement"
|
|
59
64
|
>
|
|
60
|
-
|
|
65
|
+
<ChevronDown aria-hidden="true" />
|
|
61
66
|
</KNumberField.DecrementTrigger>
|
|
62
67
|
</div>
|
|
63
68
|
<Show when={props.error}>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Show, splitProps } from 'solid-js';
|
|
2
2
|
import type { JSX } from 'solid-js';
|
|
3
|
+
import { Heading, type HeadingLevel } from '../shared/Heading';
|
|
3
4
|
|
|
4
5
|
export interface PanelProps
|
|
5
6
|
extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
6
7
|
/** Optional glossy header title. */
|
|
7
8
|
title?: JSX.Element;
|
|
9
|
+
/** Heading level of the title (default 2). */
|
|
10
|
+
headingLevel?: HeadingLevel;
|
|
8
11
|
/** Extra content rendered on the right side of the header. */
|
|
9
12
|
headerActions?: JSX.Element;
|
|
10
13
|
/** Use the brighter window-glass treatment. */
|
|
@@ -28,6 +31,7 @@ export interface PanelProps
|
|
|
28
31
|
export function Panel(props: PanelProps) {
|
|
29
32
|
const [local, rest] = splitProps(props, [
|
|
30
33
|
'title',
|
|
34
|
+
'headingLevel',
|
|
31
35
|
'headerActions',
|
|
32
36
|
'window',
|
|
33
37
|
'flush',
|
|
@@ -51,7 +55,11 @@ export function Panel(props: PanelProps) {
|
|
|
51
55
|
<div class={classes()} {...rest}>
|
|
52
56
|
<Show when={local.title || local.headerActions}>
|
|
53
57
|
<div class="zylem-panel-header">
|
|
54
|
-
<span class="zylem-panel-header-title"
|
|
58
|
+
<Show when={local.title} fallback={<span class="zylem-panel-header-title" />}>
|
|
59
|
+
<Heading level={local.headingLevel ?? 2} class="zylem-panel-header-title">
|
|
60
|
+
{local.title}
|
|
61
|
+
</Heading>
|
|
62
|
+
</Show>
|
|
55
63
|
{local.headerActions}
|
|
56
64
|
</div>
|
|
57
65
|
</Show>
|
|
@@ -219,6 +219,7 @@ export function PianoRoll(props: PianoRollProps) {
|
|
|
219
219
|
tabIndex={0}
|
|
220
220
|
role="application"
|
|
221
221
|
aria-label="Piano roll"
|
|
222
|
+
aria-disabled={props.disabled ? 'true' : undefined}
|
|
222
223
|
data-disabled={props.disabled ? '' : undefined}
|
|
223
224
|
data-dragging={dragging() ? '' : undefined}
|
|
224
225
|
onKeyDown={handleKeyDown}
|
|
@@ -25,7 +25,7 @@ globalStyle('.zylem-progress-label', {
|
|
|
25
25
|
globalStyle('.zylem-progress-value', {
|
|
26
26
|
fontSize: `calc(${vars.typography.fontSize} - 2px)`,
|
|
27
27
|
color: vars.colors.primary,
|
|
28
|
-
fontFamily: vars.typography.
|
|
28
|
+
fontFamily: vars.typography.fontFamilyMono,
|
|
29
29
|
fontVariantNumeric: 'tabular-nums',
|
|
30
30
|
});
|
|
31
31
|
|
|
@@ -6,6 +6,8 @@ export interface ProgressProps {
|
|
|
6
6
|
minValue?: number;
|
|
7
7
|
maxValue?: number;
|
|
8
8
|
label?: string;
|
|
9
|
+
/** Accessible name when there is no visible `label`. */
|
|
10
|
+
'aria-label'?: string;
|
|
9
11
|
showValue?: boolean;
|
|
10
12
|
indeterminate?: boolean;
|
|
11
13
|
class?: string;
|
|
@@ -22,6 +24,7 @@ export function Progress(props: ProgressProps) {
|
|
|
22
24
|
minValue={props.minValue}
|
|
23
25
|
maxValue={props.maxValue}
|
|
24
26
|
indeterminate={props.indeterminate}
|
|
27
|
+
aria-label={props['aria-label']}
|
|
25
28
|
>
|
|
26
29
|
<Show when={props.label || props.showValue}>
|
|
27
30
|
<div class="zylem-progress-header">
|
|
@@ -57,13 +57,26 @@ globalStyle('.zylem-property-value', {
|
|
|
57
57
|
whiteSpace: 'nowrap',
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
+
// A button that should read as the value text it stands in for.
|
|
60
61
|
globalStyle('.zylem-property-value--clickable', {
|
|
62
|
+
appearance: 'none',
|
|
63
|
+
margin: 0,
|
|
64
|
+
padding: 0,
|
|
65
|
+
border: 0,
|
|
66
|
+
background: 'none',
|
|
67
|
+
lineHeight: 'inherit',
|
|
68
|
+
textAlign: 'start',
|
|
61
69
|
cursor: 'pointer',
|
|
62
70
|
textDecoration: 'underline',
|
|
63
71
|
textDecorationStyle: 'dotted',
|
|
64
72
|
textUnderlineOffset: '2px',
|
|
65
73
|
});
|
|
66
74
|
|
|
75
|
+
globalStyle('.zylem-property-value--clickable:focus-visible', {
|
|
76
|
+
outline: 'none',
|
|
77
|
+
boxShadow: vars.effects.focusRing,
|
|
78
|
+
});
|
|
79
|
+
|
|
67
80
|
globalStyle('.zylem-property-value--clickable:hover', {
|
|
68
81
|
textDecorationStyle: 'solid',
|
|
69
82
|
color: vars.colors.active,
|
|
@@ -107,7 +107,8 @@ export function PropertyRow(props: PropertyRowProps) {
|
|
|
107
107
|
</span>
|
|
108
108
|
}
|
|
109
109
|
>
|
|
110
|
-
<
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
111
112
|
class={`zylem-property-value zylem-property-value--clickable ${props.valueClass ?? ''}`}
|
|
112
113
|
onClick={() => {
|
|
113
114
|
const fullValue = display().fullValue;
|
|
@@ -116,7 +117,7 @@ export function PropertyRow(props: PropertyRowProps) {
|
|
|
116
117
|
title="Click to reveal full path"
|
|
117
118
|
>
|
|
118
119
|
{display().element}
|
|
119
|
-
</
|
|
120
|
+
</button>
|
|
120
121
|
</Show>
|
|
121
122
|
</div>
|
|
122
123
|
);
|
|
@@ -18,7 +18,7 @@ export interface SearchInputProps {
|
|
|
18
18
|
export function SearchInput(props: SearchInputProps) {
|
|
19
19
|
return (
|
|
20
20
|
<div class={props.class ? `zylem-search ${props.class}` : 'zylem-search'}>
|
|
21
|
-
<Search class="zylem-search-icon" />
|
|
21
|
+
<Search class="zylem-search-icon" aria-hidden="true" />
|
|
22
22
|
<input
|
|
23
23
|
type="search"
|
|
24
24
|
ref={props.ref}
|
|
@@ -20,12 +20,18 @@ globalStyle('.zylem-select-value', {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
globalStyle('.zylem-select-icon', {
|
|
23
|
+
display: 'flex',
|
|
23
24
|
flexShrink: 0,
|
|
24
|
-
fontSize: '9px',
|
|
25
25
|
color: vars.colors.primary,
|
|
26
26
|
transition: `transform ${vars.motion.fast} ${vars.motion.easeOut}`,
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
globalStyle('.zylem-select-icon svg', {
|
|
30
|
+
width: '14px',
|
|
31
|
+
height: '14px',
|
|
32
|
+
stroke: 'currentColor',
|
|
33
|
+
});
|
|
34
|
+
|
|
29
35
|
globalStyle('.zylem-select-trigger[data-expanded] .zylem-select-icon', {
|
|
30
36
|
transform: 'rotate(180deg)',
|
|
31
37
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Select as KSelect } from '@kobalte/core';
|
|
2
|
+
import ChevronDown from 'lucide-solid/icons/chevron-down';
|
|
2
3
|
import { Show } from 'solid-js';
|
|
3
4
|
import { createDismissGuard, useLayer } from '../../layers';
|
|
4
5
|
|
|
@@ -13,6 +14,8 @@ export interface SelectProps {
|
|
|
13
14
|
value?: string;
|
|
14
15
|
onChange?: (value: string | null) => void;
|
|
15
16
|
label?: string;
|
|
17
|
+
/** Accessible name when there is no visible `label`. */
|
|
18
|
+
'aria-label'?: string;
|
|
16
19
|
placeholder?: string;
|
|
17
20
|
disabled?: boolean;
|
|
18
21
|
name?: string;
|
|
@@ -55,12 +58,14 @@ export function Select(props: SelectProps) {
|
|
|
55
58
|
<KSelect.Trigger
|
|
56
59
|
ref={layer.anchorRef}
|
|
57
60
|
class="zylem-field zylem-select-trigger"
|
|
58
|
-
aria-label={props
|
|
61
|
+
aria-label={props['aria-label']}
|
|
59
62
|
>
|
|
60
63
|
<KSelect.Value<SelectOption> class="zylem-select-value">
|
|
61
64
|
{(state) => state.selectedOption()?.label}
|
|
62
65
|
</KSelect.Value>
|
|
63
|
-
<KSelect.Icon class="zylem-select-icon"
|
|
66
|
+
<KSelect.Icon class="zylem-select-icon">
|
|
67
|
+
<ChevronDown aria-hidden="true" />
|
|
68
|
+
</KSelect.Icon>
|
|
64
69
|
</KSelect.Trigger>
|
|
65
70
|
<Show when={layer.mount()} keyed>
|
|
66
71
|
{(mount) => (
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import { Show, splitProps } from 'solid-js';
|
|
1
|
+
import { createUniqueId, Show, splitProps } from 'solid-js';
|
|
2
2
|
import type { JSX } from 'solid-js';
|
|
3
|
+
import { Dynamic } from 'solid-js/web';
|
|
4
|
+
import { Heading, type HeadingLevel } from '../shared/Heading';
|
|
3
5
|
|
|
4
6
|
export interface SidebarProps extends JSX.HTMLAttributes<HTMLElement> {
|
|
5
7
|
children?: JSX.Element;
|
|
8
|
+
/**
|
|
9
|
+
* Landmark element: `aside` (the default) for a rail beside the main
|
|
10
|
+
* content, `nav` when the rail is the page's navigation.
|
|
11
|
+
*/
|
|
12
|
+
as?: 'aside' | 'nav';
|
|
6
13
|
/**
|
|
7
14
|
* Drop the glass surface and trailing border so the list sits inside a
|
|
8
15
|
* panel that already draws them (an inspector rail, a dialog column).
|
|
@@ -16,34 +23,43 @@ export interface SidebarProps extends JSX.HTMLAttributes<HTMLElement> {
|
|
|
16
23
|
* and `SidebarItem`.
|
|
17
24
|
*/
|
|
18
25
|
export function Sidebar(props: SidebarProps) {
|
|
19
|
-
const [local, rest] = splitProps(props, ['children', 'class', 'borderless']);
|
|
26
|
+
const [local, rest] = splitProps(props, ['children', 'class', 'borderless', 'as']);
|
|
20
27
|
return (
|
|
21
|
-
<
|
|
28
|
+
<Dynamic
|
|
29
|
+
component={local.as ?? 'aside'}
|
|
22
30
|
class={['sidebar', 'zylem-scroll', local.borderless ? 'sidebar--borderless' : '', local.class ?? '']
|
|
23
31
|
.filter(Boolean)
|
|
24
32
|
.join(' ')}
|
|
25
33
|
{...rest}
|
|
26
34
|
>
|
|
27
35
|
{local.children}
|
|
28
|
-
</
|
|
36
|
+
</Dynamic>
|
|
29
37
|
);
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
export interface SidebarSectionProps {
|
|
33
41
|
title?: JSX.Element;
|
|
42
|
+
/** Heading level of the title (default 2). */
|
|
43
|
+
headingLevel?: HeadingLevel;
|
|
34
44
|
children?: JSX.Element;
|
|
35
45
|
class?: string;
|
|
36
46
|
}
|
|
37
47
|
|
|
48
|
+
/** A titled group of items; the title names the group for assistive tech. */
|
|
38
49
|
export function SidebarSection(props: SidebarSectionProps) {
|
|
50
|
+
const titleId = createUniqueId();
|
|
39
51
|
return (
|
|
40
52
|
<div
|
|
41
53
|
class={
|
|
42
54
|
props.class ? `sidebar-section ${props.class}` : 'sidebar-section'
|
|
43
55
|
}
|
|
56
|
+
role={props.title ? 'group' : undefined}
|
|
57
|
+
aria-labelledby={props.title ? titleId : undefined}
|
|
44
58
|
>
|
|
45
59
|
<Show when={props.title}>
|
|
46
|
-
<
|
|
60
|
+
<Heading level={props.headingLevel ?? 2} id={titleId} class="sidebar-section-title">
|
|
61
|
+
{props.title}
|
|
62
|
+
</Heading>
|
|
47
63
|
</Show>
|
|
48
64
|
{props.children}
|
|
49
65
|
</div>
|
|
@@ -52,6 +68,7 @@ export function SidebarSection(props: SidebarSectionProps) {
|
|
|
52
68
|
|
|
53
69
|
export interface SidebarItemProps
|
|
54
70
|
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
71
|
+
/** The current item; exposed as `aria-current="true"`. */
|
|
55
72
|
active?: boolean;
|
|
56
73
|
children?: JSX.Element;
|
|
57
74
|
}
|
|
@@ -63,6 +80,7 @@ export function SidebarItem(props: SidebarItemProps) {
|
|
|
63
80
|
type="button"
|
|
64
81
|
class={local.class ? `sidebar-item ${local.class}` : 'sidebar-item'}
|
|
65
82
|
data-active={local.active ? '' : undefined}
|
|
83
|
+
aria-current={local.active ? 'true' : undefined}
|
|
66
84
|
{...rest}
|
|
67
85
|
>
|
|
68
86
|
{local.children}
|
|
@@ -31,7 +31,7 @@ globalStyle('.zylem-slider-label', {
|
|
|
31
31
|
globalStyle('.zylem-slider-value', {
|
|
32
32
|
fontSize: `calc(${vars.typography.fontSize} - 2px)`,
|
|
33
33
|
color: vars.colors.primary,
|
|
34
|
-
fontFamily: vars.typography.
|
|
34
|
+
fontFamily: vars.typography.fontFamilyMono,
|
|
35
35
|
fontVariantNumeric: 'tabular-nums',
|
|
36
36
|
});
|
|
37
37
|
|
|
@@ -3,6 +3,8 @@ import { Show } from 'solid-js';
|
|
|
3
3
|
|
|
4
4
|
export interface SliderProps {
|
|
5
5
|
label?: string;
|
|
6
|
+
/** Accessible name when there is no visible `label`. */
|
|
7
|
+
'aria-label'?: string;
|
|
6
8
|
value?: number;
|
|
7
9
|
onChange?: (value: number) => void;
|
|
8
10
|
/**
|
|
@@ -48,8 +50,8 @@ export function Slider(props: SliderProps) {
|
|
|
48
50
|
</Show>
|
|
49
51
|
<KSlider.Track class="zylem-slider-track">
|
|
50
52
|
<KSlider.Fill class="zylem-slider-fill" />
|
|
51
|
-
<KSlider.Thumb class="zylem-slider-thumb">
|
|
52
|
-
<KSlider.Input class="zylem-slider-thumb-input" />
|
|
53
|
+
<KSlider.Thumb class="zylem-slider-thumb" aria-label={props['aria-label']}>
|
|
54
|
+
<KSlider.Input class="zylem-slider-thumb-input" aria-label={props['aria-label']} />
|
|
53
55
|
</KSlider.Thumb>
|
|
54
56
|
</KSlider.Track>
|
|
55
57
|
</KSlider.Root>
|
|
@@ -20,6 +20,7 @@ globalStyle('.zylem-size-picker-presets', {
|
|
|
20
20
|
|
|
21
21
|
globalStyle('.zylem-size-picker-presets .zylem-button', {
|
|
22
22
|
minWidth: '40px',
|
|
23
|
+
fontFamily: vars.typography.fontFamilyMono,
|
|
23
24
|
fontVariantNumeric: 'tabular-nums',
|
|
24
25
|
});
|
|
25
26
|
|
|
@@ -89,6 +90,7 @@ globalStyle('.zylem-size-picker-readout', {
|
|
|
89
90
|
position: 'absolute',
|
|
90
91
|
right: vars.spacing.sm,
|
|
91
92
|
bottom: vars.spacing.xs,
|
|
93
|
+
fontFamily: vars.typography.fontFamilyMono,
|
|
92
94
|
fontSize: `calc(${vars.typography.fontSize} - 2px)`,
|
|
93
95
|
fontVariantNumeric: 'tabular-nums',
|
|
94
96
|
color: vars.colors.primary,
|
|
@@ -3,6 +3,8 @@ import { Show } from 'solid-js';
|
|
|
3
3
|
|
|
4
4
|
export interface SwitchProps {
|
|
5
5
|
label?: string;
|
|
6
|
+
/** Accessible name when there is no visible `label`. */
|
|
7
|
+
'aria-label'?: string;
|
|
6
8
|
checked?: boolean;
|
|
7
9
|
defaultChecked?: boolean;
|
|
8
10
|
onChange?: (checked: boolean) => void;
|
|
@@ -24,7 +26,7 @@ export function Switch(props: SwitchProps) {
|
|
|
24
26
|
disabled={props.disabled}
|
|
25
27
|
name={props.name}
|
|
26
28
|
>
|
|
27
|
-
<KSwitch.Input class="zylem-switch-input" />
|
|
29
|
+
<KSwitch.Input class="zylem-switch-input" aria-label={props['aria-label']} />
|
|
28
30
|
<KSwitch.Control class="zylem-switch-control">
|
|
29
31
|
<KSwitch.Thumb class="zylem-switch-thumb" />
|
|
30
32
|
</KSwitch.Control>
|
|
@@ -102,11 +102,6 @@ globalStyle('.zylem-tabs-close:hover', {
|
|
|
102
102
|
color: '#FFF4F2',
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
globalStyle('.zylem-tabs-close:focus-visible', {
|
|
106
|
-
outline: 'none',
|
|
107
|
-
boxShadow: vars.effects.focusRing,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
105
|
globalStyle('.zylem-tabs-content', {
|
|
111
106
|
flex: 1,
|
|
112
107
|
minHeight: 0,
|