@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.
Files changed (72) hide show
  1. package/dist/react-ui/index.js +8 -3
  2. package/dist/react-ui/primitives/index.js +5 -0
  3. package/dist/react-ui/primitives/waapi/Gooey/Gooey.types.d.ts +120 -0
  4. package/dist/react-ui/primitives/waapi/Gooey/Gooey.types.d.ts.map +1 -0
  5. package/dist/react-ui/primitives/waapi/Gooey/GooeyCanvas.d.ts +10 -0
  6. package/dist/react-ui/primitives/waapi/Gooey/GooeyCanvas.d.ts.map +1 -0
  7. package/dist/react-ui/primitives/waapi/Gooey/GooeyCanvas.js +190 -0
  8. package/dist/react-ui/primitives/waapi/Gooey/GooeyFilter.d.ts +7 -0
  9. package/dist/react-ui/primitives/waapi/Gooey/GooeyFilter.d.ts.map +1 -0
  10. package/dist/react-ui/primitives/waapi/Gooey/GooeyFilter.js +78 -0
  11. package/dist/react-ui/primitives/waapi/Gooey/MorphPath.d.ts +7 -0
  12. package/dist/react-ui/primitives/waapi/Gooey/MorphPath.d.ts.map +1 -0
  13. package/dist/react-ui/primitives/waapi/Gooey/MorphPath.js +51 -0
  14. package/dist/react-ui/primitives/waapi/Gooey/gooey-utils.d.ts +94 -0
  15. package/dist/react-ui/primitives/waapi/Gooey/gooey-utils.d.ts.map +1 -0
  16. package/dist/react-ui/primitives/waapi/Gooey/gooey-utils.js +182 -0
  17. package/dist/react-ui/primitives/waapi/Gooey/index.d.ts +28 -0
  18. package/dist/react-ui/primitives/waapi/Gooey/index.d.ts.map +1 -0
  19. package/dist/react-ui/primitives/waapi/Gooey/index.js +5 -0
  20. package/dist/react-ui/primitives/waapi/Gooey/useMorphPath.d.ts +7 -0
  21. package/dist/react-ui/primitives/waapi/Gooey/useMorphPath.d.ts.map +1 -0
  22. package/dist/react-ui/primitives/waapi/Gooey/useMorphPath.js +47 -0
  23. package/dist/react-ui/primitives/waapi/index.d.ts +2 -0
  24. package/dist/react-ui/primitives/waapi/index.d.ts.map +1 -1
  25. package/dist/react-ui/primitives/waapi/index.js +6 -0
  26. package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts +26 -16
  27. package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts.map +1 -1
  28. package/dist/react-ui/ui/DataCard/DataCard.styles.js +36 -74
  29. package/dist/react-ui/ui/DataCard/DataCard.types.d.ts +50 -70
  30. package/dist/react-ui/ui/DataCard/DataCard.types.d.ts.map +1 -1
  31. package/dist/react-ui/ui/DataCard/index.d.ts +24 -93
  32. package/dist/react-ui/ui/DataCard/index.d.ts.map +1 -1
  33. package/dist/react-ui/ui/DataCard/index.js +76 -118
  34. package/dist/react-ui/ui/DynamicToggle/DynamicToggle-DOR3Ld-k.css +376 -0
  35. package/dist/react-ui/ui/DynamicToggle/DynamicToggle.css +376 -0
  36. package/dist/react-ui/ui/DynamicToggle/DynamicToggle.js +0 -0
  37. package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.d.ts +20 -8
  38. package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.d.ts.map +1 -1
  39. package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.js +55 -27
  40. package/dist/react-ui/ui/DynamicToggle/DynamicToggle.types.d.ts +69 -14
  41. package/dist/react-ui/ui/DynamicToggle/DynamicToggle.types.d.ts.map +1 -1
  42. package/dist/react-ui/ui/DynamicToggle/index.d.ts +22 -20
  43. package/dist/react-ui/ui/DynamicToggle/index.d.ts.map +1 -1
  44. package/dist/react-ui/ui/DynamicToggle/index.js +133 -96
  45. package/dist/react-ui/ui/Switch/index.js +1 -1
  46. package/dist/react-ui/ui/index.js +2 -2
  47. package/package.json +2 -2
  48. package/src/css.d.ts +1 -0
  49. package/src/react-ui/primitives/waapi/Gooey/Gooey.types.ts +141 -0
  50. package/src/react-ui/primitives/waapi/Gooey/GooeyCanvas.tsx +217 -0
  51. package/src/react-ui/primitives/waapi/Gooey/GooeyFilter.tsx +77 -0
  52. package/src/react-ui/primitives/waapi/Gooey/MorphPath.tsx +58 -0
  53. package/src/react-ui/primitives/waapi/Gooey/gooey-utils.ts +253 -0
  54. package/src/react-ui/primitives/waapi/Gooey/index.ts +50 -0
  55. package/src/react-ui/primitives/waapi/Gooey/useMorphPath.ts +48 -0
  56. package/src/react-ui/primitives/waapi/index.ts +23 -0
  57. package/src/react-ui/ui/DataCard/DataCard.styles.ts +45 -101
  58. package/src/react-ui/ui/DataCard/DataCard.types.ts +52 -73
  59. package/src/react-ui/ui/DataCard/index.tsx +118 -184
  60. package/src/react-ui/ui/DynamicToggle/DynamicToggle.css +320 -94
  61. package/src/react-ui/ui/DynamicToggle/DynamicToggle.styles.ts +60 -40
  62. package/src/react-ui/ui/DynamicToggle/DynamicToggle.types.ts +101 -14
  63. package/src/react-ui/ui/DynamicToggle/index.tsx +172 -96
  64. package/src/react-ui/ui/DynamicToggle/prototype-v7-ios.html +413 -0
  65. package/src/react-ui/ui/DynamicToggle/prototype-v7.html +615 -0
  66. package/src/react-ui/ui/DynamicToggle/prototype-v8-gooey-safari.html +560 -0
  67. package/src/react-ui/ui/DynamicToggle/prototype-v8b-react-structure.html +227 -0
  68. package/src/react-ui/ui/DynamicToggle/prototype.html +419 -0
  69. package/src/react-ui/ui/Switch/index.tsx +1 -1
  70. /package/dist/react-ui/blocks/Terminal/panel/{terminal-filter-dropdown.module-DAcl_XQZ.css → terminal-filter-dropdown.module-C6oDcFBS.css} +0 -0
  71. /package/dist/react-ui/blocks/Terminal/panel/{terminal-session-tabs.module-DNAop5e3.css → terminal-session-tabs.module-D_-sgyza.css} +0 -0
  72. /package/dist/react-ui/components/MorphingPopover/{morphing-popover.module-BJrjXisF.css → morphing-popover.module-B1ftlaYj.css} +0 -0
