@mks2508/mks-ui 0.5.2 → 0.5.7
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/react-ui/index.js +8 -3
- package/dist/react-ui/primitives/index.js +5 -0
- package/dist/react-ui/primitives/waapi/Gooey/Gooey.types.d.ts +120 -0
- package/dist/react-ui/primitives/waapi/Gooey/Gooey.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Gooey/GooeyCanvas.d.ts +10 -0
- package/dist/react-ui/primitives/waapi/Gooey/GooeyCanvas.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Gooey/GooeyCanvas.js +190 -0
- package/dist/react-ui/primitives/waapi/Gooey/GooeyFilter.d.ts +7 -0
- package/dist/react-ui/primitives/waapi/Gooey/GooeyFilter.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Gooey/GooeyFilter.js +78 -0
- package/dist/react-ui/primitives/waapi/Gooey/MorphPath.d.ts +7 -0
- package/dist/react-ui/primitives/waapi/Gooey/MorphPath.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Gooey/MorphPath.js +51 -0
- package/dist/react-ui/primitives/waapi/Gooey/gooey-utils.d.ts +94 -0
- package/dist/react-ui/primitives/waapi/Gooey/gooey-utils.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Gooey/gooey-utils.js +182 -0
- package/dist/react-ui/primitives/waapi/Gooey/index.d.ts +28 -0
- package/dist/react-ui/primitives/waapi/Gooey/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Gooey/index.js +5 -0
- package/dist/react-ui/primitives/waapi/Gooey/useMorphPath.d.ts +7 -0
- package/dist/react-ui/primitives/waapi/Gooey/useMorphPath.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Gooey/useMorphPath.js +47 -0
- package/dist/react-ui/primitives/waapi/index.d.ts +2 -0
- package/dist/react-ui/primitives/waapi/index.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/index.js +6 -0
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts +26 -16
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts.map +1 -1
- package/dist/react-ui/ui/DataCard/DataCard.styles.js +36 -74
- package/dist/react-ui/ui/DataCard/DataCard.types.d.ts +50 -70
- package/dist/react-ui/ui/DataCard/DataCard.types.d.ts.map +1 -1
- package/dist/react-ui/ui/DataCard/index.d.ts +24 -93
- package/dist/react-ui/ui/DataCard/index.d.ts.map +1 -1
- package/dist/react-ui/ui/DataCard/index.js +76 -118
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle-DOR3Ld-k.css +376 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.css +376 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.js +0 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.d.ts +20 -8
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.d.ts.map +1 -1
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.js +55 -27
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.types.d.ts +69 -14
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.types.d.ts.map +1 -1
- package/dist/react-ui/ui/DynamicToggle/index.d.ts +22 -20
- package/dist/react-ui/ui/DynamicToggle/index.d.ts.map +1 -1
- package/dist/react-ui/ui/DynamicToggle/index.js +133 -96
- package/dist/react-ui/ui/Switch/index.js +1 -1
- package/dist/react-ui/ui/index.js +2 -2
- package/package.json +2 -2
- package/src/css.d.ts +1 -0
- package/src/react-ui/primitives/waapi/Gooey/Gooey.types.ts +141 -0
- package/src/react-ui/primitives/waapi/Gooey/GooeyCanvas.tsx +217 -0
- package/src/react-ui/primitives/waapi/Gooey/GooeyFilter.tsx +77 -0
- package/src/react-ui/primitives/waapi/Gooey/MorphPath.tsx +58 -0
- package/src/react-ui/primitives/waapi/Gooey/gooey-utils.ts +253 -0
- package/src/react-ui/primitives/waapi/Gooey/index.ts +50 -0
- package/src/react-ui/primitives/waapi/Gooey/useMorphPath.ts +48 -0
- package/src/react-ui/primitives/waapi/index.ts +23 -0
- package/src/react-ui/ui/DataCard/DataCard.styles.ts +45 -101
- package/src/react-ui/ui/DataCard/DataCard.types.ts +52 -73
- package/src/react-ui/ui/DataCard/index.tsx +118 -184
- package/src/react-ui/ui/DynamicToggle/DynamicToggle.css +320 -94
- package/src/react-ui/ui/DynamicToggle/DynamicToggle.styles.ts +60 -40
- package/src/react-ui/ui/DynamicToggle/DynamicToggle.types.ts +101 -14
- package/src/react-ui/ui/DynamicToggle/index.tsx +172 -96
- package/src/react-ui/ui/DynamicToggle/prototype-v7-ios.html +413 -0
- package/src/react-ui/ui/DynamicToggle/prototype-v7.html +615 -0
- package/src/react-ui/ui/DynamicToggle/prototype-v8-gooey-safari.html +560 -0
- package/src/react-ui/ui/DynamicToggle/prototype-v8b-react-structure.html +227 -0
- package/src/react-ui/ui/DynamicToggle/prototype.html +419 -0
- package/src/react-ui/ui/Switch/index.tsx +1 -1
- /package/dist/react-ui/blocks/Terminal/panel/{terminal-filter-dropdown.module-DAcl_XQZ.css → terminal-filter-dropdown.module-C6oDcFBS.css} +0 -0
- /package/dist/react-ui/blocks/Terminal/panel/{terminal-session-tabs.module-DNAop5e3.css → terminal-session-tabs.module-D_-sgyza.css} +0 -0
- /package/dist/react-ui/components/MorphingPopover/{morphing-popover.module-BJrjXisF.css → morphing-popover.module-B1ftlaYj.css} +0 -0
|
@@ -5,63 +5,58 @@ import { CountingNumber } from "../../primitives/CountingNumber/index.js";
|
|
|
5
5
|
import { getStrictContext } from "../../lib/get-strict-context.js";
|
|
6
6
|
import { Switch, SwitchThumb } from "../Switch/index.js";
|
|
7
7
|
import { CornerBracket } from "../CornerBracket/index.js";
|
|
8
|
-
import {
|
|
8
|
+
import { dataCardStyles, dataCardVariants } from "./DataCard.styles.js";
|
|
9
9
|
import * as React$1 from "react";
|
|
10
10
|
import { motion } from "motion/react";
|
|
11
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
|
|
13
13
|
//#region src/react-ui/ui/DataCard/index.tsx
|
|
14
|
-
const [DataCardProvider, useDataCard] = getStrictContext("DataCardContext");
|
|
15
14
|
/**
|
|
16
|
-
* DataCard —
|
|
15
|
+
* DataCard — glassmorphism dashboard metric card.
|
|
16
|
+
*
|
|
17
|
+
* Features: animated numbers, corner brackets, toggle, size/variant CVA,
|
|
18
|
+
* state-based styling, slot overrides, config for animation tuning.
|
|
17
19
|
*
|
|
18
|
-
*
|
|
19
|
-
* - Slot overrides for customization
|
|
20
|
-
* - State-based styling (hover, pressed, disabled)
|
|
21
|
-
* - CVA variants (size, color variant)
|
|
22
|
-
* - asChild composition pattern
|
|
23
|
-
* - Motion/animation integration
|
|
24
|
-
* - Custom render functions
|
|
25
|
-
* - Form field integration
|
|
26
|
-
* - Icon composition
|
|
27
|
-
* - Glassmorphism effects
|
|
20
|
+
* @module @mks2508/mks-ui/react/ui/DataCard
|
|
28
21
|
*
|
|
29
22
|
* @example
|
|
30
23
|
* ```tsx
|
|
31
24
|
* <DataCard variant="accent" size="default">
|
|
32
|
-
* <
|
|
33
|
-
* <
|
|
25
|
+
* <DataCardLabel title="Revenue" description="This month" />
|
|
26
|
+
* <DataCardValue number={45678} unit="$" />
|
|
34
27
|
* </DataCard>
|
|
35
28
|
* ```
|
|
36
29
|
*/
|
|
37
|
-
|
|
30
|
+
const [DataCardProvider, useDataCard] = getStrictContext("DataCardContext");
|
|
31
|
+
/**
|
|
32
|
+
* Root card container with glassmorphism, corner brackets, and state tracking.
|
|
33
|
+
*
|
|
34
|
+
* @param props - {@link IDataCardProps}
|
|
35
|
+
* @returns A motion.div card with context provider
|
|
36
|
+
*/
|
|
37
|
+
function DataCard({ variant = "default", size = "default", disabled = false, glass = true, showBrackets = true, className, style, slots, config, children }) {
|
|
38
38
|
const [state, setState] = React$1.useState({
|
|
39
39
|
hovered: false,
|
|
40
40
|
pressed: false,
|
|
41
|
-
disabled
|
|
41
|
+
disabled
|
|
42
42
|
});
|
|
43
43
|
const contextValue = React$1.useMemo(() => ({
|
|
44
44
|
variant,
|
|
45
45
|
size,
|
|
46
|
-
disabled
|
|
46
|
+
disabled,
|
|
47
47
|
glass,
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
config,
|
|
49
|
+
slots
|
|
50
50
|
}), [
|
|
51
51
|
variant,
|
|
52
52
|
size,
|
|
53
53
|
disabled,
|
|
54
54
|
glass,
|
|
55
|
+
config,
|
|
55
56
|
slots
|
|
56
57
|
]);
|
|
57
|
-
const computedClassName =
|
|
58
|
-
|
|
59
|
-
return className;
|
|
60
|
-
}, [className, state]);
|
|
61
|
-
const computedStyle = React$1.useMemo(() => {
|
|
62
|
-
if (typeof style === "function") return style(state);
|
|
63
|
-
return style;
|
|
64
|
-
}, [style, state]);
|
|
58
|
+
const computedClassName = typeof className === "function" ? className(state) : className;
|
|
59
|
+
const computedStyle = typeof style === "function" ? style(state) : style;
|
|
65
60
|
return /* @__PURE__ */ jsx(DataCardProvider, {
|
|
66
61
|
value: contextValue,
|
|
67
62
|
children: /* @__PURE__ */ jsxs(motion.div, {
|
|
@@ -74,29 +69,28 @@ function DataCard({ variant = "default", size = "default", disabled = false, gla
|
|
|
74
69
|
variant,
|
|
75
70
|
size,
|
|
76
71
|
glass
|
|
77
|
-
}),
|
|
72
|
+
}), disabled && "opacity-50 pointer-events-none", slots?.root, computedClassName),
|
|
78
73
|
style: computedStyle,
|
|
79
|
-
onHoverStart: () => setState((
|
|
80
|
-
...
|
|
74
|
+
onHoverStart: () => setState((p) => ({
|
|
75
|
+
...p,
|
|
81
76
|
hovered: true
|
|
82
77
|
})),
|
|
83
|
-
onHoverEnd: () => setState((
|
|
84
|
-
...
|
|
78
|
+
onHoverEnd: () => setState((p) => ({
|
|
79
|
+
...p,
|
|
85
80
|
hovered: false
|
|
86
81
|
})),
|
|
87
|
-
onTapStart: () => setState((
|
|
88
|
-
...
|
|
82
|
+
onTapStart: () => setState((p) => ({
|
|
83
|
+
...p,
|
|
89
84
|
pressed: true
|
|
90
85
|
})),
|
|
91
|
-
onTap: () => setState((
|
|
92
|
-
...
|
|
86
|
+
onTap: () => setState((p) => ({
|
|
87
|
+
...p,
|
|
93
88
|
pressed: false
|
|
94
89
|
})),
|
|
95
|
-
onTapCancel: () => setState((
|
|
96
|
-
...
|
|
90
|
+
onTapCancel: () => setState((p) => ({
|
|
91
|
+
...p,
|
|
97
92
|
pressed: false
|
|
98
93
|
})),
|
|
99
|
-
...props,
|
|
100
94
|
children: [showBrackets && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
101
95
|
/* @__PURE__ */ jsx(DataCardBracket, {
|
|
102
96
|
position: "tl",
|
|
@@ -119,22 +113,19 @@ function DataCard({ variant = "default", size = "default", disabled = false, gla
|
|
|
119
113
|
});
|
|
120
114
|
}
|
|
121
115
|
/**
|
|
122
|
-
*
|
|
116
|
+
* Animated number display with optional label and unit.
|
|
123
117
|
*
|
|
124
|
-
* @
|
|
125
|
-
*
|
|
126
|
-
* <DataCardValue
|
|
127
|
-
* number={1234}
|
|
128
|
-
* label="Active Users"
|
|
129
|
-
* unit="users"
|
|
130
|
-
* />
|
|
131
|
-
* ```
|
|
118
|
+
* @param props - {@link IDataCardValueProps}
|
|
119
|
+
* @returns Animated number with CountingNumber primitive
|
|
132
120
|
*/
|
|
133
121
|
function DataCardValue({ number, label, unit, decimalPlaces = 0, padStart = false }) {
|
|
134
|
-
const {
|
|
122
|
+
const { size, config, slots } = useDataCard();
|
|
123
|
+
const stiffness = config?.counterStiffness ?? 90;
|
|
124
|
+
const damping = config?.counterDamping ?? 10;
|
|
125
|
+
const sizeClass = size === "compact" ? "text-3xl font-bold" : size === "spacious" ? "text-5xl font-bold" : "text-4xl font-bold";
|
|
135
126
|
return /* @__PURE__ */ jsxs("div", {
|
|
136
127
|
"data-slot": "data-card-value",
|
|
137
|
-
className: cn(dataCardStyles.value),
|
|
128
|
+
className: cn(dataCardStyles.value, slots?.value),
|
|
138
129
|
children: [
|
|
139
130
|
label && /* @__PURE__ */ jsx("span", {
|
|
140
131
|
className: "text-muted-foreground text-xs uppercase tracking-wider font-mono",
|
|
@@ -145,10 +136,10 @@ function DataCardValue({ number, label, unit, decimalPlaces = 0, padStart = fals
|
|
|
145
136
|
decimalPlaces,
|
|
146
137
|
padStart,
|
|
147
138
|
transition: {
|
|
148
|
-
stiffness
|
|
149
|
-
damping
|
|
139
|
+
stiffness,
|
|
140
|
+
damping
|
|
150
141
|
},
|
|
151
|
-
className:
|
|
142
|
+
className: sizeClass
|
|
152
143
|
}),
|
|
153
144
|
unit && /* @__PURE__ */ jsx("span", {
|
|
154
145
|
className: "text-muted-foreground text-lg ml-1",
|
|
@@ -158,15 +149,10 @@ function DataCardValue({ number, label, unit, decimalPlaces = 0, padStart = fals
|
|
|
158
149
|
});
|
|
159
150
|
}
|
|
160
151
|
/**
|
|
161
|
-
*
|
|
152
|
+
* Title + description label.
|
|
162
153
|
*
|
|
163
|
-
* @
|
|
164
|
-
*
|
|
165
|
-
* <DataCardLabel
|
|
166
|
-
* title="Revenue"
|
|
167
|
-
* description="This month"
|
|
168
|
-
* />
|
|
169
|
-
* ```
|
|
154
|
+
* @param props - {@link IDataCardLabelProps}
|
|
155
|
+
* @returns Title and optional description text
|
|
170
156
|
*/
|
|
171
157
|
function DataCardLabel({ title, description, className, ...props }) {
|
|
172
158
|
const { slots } = useDataCard();
|
|
@@ -184,60 +170,36 @@ function DataCardLabel({ title, description, className, ...props }) {
|
|
|
184
170
|
});
|
|
185
171
|
}
|
|
186
172
|
/**
|
|
187
|
-
*
|
|
173
|
+
* Switch toggle control inside a DataCard.
|
|
188
174
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* @example
|
|
192
|
-
* ```tsx
|
|
193
|
-
* <DataCardToggle
|
|
194
|
-
* checked={enabled}
|
|
195
|
-
* onCheckedChange={setEnabled}
|
|
196
|
-
* label="Enable notifications"
|
|
197
|
-
* checkedIcon={<BellIcon />}
|
|
198
|
-
* uncheckedIcon={<BellOffIcon />}
|
|
199
|
-
* />
|
|
200
|
-
* ```
|
|
175
|
+
* @param props - {@link IDataCardToggleProps}
|
|
176
|
+
* @returns Label + Switch toggle
|
|
201
177
|
*/
|
|
202
|
-
function DataCardToggle({ checked, onCheckedChange,
|
|
203
|
-
const { disabled,
|
|
178
|
+
function DataCardToggle({ checked, onCheckedChange, label }) {
|
|
179
|
+
const { disabled, slots } = useDataCard();
|
|
204
180
|
return /* @__PURE__ */ jsxs("div", {
|
|
205
181
|
"data-slot": "data-card-toggle",
|
|
206
182
|
className: cn(dataCardStyles.toggle, slots?.toggle),
|
|
207
183
|
children: [label && /* @__PURE__ */ jsx("span", {
|
|
208
184
|
className: "text-sm text-muted-foreground",
|
|
209
185
|
children: label
|
|
210
|
-
}), /* @__PURE__ */
|
|
186
|
+
}), /* @__PURE__ */ jsx(Switch, {
|
|
211
187
|
checked,
|
|
212
188
|
onCheckedChange,
|
|
213
189
|
disabled,
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
checkedIcon && /* @__PURE__ */ jsx("div", {
|
|
217
|
-
className: "text-primary",
|
|
218
|
-
children: checkedIcon
|
|
219
|
-
}),
|
|
220
|
-
!checkedIcon && /* @__PURE__ */ jsx("div", {
|
|
221
|
-
className: "text-muted-foreground",
|
|
222
|
-
children: uncheckedIcon
|
|
223
|
-
})
|
|
224
|
-
]
|
|
190
|
+
nativeButton: true,
|
|
191
|
+
children: /* @__PURE__ */ jsx(SwitchThumb, {})
|
|
225
192
|
})]
|
|
226
193
|
});
|
|
227
194
|
}
|
|
228
195
|
/**
|
|
229
|
-
*
|
|
196
|
+
* Action button container.
|
|
230
197
|
*
|
|
231
|
-
* @
|
|
232
|
-
*
|
|
233
|
-
* <DataCardActions align="end">
|
|
234
|
-
* <Button size="sm">Edit</Button>
|
|
235
|
-
* <Button size="sm" variant="ghost">Delete</Button>
|
|
236
|
-
* </DataCardActions>
|
|
237
|
-
* ```
|
|
198
|
+
* @param props - {@link IDataCardActionsProps}
|
|
199
|
+
* @returns Flex container for action buttons
|
|
238
200
|
*/
|
|
239
201
|
function DataCardActions({ align = "end", className, children, ...props }) {
|
|
240
|
-
const {
|
|
202
|
+
const { slots } = useDataCard();
|
|
241
203
|
return /* @__PURE__ */ jsx("div", {
|
|
242
204
|
"data-slot": "data-card-actions",
|
|
243
205
|
"data-align": align,
|
|
@@ -247,28 +209,24 @@ function DataCardActions({ align = "end", className, children, ...props }) {
|
|
|
247
209
|
});
|
|
248
210
|
}
|
|
249
211
|
/**
|
|
250
|
-
*
|
|
212
|
+
* Decorative corner bracket. Rendered directly via CornerBracket
|
|
213
|
+
* (no wrapper div — the SVG positions itself via absolute positioning).
|
|
251
214
|
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
* @example
|
|
255
|
-
* ```tsx
|
|
256
|
-
* <DataCardBracket position="tl" variant="accent" />
|
|
257
|
-
* ```
|
|
215
|
+
* @param props - {@link IDataCardBracketProps}
|
|
216
|
+
* @returns CornerBracket SVG at the specified corner
|
|
258
217
|
*/
|
|
259
|
-
function DataCardBracket({ position, variant = "default"
|
|
260
|
-
const { size,
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
})
|
|
218
|
+
function DataCardBracket({ position, variant = "default" }) {
|
|
219
|
+
const { size, config } = useDataCard();
|
|
220
|
+
const animate = config?.animateBrackets ?? true;
|
|
221
|
+
return /* @__PURE__ */ jsx(CornerBracket, {
|
|
222
|
+
position,
|
|
223
|
+
variant,
|
|
224
|
+
size: {
|
|
225
|
+
compact: 16,
|
|
226
|
+
default: 20,
|
|
227
|
+
spacious: 24
|
|
228
|
+
}[size ?? "default"],
|
|
229
|
+
className: cn(animate && "opacity-60 group-hover/data-card:opacity-100 transition-opacity", !animate && "opacity-50")
|
|
272
230
|
});
|
|
273
231
|
}
|
|
274
232
|
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DynamicToggle — CSS state transitions.
|
|
3
|
+
*
|
|
4
|
+
* Rules requiring :has(), container queries, clip-path, or pseudo-elements.
|
|
5
|
+
* Layout, colors, sizing in Tailwind (DynamicToggle.styles.ts).
|
|
6
|
+
*
|
|
7
|
+
* @import '@mks2508/mks-ui/dist/react-ui/ui/DynamicToggle/DynamicToggle.css';
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* ── Variables ── */
|
|
11
|
+
[data-slot="dt-root"] {
|
|
12
|
+
--dt-dur: 0.22s;
|
|
13
|
+
--dt-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
14
|
+
--dt-fade: 0.45;
|
|
15
|
+
--dt-indicator-dur: 0.3s;
|
|
16
|
+
--dt-indicator-ease: cubic-bezier(0.4, 0, 0.2, 1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* ── Track: explicit row prevents h-full items from overflowing container ── */
|
|
20
|
+
[data-slot="dt-root"] [data-slot="dt-track"] {
|
|
21
|
+
grid-template-rows: minmax(0, 1fr);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* ── Top-level option spans 2 grid cols ── */
|
|
25
|
+
[data-slot="dt-root"] [data-slot="dt-track"] > label {
|
|
26
|
+
grid-column: span 2;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* ── Primary option text ── */
|
|
30
|
+
[data-slot="dt-root"] [data-slot="dt-track"]:has(> input:checked) > label {
|
|
31
|
+
color: var(--accent-foreground);
|
|
32
|
+
z-index: 2;
|
|
33
|
+
}
|
|
34
|
+
[data-slot="dt-root"] [data-slot="dt-track"]:not(:has(> input:checked)) > label {
|
|
35
|
+
color: var(--foreground);
|
|
36
|
+
opacity: var(--dt-fade);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* ── Group: container queries ── */
|
|
40
|
+
[data-slot="dt-root"] [data-slot="dt-group"] {
|
|
41
|
+
container-type: size;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* ══════════════════════════════════════════════════════════
|
|
46
|
+
* INDICATOR POSITIONING
|
|
47
|
+
*
|
|
48
|
+
* Modern: CSS Anchor Positioning — indicator follows active option
|
|
49
|
+
* Fallback: translate-based positioning for older browsers
|
|
50
|
+
* ══════════════════════════════════════════════════════════ */
|
|
51
|
+
|
|
52
|
+
/* ── Anchor-based indicator (requires full anchor API) ── */
|
|
53
|
+
@supports (anchor-scope: all) {
|
|
54
|
+
/* Scope anchors per toggle instance */
|
|
55
|
+
[data-slot="dt-root"]:not([data-indicator="translate"]) {
|
|
56
|
+
anchor-scope: --dt-active;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Active option becomes the anchor via native :checked */
|
|
60
|
+
[data-slot="dt-root"]:not([data-indicator="translate"]) [data-slot="dt-track"] > label:has(+ input:checked) {
|
|
61
|
+
anchor-name: --dt-active;
|
|
62
|
+
}
|
|
63
|
+
[data-slot="dt-root"]:not([data-indicator="translate"]) [data-slot="dt-group"] > label:has(+ input:checked) {
|
|
64
|
+
anchor-name: --dt-active;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Single unified indicator: morphs from full-width to half-width */
|
|
68
|
+
[data-slot="dt-root"]:not([data-indicator="translate"]) [data-slot="dt-indicator"] {
|
|
69
|
+
position-anchor: --dt-active;
|
|
70
|
+
top: anchor(top);
|
|
71
|
+
right: anchor(right);
|
|
72
|
+
bottom: anchor(bottom);
|
|
73
|
+
left: anchor(left);
|
|
74
|
+
translate: none;
|
|
75
|
+
width: auto;
|
|
76
|
+
transition:
|
|
77
|
+
top var(--dt-indicator-dur) var(--dt-indicator-ease),
|
|
78
|
+
right var(--dt-indicator-dur) var(--dt-indicator-ease),
|
|
79
|
+
bottom var(--dt-indicator-dur) var(--dt-indicator-ease),
|
|
80
|
+
left var(--dt-indicator-dur) var(--dt-indicator-ease);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Hide the group indicator — unified indicator handles everything */
|
|
84
|
+
[data-slot="dt-root"]:not([data-indicator="translate"]) [data-slot="dt-group-indicator"] {
|
|
85
|
+
display: none;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ── Inset-based fallback (older browsers) — same morph as anchor but hardcoded ── */
|
|
90
|
+
@supports not (anchor-scope: all) {
|
|
91
|
+
/* Unified indicator: left/right transition morphs width + position */
|
|
92
|
+
[data-slot="dt-root"] [data-slot="dt-indicator"] {
|
|
93
|
+
left: 50%;
|
|
94
|
+
right: 0;
|
|
95
|
+
width: auto;
|
|
96
|
+
translate: none;
|
|
97
|
+
transition:
|
|
98
|
+
left var(--dt-indicator-dur) var(--dt-indicator-ease),
|
|
99
|
+
right var(--dt-indicator-dur) var(--dt-indicator-ease);
|
|
100
|
+
}
|
|
101
|
+
/* Top-level checked: indicator covers left half */
|
|
102
|
+
[data-slot="dt-root"] [data-slot="dt-track"]:has(> input:checked) [data-slot="dt-indicator"] {
|
|
103
|
+
left: 0;
|
|
104
|
+
right: 50%;
|
|
105
|
+
}
|
|
106
|
+
/* Group option 1 checked: indicator at 3rd quarter */
|
|
107
|
+
[data-slot="dt-root"] [data-slot="dt-group"]:has(input:nth-of-type(1):checked) ~ [data-slot="dt-indicator"],
|
|
108
|
+
[data-slot="dt-root"] [data-slot="dt-track"]:has([data-slot="dt-group"] input:nth-of-type(1):checked) [data-slot="dt-indicator"] {
|
|
109
|
+
left: 50%;
|
|
110
|
+
right: 25%;
|
|
111
|
+
}
|
|
112
|
+
/* Group option 2 checked: indicator at 4th quarter */
|
|
113
|
+
[data-slot="dt-root"] [data-slot="dt-group"]:has(input:nth-of-type(2):checked) ~ [data-slot="dt-indicator"],
|
|
114
|
+
[data-slot="dt-root"] [data-slot="dt-track"]:has([data-slot="dt-group"] input:nth-of-type(2):checked) [data-slot="dt-indicator"] {
|
|
115
|
+
left: 75%;
|
|
116
|
+
right: 0;
|
|
117
|
+
}
|
|
118
|
+
/* Hide group indicator — unified indicator handles everything */
|
|
119
|
+
[data-slot="dt-root"] [data-slot="dt-group-indicator"] {
|
|
120
|
+
display: none;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ── Force inset mode via data-indicator="translate" (works regardless of @supports) ── */
|
|
125
|
+
[data-slot="dt-root"][data-indicator="translate"] [data-slot="dt-indicator"] {
|
|
126
|
+
left: 50%;
|
|
127
|
+
right: 0;
|
|
128
|
+
width: auto;
|
|
129
|
+
translate: none;
|
|
130
|
+
transition:
|
|
131
|
+
left var(--dt-indicator-dur) var(--dt-indicator-ease),
|
|
132
|
+
right var(--dt-indicator-dur) var(--dt-indicator-ease);
|
|
133
|
+
}
|
|
134
|
+
[data-slot="dt-root"][data-indicator="translate"] [data-slot="dt-track"]:has(> input:checked) [data-slot="dt-indicator"] {
|
|
135
|
+
left: 0;
|
|
136
|
+
right: 50%;
|
|
137
|
+
}
|
|
138
|
+
[data-slot="dt-root"][data-indicator="translate"] [data-slot="dt-track"]:has([data-slot="dt-group"] input:nth-of-type(1):checked) [data-slot="dt-indicator"] {
|
|
139
|
+
left: 50%;
|
|
140
|
+
right: 25%;
|
|
141
|
+
}
|
|
142
|
+
[data-slot="dt-root"][data-indicator="translate"] [data-slot="dt-track"]:has([data-slot="dt-group"] input:nth-of-type(2):checked) [data-slot="dt-indicator"] {
|
|
143
|
+
left: 75%;
|
|
144
|
+
right: 0;
|
|
145
|
+
}
|
|
146
|
+
[data-slot="dt-root"][data-indicator="translate"] [data-slot="dt-group-indicator"] {
|
|
147
|
+
display: none;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* ══════════════════════════════════════════════════════════
|
|
151
|
+
* GROUP COLLAPSED STATE
|
|
152
|
+
*
|
|
153
|
+
* ::before = title text (via data-label attr)
|
|
154
|
+
* ::after = combined opts text (via data-opts attr)
|
|
155
|
+
* <label>s = controlled by data-collapsed mode
|
|
156
|
+
*
|
|
157
|
+
* 3 modes: title | opts | title-opts (default)
|
|
158
|
+
* ══════════════════════════════════════════════════════════ */
|
|
159
|
+
|
|
160
|
+
/* ── ::before — group title ── */
|
|
161
|
+
[data-slot="dt-group"]::before {
|
|
162
|
+
content: attr(data-label);
|
|
163
|
+
position: absolute;
|
|
164
|
+
left: 50%;
|
|
165
|
+
top: 50%;
|
|
166
|
+
translate: -50% -80%;
|
|
167
|
+
color: var(--foreground);
|
|
168
|
+
font-size: inherit;
|
|
169
|
+
font-weight: 500;
|
|
170
|
+
z-index: 2;
|
|
171
|
+
white-space: nowrap;
|
|
172
|
+
pointer-events: none;
|
|
173
|
+
transition:
|
|
174
|
+
scale var(--dt-dur) var(--dt-ease),
|
|
175
|
+
translate var(--dt-dur) var(--dt-ease),
|
|
176
|
+
opacity var(--dt-dur) var(--dt-ease);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* ── ::after — combined opts text ── */
|
|
180
|
+
[data-slot="dt-group"]::after {
|
|
181
|
+
content: attr(data-opts);
|
|
182
|
+
position: absolute;
|
|
183
|
+
left: 50%;
|
|
184
|
+
top: 50%;
|
|
185
|
+
translate: -50% 20%;
|
|
186
|
+
color: var(--muted-foreground);
|
|
187
|
+
font-size: 0.85em;
|
|
188
|
+
opacity: 0.6;
|
|
189
|
+
z-index: 2;
|
|
190
|
+
white-space: nowrap;
|
|
191
|
+
pointer-events: none;
|
|
192
|
+
transition: opacity var(--dt-dur) var(--dt-ease);
|
|
193
|
+
}
|
|
194
|
+
[data-slot="dt-group"]:not([data-opts])::after {
|
|
195
|
+
content: none;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* ── Group labels — transition props ── */
|
|
199
|
+
[data-slot="dt-root"] [data-slot="dt-group"] label {
|
|
200
|
+
color: var(--muted-foreground);
|
|
201
|
+
cursor: pointer;
|
|
202
|
+
z-index: 2;
|
|
203
|
+
transition:
|
|
204
|
+
color var(--dt-dur) var(--dt-ease),
|
|
205
|
+
opacity var(--dt-dur) var(--dt-ease),
|
|
206
|
+
translate var(--dt-dur) var(--dt-ease);
|
|
207
|
+
}
|
|
208
|
+
[data-slot="dt-root"] [data-slot="dt-group"] label span {
|
|
209
|
+
display: grid;
|
|
210
|
+
place-items: center;
|
|
211
|
+
height: 100%;
|
|
212
|
+
width: 100%;
|
|
213
|
+
border-radius: var(--dt-radius, 9999px);
|
|
214
|
+
transition: scale var(--dt-dur) var(--dt-ease);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* ── Collapsed mode: "title" — only ::before, labels slide+scale out ── */
|
|
218
|
+
[data-slot="dt-group"][data-collapsed="title"]::before {
|
|
219
|
+
translate: -50% -50%;
|
|
220
|
+
}
|
|
221
|
+
[data-slot="dt-group"][data-collapsed="title"]::after {
|
|
222
|
+
display: none;
|
|
223
|
+
}
|
|
224
|
+
[data-slot="dt-group"][data-collapsed="title"]:not(:has(input:checked)) label {
|
|
225
|
+
opacity: 0;
|
|
226
|
+
translate: 0 30%;
|
|
227
|
+
}
|
|
228
|
+
[data-slot="dt-group"][data-collapsed="title"]:not(:has(input:checked)) label span {
|
|
229
|
+
scale: 0.5;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* ── Collapsed mode: "opts" — only ::after, labels slide+scale out ── */
|
|
233
|
+
[data-slot="dt-group"][data-collapsed="opts"]::before {
|
|
234
|
+
display: none;
|
|
235
|
+
}
|
|
236
|
+
[data-slot="dt-group"][data-collapsed="opts"]::after {
|
|
237
|
+
translate: -50% -50%;
|
|
238
|
+
font-size: inherit;
|
|
239
|
+
opacity: 0.7;
|
|
240
|
+
}
|
|
241
|
+
[data-slot="dt-group"][data-collapsed="opts"]:not(:has(input:checked)) label {
|
|
242
|
+
opacity: 0;
|
|
243
|
+
translate: 0 30%;
|
|
244
|
+
}
|
|
245
|
+
[data-slot="dt-group"][data-collapsed="opts"]:not(:has(input:checked)) label span {
|
|
246
|
+
scale: 0.5;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* ── Collapsed mode: "title-opts" — WIP: disabled, falls back to "title" behavior ── */
|
|
250
|
+
/* TODO: title-opts needs a redesign — title (::before) and scaled labels overlap
|
|
251
|
+
at all container sizes. The codepen original morph relied on specific dimensions
|
|
252
|
+
that don't translate to the component's size variants. Needs a different approach
|
|
253
|
+
(e.g., crossfade, flex layout, or JS-measured positions). */
|
|
254
|
+
[data-slot="dt-group"][data-collapsed="title-opts"]::after {
|
|
255
|
+
content: none;
|
|
256
|
+
}
|
|
257
|
+
[data-slot="dt-group"][data-collapsed="title-opts"]::before {
|
|
258
|
+
translate: -50% -50%;
|
|
259
|
+
}
|
|
260
|
+
[data-slot="dt-group"][data-collapsed="title-opts"]:not(:has(input:checked)) label {
|
|
261
|
+
opacity: 0;
|
|
262
|
+
translate: 0 30%;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* ── When group expanded ── */
|
|
266
|
+
[data-slot="dt-group"]:has(input:checked)::before {
|
|
267
|
+
translate: -50% -250%;
|
|
268
|
+
scale: 0.85;
|
|
269
|
+
}
|
|
270
|
+
[data-slot="dt-group"]:has(input:checked)::after {
|
|
271
|
+
opacity: 0;
|
|
272
|
+
}
|
|
273
|
+
[data-slot="dt-group"]:has(input:checked) label {
|
|
274
|
+
opacity: 0.75;
|
|
275
|
+
color: var(--muted-foreground);
|
|
276
|
+
translate: 0 0;
|
|
277
|
+
}
|
|
278
|
+
[data-slot="dt-group"]:has(input:checked) label span {
|
|
279
|
+
scale: 1;
|
|
280
|
+
}
|
|
281
|
+
[data-slot="dt-group"]:has(input:nth-of-type(1):checked) label:nth-of-type(1),
|
|
282
|
+
[data-slot="dt-group"]:has(input:nth-of-type(2):checked) label:nth-of-type(2) {
|
|
283
|
+
color: var(--foreground);
|
|
284
|
+
opacity: 1;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* ══════════════════════════════════════════════════════════
|
|
288
|
+
* GROUP LABEL (above/below the pill)
|
|
289
|
+
*
|
|
290
|
+
* Replaces the old "bubble" element. Positioned via CSS grid.
|
|
291
|
+
* In filter/path morph modes, rendered inside GooeyCanvas.
|
|
292
|
+
* In none mode, simple CSS-driven show/hide.
|
|
293
|
+
* ══════════════════════════════════════════════════════════ */
|
|
294
|
+
|
|
295
|
+
[data-slot="dt-group-label"] {
|
|
296
|
+
display: grid;
|
|
297
|
+
grid-template-rows: 0fr;
|
|
298
|
+
left: 20%;
|
|
299
|
+
right: 20%;
|
|
300
|
+
transition:
|
|
301
|
+
grid-template-rows calc(var(--dt-dur) * 1.5) var(--dt-ease),
|
|
302
|
+
opacity var(--dt-dur) var(--dt-ease);
|
|
303
|
+
opacity: 0;
|
|
304
|
+
background: var(--card);
|
|
305
|
+
border: 1px solid var(--border);
|
|
306
|
+
z-index: 3;
|
|
307
|
+
transform: translateZ(0);
|
|
308
|
+
-webkit-transform: translateZ(0);
|
|
309
|
+
}
|
|
310
|
+
[data-slot="dt-group-label"] > span {
|
|
311
|
+
overflow: hidden;
|
|
312
|
+
min-height: 0;
|
|
313
|
+
display: flex;
|
|
314
|
+
align-items: center;
|
|
315
|
+
justify-content: center;
|
|
316
|
+
padding: 0 0.75em;
|
|
317
|
+
height: calc(var(--dt-h, 38px) * 0.4);
|
|
318
|
+
box-sizing: border-box;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* Top position */
|
|
322
|
+
[data-slot="dt-group-label"][data-position="top"] {
|
|
323
|
+
bottom: 100%;
|
|
324
|
+
border-radius: calc(var(--dt-h, 38px) * 0.2) calc(var(--dt-h, 38px) * 0.2) 0 0;
|
|
325
|
+
border-bottom: none;
|
|
326
|
+
margin-bottom: -1px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Bottom position */
|
|
330
|
+
[data-slot="dt-group-label"][data-position="bottom"] {
|
|
331
|
+
top: 100%;
|
|
332
|
+
border-radius: 0 0 calc(var(--dt-h, 38px) * 0.2) calc(var(--dt-h, 38px) * 0.2);
|
|
333
|
+
border-top: none;
|
|
334
|
+
margin-top: -1px;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* When group active → group label grows */
|
|
338
|
+
[data-slot="dt-root"]:not(:has([data-slot="dt-track"] > input:checked)) [data-slot="dt-group-label"] {
|
|
339
|
+
grid-template-rows: 1fr;
|
|
340
|
+
opacity: 1;
|
|
341
|
+
}
|
|
342
|
+
[data-slot="dt-root"]:not(:has([data-slot="dt-track"] > input:checked)) [data-slot="dt-group-label"] > span {
|
|
343
|
+
padding: 0.35em 0.75em;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* ── Filter morph mode ── */
|
|
347
|
+
[data-slot="dt-root"][data-morph="filter"] {
|
|
348
|
+
background: transparent;
|
|
349
|
+
border-color: transparent;
|
|
350
|
+
box-shadow: none;
|
|
351
|
+
overflow: visible;
|
|
352
|
+
}
|
|
353
|
+
[data-slot="dt-root"][data-morph="filter"] [data-slot="dt-group-label"] {
|
|
354
|
+
border: none;
|
|
355
|
+
}
|
|
356
|
+
[data-slot="dt-root"][data-morph="filter"] [data-slot="dt-track"] {
|
|
357
|
+
position: relative;
|
|
358
|
+
z-index: 1;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* ── Filter morph: ::before hides on expand, gooey canvas handles junction ── */
|
|
362
|
+
[data-slot="dt-root"][data-morph="filter"] [data-slot="dt-group"]:has(input:checked)::before {
|
|
363
|
+
opacity: 0;
|
|
364
|
+
translate: -50% -80%;
|
|
365
|
+
scale: 1;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* ── Path morph mode ── */
|
|
369
|
+
[data-slot="dt-root"][data-morph="path"] {
|
|
370
|
+
background: transparent;
|
|
371
|
+
border-color: transparent;
|
|
372
|
+
}
|
|
373
|
+
[data-slot="dt-root"][data-morph="path"] [data-slot="dt-track"] {
|
|
374
|
+
position: relative;
|
|
375
|
+
z-index: 1;
|
|
376
|
+
}
|