@zylem/ui 0.1.0 → 0.2.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/dist/chunk-VGOOWBSO.js +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +75 -2
- package/dist/index.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.js +1 -1
- package/package.json +13 -11
- package/src/components/Accordion/Accordion.tsx +60 -0
- package/src/components/Badge/Badge.css.ts +52 -0
- package/src/components/Badge/Badge.tsx +23 -0
- package/src/components/Button/Button.css.ts +127 -0
- package/src/components/Button/Button.tsx +34 -0
- package/src/components/Card/Card.css.ts +62 -0
- package/src/components/Card/Card.tsx +54 -0
- package/src/{global/checkbox.css.ts → components/Checkbox/Checkbox.css.ts} +23 -23
- package/src/components/Checkbox/Checkbox.tsx +41 -0
- package/src/components/Console/Console.css.ts +67 -0
- package/src/components/Console/Console.tsx +51 -0
- package/src/components/Dialog/Dialog.css.ts +86 -0
- package/src/components/Dialog/Dialog.tsx +89 -0
- package/src/components/DropdownMenu/DropdownMenu.css.ts +76 -0
- package/src/components/DropdownMenu/DropdownMenu.tsx +63 -0
- package/src/components/EmptyState/EmptyState.css.ts +29 -0
- package/src/components/EmptyState/EmptyState.tsx +32 -0
- package/src/components/Kbd/Kbd.css.ts +27 -0
- package/src/components/Kbd/Kbd.tsx +17 -0
- package/src/components/NumberField/NumberField.css.ts +47 -0
- package/src/components/NumberField/NumberField.tsx +66 -0
- package/src/components/Panel/Panel.css.ts +88 -0
- package/src/components/Panel/Panel.tsx +66 -0
- package/src/components/Progress/Progress.css.ts +51 -0
- package/src/components/Progress/Progress.tsx +43 -0
- package/src/components/Property/Property.css.ts +70 -0
- package/src/components/Property/Property.tsx +118 -0
- package/src/components/ScrollArea/ScrollArea.tsx +41 -0
- package/src/components/SearchInput/SearchInput.css.ts +25 -0
- package/src/components/SearchInput/SearchInput.tsx +31 -0
- package/src/components/Select/Select.css.ts +93 -0
- package/src/components/Select/Select.tsx +68 -0
- package/src/components/Separator/Separator.css.ts +22 -0
- package/src/components/Separator/Separator.tsx +18 -0
- package/src/components/Sidebar/Sidebar.css.ts +79 -0
- package/src/components/Sidebar/Sidebar.tsx +69 -0
- package/src/components/Slider/Slider.css.ts +91 -0
- package/src/components/Slider/Slider.tsx +51 -0
- package/src/components/Switch/Switch.css.ts +72 -0
- package/src/components/Switch/Switch.tsx +36 -0
- package/src/components/Tabs/Tabs.css.ts +70 -0
- package/src/components/Tabs/Tabs.tsx +79 -0
- package/src/components/TextField/TextField.css.ts +16 -0
- package/src/components/TextField/TextField.tsx +76 -0
- package/src/components/TitleBar/TitleBar.css.ts +46 -0
- package/src/components/TitleBar/TitleBar.tsx +60 -0
- package/src/components/Toolbar/Toolbar.css.ts +29 -0
- package/src/components/Toolbar/Toolbar.tsx +30 -0
- package/src/components/ToolbarButton/ToolbarButton.css.ts +67 -0
- package/src/components/ToolbarButton/ToolbarButton.tsx +42 -0
- package/src/components/Tooltip/Tooltip.css.ts +35 -0
- package/src/components/Tooltip/Tooltip.tsx +33 -0
- package/src/components/WindowControls/WindowControls.css.ts +59 -0
- package/src/components/WindowControls/WindowControls.tsx +51 -0
- package/src/components/index.ts +67 -6
- package/src/components/shared/field.css.ts +60 -0
- package/src/global/accordion.css.ts +32 -18
- package/src/global/common.css.ts +14 -17
- package/src/global/detached-panel.css.ts +31 -8
- package/src/global/editor-base.css.ts +96 -121
- package/src/global/entities.css.ts +19 -15
- package/src/global/hyperglass-base.css.ts +166 -0
- package/src/global/menu.css.ts +8 -3
- package/src/sprinkles.css.ts +22 -0
- package/src/styles.ts +32 -4
- package/src/theme.css.ts +190 -99
- package/dist/chunk-3R5KFBTB.js +0 -1
- package/src/components/Button.tsx +0 -19
- package/src/global/console.css.ts +0 -43
- package/src/global/sidebar.css.ts +0 -18
- package/src/global/toolbar.css.ts +0 -62
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
/** Owns the `.sidebar` / `.sidebar-item` classes (previously sidebar.css.ts). */
|
|
5
|
+
globalStyle('.sidebar', {
|
|
6
|
+
boxSizing: 'border-box',
|
|
7
|
+
display: 'flex',
|
|
8
|
+
flexDirection: 'column',
|
|
9
|
+
minHeight: 0,
|
|
10
|
+
height: '100%',
|
|
11
|
+
overflowY: 'auto',
|
|
12
|
+
background: vars.material.glassPanelDark,
|
|
13
|
+
borderRight: '1px solid rgba(97, 166, 232, 0.28)',
|
|
14
|
+
backdropFilter: `blur(${vars.effects.blurSm}) saturate(1.1)`,
|
|
15
|
+
'@supports': {
|
|
16
|
+
'not (backdrop-filter: blur(1px))': {
|
|
17
|
+
background: vars.colors.surface,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
globalStyle('.sidebar-section', {
|
|
23
|
+
display: 'flex',
|
|
24
|
+
flexDirection: 'column',
|
|
25
|
+
paddingBottom: vars.spacing.sm,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
globalStyle('.sidebar-section-title', {
|
|
29
|
+
padding: `${vars.spacing.sm} ${vars.spacing.md} ${vars.spacing.xs}`,
|
|
30
|
+
fontSize: '10px',
|
|
31
|
+
fontWeight: 700,
|
|
32
|
+
letterSpacing: '0.12em',
|
|
33
|
+
textTransform: 'uppercase',
|
|
34
|
+
color: vars.colors.textSecondary,
|
|
35
|
+
fontFamily: vars.typography.fontFamily,
|
|
36
|
+
userSelect: 'none',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
globalStyle('.sidebar-item', {
|
|
40
|
+
display: 'flex',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
gap: vars.spacing.sm,
|
|
43
|
+
padding: `${vars.spacing.xs} ${vars.spacing.md}`,
|
|
44
|
+
margin: `0 ${vars.spacing.xs}`,
|
|
45
|
+
borderRadius: vars.radii.control,
|
|
46
|
+
border: '1px solid transparent',
|
|
47
|
+
color: vars.colors.text,
|
|
48
|
+
fontFamily: vars.typography.fontFamily,
|
|
49
|
+
fontSize: vars.typography.fontSize,
|
|
50
|
+
cursor: 'pointer',
|
|
51
|
+
userSelect: 'none',
|
|
52
|
+
textDecoration: 'none',
|
|
53
|
+
background: 'none',
|
|
54
|
+
textAlign: 'left',
|
|
55
|
+
transition: `background ${vars.motion.fast} ${vars.motion.easeOut}, border-color ${vars.motion.fast} ${vars.motion.easeOut}`,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
globalStyle('.sidebar-item:hover', {
|
|
59
|
+
background: 'rgba(97, 166, 232, 0.12)',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
globalStyle('.sidebar-item[data-active], .sidebar-item.is-active', {
|
|
63
|
+
background: vars.material.buttonGlass,
|
|
64
|
+
border: '1px solid rgba(150, 210, 255, 0.5)',
|
|
65
|
+
boxShadow: vars.effects.shadowButton,
|
|
66
|
+
color: '#F4FAFF',
|
|
67
|
+
fontWeight: 600,
|
|
68
|
+
textShadow: '0 1px 1px rgba(0,0,0,0.6)',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
globalStyle('.sidebar-item:focus-visible', {
|
|
72
|
+
outline: 'none',
|
|
73
|
+
boxShadow: vars.effects.focusRing,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
globalStyle('.sidebar-item[disabled], .sidebar-item[data-disabled]', {
|
|
77
|
+
opacity: 0.45,
|
|
78
|
+
cursor: 'not-allowed',
|
|
79
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Show, splitProps } from 'solid-js';
|
|
2
|
+
import type { JSX } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
export interface SidebarProps extends JSX.HTMLAttributes<HTMLElement> {
|
|
5
|
+
children?: JSX.Element;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* HyperGlass sidebar: glass navigation rail. Compose with `SidebarSection`
|
|
10
|
+
* and `SidebarItem`.
|
|
11
|
+
*/
|
|
12
|
+
export function Sidebar(props: SidebarProps) {
|
|
13
|
+
const [local, rest] = splitProps(props, ['children', 'class']);
|
|
14
|
+
return (
|
|
15
|
+
<aside
|
|
16
|
+
class={local.class ? `sidebar zylem-scroll ${local.class}` : 'sidebar zylem-scroll'}
|
|
17
|
+
{...rest}
|
|
18
|
+
>
|
|
19
|
+
{local.children}
|
|
20
|
+
</aside>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SidebarSectionProps {
|
|
25
|
+
title?: JSX.Element;
|
|
26
|
+
children?: JSX.Element;
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function SidebarSection(props: SidebarSectionProps) {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
class={
|
|
34
|
+
props.class ? `sidebar-section ${props.class}` : 'sidebar-section'
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
<Show when={props.title}>
|
|
38
|
+
<div class="sidebar-section-title">{props.title}</div>
|
|
39
|
+
</Show>
|
|
40
|
+
{props.children}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SidebarItemProps
|
|
46
|
+
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
47
|
+
active?: boolean;
|
|
48
|
+
children?: JSX.Element;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function SidebarItem(props: SidebarItemProps) {
|
|
52
|
+
const [local, rest] = splitProps(props, ['active', 'children', 'class']);
|
|
53
|
+
return (
|
|
54
|
+
<button
|
|
55
|
+
type="button"
|
|
56
|
+
class={local.class ? `sidebar-item ${local.class}` : 'sidebar-item'}
|
|
57
|
+
data-active={local.active ? '' : undefined}
|
|
58
|
+
{...rest}
|
|
59
|
+
>
|
|
60
|
+
{local.children}
|
|
61
|
+
</button>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Sidebar.Section = SidebarSection;
|
|
66
|
+
Sidebar.Item = SidebarItem;
|
|
67
|
+
|
|
68
|
+
/** Class hook for anchor-based sidebar items (router links). */
|
|
69
|
+
export const sidebarItemClass = 'sidebar-item';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
globalStyle('.zylem-slider-root', {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
flexDirection: 'column',
|
|
7
|
+
gap: vars.spacing.xxs,
|
|
8
|
+
width: '100%',
|
|
9
|
+
userSelect: 'none',
|
|
10
|
+
touchAction: 'none',
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
globalStyle('.zylem-slider-root[data-disabled]', {
|
|
14
|
+
opacity: 0.5,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
globalStyle('.zylem-slider-header', {
|
|
18
|
+
display: 'flex',
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
justifyContent: 'space-between',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
globalStyle('.zylem-slider-label', {
|
|
24
|
+
fontSize: '11px',
|
|
25
|
+
letterSpacing: '0.08em',
|
|
26
|
+
textTransform: 'uppercase',
|
|
27
|
+
color: vars.colors.textSecondary,
|
|
28
|
+
fontFamily: vars.typography.fontFamily,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
globalStyle('.zylem-slider-value', {
|
|
32
|
+
fontSize: `calc(${vars.typography.fontSize} - 2px)`,
|
|
33
|
+
color: vars.colors.primary,
|
|
34
|
+
fontFamily: vars.typography.fontFamily,
|
|
35
|
+
fontVariantNumeric: 'tabular-nums',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
globalStyle('.zylem-slider-track', {
|
|
39
|
+
position: 'relative',
|
|
40
|
+
height: '8px',
|
|
41
|
+
width: '100%',
|
|
42
|
+
borderRadius: '999px',
|
|
43
|
+
border: '1px solid rgba(97, 166, 232, 0.28)',
|
|
44
|
+
background: vars.material.fieldGlass,
|
|
45
|
+
boxShadow: vars.effects.shadowInset,
|
|
46
|
+
cursor: 'pointer',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
globalStyle('.zylem-slider-fill', {
|
|
50
|
+
position: 'absolute',
|
|
51
|
+
height: '100%',
|
|
52
|
+
borderRadius: '999px',
|
|
53
|
+
background:
|
|
54
|
+
'linear-gradient(180deg, rgba(178, 219, 255, 0.65), rgba(48, 137, 220, 0.9))',
|
|
55
|
+
boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.45)',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
globalStyle('.zylem-slider-thumb', {
|
|
59
|
+
display: 'block',
|
|
60
|
+
width: '16px',
|
|
61
|
+
height: '16px',
|
|
62
|
+
top: '-5px',
|
|
63
|
+
borderRadius: '999px',
|
|
64
|
+
border: '1px solid rgba(255,255,255,0.5)',
|
|
65
|
+
background:
|
|
66
|
+
'linear-gradient(180deg, rgba(240,250,255,0.96), rgba(140,190,235,0.92))',
|
|
67
|
+
boxShadow: `inset 0 1px 0 rgba(255,255,255,0.75), 0 1px 4px rgba(0,0,0,0.5), ${vars.effects.glowPrimary}`,
|
|
68
|
+
cursor: 'grab',
|
|
69
|
+
outline: 'none',
|
|
70
|
+
transition: `box-shadow ${vars.motion.fast} ${vars.motion.easeOut}`,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
globalStyle('.zylem-slider-thumb:active', {
|
|
74
|
+
cursor: 'grabbing',
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
globalStyle('.zylem-slider-thumb:focus-visible', {
|
|
78
|
+
boxShadow: `inset 0 1px 0 rgba(255,255,255,0.75), ${vars.effects.focusRing}`,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
globalStyle('.zylem-slider-thumb-input', {
|
|
82
|
+
position: 'absolute',
|
|
83
|
+
width: '1px',
|
|
84
|
+
height: '1px',
|
|
85
|
+
padding: 0,
|
|
86
|
+
margin: '-1px',
|
|
87
|
+
overflow: 'hidden',
|
|
88
|
+
clip: 'rect(0, 0, 0, 0)',
|
|
89
|
+
whiteSpace: 'nowrap',
|
|
90
|
+
border: 0,
|
|
91
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Slider as KSlider } from '@kobalte/core';
|
|
2
|
+
import { Show } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
export interface SliderProps {
|
|
5
|
+
label?: string;
|
|
6
|
+
value?: number;
|
|
7
|
+
onChange?: (value: number) => void;
|
|
8
|
+
minValue?: number;
|
|
9
|
+
maxValue?: number;
|
|
10
|
+
step?: number;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
showValue?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* HyperGlass slider: inset glass track, blue glass fill, and a glowing
|
|
18
|
+
* glossy thumb.
|
|
19
|
+
*/
|
|
20
|
+
export function Slider(props: SliderProps) {
|
|
21
|
+
return (
|
|
22
|
+
<KSlider.Root
|
|
23
|
+
class={props.class ? `zylem-slider-root ${props.class}` : 'zylem-slider-root'}
|
|
24
|
+
value={props.value !== undefined ? [props.value] : undefined}
|
|
25
|
+
onChange={(values) => props.onChange?.(values[0])}
|
|
26
|
+
minValue={props.minValue}
|
|
27
|
+
maxValue={props.maxValue}
|
|
28
|
+
step={props.step}
|
|
29
|
+
disabled={props.disabled}
|
|
30
|
+
>
|
|
31
|
+
<Show when={props.label || props.showValue}>
|
|
32
|
+
<div class="zylem-slider-header">
|
|
33
|
+
<Show when={props.label}>
|
|
34
|
+
<KSlider.Label class="zylem-slider-label">
|
|
35
|
+
{props.label}
|
|
36
|
+
</KSlider.Label>
|
|
37
|
+
</Show>
|
|
38
|
+
<Show when={props.showValue}>
|
|
39
|
+
<KSlider.ValueLabel class="zylem-slider-value" />
|
|
40
|
+
</Show>
|
|
41
|
+
</div>
|
|
42
|
+
</Show>
|
|
43
|
+
<KSlider.Track class="zylem-slider-track">
|
|
44
|
+
<KSlider.Fill class="zylem-slider-fill" />
|
|
45
|
+
<KSlider.Thumb class="zylem-slider-thumb">
|
|
46
|
+
<KSlider.Input class="zylem-slider-thumb-input" />
|
|
47
|
+
</KSlider.Thumb>
|
|
48
|
+
</KSlider.Track>
|
|
49
|
+
</KSlider.Root>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
globalStyle('.zylem-switch-root', {
|
|
5
|
+
display: 'inline-flex',
|
|
6
|
+
alignItems: 'center',
|
|
7
|
+
gap: vars.spacing.sm,
|
|
8
|
+
cursor: 'pointer',
|
|
9
|
+
userSelect: 'none',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
globalStyle('.zylem-switch-root[data-disabled]', {
|
|
13
|
+
opacity: 0.5,
|
|
14
|
+
cursor: 'not-allowed',
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
globalStyle('.zylem-switch-input', {
|
|
18
|
+
position: 'absolute',
|
|
19
|
+
width: '1px',
|
|
20
|
+
height: '1px',
|
|
21
|
+
padding: 0,
|
|
22
|
+
margin: '-1px',
|
|
23
|
+
overflow: 'hidden',
|
|
24
|
+
clip: 'rect(0, 0, 0, 0)',
|
|
25
|
+
whiteSpace: 'nowrap',
|
|
26
|
+
border: 0,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
globalStyle('.zylem-switch-control', {
|
|
30
|
+
boxSizing: 'border-box',
|
|
31
|
+
width: '38px',
|
|
32
|
+
height: '20px',
|
|
33
|
+
borderRadius: '999px',
|
|
34
|
+
border: '1px solid rgba(97, 166, 232, 0.42)',
|
|
35
|
+
background: vars.material.fieldGlass,
|
|
36
|
+
boxShadow: vars.effects.shadowInset,
|
|
37
|
+
padding: '2px',
|
|
38
|
+
display: 'flex',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
transition: `background ${vars.motion.normal} ${vars.motion.easeOut}, box-shadow ${vars.motion.normal} ${vars.motion.easeOut}`,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
globalStyle('.zylem-switch-root[data-checked] .zylem-switch-control', {
|
|
44
|
+
background:
|
|
45
|
+
'linear-gradient(180deg, rgba(178, 219, 255, 0.3), rgba(30, 94, 148, 0.85))',
|
|
46
|
+
boxShadow: `${vars.effects.shadowInset}, ${vars.effects.glowPrimary}`,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
globalStyle('.zylem-switch-root:focus-within .zylem-switch-control', {
|
|
50
|
+
boxShadow: `${vars.effects.shadowInset}, ${vars.effects.focusRing}`,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
globalStyle('.zylem-switch-thumb', {
|
|
54
|
+
width: '14px',
|
|
55
|
+
height: '14px',
|
|
56
|
+
borderRadius: '999px',
|
|
57
|
+
border: '1px solid rgba(255,255,255,0.4)',
|
|
58
|
+
background:
|
|
59
|
+
'linear-gradient(180deg, rgba(240,250,255,0.95), rgba(160,200,235,0.9))',
|
|
60
|
+
boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.7), 0 1px 3px rgba(0,0,0,0.5)',
|
|
61
|
+
transition: `transform ${vars.motion.normal} ${vars.motion.easeOut}`,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
globalStyle('.zylem-switch-thumb[data-checked]', {
|
|
65
|
+
transform: 'translateX(18px)',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
globalStyle('.zylem-switch-label', {
|
|
69
|
+
fontFamily: vars.typography.fontFamily,
|
|
70
|
+
fontSize: vars.typography.fontSize,
|
|
71
|
+
color: vars.colors.text,
|
|
72
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Switch as KSwitch } from '@kobalte/core';
|
|
2
|
+
import { Show } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
export interface SwitchProps {
|
|
5
|
+
label?: string;
|
|
6
|
+
checked?: boolean;
|
|
7
|
+
defaultChecked?: boolean;
|
|
8
|
+
onChange?: (checked: boolean) => void;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
name?: string;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* HyperGlass switch: glass pill track with a glossy sliding thumb.
|
|
16
|
+
*/
|
|
17
|
+
export function Switch(props: SwitchProps) {
|
|
18
|
+
return (
|
|
19
|
+
<KSwitch.Root
|
|
20
|
+
class={props.class ? `zylem-switch-root ${props.class}` : 'zylem-switch-root'}
|
|
21
|
+
checked={props.checked}
|
|
22
|
+
defaultChecked={props.defaultChecked}
|
|
23
|
+
onChange={props.onChange}
|
|
24
|
+
disabled={props.disabled}
|
|
25
|
+
name={props.name}
|
|
26
|
+
>
|
|
27
|
+
<KSwitch.Input class="zylem-switch-input" />
|
|
28
|
+
<KSwitch.Control class="zylem-switch-control">
|
|
29
|
+
<KSwitch.Thumb class="zylem-switch-thumb" />
|
|
30
|
+
</KSwitch.Control>
|
|
31
|
+
<Show when={props.label}>
|
|
32
|
+
<KSwitch.Label class="zylem-switch-label">{props.label}</KSwitch.Label>
|
|
33
|
+
</Show>
|
|
34
|
+
</KSwitch.Root>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
globalStyle('.zylem-tabs-root', {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
flexDirection: 'column',
|
|
7
|
+
minHeight: 0,
|
|
8
|
+
width: '100%',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// Stack-card tab list: tabs read as cards peeking out of a stack.
|
|
12
|
+
globalStyle('.zylem-tabs-list', {
|
|
13
|
+
display: 'flex',
|
|
14
|
+
alignItems: 'flex-end',
|
|
15
|
+
gap: '3px',
|
|
16
|
+
position: 'relative',
|
|
17
|
+
padding: `${vars.spacing.xs} ${vars.spacing.xs} 0`,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
globalStyle('.zylem-tabs-trigger', {
|
|
21
|
+
display: 'inline-flex',
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
gap: vars.spacing.xs,
|
|
24
|
+
padding: `${vars.spacing.xs} ${vars.spacing.md}`,
|
|
25
|
+
borderRadius: `${vars.radii.button} ${vars.radii.button} 0 0`,
|
|
26
|
+
border: '1px solid rgba(97, 166, 232, 0.3)',
|
|
27
|
+
borderBottom: 'none',
|
|
28
|
+
background:
|
|
29
|
+
'linear-gradient(180deg, rgba(26, 31, 39, 0.6), rgba(10, 20, 30, 0.5))',
|
|
30
|
+
color: vars.colors.textSecondary,
|
|
31
|
+
fontFamily: vars.typography.fontFamily,
|
|
32
|
+
fontSize: `calc(${vars.typography.fontSize} - 1px)`,
|
|
33
|
+
fontWeight: 600,
|
|
34
|
+
cursor: 'pointer',
|
|
35
|
+
outline: 'none',
|
|
36
|
+
transition: `background ${vars.motion.fast} ${vars.motion.easeOut}, color ${vars.motion.fast} ${vars.motion.easeOut}`,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
globalStyle('.zylem-tabs-trigger:hover', {
|
|
40
|
+
color: vars.colors.text,
|
|
41
|
+
background:
|
|
42
|
+
'linear-gradient(180deg, rgba(38, 76, 112, 0.5), rgba(15, 39, 62, 0.45))',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
globalStyle('.zylem-tabs-trigger[data-selected]', {
|
|
46
|
+
color: '#F4FAFF',
|
|
47
|
+
background: vars.material.buttonGlass,
|
|
48
|
+
borderColor: 'rgba(150, 210, 255, 0.55)',
|
|
49
|
+
boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.35)',
|
|
50
|
+
textShadow: '0 1px 1px rgba(0,0,0,0.6)',
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
globalStyle('.zylem-tabs-trigger:focus-visible', {
|
|
54
|
+
boxShadow: vars.effects.focusRing,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
globalStyle('.zylem-tabs-trigger[data-disabled]', {
|
|
58
|
+
opacity: 0.45,
|
|
59
|
+
cursor: 'not-allowed',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
globalStyle('.zylem-tabs-content', {
|
|
63
|
+
flex: 1,
|
|
64
|
+
minHeight: 0,
|
|
65
|
+
borderRadius: `0 ${vars.radii.card} ${vars.radii.card} ${vars.radii.card}`,
|
|
66
|
+
border: '1px solid rgba(97, 166, 232, 0.3)',
|
|
67
|
+
background: vars.material.glassPanelDark,
|
|
68
|
+
padding: vars.spacing.md,
|
|
69
|
+
outline: 'none',
|
|
70
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Tabs as KTabs } from '@kobalte/core';
|
|
2
|
+
import type { JSX } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
export interface TabsProps {
|
|
5
|
+
value?: string;
|
|
6
|
+
onChange?: (value: string) => void;
|
|
7
|
+
defaultValue?: string;
|
|
8
|
+
class?: string;
|
|
9
|
+
children: JSX.Element;
|
|
10
|
+
'aria-label'?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* HyperGlass tabs: stack-card style tab strip over a glass content panel.
|
|
15
|
+
* Compose with `Tabs.List`, `Tabs.Trigger`, and `Tabs.Content`.
|
|
16
|
+
*/
|
|
17
|
+
export function Tabs(props: TabsProps) {
|
|
18
|
+
return (
|
|
19
|
+
<KTabs.Root
|
|
20
|
+
class={props.class ? `zylem-tabs-root ${props.class}` : 'zylem-tabs-root'}
|
|
21
|
+
value={props.value}
|
|
22
|
+
onChange={props.onChange}
|
|
23
|
+
defaultValue={props.defaultValue}
|
|
24
|
+
aria-label={props['aria-label']}
|
|
25
|
+
>
|
|
26
|
+
{props.children}
|
|
27
|
+
</KTabs.Root>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function TabsList(props: { children: JSX.Element; class?: string }) {
|
|
32
|
+
return (
|
|
33
|
+
<KTabs.List
|
|
34
|
+
class={props.class ? `zylem-tabs-list ${props.class}` : 'zylem-tabs-list'}
|
|
35
|
+
>
|
|
36
|
+
{props.children}
|
|
37
|
+
</KTabs.List>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function TabsTrigger(props: {
|
|
42
|
+
value: string;
|
|
43
|
+
children: JSX.Element;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
class?: string;
|
|
46
|
+
}) {
|
|
47
|
+
return (
|
|
48
|
+
<KTabs.Trigger
|
|
49
|
+
class={
|
|
50
|
+
props.class ? `zylem-tabs-trigger ${props.class}` : 'zylem-tabs-trigger'
|
|
51
|
+
}
|
|
52
|
+
value={props.value}
|
|
53
|
+
disabled={props.disabled}
|
|
54
|
+
>
|
|
55
|
+
{props.children}
|
|
56
|
+
</KTabs.Trigger>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function TabsContent(props: {
|
|
61
|
+
value: string;
|
|
62
|
+
children: JSX.Element;
|
|
63
|
+
class?: string;
|
|
64
|
+
}) {
|
|
65
|
+
return (
|
|
66
|
+
<KTabs.Content
|
|
67
|
+
class={
|
|
68
|
+
props.class ? `zylem-tabs-content ${props.class}` : 'zylem-tabs-content'
|
|
69
|
+
}
|
|
70
|
+
value={props.value}
|
|
71
|
+
>
|
|
72
|
+
{props.children}
|
|
73
|
+
</KTabs.Content>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Tabs.List = TabsList;
|
|
78
|
+
Tabs.Trigger = TabsTrigger;
|
|
79
|
+
Tabs.Content = TabsContent;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
import '../shared/field.css';
|
|
4
|
+
|
|
5
|
+
globalStyle('.zylem-textfield-input', {
|
|
6
|
+
width: '100%',
|
|
7
|
+
height: '28px',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
globalStyle('.zylem-textfield-textarea', {
|
|
11
|
+
width: '100%',
|
|
12
|
+
minHeight: '72px',
|
|
13
|
+
padding: vars.spacing.sm,
|
|
14
|
+
resize: 'vertical',
|
|
15
|
+
lineHeight: 1.45,
|
|
16
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { TextField as KTextField } from '@kobalte/core';
|
|
2
|
+
import { Show, splitProps } from 'solid-js';
|
|
3
|
+
import type { JSX } from 'solid-js';
|
|
4
|
+
|
|
5
|
+
export interface TextFieldProps {
|
|
6
|
+
label?: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
onChange?: (value: string) => void;
|
|
11
|
+
onInput?: JSX.EventHandlerUnion<HTMLInputElement | HTMLTextAreaElement, InputEvent>;
|
|
12
|
+
type?: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
readOnly?: boolean;
|
|
16
|
+
required?: boolean;
|
|
17
|
+
multiline?: boolean;
|
|
18
|
+
rows?: number;
|
|
19
|
+
class?: string;
|
|
20
|
+
autofocus?: boolean;
|
|
21
|
+
onKeyDown?: JSX.EventHandlerUnion<HTMLInputElement | HTMLTextAreaElement, KeyboardEvent>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* HyperGlass text field: inset glass input with an uppercase HyperCard-style
|
|
26
|
+
* label. Set `multiline` for a textarea.
|
|
27
|
+
*/
|
|
28
|
+
export function TextField(props: TextFieldProps) {
|
|
29
|
+
const [local] = splitProps(props, ['label', 'error', 'multiline', 'class']);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<KTextField.Root
|
|
33
|
+
class={local.class ? `zylem-field-root ${local.class}` : 'zylem-field-root'}
|
|
34
|
+
value={props.value}
|
|
35
|
+
onChange={props.onChange}
|
|
36
|
+
name={props.name}
|
|
37
|
+
disabled={props.disabled}
|
|
38
|
+
readOnly={props.readOnly}
|
|
39
|
+
required={props.required}
|
|
40
|
+
validationState={local.error ? 'invalid' : 'valid'}
|
|
41
|
+
>
|
|
42
|
+
<Show when={local.label}>
|
|
43
|
+
<KTextField.Label class="zylem-field-label">
|
|
44
|
+
{local.label}
|
|
45
|
+
</KTextField.Label>
|
|
46
|
+
</Show>
|
|
47
|
+
<Show
|
|
48
|
+
when={local.multiline}
|
|
49
|
+
fallback={
|
|
50
|
+
<KTextField.Input
|
|
51
|
+
class="zylem-field zylem-textfield-input"
|
|
52
|
+
type={props.type ?? 'text'}
|
|
53
|
+
placeholder={props.placeholder}
|
|
54
|
+
autofocus={props.autofocus}
|
|
55
|
+
onInput={props.onInput as JSX.EventHandlerUnion<HTMLInputElement, InputEvent>}
|
|
56
|
+
onKeyDown={props.onKeyDown as JSX.EventHandlerUnion<HTMLInputElement, KeyboardEvent>}
|
|
57
|
+
/>
|
|
58
|
+
}
|
|
59
|
+
>
|
|
60
|
+
<KTextField.TextArea
|
|
61
|
+
class="zylem-field zylem-textfield-textarea"
|
|
62
|
+
placeholder={props.placeholder}
|
|
63
|
+
rows={props.rows}
|
|
64
|
+
autofocus={props.autofocus}
|
|
65
|
+
onInput={props.onInput as JSX.EventHandlerUnion<HTMLTextAreaElement, InputEvent>}
|
|
66
|
+
onKeyDown={props.onKeyDown as JSX.EventHandlerUnion<HTMLTextAreaElement, KeyboardEvent>}
|
|
67
|
+
/>
|
|
68
|
+
</Show>
|
|
69
|
+
<Show when={local.error}>
|
|
70
|
+
<KTextField.ErrorMessage class="zylem-field-error">
|
|
71
|
+
{local.error}
|
|
72
|
+
</KTextField.ErrorMessage>
|
|
73
|
+
</Show>
|
|
74
|
+
</KTextField.Root>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Glossy molded title bar: vertical gradient glass with inner highlight,
|
|
6
|
+
* like a bar of molded glass rather than a flat web header.
|
|
7
|
+
*/
|
|
8
|
+
globalStyle('.zylem-titlebar', {
|
|
9
|
+
boxSizing: 'border-box',
|
|
10
|
+
minHeight: '42px',
|
|
11
|
+
display: 'flex',
|
|
12
|
+
alignItems: 'center',
|
|
13
|
+
gap: vars.spacing.sm,
|
|
14
|
+
padding: `0 ${vars.spacing.md}`,
|
|
15
|
+
background: vars.material.glossyBar,
|
|
16
|
+
borderBottom: '1px solid rgba(5, 18, 32, 0.85)',
|
|
17
|
+
boxShadow:
|
|
18
|
+
'inset 0 1px 0 rgba(255,255,255,0.62), inset 0 -1px 0 rgba(255,255,255,0.08)',
|
|
19
|
+
userSelect: 'none',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
globalStyle('.zylem-titlebar--compact', {
|
|
23
|
+
minHeight: '32px',
|
|
24
|
+
padding: `0 ${vars.spacing.sm}`,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
globalStyle('.zylem-titlebar-title', {
|
|
28
|
+
flex: 1,
|
|
29
|
+
fontSize: '13px',
|
|
30
|
+
fontWeight: 700,
|
|
31
|
+
letterSpacing: '0.02em',
|
|
32
|
+
color: '#F4FAFF',
|
|
33
|
+
fontFamily: vars.typography.fontFamily,
|
|
34
|
+
textShadow: '0 1px 1px rgba(0,0,0,0.65)',
|
|
35
|
+
overflow: 'hidden',
|
|
36
|
+
textOverflow: 'ellipsis',
|
|
37
|
+
whiteSpace: 'nowrap',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
globalStyle('.zylem-titlebar--draggable', {
|
|
41
|
+
cursor: 'grab',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
globalStyle('.zylem-titlebar--draggable:active', {
|
|
45
|
+
cursor: 'grabbing',
|
|
46
|
+
});
|