@@ -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
+ }
@@ -1,23 +1,35 @@
1
1
  /**
2
- * DynamicToggle style slots and types.
2
+ * DynamicToggle style slots + CVA variants.
3
3
  *
4
- * Uses semantic CSS variables for all colors.
5
- * Animation handled in DynamicToggle.css (clip-path, transitions).
4
+ * Layout via Tailwind. State animations via CSS file (`:has()`, `clip-path`).
5
+ * Shape propagated to indicators via `--dt-radius` CSS variable.
6
6
  *
7
7
  * @module @mks2508/mks-ui/react/ui/DynamicToggle
8
8
  */
9
+ import { type VariantProps } from 'class-variance-authority';
9
10
  import type { StyleSlots } from '../../../core/types';
10
11
  /** Slot names for DynamicToggle */
11
- export type DynamicToggleSlot = 'root' | 'track' | 'option' | 'indicator' | 'group' | 'groupLabel' | 'groupIndicator';
12
+ export type DynamicToggleSlot = 'root' | 'track' | 'option' | 'indicator' | 'group' | 'groupIndicator' | 'groupLabel';
12
13
  /**
13
14
  * Default styles for each DynamicToggle slot.
14
15
  *
16
+ * Width is set by size variants — required because indicator uses `width: 50%`
17
+ * and clip-path uses container query units. Override: `slots={{ root: 'w-80' }}`.
18
+ */
19
+ export declare const dynamicToggleStyles: StyleSlots<DynamicToggleSlot>;
20
+ /**
21
+ * CVA variants for DynamicToggle root.
22
+ *
15
23
  * @example
16
24
  * ```tsx
17
- * <DynamicToggle slots={{ root: 'w-72', indicator: 'bg-primary' }}>
18
- * ...
19
- * </DynamicToggle>
25
+ * <DynamicToggle size="sm" variant="outline" shape="rounded">
20
26
  * ```
21
27
  */
