@zylem/ui 0.1.0 → 0.1.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.
Files changed (78) hide show
  1. package/dist/chunk-VGOOWBSO.js +1 -0
  2. package/dist/index.css +1 -1
  3. package/dist/index.d.ts +75 -2
  4. package/dist/index.js +1 -1
  5. package/dist/styles.css +1 -1
  6. package/dist/styles.js +1 -1
  7. package/package.json +7 -4
  8. package/src/components/Accordion/Accordion.tsx +60 -0
  9. package/src/components/Badge/Badge.css.ts +52 -0
  10. package/src/components/Badge/Badge.tsx +23 -0
  11. package/src/components/Button/Button.css.ts +124 -0
  12. package/src/components/Button/Button.tsx +34 -0
  13. package/src/components/Card/Card.css.ts +62 -0
  14. package/src/components/Card/Card.tsx +54 -0
  15. package/src/{global/checkbox.css.ts → components/Checkbox/Checkbox.css.ts} +23 -23
  16. package/src/components/Checkbox/Checkbox.tsx +41 -0
  17. package/src/components/Console/Console.css.ts +65 -0
  18. package/src/components/Console/Console.tsx +51 -0
  19. package/src/components/Dialog/Dialog.css.ts +86 -0
  20. package/src/components/Dialog/Dialog.tsx +89 -0
  21. package/src/components/DropdownMenu/DropdownMenu.css.ts +76 -0
  22. package/src/components/DropdownMenu/DropdownMenu.tsx +63 -0
  23. package/src/components/EmptyState/EmptyState.css.ts +29 -0
  24. package/src/components/EmptyState/EmptyState.tsx +32 -0
  25. package/src/components/Kbd/Kbd.css.ts +27 -0
  26. package/src/components/Kbd/Kbd.tsx +17 -0
  27. package/src/components/NumberField/NumberField.css.ts +47 -0
  28. package/src/components/NumberField/NumberField.tsx +66 -0
  29. package/src/components/Panel/Panel.css.ts +88 -0
  30. package/src/components/Panel/Panel.tsx +66 -0
  31. package/src/components/Progress/Progress.css.ts +51 -0
  32. package/src/components/Progress/Progress.tsx +43 -0
  33. package/src/components/Property/Property.css.ts +70 -0
  34. package/src/components/Property/Property.tsx +118 -0
  35. package/src/components/ScrollArea/ScrollArea.tsx +41 -0
  36. package/src/components/SearchInput/SearchInput.css.ts +25 -0
  37. package/src/components/SearchInput/SearchInput.tsx +31 -0
  38. package/src/components/Select/Select.css.ts +93 -0
  39. package/src/components/Select/Select.tsx +68 -0
  40. package/src/components/Separator/Separator.css.ts +22 -0
  41. package/src/components/Separator/Separator.tsx +18 -0
  42. package/src/components/Sidebar/Sidebar.css.ts +79 -0
  43. package/src/components/Sidebar/Sidebar.tsx +69 -0
  44. package/src/components/Slider/Slider.css.ts +91 -0
  45. package/src/components/Slider/Slider.tsx +51 -0
  46. package/src/components/Switch/Switch.css.ts +72 -0
  47. package/src/components/Switch/Switch.tsx +36 -0
  48. package/src/components/Tabs/Tabs.css.ts +70 -0
  49. package/src/components/Tabs/Tabs.tsx +79 -0
  50. package/src/components/TextField/TextField.css.ts +16 -0
  51. package/src/components/TextField/TextField.tsx +76 -0
  52. package/src/components/TitleBar/TitleBar.css.ts +46 -0
  53. package/src/components/TitleBar/TitleBar.tsx +60 -0
  54. package/src/components/Toolbar/Toolbar.css.ts +29 -0
  55. package/src/components/Toolbar/Toolbar.tsx +30 -0
  56. package/src/components/ToolbarButton/ToolbarButton.css.ts +64 -0
  57. package/src/components/ToolbarButton/ToolbarButton.tsx +42 -0
  58. package/src/components/Tooltip/Tooltip.css.ts +32 -0
  59. package/src/components/Tooltip/Tooltip.tsx +27 -0
  60. package/src/components/WindowControls/WindowControls.css.ts +59 -0
  61. package/src/components/WindowControls/WindowControls.tsx +51 -0
  62. package/src/components/index.ts +67 -6
  63. package/src/components/shared/field.css.ts +60 -0
  64. package/src/global/accordion.css.ts +32 -18
  65. package/src/global/common.css.ts +14 -17
  66. package/src/global/detached-panel.css.ts +31 -8
  67. package/src/global/editor-base.css.ts +72 -119
  68. package/src/global/entities.css.ts +19 -15
  69. package/src/global/hyperglass-base.css.ts +91 -0
  70. package/src/global/menu.css.ts +8 -3
  71. package/src/sprinkles.css.ts +22 -0
  72. package/src/styles.ts +32 -4
  73. package/src/theme.css.ts +190 -99
  74. package/dist/chunk-3R5KFBTB.js +0 -1
  75. package/src/components/Button.tsx +0 -19
  76. package/src/global/console.css.ts +0 -43
  77. package/src/global/sidebar.css.ts +0 -18
  78. 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
+ });