@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,51 @@
1
+ import { Show } from 'solid-js';
2
+ import type { JSX } from 'solid-js';
3
+ import { Button } from '../Button/Button';
4
+
5
+ export interface ConsoleProps {
6
+ /** Console text content. */
7
+ value: string;
8
+ /** Editable textarea input handler; omit for read-only display. */
9
+ onInput?: (value: string) => void;
10
+ onClear?: () => void;
11
+ readOnly?: boolean;
12
+ class?: string;
13
+ /** Extra action buttons rendered next to Clear. */
14
+ actions?: JSX.Element;
15
+ }
16
+
17
+ /**
18
+ * HyperGlass console: dark low-gloss terminal field with a floating Clear
19
+ * action.
20
+ */
21
+ export function Console(props: ConsoleProps) {
22
+ return (
23
+ <div
24
+ class={
25
+ props.class
26
+ ? `zylem-console-container ${props.class}`
27
+ : 'zylem-console-container'
28
+ }
29
+ >
30
+ <div class="zylem-console-wrapper">
31
+ <textarea
32
+ class="zylem-console zylem-scroll"
33
+ value={props.value}
34
+ spellcheck={false}
35
+ readOnly={props.readOnly || !props.onInput}
36
+ onInput={(event) => props.onInput?.(event.currentTarget.value)}
37
+ />
38
+ <Show when={props.onClear || props.actions}>
39
+ <div class="zylem-console-actions">
40
+ {props.actions}
41
+ <Show when={props.onClear}>
42
+ <Button size="sm" variant="ghost" onClick={() => props.onClear?.()}>
43
+ Clear
44
+ </Button>
45
+ </Show>
46
+ </div>
47
+ </Show>
48
+ </div>
49
+ </div>
50
+ );
51
+ }
@@ -0,0 +1,86 @@
1
+ import { globalStyle, keyframes } from '@vanilla-extract/css';
2
+ import { vars } from '../../theme.css';
3
+
4
+ const overlayEnter = keyframes({
5
+ from: { opacity: 0 },
6
+ to: { opacity: 1 },
7
+ });
8
+
9
+ const contentEnter = keyframes({
10
+ from: { opacity: 0, transform: 'translateY(8px) scale(0.98)' },
11
+ to: { opacity: 1, transform: 'translateY(0) scale(1)' },
12
+ });
13
+
14
+ globalStyle('.zylem-dialog-overlay', {
15
+ position: 'fixed',
16
+ inset: 0,
17
+ zIndex: 10000,
18
+ background: 'rgba(5, 10, 18, 0.6)',
19
+ backdropFilter: 'blur(3px)',
20
+ animation: `${overlayEnter} 0.15s ${vars.motion.easeOut}`,
21
+ });
22
+
23
+ globalStyle('.zylem-dialog-positioner', {
24
+ position: 'fixed',
25
+ inset: 0,
26
+ zIndex: 10001,
27
+ display: 'flex',
28
+ alignItems: 'center',
29
+ justifyContent: 'center',
30
+ padding: vars.spacing.lg,
31
+ });
32
+
33
+ globalStyle('.zylem-dialog-content', {
34
+ width: '100%',
35
+ maxWidth: '440px',
36
+ borderRadius: vars.radii.window,
37
+ border: '1px solid rgba(146, 205, 255, 0.54)',
38
+ background: vars.material.glassPanelDark,
39
+ boxShadow: vars.effects.shadowPanel,
40
+ backdropFilter: `blur(${vars.effects.blurMd}) saturate(1.22)`,
41
+ overflow: 'hidden',
42
+ animation: `${contentEnter} 0.16s ${vars.motion.easeOut}`,
43
+ '@supports': {
44
+ 'not (backdrop-filter: blur(1px))': {
45
+ background: vars.colors.surface,
46
+ },
47
+ },
48
+ });
49
+
50
+ globalStyle('.zylem-dialog-header', {
51
+ minHeight: '40px',
52
+ display: 'flex',
53
+ alignItems: 'center',
54
+ justifyContent: 'space-between',
55
+ gap: vars.spacing.sm,
56
+ padding: `0 ${vars.spacing.md}`,
57
+ background: vars.material.glossyBar,
58
+ borderBottom: '1px solid rgba(5, 18, 32, 0.85)',
59
+ boxShadow:
60
+ 'inset 0 1px 0 rgba(255,255,255,0.62), inset 0 -1px 0 rgba(255,255,255,0.08)',
61
+ });
62
+
63
+ globalStyle('.zylem-dialog-title', {
64
+ margin: 0,
65
+ fontSize: '13px',
66
+ fontWeight: 700,
67
+ letterSpacing: '0.02em',
68
+ color: '#F4FAFF',
69
+ fontFamily: vars.typography.fontFamily,
70
+ textShadow: '0 1px 1px rgba(0,0,0,0.65)',
71
+ });
72
+
73
+ globalStyle('.zylem-dialog-body', {
74
+ padding: vars.spacing.lg,
75
+ color: vars.colors.text,
76
+ fontFamily: vars.typography.fontFamily,
77
+ fontSize: vars.typography.fontSize,
78
+ lineHeight: 1.45,
79
+ });
80
+
81
+ globalStyle('.zylem-dialog-footer', {
82
+ display: 'flex',
83
+ justifyContent: 'flex-end',
84
+ gap: vars.spacing.sm,
85
+ padding: `0 ${vars.spacing.lg} ${vars.spacing.lg}`,
86
+ });
@@ -0,0 +1,89 @@
1
+ import { Dialog as KDialog } from '@kobalte/core';
2
+ import { Show } from 'solid-js';
3
+ import type { JSX } from 'solid-js';
4
+ import { Button } from '../Button/Button';
5
+ import { WindowControls } from '../WindowControls/WindowControls';
6
+
7
+ export interface DialogProps {
8
+ open?: boolean;
9
+ onOpenChange?: (open: boolean) => void;
10
+ title?: JSX.Element;
11
+ children: JSX.Element;
12
+ /** Optional footer content (e.g. action buttons). */
13
+ footer?: JSX.Element;
14
+ }
15
+
16
+ /**
17
+ * HyperGlass dialog: glass window with a glossy title bar and jewel close
18
+ * control, centered over a dimmed backdrop.
19
+ */
20
+ export function Dialog(props: DialogProps) {
21
+ return (
22
+ <KDialog.Root open={props.open} onOpenChange={props.onOpenChange}>
23
+ <KDialog.Portal>
24
+ <KDialog.Overlay class="zylem-dialog-overlay" />
25
+ <div class="zylem-dialog-positioner">
26
+ <KDialog.Content class="zylem-dialog-content">
27
+ <div class="zylem-dialog-header">
28
+ <Show when={props.title}>
29
+ <KDialog.Title class="zylem-dialog-title">
30
+ {props.title}
31
+ </KDialog.Title>
32
+ </Show>
33
+ <WindowControls onClose={() => props.onOpenChange?.(false)} />
34
+ </div>
35
+ <KDialog.Description as="div" class="zylem-dialog-body">
36
+ {props.children}
37
+ </KDialog.Description>
38
+ <Show when={props.footer}>
39
+ <div class="zylem-dialog-footer">{props.footer}</div>
40
+ </Show>
41
+ </KDialog.Content>
42
+ </div>
43
+ </KDialog.Portal>
44
+ </KDialog.Root>
45
+ );
46
+ }
47
+
48
+ export interface ConfirmDialogProps {
49
+ open: boolean;
50
+ onOpenChange: (open: boolean) => void;
51
+ title?: JSX.Element;
52
+ message: JSX.Element;
53
+ confirmLabel?: string;
54
+ cancelLabel?: string;
55
+ danger?: boolean;
56
+ onConfirm: () => void;
57
+ }
58
+
59
+ /**
60
+ * Confirmation dialog built on Dialog — a drop-in replacement for
61
+ * `window.confirm()` flows.
62
+ */
63
+ export function ConfirmDialog(props: ConfirmDialogProps) {
64
+ return (
65
+ <Dialog
66
+ open={props.open}
67
+ onOpenChange={props.onOpenChange}
68
+ title={props.title ?? 'Confirm'}
69
+ footer={
70
+ <>
71
+ <Button variant="ghost" onClick={() => props.onOpenChange(false)}>
72
+ {props.cancelLabel ?? 'Cancel'}
73
+ </Button>
74
+ <Button
75
+ variant={props.danger ? 'danger' : 'primary'}
76
+ onClick={() => {
77
+ props.onConfirm();
78
+ props.onOpenChange(false);
79
+ }}
80
+ >
81
+ {props.confirmLabel ?? 'Confirm'}
82
+ </Button>
83
+ </>
84
+ }
85
+ >
86
+ {props.message}
87
+ </Dialog>
88
+ );
89
+ }
@@ -0,0 +1,76 @@
1
+ import { globalStyle, keyframes } from '@vanilla-extract/css';
2
+ import { vars } from '../../theme.css';
3
+
4
+ const enter = keyframes({
5
+ from: { opacity: 0, transform: 'translateY(-4px)' },
6
+ to: { opacity: 1, transform: 'translateY(0)' },
7
+ });
8
+
9
+ globalStyle('.zylem-dropdown-content', {
10
+ zIndex: 10000,
11
+ minWidth: '180px',
12
+ padding: vars.spacing.xs,
13
+ borderRadius: vars.radii.control,
14
+ border: '1px solid rgba(97, 166, 232, 0.45)',
15
+ background: vars.material.glassPanelDark,
16
+ boxShadow: vars.effects.shadowPanel,
17
+ backdropFilter: `blur(${vars.effects.blurMd}) saturate(1.22)`,
18
+ outline: 'none',
19
+ '@supports': {
20
+ 'not (backdrop-filter: blur(1px))': {
21
+ background: vars.colors.surface,
22
+ },
23
+ },
24
+ });
25
+
26
+ globalStyle('.zylem-dropdown-content[data-expanded]', {
27
+ animation: `${enter} 0.12s ${vars.motion.easeOut}`,
28
+ });
29
+
30
+ globalStyle('.zylem-dropdown-item', {
31
+ display: 'flex',
32
+ alignItems: 'center',
33
+ justifyContent: 'space-between',
34
+ gap: vars.spacing.md,
35
+ padding: `${vars.spacing.xs} ${vars.spacing.sm}`,
36
+ borderRadius: '4px',
37
+ color: vars.colors.text,
38
+ fontFamily: vars.typography.fontFamily,
39
+ fontSize: vars.typography.fontSize,
40
+ cursor: 'pointer',
41
+ userSelect: 'none',
42
+ outline: 'none',
43
+ });
44
+
45
+ globalStyle('.zylem-dropdown-item[data-highlighted]', {
46
+ background: 'rgba(97, 166, 232, 0.22)',
47
+ color: '#F4FAFF',
48
+ });
49
+
50
+ globalStyle('.zylem-dropdown-item[data-disabled]', {
51
+ opacity: 0.45,
52
+ cursor: 'not-allowed',
53
+ });
54
+
55
+ globalStyle('.zylem-dropdown-item--danger', {
56
+ color: '#FF9C8F',
57
+ });
58
+
59
+ globalStyle('.zylem-dropdown-item--danger[data-highlighted]', {
60
+ background: 'rgba(230, 69, 52, 0.25)',
61
+ color: '#FFD9D3',
62
+ });
63
+
64
+ globalStyle('.zylem-dropdown-shortcut', {
65
+ fontSize: `calc(${vars.typography.fontSize} - 3px)`,
66
+ color: vars.colors.textSecondary,
67
+ letterSpacing: '0.06em',
68
+ });
69
+
70
+ globalStyle('.zylem-dropdown-separator', {
71
+ height: '1px',
72
+ border: 'none',
73
+ margin: `${vars.spacing.xs} ${vars.spacing.sm}`,
74
+ background:
75
+ 'linear-gradient(90deg, transparent, rgba(97, 166, 232, 0.35), transparent)',
76
+ });
@@ -0,0 +1,63 @@
1
+ import { DropdownMenu as KDropdownMenu } from '@kobalte/core';
2
+ import { For, Show } from 'solid-js';
3
+ import type { JSX } from 'solid-js';
4
+
5
+ export interface DropdownMenuItemConfig {
6
+ id: string;
7
+ label: JSX.Element;
8
+ onSelect?: () => void;
9
+ shortcut?: string;
10
+ disabled?: boolean;
11
+ danger?: boolean;
12
+ /** Render a separator line above this item. */
13
+ separatorAbove?: boolean;
14
+ }
15
+
16
+ export interface DropdownMenuProps {
17
+ /** Trigger element; rendered inside a Kobalte trigger button. */
18
+ trigger: JSX.Element;
19
+ items: DropdownMenuItemConfig[];
20
+ placement?: 'bottom-start' | 'bottom-end' | 'bottom' | 'top-start' | 'top-end' | 'top' | 'right-start' | 'left-start';
21
+ /** Class applied to the trigger button. */
22
+ triggerClass?: string;
23
+ }
24
+
25
+ /**
26
+ * HyperGlass dropdown menu: floating glass sheet with highlight rows.
27
+ */
28
+ export function DropdownMenu(props: DropdownMenuProps) {
29
+ return (
30
+ <KDropdownMenu.Root placement={props.placement ?? 'bottom-start'}>
31
+ <KDropdownMenu.Trigger class={props.triggerClass}>
32
+ {props.trigger}
33
+ </KDropdownMenu.Trigger>
34
+ <KDropdownMenu.Portal>
35
+ <KDropdownMenu.Content class="zylem-dropdown-content">
36
+ <For each={props.items}>
37
+ {(item) => (
38
+ <>
39
+ <Show when={item.separatorAbove}>
40
+ <KDropdownMenu.Separator class="zylem-dropdown-separator" />
41
+ </Show>
42
+ <KDropdownMenu.Item
43
+ class={
44
+ item.danger
45
+ ? 'zylem-dropdown-item zylem-dropdown-item--danger'
46
+ : 'zylem-dropdown-item'
47
+ }
48
+ disabled={item.disabled}
49
+ onSelect={item.onSelect}
50
+ >
51
+ <span>{item.label}</span>
52
+ <Show when={item.shortcut}>
53
+ <span class="zylem-dropdown-shortcut">{item.shortcut}</span>
54
+ </Show>
55
+ </KDropdownMenu.Item>
56
+ </>
57
+ )}
58
+ </For>
59
+ </KDropdownMenu.Content>
60
+ </KDropdownMenu.Portal>
61
+ </KDropdownMenu.Root>
62
+ );
63
+ }
@@ -0,0 +1,29 @@
1
+ import { globalStyle } from '@vanilla-extract/css';
2
+ import { vars } from '../../theme.css';
3
+
4
+ globalStyle('.zylem-empty-state', {
5
+ display: 'flex',
6
+ flexDirection: 'column',
7
+ alignItems: 'center',
8
+ justifyContent: 'center',
9
+ gap: vars.spacing.sm,
10
+ padding: vars.spacing.xl,
11
+ textAlign: 'center',
12
+ borderRadius: vars.radii.card,
13
+ border: '1px dashed rgba(97, 166, 232, 0.3)',
14
+ background: 'rgba(8, 19, 31, 0.3)',
15
+ color: vars.colors.textSecondary,
16
+ fontFamily: vars.typography.fontFamily,
17
+ });
18
+
19
+ globalStyle('.zylem-empty-state-title', {
20
+ fontSize: vars.typography.fontSize,
21
+ fontWeight: 600,
22
+ color: vars.colors.text,
23
+ });
24
+
25
+ globalStyle('.zylem-empty-state-message', {
26
+ fontSize: `calc(${vars.typography.fontSize} - 1px)`,
27
+ lineHeight: 1.45,
28
+ maxWidth: '360px',
29
+ });
@@ -0,0 +1,32 @@
1
+ import { Show } from 'solid-js';
2
+ import type { JSX } from 'solid-js';
3
+
4
+ export interface EmptyStateProps {
5
+ title?: JSX.Element;
6
+ children?: JSX.Element;
7
+ /** Optional action (e.g. a Button). */
8
+ action?: JSX.Element;
9
+ class?: string;
10
+ }
11
+
12
+ /**
13
+ * HyperGlass empty state: dashed glass placeholder card for empty lists and
14
+ * unbuilt modes.
15
+ */
16
+ export function EmptyState(props: EmptyStateProps) {
17
+ return (
18
+ <div
19
+ class={
20
+ props.class ? `zylem-empty-state ${props.class}` : 'zylem-empty-state'
21
+ }
22
+ >
23
+ <Show when={props.title}>
24
+ <div class="zylem-empty-state-title">{props.title}</div>
25
+ </Show>
26
+ <Show when={props.children}>
27
+ <div class="zylem-empty-state-message">{props.children}</div>
28
+ </Show>
29
+ {props.action}
30
+ </div>
31
+ );
32
+ }
@@ -0,0 +1,27 @@
1
+ import { globalStyle } from '@vanilla-extract/css';
2
+ import { vars } from '../../theme.css';
3
+
4
+ /**
5
+ * Keyboard hint chip: tiny beveled glass key cap.
6
+ */
7
+ globalStyle('.zylem-kbd', {
8
+ display: 'inline-flex',
9
+ alignItems: 'center',
10
+ justifyContent: 'center',
11
+ minWidth: '18px',
12
+ padding: `1px ${vars.spacing.xs}`,
13
+ borderRadius: '4px',
14
+ border: '1px solid rgba(97, 166, 232, 0.4)',
15
+ background:
16
+ 'linear-gradient(180deg, rgba(60, 85, 115, 0.7), rgba(20, 32, 48, 0.85))',
17
+ boxShadow:
18
+ 'inset 0 1px 0 rgba(255,255,255,0.28), inset 0 -1px 0 rgba(0,0,0,0.45), 0 1px 2px rgba(0,0,0,0.4)',
19
+ color: vars.colors.text,
20
+ fontFamily: vars.typography.fontFamily,
21
+ fontSize: '10px',
22
+ fontWeight: 700,
23
+ letterSpacing: '0.04em',
24
+ textTransform: 'uppercase',
25
+ userSelect: 'none',
26
+ whiteSpace: 'nowrap',
27
+ });
@@ -0,0 +1,17 @@
1
+ import type { JSX } from 'solid-js';
2
+
3
+ export interface KbdProps {
4
+ children: JSX.Element;
5
+ class?: string;
6
+ }
7
+
8
+ /**
9
+ * HyperGlass keyboard hint: tiny beveled glass key cap for shortcut hints.
10
+ */
11
+ export function Kbd(props: KbdProps) {
12
+ return (
13
+ <kbd class={props.class ? `zylem-kbd ${props.class}` : 'zylem-kbd'}>
14
+ {props.children}
15
+ </kbd>
16
+ );
17
+ }
@@ -0,0 +1,47 @@
1
+ import { globalStyle } from '@vanilla-extract/css';
2
+ import { vars } from '../../theme.css';
3
+ import '../shared/field.css';
4
+
5
+ globalStyle('.zylem-numberfield-group', {
6
+ display: 'inline-flex',
7
+ alignItems: 'stretch',
8
+ position: 'relative',
9
+ width: '100%',
10
+ });
11
+
12
+ globalStyle('.zylem-numberfield-input', {
13
+ width: '100%',
14
+ height: '28px',
15
+ paddingRight: '26px',
16
+ fontVariantNumeric: 'tabular-nums',
17
+ });
18
+
19
+ globalStyle('.zylem-numberfield-stepper', {
20
+ position: 'absolute',
21
+ right: '3px',
22
+ width: '20px',
23
+ height: '11px',
24
+ display: 'flex',
25
+ alignItems: 'center',
26
+ justifyContent: 'center',
27
+ cursor: 'pointer',
28
+ border: '1px solid rgba(150, 210, 255, 0.4)',
29
+ borderRadius: '4px',
30
+ background: vars.material.buttonGlass,
31
+ color: '#F4FAFF',
32
+ fontSize: '8px',
33
+ lineHeight: 1,
34
+ padding: 0,
35
+ transition: `filter ${vars.motion.fast} ${vars.motion.easeOut}`,
36
+ });
37
+
38
+ globalStyle('.zylem-numberfield-stepper:hover', {
39
+ filter: 'brightness(1.25)',
40
+ });
41
+
42
+ globalStyle('.zylem-numberfield-stepper:active', {
43
+ filter: 'brightness(0.85)',
44
+ });
45
+
46
+ globalStyle('.zylem-numberfield-stepper--up', { top: '3px' });
47
+ globalStyle('.zylem-numberfield-stepper--down', { bottom: '3px' });
@@ -0,0 +1,66 @@
1
+ import { NumberField as KNumberField } from '@kobalte/core';
2
+ import { Show } from 'solid-js';
3
+
4
+ export interface NumberFieldProps {
5
+ label?: string;
6
+ error?: string;
7
+ value?: number;
8
+ onChange?: (value: number) => void;
9
+ minValue?: number;
10
+ maxValue?: number;
11
+ step?: number;
12
+ disabled?: boolean;
13
+ placeholder?: string;
14
+ name?: string;
15
+ class?: string;
16
+ }
17
+
18
+ /**
19
+ * HyperGlass number field: inset glass input with square jewel steppers.
20
+ */
21
+ export function NumberField(props: NumberFieldProps) {
22
+ return (
23
+ <KNumberField.Root
24
+ class={props.class ? `zylem-field-root ${props.class}` : 'zylem-field-root'}
25
+ rawValue={props.value}
26
+ onRawValueChange={(value) => {
27
+ if (props.onChange && !Number.isNaN(value)) props.onChange(value);
28
+ }}
29
+ minValue={props.minValue}
30
+ maxValue={props.maxValue}
31
+ step={props.step}
32
+ disabled={props.disabled}
33
+ name={props.name}
34
+ validationState={props.error ? 'invalid' : 'valid'}
35
+ >
36
+ <Show when={props.label}>
37
+ <KNumberField.Label class="zylem-field-label">
38
+ {props.label}
39
+ </KNumberField.Label>
40
+ </Show>
41
+ <div class="zylem-numberfield-group">
42
+ <KNumberField.Input
43
+ class="zylem-field zylem-numberfield-input"
44
+ placeholder={props.placeholder}
45
+ />
46
+ <KNumberField.IncrementTrigger
47
+ class="zylem-numberfield-stepper zylem-numberfield-stepper--up"
48
+ aria-label="Increment"
49
+ >
50
+
51
+ </KNumberField.IncrementTrigger>
52
+ <KNumberField.DecrementTrigger
53
+ class="zylem-numberfield-stepper zylem-numberfield-stepper--down"
54
+ aria-label="Decrement"
55
+ >
56
+
57
+ </KNumberField.DecrementTrigger>
58
+ </div>
59
+ <Show when={props.error}>
60
+ <KNumberField.ErrorMessage class="zylem-field-error">
61
+ {props.error}
62
+ </KNumberField.ErrorMessage>
63
+ </Show>
64
+ </KNumberField.Root>
65
+ );
66
+ }
@@ -0,0 +1,88 @@
1
+ import { globalStyle } from '@vanilla-extract/css';
2
+ import { vars } from '../../theme.css';
3
+
4
+ /**
5
+ * Glass card: transparent panel with 1px electric-blue border, inner
6
+ * highlight, subtle blur, and rounded panel corners.
7
+ */
8
+ globalStyle('.zylem-panel', {
9
+ boxSizing: 'border-box',
10
+ display: 'flex',
11
+ flexDirection: 'column',
12
+ minHeight: 0,
13
+ borderRadius: vars.radii.panel,
14
+ border: '1px solid rgba(97, 166, 232, 0.38)',
15
+ background: vars.material.glassPanelDark,
16
+ boxShadow:
17
+ '0 16px 36px rgba(0,0,0,0.36), inset 0 1px 0 rgba(255,255,255,0.09)',
18
+ backdropFilter: `blur(${vars.effects.blurSm}) saturate(1.14)`,
19
+ overflow: 'hidden',
20
+ '@supports': {
21
+ 'not (backdrop-filter: blur(1px))': {
22
+ background: vars.colors.surface,
23
+ },
24
+ },
25
+ });
26
+
27
+ /**
28
+ * Borderless variant: drops the outline, outer shadow, and background so a
29
+ * panel can sit flush inside an already-outlined region (fewer outlines).
30
+ */
31
+ globalStyle('.zylem-panel--borderless', {
32
+ border: 'none',
33
+ borderRadius: 0,
34
+ background: 'transparent',
35
+ boxShadow: 'none',
36
+ backdropFilter: 'none',
37
+ '@supports': {
38
+ 'not (backdrop-filter: blur(1px))': {
39
+ background: 'transparent',
40
+ },
41
+ },
42
+ });
43
+
44
+ /** Brighter blue-glass variant for hero/window surfaces. */
45
+ globalStyle('.zylem-panel--window', {
46
+ borderRadius: vars.radii.window,
47
+ border: '1px solid rgba(146, 205, 255, 0.54)',
48
+ boxShadow: vars.effects.shadowPanel,
49
+ backdropFilter: `blur(${vars.effects.blurMd}) saturate(1.22)`,
50
+ });
51
+
52
+ /** Aqua-inspired glossy header strip for panels. */
53
+ globalStyle('.zylem-panel-header', {
54
+ boxSizing: 'border-box',
55
+ minHeight: '32px',
56
+ display: 'flex',
57
+ alignItems: 'center',
58
+ justifyContent: 'space-between',
59
+ gap: vars.spacing.sm,
60
+ padding: `0 ${vars.spacing.md}`,
61
+ borderBottom: '1px solid rgba(97, 166, 232, 0.22)',
62
+ background: vars.material.panelHeaderGloss,
63
+ boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.15)',
64
+ userSelect: 'none',
65
+ });
66
+
67
+ globalStyle('.zylem-panel-header-title', {
68
+ fontSize: '11px',
69
+ fontWeight: 700,
70
+ letterSpacing: '0.09em',
71
+ textTransform: 'uppercase',
72
+ color: vars.colors.text,
73
+ fontFamily: vars.typography.fontFamily,
74
+ textShadow: '0 1px 1px rgba(0,0,0,0.55)',
75
+ overflow: 'hidden',
76
+ textOverflow: 'ellipsis',
77
+ whiteSpace: 'nowrap',
78
+ });
79
+
80
+ globalStyle('.zylem-panel-body', {
81
+ flex: 1,
82
+ minHeight: 0,
83
+ padding: vars.spacing.md,
84
+ });
85
+
86
+ globalStyle('.zylem-panel-body--flush', {
87
+ padding: 0,
88
+ });