doom-design-system 0.4.14 → 0.4.15
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/components/Alert/Alert.js +2 -1
- package/dist/components/Chart/Chart.module.css +37 -9
- package/dist/components/Drawer/Drawer.module.css +38 -14
- package/dist/components/Form/Form.module.css +1 -1
- package/dist/components/Image/Image.js +21 -18
- package/dist/components/Modal/Modal.module.css +41 -23
- package/dist/components/Sheet/Sheet.js +65 -2
- package/dist/components/Sheet/Sheet.module.css +45 -20
- package/dist/components/Skeleton/Skeleton.module.css +1 -1
- package/dist/styles/themes/ThemeProvider.js +6 -4
- package/dist/styles/themes/definitions.d.ts +41 -5
- package/dist/styles/themes/definitions.js +25 -4
- package/dist/styles/themes/solid-tokens.d.ts +21 -0
- package/dist/styles/themes/solid-tokens.js +19 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { AlertCircle, CheckCircle, Info, XCircle } from "lucide-react";
|
|
5
|
+
import { Text } from "../Text/Text.js";
|
|
5
6
|
import styles from "./Alert.module.css";
|
|
6
7
|
const icons = {
|
|
7
8
|
info: Info,
|
|
@@ -11,5 +12,5 @@ const icons = {
|
|
|
11
12
|
};
|
|
12
13
|
export function Alert({ variant = "info", title, description, icon, className, }) {
|
|
13
14
|
const IconComponent = icons[variant];
|
|
14
|
-
return (_jsxs("div", { className: clsx(styles.alert, styles[variant], className), role: "alert", children: [_jsx("div", { className: clsx(styles.iconWrapper, styles[variant]), children: icon || _jsx(IconComponent, { size: 20, strokeWidth: 2.5 }) }), _jsxs("div", { className: styles.content, children: [_jsx("
|
|
15
|
+
return (_jsxs("div", { className: clsx(styles.alert, styles[variant], className), role: "alert", children: [_jsx("div", { className: clsx(styles.iconWrapper, styles[variant]), children: icon || _jsx(IconComponent, { size: 20, strokeWidth: 2.5 }) }), _jsxs("div", { className: styles.content, children: [_jsx(Text, { as: "h1", className: styles.title, variant: "h5", children: title }), description && (_jsx(Text, { as: "p", className: styles.description, variant: "body", children: description }))] })] }));
|
|
15
16
|
}
|
|
@@ -104,20 +104,48 @@
|
|
|
104
104
|
padding: 0;
|
|
105
105
|
}
|
|
106
106
|
.chartContainer.solid {
|
|
107
|
-
|
|
108
|
-
--solid-fg: var(--primary-foreground);
|
|
107
|
+
/* ROOT CONTEXT (The Field) */
|
|
109
108
|
background-color: var(--solid-bg);
|
|
110
109
|
color: var(--solid-fg);
|
|
111
|
-
|
|
112
|
-
--text-primary: var(--solid-fg);
|
|
113
|
-
--muted-foreground: color-mix(in srgb, var(--solid-fg) 70%, transparent);
|
|
114
|
-
--muted: color-mix(in srgb, var(--solid-fg) 20%, transparent);
|
|
110
|
+
/* Root Variables */
|
|
115
111
|
--background: var(--solid-bg);
|
|
116
112
|
--foreground: var(--solid-fg);
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
--muted-foreground: color-mix(in srgb, var(--solid-fg) 70%, transparent);
|
|
114
|
+
/*
|
|
115
|
+
* Standardized Brand Surface Logic
|
|
116
|
+
* Decouples Modals (Surface) from Buttons (Action)
|
|
117
|
+
*/
|
|
118
|
+
--surface-brand: var(--solid-bg);
|
|
119
|
+
--surface-brand-foreground: var(--solid-fg);
|
|
120
|
+
/* SEMANTICS (True Semantic Colors) */
|
|
121
|
+
--success: var(--solid-success);
|
|
122
|
+
--success-foreground: var(--solid-fg);
|
|
123
|
+
--error: var(--solid-error);
|
|
124
|
+
--error-foreground: var(--solid-fg);
|
|
125
|
+
--warning: var(--solid-warning);
|
|
126
|
+
--warning-foreground: var(--solid-fg);
|
|
127
|
+
/* SURFACE COLORS */
|
|
128
|
+
--on-surface: var(--solid-bg);
|
|
129
|
+
--on-surface-muted: var(--solid-bg);
|
|
130
|
+
/* COMPONENT TOKENS */
|
|
131
|
+
--card-bg: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
132
|
+
--card-border: var(--solid-fg);
|
|
133
|
+
--card-foreground: var(--solid-fg);
|
|
134
|
+
/* POPOVER TOKENS */
|
|
135
|
+
--popover: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
136
|
+
--popover-foreground: var(--solid-bg);
|
|
137
|
+
/* INPUT TOKENS */
|
|
138
|
+
--input: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
139
|
+
--border-strong: var(--solid-fg);
|
|
140
|
+
/* BUTTON TOKENS */
|
|
119
141
|
--primary: var(--solid-fg);
|
|
120
|
-
--primary-
|
|
142
|
+
--primary-foreground: var(--solid-bg);
|
|
143
|
+
/* SECONDARY TOKENS */
|
|
144
|
+
--secondary: color-mix(in srgb, var(--solid-bg) 90%, transparent);
|
|
145
|
+
--secondary-foreground: var(--solid-fg);
|
|
146
|
+
/* MUTED TOKENS */
|
|
147
|
+
--muted: color-mix(in srgb, var(--solid-fg) 20%, transparent);
|
|
148
|
+
border-color: var(--border-strong);
|
|
121
149
|
}
|
|
122
150
|
.chartContainer.solid :global(.tick) text {
|
|
123
151
|
fill: var(--solid-fg);
|
|
@@ -56,29 +56,53 @@
|
|
|
56
56
|
transform: translateX(0);
|
|
57
57
|
}
|
|
58
58
|
.panel.solid {
|
|
59
|
-
/*
|
|
60
|
-
SCALABLE CONTEXTUAL REMAPPING
|
|
61
|
-
Save original values then swap semantic tokens to auto-invert content.
|
|
62
|
-
*/
|
|
63
|
-
--solid-bg: var(--primary);
|
|
64
|
-
--solid-fg: var(--primary-foreground);
|
|
59
|
+
/* ROOT CONTEXT (The Field) */
|
|
65
60
|
background-color: var(--solid-bg);
|
|
66
61
|
color: var(--solid-fg);
|
|
67
|
-
/*
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
/* Root Variables */
|
|
63
|
+
--background: var(--solid-bg);
|
|
64
|
+
--foreground: var(--solid-fg);
|
|
65
|
+
--muted-foreground: color-mix(in srgb, var(--solid-fg) 70%, transparent);
|
|
66
|
+
/*
|
|
67
|
+
* Standardized Brand Surface Logic
|
|
68
|
+
* Decouples Modals (Surface) from Buttons (Action)
|
|
69
|
+
*/
|
|
70
|
+
--surface-brand: var(--solid-bg);
|
|
71
|
+
--surface-brand-foreground: var(--solid-fg);
|
|
72
|
+
/* SEMANTICS (True Semantic Colors) */
|
|
73
|
+
--success: var(--solid-success);
|
|
74
|
+
--success-foreground: var(--solid-fg);
|
|
75
|
+
--error: var(--solid-error);
|
|
76
|
+
--error-foreground: var(--solid-fg);
|
|
77
|
+
--warning: var(--solid-warning);
|
|
78
|
+
--warning-foreground: var(--solid-fg);
|
|
79
|
+
/* SURFACE COLORS */
|
|
80
|
+
--on-surface: var(--solid-bg);
|
|
81
|
+
--on-surface-muted: var(--solid-bg);
|
|
82
|
+
/* COMPONENT TOKENS */
|
|
83
|
+
--card-bg: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
84
|
+
--card-border: var(--solid-fg);
|
|
85
|
+
--card-foreground: var(--solid-fg);
|
|
86
|
+
/* POPOVER TOKENS */
|
|
87
|
+
--popover: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
88
|
+
--popover-foreground: var(--solid-bg);
|
|
89
|
+
/* INPUT TOKENS */
|
|
90
|
+
--input: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
91
|
+
--border-strong: var(--solid-fg);
|
|
92
|
+
/* BUTTON TOKENS */
|
|
70
93
|
--primary: var(--solid-fg);
|
|
71
94
|
--primary-foreground: var(--solid-bg);
|
|
72
|
-
|
|
73
|
-
--
|
|
95
|
+
/* SECONDARY TOKENS */
|
|
96
|
+
--secondary: color-mix(in srgb, var(--solid-bg) 90%, transparent);
|
|
97
|
+
--secondary-foreground: var(--solid-fg);
|
|
98
|
+
/* MUTED TOKENS */
|
|
99
|
+
--muted: color-mix(in srgb, var(--solid-fg) 20%, transparent);
|
|
74
100
|
}
|
|
75
101
|
.panel.solid .header {
|
|
76
102
|
background-color: transparent !important;
|
|
77
103
|
color: var(--solid-fg);
|
|
78
104
|
}
|
|
79
|
-
.panel.solid .content
|
|
80
|
-
background-color: transparent !important;
|
|
81
|
-
}
|
|
105
|
+
.panel.solid .content,
|
|
82
106
|
.panel.solid .footer {
|
|
83
107
|
background-color: transparent !important;
|
|
84
108
|
}
|
|
@@ -34,10 +34,22 @@ const getIntrinsicSize = (val) => {
|
|
|
34
34
|
}
|
|
35
35
|
return undefined;
|
|
36
36
|
};
|
|
37
|
+
const ImageStatus = {
|
|
38
|
+
Loading: "loading",
|
|
39
|
+
Loaded: "loaded",
|
|
40
|
+
Error: "error",
|
|
41
|
+
};
|
|
37
42
|
export function Image(_a) {
|
|
38
43
|
var { src, alt, className, fit, style, onLoad, onError, fallbackSrc, aspectRatio, rounded = true, width, height } = _a, props = __rest(_a, ["src", "alt", "className", "fit", "style", "onLoad", "onError", "fallbackSrc", "aspectRatio", "rounded", "width", "height"]);
|
|
39
|
-
const [status, setStatus] = useState(
|
|
44
|
+
const [status, setStatus] = useState(ImageStatus.Loading);
|
|
40
45
|
const [showSkeleton, setShowSkeleton] = useState(true);
|
|
46
|
+
const [storedSrc, setStoredSrc] = useState(src);
|
|
47
|
+
// Render-time state update to avoid flash of broken image
|
|
48
|
+
if (src !== storedSrc) {
|
|
49
|
+
setStoredSrc(src);
|
|
50
|
+
setStatus(ImageStatus.Loading);
|
|
51
|
+
setShowSkeleton(true);
|
|
52
|
+
}
|
|
41
53
|
const computedAspectRatio = useMemo(() => {
|
|
42
54
|
if (aspectRatio) {
|
|
43
55
|
return aspectRatio;
|
|
@@ -46,25 +58,16 @@ export function Image(_a) {
|
|
|
46
58
|
const h = getIntrinsicSize(height);
|
|
47
59
|
return w && h ? `${w} / ${h}` : undefined;
|
|
48
60
|
}, [aspectRatio, width, height]);
|
|
49
|
-
const prevSrcRef = useRef(src);
|
|
50
61
|
const imgRef = useRef(null);
|
|
51
62
|
useEffect(() => {
|
|
52
63
|
var _a;
|
|
53
64
|
if ((_a = imgRef.current) === null || _a === void 0 ? void 0 : _a.complete) {
|
|
54
|
-
setStatus(
|
|
65
|
+
setStatus(ImageStatus.Loaded);
|
|
55
66
|
}
|
|
56
67
|
}, []);
|
|
57
|
-
// Reset state when source changes
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (prevSrcRef.current !== src) {
|
|
60
|
-
setStatus("loading");
|
|
61
|
-
setShowSkeleton(true);
|
|
62
|
-
prevSrcRef.current = src;
|
|
63
|
-
}
|
|
64
|
-
}, [src]);
|
|
65
68
|
// When loaded, keep skeleton for a moment to allow cross-fade
|
|
66
69
|
useEffect(() => {
|
|
67
|
-
if (status ===
|
|
70
|
+
if (status === ImageStatus.Loaded) {
|
|
68
71
|
const timer = setTimeout(() => {
|
|
69
72
|
setShowSkeleton(false);
|
|
70
73
|
}, 500); // 500ms delay to allow image to fade in completely
|
|
@@ -79,27 +82,27 @@ export function Image(_a) {
|
|
|
79
82
|
await img.decode();
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
|
-
catch (
|
|
85
|
+
catch (_error) {
|
|
83
86
|
// ignore decode errors (e.g. invalid image data)
|
|
84
87
|
}
|
|
85
88
|
finally {
|
|
86
|
-
setStatus(
|
|
89
|
+
setStatus(ImageStatus.Loaded);
|
|
87
90
|
}
|
|
88
91
|
}, [onLoad]);
|
|
89
92
|
const handleError = useCallback((e) => {
|
|
90
|
-
if (fallbackSrc && status !==
|
|
93
|
+
if (fallbackSrc && status !== ImageStatus.Error) {
|
|
91
94
|
// Prevents infinite loop if fallback also fails
|
|
92
95
|
if (e.currentTarget.src !== fallbackSrc) {
|
|
93
96
|
e.currentTarget.src = fallbackSrc;
|
|
94
97
|
return;
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
|
-
setStatus(
|
|
100
|
+
setStatus(ImageStatus.Error);
|
|
98
101
|
setShowSkeleton(false); // Remove skeleton immediately on error
|
|
99
102
|
onError === null || onError === void 0 ? void 0 : onError(e);
|
|
100
103
|
}, [fallbackSrc, status, onError]);
|
|
101
|
-
return (_jsxs("div", { className: clsx(styles.wrapper, rounded && styles.rounded, className), style: Object.assign({ aspectRatio: computedAspectRatio, width: toCssValue(width), height: toCssValue(height) }, style), children: [_jsx("div", { "aria-hidden": "true", className: clsx(styles.skeletonLayer, status ===
|
|
104
|
+
return (_jsxs("div", { className: clsx(styles.wrapper, rounded && styles.rounded, className), style: Object.assign({ aspectRatio: computedAspectRatio, width: toCssValue(width), height: toCssValue(height) }, style), children: [_jsx("div", { "aria-hidden": "true", className: clsx(styles.skeletonLayer, status === ImageStatus.Loaded && styles.fadeOut), children: showSkeleton && (_jsx(Skeleton, { style: {
|
|
102
105
|
width: "100%",
|
|
103
106
|
height: "100%",
|
|
104
|
-
} })) }), _jsx("img", Object.assign({ ref: imgRef, alt: alt, className: clsx(styles.image, fit && styles[`fit-${fit}`], status ===
|
|
107
|
+
} })) }), src && (_jsx("img", Object.assign({ ref: imgRef, alt: alt, className: clsx(styles.image, fit && styles[`fit-${fit}`], status === ImageStatus.Loaded ? styles.visible : styles.hidden), height: height, src: src, width: width, onError: handleError, onLoad: handleLoad }, props)))] }));
|
|
105
108
|
}
|
|
@@ -30,38 +30,56 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
.modalCard {
|
|
33
|
-
background-color: var(--
|
|
33
|
+
background-color: var(--surface-brand);
|
|
34
34
|
}
|
|
35
35
|
.modalCard.solid {
|
|
36
|
-
/*
|
|
37
|
-
SCALABLE CONTEXTUAL REMAPPING
|
|
38
|
-
Save original values then swap semantic tokens to auto-invert content.
|
|
39
|
-
*/
|
|
40
|
-
--solid-bg: var(--primary);
|
|
41
|
-
--solid-fg: var(--primary-foreground);
|
|
42
|
-
--original-border: var(--card-border);
|
|
36
|
+
/* ROOT CONTEXT (The Field) */
|
|
43
37
|
background-color: var(--solid-bg);
|
|
44
38
|
color: var(--solid-fg);
|
|
45
|
-
/*
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
/* Root Variables */
|
|
40
|
+
--background: var(--solid-bg);
|
|
41
|
+
--foreground: var(--solid-fg);
|
|
42
|
+
--muted-foreground: color-mix(in srgb, var(--solid-fg) 70%, transparent);
|
|
43
|
+
/*
|
|
44
|
+
* Standardized Brand Surface Logic
|
|
45
|
+
* Decouples Modals (Surface) from Buttons (Action)
|
|
48
46
|
*/
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
--surface-brand: var(--solid-bg);
|
|
48
|
+
--surface-brand-foreground: var(--solid-fg);
|
|
49
|
+
/* SEMANTICS (True Semantic Colors) */
|
|
50
|
+
--success: var(--solid-success);
|
|
51
|
+
--success-foreground: var(--solid-fg);
|
|
52
|
+
--error: var(--solid-error);
|
|
53
|
+
--error-foreground: var(--solid-fg);
|
|
54
|
+
--warning: var(--solid-warning);
|
|
55
|
+
--warning-foreground: var(--solid-fg);
|
|
56
|
+
/* SURFACE COLORS */
|
|
57
|
+
--on-surface: var(--solid-bg);
|
|
58
|
+
--on-surface-muted: var(--solid-bg);
|
|
59
|
+
/* COMPONENT TOKENS */
|
|
60
|
+
--card-bg: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
61
|
+
--card-border: var(--solid-fg);
|
|
62
|
+
--card-foreground: var(--solid-fg);
|
|
63
|
+
/* POPOVER TOKENS */
|
|
64
|
+
--popover: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
65
|
+
--popover-foreground: var(--solid-bg);
|
|
66
|
+
/* INPUT TOKENS */
|
|
67
|
+
--input: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
68
|
+
--border-strong: var(--solid-fg);
|
|
69
|
+
/* BUTTON TOKENS */
|
|
51
70
|
--primary: var(--solid-fg);
|
|
52
71
|
--primary-foreground: var(--solid-bg);
|
|
53
|
-
|
|
54
|
-
--
|
|
72
|
+
/* SECONDARY TOKENS */
|
|
73
|
+
--secondary: color-mix(in srgb, var(--solid-bg) 90%, transparent);
|
|
74
|
+
--secondary-foreground: var(--solid-fg);
|
|
75
|
+
/* MUTED TOKENS */
|
|
76
|
+
--muted: color-mix(in srgb, var(--solid-fg) 20%, transparent);
|
|
55
77
|
}
|
|
56
78
|
.modalCard.solid .header,
|
|
57
79
|
.modalCard.solid .body,
|
|
58
80
|
.modalCard.solid .footer,
|
|
59
81
|
.modalCard.solid .modalContent {
|
|
60
82
|
background-color: transparent !important;
|
|
61
|
-
color: var(--solid-fg);
|
|
62
|
-
}
|
|
63
|
-
.modalCard.solid {
|
|
64
|
-
/* In solid mode, we need to override the close button to ensure contrast */
|
|
65
83
|
}
|
|
66
84
|
.modalCard.solid .closeButton:hover {
|
|
67
85
|
transform: translate(-2px, -2px);
|
|
@@ -76,12 +94,12 @@
|
|
|
76
94
|
|
|
77
95
|
.header {
|
|
78
96
|
padding: var(--spacing-lg);
|
|
79
|
-
background-color: var(--
|
|
80
|
-
color: var(--
|
|
97
|
+
background-color: var(--surface-brand);
|
|
98
|
+
color: var(--surface-brand-foreground);
|
|
81
99
|
border-bottom: var(--border-width) solid var(--border-strong);
|
|
82
100
|
/* Remap foreground variables so children (like Text) use the correct contrast color */
|
|
83
|
-
--foreground: var(--
|
|
84
|
-
--muted-foreground: var(--
|
|
101
|
+
--foreground: var(--surface-brand-foreground);
|
|
102
|
+
--muted-foreground: var(--surface-brand-foreground);
|
|
85
103
|
}
|
|
86
104
|
|
|
87
105
|
.headerContent {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { X } from "lucide-react";
|
|
5
|
-
import React, { useEffect, useState } from "react";
|
|
5
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
6
6
|
import { createPortal } from "react-dom";
|
|
7
7
|
import { Button } from "../Button/Button.js";
|
|
8
8
|
import { Flex } from "../Layout/Layout.js";
|
|
@@ -11,6 +11,16 @@ export function Sheet({ isOpen, onClose, title, children, footer, variant = "def
|
|
|
11
11
|
const reactId = React.useId();
|
|
12
12
|
const titleId = `sheet-title-${reactId}`;
|
|
13
13
|
const [mounted, setMounted] = useState(false);
|
|
14
|
+
const panelRef = useRef(null);
|
|
15
|
+
const isDragging = useRef(false);
|
|
16
|
+
const startY = useRef(0);
|
|
17
|
+
const cleanupRef = useRef(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!isOpen && panelRef.current) {
|
|
20
|
+
panelRef.current.style.transform = "";
|
|
21
|
+
panelRef.current.style.transition = "";
|
|
22
|
+
}
|
|
23
|
+
}, [isOpen]);
|
|
14
24
|
useEffect(() => {
|
|
15
25
|
setMounted(true);
|
|
16
26
|
if (isOpen) {
|
|
@@ -23,6 +33,59 @@ export function Sheet({ isOpen, onClose, title, children, footer, variant = "def
|
|
|
23
33
|
document.body.style.overflow = "";
|
|
24
34
|
};
|
|
25
35
|
}, [isOpen]);
|
|
36
|
+
// Ensure strict cleanup on unmount
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
return () => {
|
|
39
|
+
if (cleanupRef.current) {
|
|
40
|
+
cleanupRef.current();
|
|
41
|
+
cleanupRef.current = null;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}, []);
|
|
45
|
+
const handlePointerDown = (e) => {
|
|
46
|
+
if (!panelRef.current) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
isDragging.current = true;
|
|
50
|
+
startY.current = e.clientY;
|
|
51
|
+
const onMove = (moveEvent) => {
|
|
52
|
+
if (!isDragging.current || !panelRef.current) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const delta = moveEvent.clientY - startY.current;
|
|
56
|
+
if (delta < 0) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
panelRef.current.style.transition = "none";
|
|
60
|
+
panelRef.current.style.transform = `translateY(${delta}px)`;
|
|
61
|
+
};
|
|
62
|
+
const onUp = (upEvent) => {
|
|
63
|
+
isDragging.current = false;
|
|
64
|
+
document.removeEventListener("pointermove", onMove);
|
|
65
|
+
document.removeEventListener("pointerup", onUp);
|
|
66
|
+
document.removeEventListener("pointercancel", onUp);
|
|
67
|
+
cleanupRef.current = null;
|
|
68
|
+
if (!panelRef.current) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const delta = upEvent.clientY - startY.current;
|
|
72
|
+
if (delta > 150) {
|
|
73
|
+
onClose();
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
panelRef.current.style.transition = "";
|
|
77
|
+
panelRef.current.style.transform = "";
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
document.addEventListener("pointermove", onMove);
|
|
81
|
+
document.addEventListener("pointerup", onUp);
|
|
82
|
+
document.addEventListener("pointercancel", onUp);
|
|
83
|
+
cleanupRef.current = () => {
|
|
84
|
+
document.removeEventListener("pointermove", onMove);
|
|
85
|
+
document.removeEventListener("pointerup", onUp);
|
|
86
|
+
document.removeEventListener("pointercancel", onUp);
|
|
87
|
+
};
|
|
88
|
+
};
|
|
26
89
|
useEffect(() => {
|
|
27
90
|
const handleEsc = (e) => {
|
|
28
91
|
if (e.key === "Escape") {
|
|
@@ -37,5 +100,5 @@ export function Sheet({ isOpen, onClose, title, children, footer, variant = "def
|
|
|
37
100
|
if (!mounted) {
|
|
38
101
|
return null;
|
|
39
102
|
}
|
|
40
|
-
return createPortal(_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", className: clsx(styles.overlay, isOpen && styles.isOpen), onClick: onClose }), _jsxs("div", { "aria-label": !title ? "Sheet" : undefined, "aria-labelledby": title ? titleId : undefined, "aria-modal": "true", className: clsx(styles.panel, styles[variant], isOpen && styles.isOpen, className), role: "dialog", children: [_jsxs("div", { className: styles.header, children: [_jsx("div", { className: styles.handleBar }), _jsxs(Flex, { align: "center", className: styles.headerBody, justify: "space-between", children: [title && (_jsx("h2", { className: styles.title, id: titleId, children: title })), _jsx(Button, { "aria-label": "Close sheet", size: "sm", variant: "danger", onClick: onClose, children: _jsx(X, { size: 24 }) })] })] }), _jsx("div", { className: styles.content, children: children }), footer && _jsx("div", { className: styles.footer, children: footer })] })] }), document.body);
|
|
103
|
+
return createPortal(_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", className: clsx(styles.overlay, isOpen && styles.isOpen), onClick: onClose }), _jsxs("div", { ref: panelRef, "aria-label": !title ? "Sheet" : undefined, "aria-labelledby": title ? titleId : undefined, "aria-modal": "true", className: clsx(styles.panel, styles[variant], isOpen && styles.isOpen, className), role: "dialog", children: [_jsxs("div", { className: styles.header, onPointerDown: handlePointerDown, children: [_jsx("div", { className: styles.handleBar }), _jsxs(Flex, { align: "center", className: styles.headerBody, justify: "space-between", children: [title && (_jsx("h2", { className: styles.title, id: titleId, children: title })), _jsx(Button, { "aria-label": "Close sheet", size: "sm", variant: "danger", onClick: onClose, children: _jsx(X, { size: 24 }) })] })] }), _jsx("div", { className: styles.content, children: children }), footer && _jsx("div", { className: styles.footer, children: footer })] })] }), document.body);
|
|
41
104
|
}
|
|
@@ -42,44 +42,69 @@
|
|
|
42
42
|
transform: translateY(0);
|
|
43
43
|
}
|
|
44
44
|
.panel.solid {
|
|
45
|
-
/*
|
|
46
|
-
SCALABLE CONTEXTUAL REMAPPING
|
|
47
|
-
Save original values then swap semantic tokens to auto-invert content.
|
|
48
|
-
*/
|
|
49
|
-
--solid-bg: var(--primary);
|
|
50
|
-
--solid-fg: var(--primary-foreground);
|
|
45
|
+
/* ROOT CONTEXT (The Field) */
|
|
51
46
|
background-color: var(--solid-bg);
|
|
52
47
|
color: var(--solid-fg);
|
|
53
|
-
/*
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
/* Root Variables */
|
|
49
|
+
--background: var(--solid-bg);
|
|
50
|
+
--foreground: var(--solid-fg);
|
|
51
|
+
--muted-foreground: color-mix(in srgb, var(--solid-fg) 70%, transparent);
|
|
52
|
+
/*
|
|
53
|
+
* Standardized Brand Surface Logic
|
|
54
|
+
* Decouples Modals (Surface) from Buttons (Action)
|
|
55
|
+
*/
|
|
56
|
+
--surface-brand: var(--solid-bg);
|
|
57
|
+
--surface-brand-foreground: var(--solid-fg);
|
|
58
|
+
/* SEMANTICS (True Semantic Colors) */
|
|
59
|
+
--success: var(--solid-success);
|
|
60
|
+
--success-foreground: var(--solid-fg);
|
|
61
|
+
--error: var(--solid-error);
|
|
62
|
+
--error-foreground: var(--solid-fg);
|
|
63
|
+
--warning: var(--solid-warning);
|
|
64
|
+
--warning-foreground: var(--solid-fg);
|
|
65
|
+
/* SURFACE COLORS */
|
|
66
|
+
--on-surface: var(--solid-bg);
|
|
67
|
+
--on-surface-muted: var(--solid-bg);
|
|
68
|
+
/* COMPONENT TOKENS */
|
|
69
|
+
--card-bg: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
70
|
+
--card-border: var(--solid-fg);
|
|
71
|
+
--card-foreground: var(--solid-fg);
|
|
72
|
+
/* POPOVER TOKENS */
|
|
73
|
+
--popover: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
74
|
+
--popover-foreground: var(--solid-bg);
|
|
75
|
+
/* INPUT TOKENS */
|
|
76
|
+
--input: color-mix(in srgb, var(--solid-fg) 95%, var(--solid-bg) 5%);
|
|
77
|
+
--border-strong: var(--solid-fg);
|
|
78
|
+
/* BUTTON TOKENS */
|
|
56
79
|
--primary: var(--solid-fg);
|
|
57
80
|
--primary-foreground: var(--solid-bg);
|
|
58
|
-
|
|
59
|
-
--
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
color: var(--solid-fg);
|
|
81
|
+
/* SECONDARY TOKENS */
|
|
82
|
+
--secondary: color-mix(in srgb, var(--solid-bg) 90%, transparent);
|
|
83
|
+
--secondary-foreground: var(--solid-fg);
|
|
84
|
+
/* MUTED TOKENS */
|
|
85
|
+
--muted: color-mix(in srgb, var(--solid-fg) 20%, transparent);
|
|
64
86
|
}
|
|
65
87
|
.panel.solid .handleBar {
|
|
66
88
|
background-color: var(--solid-fg);
|
|
67
89
|
opacity: 0.8;
|
|
68
90
|
}
|
|
69
|
-
.panel.solid .content
|
|
70
|
-
background-color: transparent !important;
|
|
71
|
-
}
|
|
91
|
+
.panel.solid .content,
|
|
72
92
|
.panel.solid .footer {
|
|
73
93
|
background-color: transparent !important;
|
|
74
94
|
}
|
|
75
95
|
|
|
76
96
|
.header {
|
|
77
|
-
background-color: var(--
|
|
78
|
-
color: var(--
|
|
97
|
+
background-color: var(--surface-brand);
|
|
98
|
+
color: var(--surface-brand-foreground);
|
|
79
99
|
border-bottom: var(--border-width) solid var(--border-strong);
|
|
80
100
|
display: flex;
|
|
81
101
|
flex-direction: column;
|
|
82
102
|
flex-shrink: 0;
|
|
103
|
+
touch-action: none;
|
|
104
|
+
cursor: grab;
|
|
105
|
+
}
|
|
106
|
+
.header:active {
|
|
107
|
+
cursor: grabbing;
|
|
83
108
|
}
|
|
84
109
|
|
|
85
110
|
.handleBar {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
.skeleton {
|
|
10
|
-
background: linear-gradient(90deg,
|
|
10
|
+
background: linear-gradient(90deg, color-mix(in srgb, var(--foreground), transparent 90%) 25%, color-mix(in srgb, var(--foreground), transparent 80%) 37%, color-mix(in srgb, var(--foreground), transparent 90%) 63%);
|
|
11
11
|
background-size: 200% 100%;
|
|
12
12
|
animation: shimmer 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
13
13
|
width: var(--width, 100%);
|
|
@@ -4,7 +4,6 @@ import { createContext, useContext, useEffect, useState } from "react";
|
|
|
4
4
|
import { themes } from "./definitions.js";
|
|
5
5
|
const ThemeContext = createContext(undefined);
|
|
6
6
|
export function ThemeProvider({ children, initialTheme, onThemeChange, }) {
|
|
7
|
-
var _a;
|
|
8
7
|
const [currentTheme, setCurrentTheme] = useState(initialTheme);
|
|
9
8
|
useEffect(() => {
|
|
10
9
|
setCurrentTheme(initialTheme);
|
|
@@ -14,9 +13,12 @@ export function ThemeProvider({ children, initialTheme, onThemeChange, }) {
|
|
|
14
13
|
onThemeChange === null || onThemeChange === void 0 ? void 0 : onThemeChange(newTheme);
|
|
15
14
|
};
|
|
16
15
|
// Get the variables for the current theme
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const
|
|
16
|
+
const themeConfig = themes[currentTheme] || themes.default;
|
|
17
|
+
const themeVars = themeConfig.variables;
|
|
18
|
+
const solidVars = themeConfig.solid || {};
|
|
19
|
+
// Generate CSS variables string (includes both theme and solid tokens)
|
|
20
|
+
const allVars = Object.assign(Object.assign({}, themeVars), solidVars);
|
|
21
|
+
const cssVariables = Object.entries(allVars)
|
|
20
22
|
.map(([key, value]) => `${key}: ${value};`)
|
|
21
23
|
.join("\n");
|
|
22
24
|
return (_jsxs(ThemeContext.Provider, { value: {
|
|
@@ -16,6 +16,8 @@ export declare const themes: {
|
|
|
16
16
|
readonly "--on-surface-muted": "#374151";
|
|
17
17
|
readonly "--primary": "#a855f7";
|
|
18
18
|
readonly "--primary-foreground": "#000000";
|
|
19
|
+
readonly "--surface-brand": "#a855f7";
|
|
20
|
+
readonly "--surface-brand-foreground": "#000000";
|
|
19
21
|
readonly "--primary-hover": "#9333ea";
|
|
20
22
|
readonly "--secondary": "#fbbf24";
|
|
21
23
|
readonly "--secondary-foreground": "#000000";
|
|
@@ -90,6 +92,13 @@ export declare const themes: {
|
|
|
90
92
|
readonly "--shadow-sm-checked-hover": string;
|
|
91
93
|
readonly "--shadow-lg": string;
|
|
92
94
|
};
|
|
95
|
+
readonly solid: {
|
|
96
|
+
"--solid-bg": string;
|
|
97
|
+
"--solid-fg": string;
|
|
98
|
+
"--solid-success": string;
|
|
99
|
+
"--solid-error": string;
|
|
100
|
+
"--solid-warning": string;
|
|
101
|
+
};
|
|
93
102
|
};
|
|
94
103
|
readonly doom: {
|
|
95
104
|
readonly name: "DOOMSDAY";
|
|
@@ -108,6 +117,8 @@ export declare const themes: {
|
|
|
108
117
|
readonly "--on-surface-muted": "#94a3b8";
|
|
109
118
|
readonly "--primary": "#10b981";
|
|
110
119
|
readonly "--primary-foreground": "#020617";
|
|
120
|
+
readonly "--surface-brand": "#10b981";
|
|
121
|
+
readonly "--surface-brand-foreground": "#020617";
|
|
111
122
|
readonly "--primary-hover": "#059669";
|
|
112
123
|
readonly "--secondary": "#475569";
|
|
113
124
|
readonly "--secondary-foreground": "#F8FAFC";
|
|
@@ -182,6 +193,13 @@ export declare const themes: {
|
|
|
182
193
|
readonly "--shadow-sm-checked-hover": string;
|
|
183
194
|
readonly "--shadow-lg": string;
|
|
184
195
|
};
|
|
196
|
+
readonly solid: {
|
|
197
|
+
"--solid-bg": string;
|
|
198
|
+
"--solid-fg": string;
|
|
199
|
+
"--solid-success": string;
|
|
200
|
+
"--solid-error": string;
|
|
201
|
+
"--solid-warning": string;
|
|
202
|
+
};
|
|
185
203
|
};
|
|
186
204
|
readonly captain: {
|
|
187
205
|
readonly name: "THE CAPTAIN";
|
|
@@ -198,16 +216,18 @@ export declare const themes: {
|
|
|
198
216
|
readonly "--muted-foreground": "#475569";
|
|
199
217
|
readonly "--on-surface": "#0f172a";
|
|
200
218
|
readonly "--on-surface-muted": "#475569";
|
|
201
|
-
readonly "--primary": "#
|
|
202
|
-
readonly "--primary-foreground": "#
|
|
203
|
-
readonly "--
|
|
219
|
+
readonly "--primary": "#3B82F6";
|
|
220
|
+
readonly "--primary-foreground": "#000000";
|
|
221
|
+
readonly "--surface-brand": "#3B82F6";
|
|
222
|
+
readonly "--surface-brand-foreground": "#000000";
|
|
223
|
+
readonly "--primary-hover": "#2563eb";
|
|
204
224
|
readonly "--secondary": "#64748b";
|
|
205
225
|
readonly "--secondary-foreground": "#ffffff";
|
|
206
226
|
readonly "--shadow-base": "#000000";
|
|
207
227
|
readonly "--shadow-error": "#7f1d1d";
|
|
208
|
-
readonly "--shadow-primary": "#
|
|
228
|
+
readonly "--shadow-primary": "#1e40af";
|
|
209
229
|
readonly "--success": "#10b981";
|
|
210
|
-
readonly "--success-foreground": "#
|
|
230
|
+
readonly "--success-foreground": "#000000";
|
|
211
231
|
readonly "--surface-accent": "#f1f5f9";
|
|
212
232
|
readonly "--warning": "#F7B731";
|
|
213
233
|
readonly "--warning-foreground": "#0F1419";
|
|
@@ -274,6 +294,13 @@ export declare const themes: {
|
|
|
274
294
|
readonly "--shadow-sm-checked-hover": string;
|
|
275
295
|
readonly "--shadow-lg": string;
|
|
276
296
|
};
|
|
297
|
+
readonly solid: {
|
|
298
|
+
"--solid-bg": string;
|
|
299
|
+
"--solid-fg": string;
|
|
300
|
+
"--solid-success": string;
|
|
301
|
+
"--solid-error": string;
|
|
302
|
+
"--solid-warning": string;
|
|
303
|
+
};
|
|
277
304
|
};
|
|
278
305
|
readonly vigilante: {
|
|
279
306
|
readonly name: "DARK KNIGHT";
|
|
@@ -292,6 +319,8 @@ export declare const themes: {
|
|
|
292
319
|
readonly "--on-surface-muted": "#9ca3af";
|
|
293
320
|
readonly "--primary": "#F7B731";
|
|
294
321
|
readonly "--primary-foreground": "#0F1419";
|
|
322
|
+
readonly "--surface-brand": "#F7B731";
|
|
323
|
+
readonly "--surface-brand-foreground": "#0F1419";
|
|
295
324
|
readonly "--primary-hover": "#F5A623";
|
|
296
325
|
readonly "--secondary": "#4b5563";
|
|
297
326
|
readonly "--secondary-foreground": "#E8E9ED";
|
|
@@ -366,6 +395,13 @@ export declare const themes: {
|
|
|
366
395
|
readonly "--shadow-sm-checked-hover": string;
|
|
367
396
|
readonly "--shadow-lg": string;
|
|
368
397
|
};
|
|
398
|
+
readonly solid: {
|
|
399
|
+
"--solid-bg": string;
|
|
400
|
+
"--solid-fg": string;
|
|
401
|
+
"--solid-success": string;
|
|
402
|
+
"--solid-error": string;
|
|
403
|
+
"--solid-warning": string;
|
|
404
|
+
};
|
|
369
405
|
};
|
|
370
406
|
};
|
|
371
407
|
export type ThemeKey = keyof typeof themes;
|