22
- export declare const dynamicToggleStyles: StyleSlots<DynamicToggleSlot>;
28
+ export declare const dynamicToggleVariants: (props?: ({
29
+ variant?: "muted" | "default" | "outline" | "ghost" | null | undefined;
30
+ size?: "default" | "sm" | "lg" | null | undefined;
31
+ shape?: "square" | "pill" | "rounded" | null | undefined;
32
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
33
+ /** Variant props extracted from CVA */
34
+ export type DynamicToggleVariantProps = VariantProps<typeof dynamicToggleVariants>;
23
35
  //# sourceMappingURL=DynamicToggle.styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DynamicToggle.styles.d.ts","sourceRoot":"","sources":["../../../../src/react-ui/ui/DynamicToggle/DynamicToggle.styles.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,mCAAmC;AACnC,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,OAAO,GACP,QAAQ,GACR,WAAW,GACX,OAAO,GACP,YAAY,GACZ,gBAAgB,CAAC;AAErB;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAAU,CAAC,iBAAiB,CAiC7D,CAAC"}
1
+ {"version":3,"file":"DynamicToggle.styles.d.ts","sourceRoot":"","sources":["../../../../src/react-ui/ui/DynamicToggle/DynamicToggle.styles.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,mCAAmC;AACnC,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,OAAO,GACP,QAAQ,GACR,WAAW,GACX,OAAO,GACP,gBAAgB,GAChB,YAAY,CAAC;AAEjB;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAAU,CAAC,iBAAiB,CAa7D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;8EA8BhC,CAAC;AAEH,uCAAuC;AACvC,MAAM,MAAM,yBAAyB,GAAG,YAAY,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -1,39 +1,67 @@
1
+ import { cva } from "class-variance-authority";
2
+
1
3
  //#region src/react-ui/ui/DynamicToggle/DynamicToggle.styles.ts
2
4
  /**
5
+ * DynamicToggle style slots + CVA variants.
6
+ *
7
+ * Layout via Tailwind. State animations via CSS file (`:has()`, `clip-path`).
8
+ * Shape propagated to indicators via `--dt-radius` CSS variable.
9
+ *
10
+ * @module @mks2508/mks-ui/react/ui/DynamicToggle
11
+ */
12
+ /**
3
13
  * Default styles for each DynamicToggle slot.
4
14
  *
5
- * @example
6
- * ```tsx
7
- * <DynamicToggle slots={{ root: 'w-72', indicator: 'bg-primary' }}>
8
- * ...
9
- * </DynamicToggle>
10
- * ```
15
+ * Width is set by size variants — required because indicator uses `width: 50%`
16
+ * and clip-path uses container query units. Override: `slots={{ root: 'w-80' }}`.
11
17
  */
12
18
  const dynamicToggleStyles = {
13
- root: ["relative rounded-full border border-border bg-card", "p-[2px] select-none"].join(" "),
14
- track: ["relative grid place-items-center", "w-full h-full"].join(" "),
15
- option: [
16
- "inline-grid place-items-center cursor-pointer",
17
- "text-xs font-medium z-[2] h-full w-full",
18
- "transition-[color,opacity] duration-[220ms]"
19
- ].join(" "),
20
- indicator: [
21
- "absolute w-1/2 left-0 top-0 bottom-0",
22
- "bg-foreground rounded-full",
23
- "pointer-events-none z-0"
24
- ].join(" "),
25
- group: ["relative w-full h-full grid", "border border-transparent"].join(" "),
19
+ root: "relative border p-[2px] select-none",
20
+ track: "relative grid grid-cols-[repeat(4,1fr)] place-items-center w-full h-full",
21
+ option: "inline-grid place-items-center cursor-pointer font-medium z-[2] h-full w-full whitespace-nowrap",
22
+ indicator: "absolute w-1/2 left-0 top-0 bottom-0 bg-accent rounded-[var(--dt-radius,9999px)] pointer-events-none z-0",
23
+ group: "col-span-2 relative w-full h-full grid grid-cols-2",
24
+ groupIndicator: "absolute left-1/2 top-0 bottom-0 w-1/2 bg-accent rounded-[var(--dt-radius,9999px)] pointer-events-none z-0",
26
25
  groupLabel: [
27
- "absolute left-1/2 top-1/2 z-[2]",
28
- "text-xs font-medium text-foreground",
26
+ "absolute",
27
+ "flex items-center justify-center",
28
+ "text-muted-foreground font-medium whitespace-nowrap",
29
29
  "pointer-events-none"
30
- ].join(" "),
31
- groupIndicator: [
32
- "absolute left-1/2 top-0 bottom-0",
33
- "bg-foreground rounded-full",
34
- "pointer-events-none z-0"
35
30
  ].join(" ")
36
31
  };
32
+ /**
33
+ * CVA variants for DynamicToggle root.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * <DynamicToggle size="sm" variant="outline" shape="rounded">
38
+ * ```
39
+ */
40
+ const dynamicToggleVariants = cva(dynamicToggleStyles.root, {
41
+ variants: {
42
+ variant: {
43
+ default: "bg-card border-border shadow-sm",
44
+ ghost: "bg-transparent border-transparent",
45
+ muted: "bg-muted border-muted",
46
+ outline: "bg-transparent border-border"
47
+ },
48
+ size: {
49
+ sm: "h-[30px] w-[210px] text-[10px] [--dt-h:30px]",
50
+ default: "h-[38px] w-[260px] text-xs [--dt-h:38px]",
51
+ lg: "h-[44px] w-80 text-sm [--dt-h:44px]"
52
+ },
53
+ shape: {
54
+ pill: "rounded-full [--dt-radius:9999px]",
55
+ rounded: "rounded-xl [--dt-radius:0.75rem]",
56
+ square: "rounded-md [--dt-radius:0.375rem]"
57
+ }
58
+ },
59
+ defaultVariants: {
60
+ variant: "default",
61
+ size: "default",
62
+ shape: "pill"
63
+ }
64
+ });
37
65
 
38
66
  //#endregion
39
- export { dynamicToggleStyles };
67
+ export { dynamicToggleStyles, dynamicToggleVariants };
@@ -1,13 +1,42 @@
1
1
  /**
2
2
  * DynamicToggle type definitions.
3
3
  *
4
- * A CSS-animated toggle where one option can expand into sub-options.
5
- * Uses hidden radio inputs + `:has(:checked)` for zero-JS animation.
4
+ * CSS-animated toggle where one option expands into sub-options.
5
+ * Uses hidden radios + `:has(:checked)` for zero-JS animation.
6
+ * Optional gooey morph via `GooeyCanvas` or `MorphPath` primitives.
6
7
  *
7
8
  * @module @mks2508/mks-ui/react/ui/DynamicToggle
8
9
  */
9
- import type { SlotOverrides } from '../../../core/types';
10
- import type { DynamicToggleSlot } from './DynamicToggle.styles';
10
+ import type { SlotOverrides, IBaseConfig } from '../../../core/types';
11
+ import type { DynamicToggleSlot, DynamicToggleVariantProps } from './DynamicToggle.styles';
12
+ /** How the group appears when collapsed (standalone option active). */
13
+ export type DynamicToggleCollapsedMode = 'title' | 'opts' | 'title-opts';
14
+ /** Morph technique for the pill↔groupLabel junction. */
15
+ export type DynamicToggleMorphMode = 'none' | 'filter' | 'path';
16
+ /**
17
+ * Configuration for DynamicToggle animation behavior.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * <DynamicToggle config={{ morphMode: 'filter', duration: 0.3 }}>
22
+ * ...
23
+ * </DynamicToggle>
24
+ * ```
25
+ */
26
+ export interface IDynamicToggleConfig extends IBaseConfig {
27
+ /** CSS transition duration in seconds (default: 0.22) */
28
+ duration?: number;
29
+ /** Label animation style (default: 'morph') */
30
+ labelAnimation?: 'morph' | 'float' | 'none';
31
+ /** Gooey morph mode for the pill↔groupLabel junction (default: 'none') */
32
+ morphMode?: DynamicToggleMorphMode;
33
+ /** Indicator slide duration in seconds (default: 0.3) */
34
+ indicatorDuration?: number;
35
+ /** Indicator slide easing (default: material standard cubic-bezier) */
36
+ indicatorEasing?: string;
37
+ /** Force translate-based indicator instead of CSS Anchor (debug/compat) */
38
+ forceTranslateIndicator?: boolean;
39
+ }
11
40
  /**
12
41
  * Context shared between DynamicToggle root and its children.
13
42
  */
@@ -20,30 +49,46 @@ export type DynamicToggleContextType = {
20
49
  groupName: string;
21
50
  /** Whether a group child is active */
22
51
  groupActive: boolean;
52
+ /** Whether the toggle is disabled */
53
+ disabled: boolean;
54
+ /** Register group info (called by DynamicToggleGroup on mount) */
55
+ registerGroup: (label: string, values: string[], position: 'top' | 'bottom' | 'hidden', collapsedMode: DynamicToggleCollapsedMode) => void;
23
56
  };
24
57
  /**
25
58
  * Props for the DynamicToggle root container.
26
59
  *
60
+ * Supports exactly one `DynamicToggleOption` + one `DynamicToggleGroup`.
61
+ * The group expands into sub-options when one of its children is active.
62
+ *
27
63
  * @example
28
64
  * ```tsx
29
- * <DynamicToggle value="tree" onValueChange={setVal}>
65
+ * <DynamicToggle
66
+ * value="tree" onValueChange={setVal}
67
+ * size="sm" config={{ morphMode: 'filter' }}
68
+ * >
30
69
  * <DynamicToggleOption value="tree">Tree</DynamicToggleOption>
31
- * <DynamicToggleGroup label="Changes">
70
+ * <DynamicToggleGroup label="Changes" collapsedMode="title">
32
71
  * <DynamicToggleOption value="flat">Flat</DynamicToggleOption>
33
72
  * <DynamicToggleOption value="grouped">Grouped</DynamicToggleOption>
34
73
  * </DynamicToggleGroup>
35
74
  * </DynamicToggle>
36
75
  * ```
37
76
  */
38
- export interface IDynamicToggleProps {
77
+ export interface IDynamicToggleProps extends DynamicToggleVariantProps {
39
78
  /** Controlled value */
40
79
  value?: string;
41
80
  /** Uncontrolled default value */
42
81
  defaultValue?: string;
43
82
  /** Change callback */
44
83
  onValueChange?: (value: string) => void;
84
+ /** Disable the entire toggle */
85
+ disabled?: boolean;
45
86
  /** Slot class overrides */
46
87
  slots?: SlotOverrides<DynamicToggleSlot>;
88
+ /** Animation/behavior configuration */
89
+ config?: IDynamicToggleConfig;
90
+ /** Accessible label for the radio group */
91
+ 'aria-label'?: string;
47
92
  /** Additional class for the root */
48
93
  className?: string;
49
94
  /** DynamicToggleOption and DynamicToggleGroup children */
@@ -67,21 +112,31 @@ export interface IDynamicToggleOptionProps {
67
112
  }
68
113
  /**
69
114
  * Props for an expandable group of options.
70
- * When none of the group's options are active, shows the collapsed `label`.
71
- * When one is active, expands to show all sub-options.
115
+ *
116
+ * When none of the group's options are active, shows collapsed content
117
+ * based on `collapsedMode`:
118
+ * - `'title'` — only the group label
119
+ * - `'opts'` — only the combined sub-option text ("Solo · Team")
120
+ * - `'title-opts'` — WIP: currently falls back to 'title' behavior
121
+ *
122
+ * When one is active, expands with a clip-path reveal animation.
72
123
  *
73
124
  * @example
74
125
  * ```tsx
75
- * <DynamicToggleGroup label="Changes">
76
- * <DynamicToggleOption value="flat">Flat</DynamicToggleOption>
77
- * <DynamicToggleOption value="grouped">Grouped</DynamicToggleOption>
126
+ * <DynamicToggleGroup label="Premium" collapsedMode="title">
127
+ * <DynamicToggleOption value="solo">Solo</DynamicToggleOption>
128
+ * <DynamicToggleOption value="team">Team</DynamicToggleOption>
78
129
  * </DynamicToggleGroup>
79
130
  * ```
80
131
  */
81
132
  export interface IDynamicToggleGroupProps {
82
- /** Label shown when collapsed */
133
+ /** Label shown as group title / group label text */
83
134
  label: string;
84
- /** DynamicToggleOption children */
135
+ /** Group label position relative to the pill (default: 'top') */
136
+ labelPosition?: 'top' | 'bottom' | 'hidden';
137
+ /** How the group appears when collapsed (default: 'title') */
138
+ collapsedMode?: DynamicToggleCollapsedMode;
139
+ /** Exactly 2 DynamicToggleOption children */
85
140
  children: React.ReactNode;
86
141
  /** Additional class */
87
142
  className?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"DynamicToggle.types.d.ts","sourceRoot":"","sources":["../../../../src/react-ui/ui/DynamicToggle/DynamicToggle.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,2BAA2B;IAC3B,KAAK,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACzC,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,wBAAwB;IACvC,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"DynamicToggle.types.d.ts","sourceRoot":"","sources":["../../../../src/react-ui/ui/DynamicToggle/DynamicToggle.types.ts"],"names":[],"mappings":"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"}