@mks2508/mks-ui 0.5.1 → 0.5.4
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 -1
- package/dist/react-ui/primitives/index.js +5 -0
- package/dist/react-ui/primitives/waapi/Gooey/Gooey.types.d.ts +103 -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 +59 -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 +87 -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 +177 -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-Cm6-VceQ.css +304 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.css +303 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.js +0 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.d.ts +35 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.styles.js +67 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.types.d.ts +138 -0
- package/dist/react-ui/ui/DynamicToggle/DynamicToggle.types.d.ts.map +1 -0
- package/dist/react-ui/ui/DynamicToggle/index.d.ts +31 -0
- package/dist/react-ui/ui/DynamicToggle/index.d.ts.map +1 -0
- package/dist/react-ui/ui/DynamicToggle/index.js +188 -0
- package/dist/react-ui/ui/Switch/index.js +1 -1
- package/dist/react-ui/ui/index.d.ts +1 -0
- package/dist/react-ui/ui/index.d.ts.map +1 -1
- package/dist/react-ui/ui/index.js +2 -0
- package/package.json +2 -2
- package/src/css.d.ts +1 -0
- package/src/react-ui/primitives/waapi/Gooey/Gooey.types.ts +123 -0
- package/src/react-ui/primitives/waapi/Gooey/GooeyCanvas.tsx +80 -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 +244 -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 +303 -0
- package/src/react-ui/ui/DynamicToggle/DynamicToggle.styles.ts +85 -0
- package/src/react-ui/ui/DynamicToggle/DynamicToggle.types.ts +174 -0
- package/src/react-ui/ui/DynamicToggle/index.tsx +294 -0
- package/src/react-ui/ui/DynamicToggle/prototype-v7.html +615 -0
- package/src/react-ui/ui/DynamicToggle/prototype.html +419 -0
- package/src/react-ui/ui/Switch/index.tsx +1 -1
- package/src/react-ui/ui/index.ts +3 -0
- /package/dist/react-ui/blocks/Terminal/panel/{terminal-filter-dropdown.module-CNVWCefU.css → terminal-filter-dropdown.module-C6oDcFBS.css} +0 -0
- /package/dist/react-ui/blocks/Terminal/panel/{terminal-session-tabs.module-cmyJ11jP.css → terminal-session-tabs.module-D_-sgyza.css} +0 -0
- /package/dist/react-ui/components/MorphingPopover/{morphing-popover.module-BycNI8nU.css → morphing-popover.module-B1ftlaYj.css} +0 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DynamicToggle — CSS-animated toggle with expanding sub-options and group label.
|
|
5
|
+
*
|
|
6
|
+
* Pure CSS animation via `:has(:checked)` on hidden radio inputs.
|
|
7
|
+
* When the group is active, a group label grows out of the pill.
|
|
8
|
+
* Optional gooey morph via `config.morphMode` for organic junction.
|
|
9
|
+
*
|
|
10
|
+
* Supports exactly 1 `DynamicToggleOption` + 1 `DynamicToggleGroup` (with 2 sub-options).
|
|
11
|
+
*
|
|
12
|
+
* @module @mks2508/mks-ui/react/ui/DynamicToggle
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <DynamicToggle value="tree" onValueChange={setVal} size="sm" shape="pill">
|
|
17
|
+
* <DynamicToggleOption value="tree">Tree</DynamicToggleOption>
|
|
18
|
+
* <DynamicToggleGroup label="Changes" collapsedMode="title" labelPosition="top">
|
|
19
|
+
* <DynamicToggleOption value="flat">Flat</DynamicToggleOption>
|
|
20
|
+
* <DynamicToggleOption value="grouped">Grouped</DynamicToggleOption>
|
|
21
|
+
* </DynamicToggleGroup>
|
|
22
|
+
* </DynamicToggle>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import * as React from 'react';
|
|
27
|
+
import { useControlledState } from '@/react-ui/hooks/State/UseControlledState';
|
|
28
|
+
import { getStrictContext } from '@/react-ui/lib/get-strict-context';
|
|
29
|
+
import { cn } from '@/react-ui/lib/utils';
|
|
30
|
+
import { GooeyCanvas } from '@/react-ui/primitives/waapi/Gooey/GooeyCanvas';
|
|
31
|
+
import './DynamicToggle.css';
|
|
32
|
+
import { dynamicToggleStyles, dynamicToggleVariants } from './DynamicToggle.styles';
|
|
33
|
+
import type {
|
|
34
|
+
DynamicToggleContextType,
|
|
35
|
+
DynamicToggleCollapsedMode,
|
|
36
|
+
IDynamicToggleProps,
|
|
37
|
+
IDynamicToggleOptionProps,
|
|
38
|
+
IDynamicToggleGroupProps,
|
|
39
|
+
} from './DynamicToggle.types';
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Context
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
const [DynamicToggleProvider, useDynamicToggle] =
|
|
46
|
+
getStrictContext<DynamicToggleContextType>('DynamicToggleContext');
|
|
47
|
+
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// SSR-safe layout effect — useLayoutEffect on client, useEffect on server
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
const useIsomorphicLayoutEffect =
|
|
53
|
+
typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
|
54
|
+
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Size height map (for auto-blur calculation)
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
const SIZE_HEIGHT_PX: Record<string, number> = {
|
|
60
|
+
sm: 30,
|
|
61
|
+
default: 38,
|
|
62
|
+
lg: 44,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// DynamicToggle (Root)
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Root container — pill-shaped toggle with expanding sub-options and group label.
|
|
71
|
+
*/
|
|
72
|
+
function DynamicToggle({
|
|
73
|
+
variant,
|
|
74
|
+
size,
|
|
75
|
+
shape,
|
|
76
|
+
slots,
|
|
77
|
+
config,
|
|
78
|
+
disabled = false,
|
|
79
|
+
className,
|
|
80
|
+
children,
|
|
81
|
+
'aria-label': ariaLabel,
|
|
82
|
+
...props
|
|
83
|
+
}: IDynamicToggleProps) {
|
|
84
|
+
const [value, setValue] = useControlledState({
|
|
85
|
+
value: props.value,
|
|
86
|
+
defaultValue: props.defaultValue ?? '',
|
|
87
|
+
onChange: props.onValueChange,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const groupName = React.useId();
|
|
91
|
+
|
|
92
|
+
// Group info — registered by DynamicToggleGroup child via context + useLayoutEffect
|
|
93
|
+
const [groupLabel, setGroupLabel] = React.useState('');
|
|
94
|
+
const [groupValues, setGroupValues] = React.useState<string[]>([]);
|
|
95
|
+
const [groupPosition, setGroupPosition] = React.useState<'top' | 'bottom' | 'hidden'>('top');
|
|
96
|
+
const [groupCollapsedMode, setGroupCollapsedMode] = React.useState<DynamicToggleCollapsedMode>('title');
|
|
97
|
+
|
|
98
|
+
const registerGroup = React.useCallback(
|
|
99
|
+
(label: string, values: string[], position: 'top' | 'bottom' | 'hidden', collapsedMode: DynamicToggleCollapsedMode) => {
|
|
100
|
+
setGroupLabel(label);
|
|
101
|
+
setGroupValues(values);
|
|
102
|
+
setGroupPosition(position);
|
|
103
|
+
setGroupCollapsedMode(collapsedMode);
|
|
104
|
+
},
|
|
105
|
+
[],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const groupActive = groupValues.includes(value);
|
|
109
|
+
|
|
110
|
+
// Config
|
|
111
|
+
const morphMode = config?.morphMode ?? 'none';
|
|
112
|
+
const resolvedVariant = variant ?? 'default';
|
|
113
|
+
const effectiveMorphMode = (resolvedVariant === 'ghost' || resolvedVariant === 'outline') ? 'none' : morphMode;
|
|
114
|
+
const labelAnimation = config?.labelAnimation ?? 'morph';
|
|
115
|
+
const showGroupLabel = labelAnimation !== 'none' && groupPosition !== 'hidden' && groupLabel;
|
|
116
|
+
const heightPx = SIZE_HEIGHT_PX[size ?? 'default'] ?? 32;
|
|
117
|
+
|
|
118
|
+
const style = config?.duration
|
|
119
|
+
? { '--dt-dur': `${config.duration}s` } as React.CSSProperties
|
|
120
|
+
: undefined;
|
|
121
|
+
|
|
122
|
+
// Group label element (shared between modes)
|
|
123
|
+
const groupLabelElement = showGroupLabel ? (
|
|
124
|
+
<div
|
|
125
|
+
data-slot="dt-group-label"
|
|
126
|
+
data-position={groupPosition}
|
|
127
|
+
className={cn(dynamicToggleStyles.groupLabel, slots?.groupLabel)}
|
|
128
|
+
>
|
|
129
|
+
<span>{groupLabel || '\u00A0'}</span>
|
|
130
|
+
</div>
|
|
131
|
+
) : null;
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<DynamicToggleProvider value={{ value, setValue, groupName, groupActive, disabled, registerGroup }}>
|
|
135
|
+
<div
|
|
136
|
+
data-slot="dt-root"
|
|
137
|
+
data-morph={effectiveMorphMode !== 'none' ? effectiveMorphMode : undefined}
|
|
138
|
+
data-group-active={groupActive || undefined}
|
|
139
|
+
data-disabled={disabled || undefined}
|
|
140
|
+
role="radiogroup"
|
|
141
|
+
aria-label={ariaLabel}
|
|
142
|
+
style={style}
|
|
143
|
+
className={cn(dynamicToggleVariants({ variant, size, shape }), slots?.root, className)}
|
|
144
|
+
>
|
|
145
|
+
{/* Filter morph: GooeyCanvas wraps backgrounds only */}
|
|
146
|
+
{effectiveMorphMode === 'filter' && (
|
|
147
|
+
<GooeyCanvas height={heightPx}>
|
|
148
|
+
<div className="absolute inset-0 rounded-[inherit] bg-card" />
|
|
149
|
+
{groupLabelElement}
|
|
150
|
+
</GooeyCanvas>
|
|
151
|
+
)}
|
|
152
|
+
|
|
153
|
+
{/* Path morph: group label rendered directly (no gooey filter) */}
|
|
154
|
+
{effectiveMorphMode === 'path' && groupLabelElement}
|
|
155
|
+
|
|
156
|
+
{/* Track — always rendered, z-indexed above gooey layer */}
|
|
157
|
+
<div
|
|
158
|
+
data-slot="dt-track"
|
|
159
|
+
className={cn(dynamicToggleStyles.track, slots?.track)}
|
|
160
|
+
>
|
|
161
|
+
<div
|
|
162
|
+
data-slot="dt-indicator"
|
|
163
|
+
className={cn(dynamicToggleStyles.indicator, slots?.indicator)}
|
|
164
|
+
/>
|
|
165
|
+
{children}
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</DynamicToggleProvider>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// DynamicToggleOption
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* A single toggle option — hidden radio + visible label.
|
|
178
|
+
*/
|
|
179
|
+
function DynamicToggleOption({ value, children, className }: IDynamicToggleOptionProps) {
|
|
180
|
+
const ctx = useDynamicToggle();
|
|
181
|
+
const id = React.useId();
|
|
182
|
+
const isActive = ctx.value === value;
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<>
|
|
186
|
+
<label
|
|
187
|
+
htmlFor={id}
|
|
188
|
+
data-slot="dt-option"
|
|
189
|
+
data-active={isActive || undefined}
|
|
190
|
+
className={cn(dynamicToggleStyles.option, className)}
|
|
191
|
+
>
|
|
192
|
+
<span>{children}</span>
|
|
193
|
+
</label>
|
|
194
|
+
<input
|
|
195
|
+
className="sr-only"
|
|
196
|
+
type="radio"
|
|
197
|
+
name={ctx.groupName}
|
|
198
|
+
id={id}
|
|
199
|
+
value={value}
|
|
200
|
+
checked={isActive}
|
|
201
|
+
disabled={ctx.disabled}
|
|
202
|
+
onChange={() => ctx.setValue(value)}
|
|
203
|
+
/>
|
|
204
|
+
</>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
// DynamicToggleGroup
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Expandable group — registers with root on mount, renders sub-options.
|
|
214
|
+
* The group label is rendered by the root based on registered info.
|
|
215
|
+
*/
|
|
216
|
+
function DynamicToggleGroup({
|
|
217
|
+
label,
|
|
218
|
+
labelPosition = 'top',
|
|
219
|
+
collapsedMode = 'title',
|
|
220
|
+
children,
|
|
221
|
+
className,
|
|
222
|
+
}: IDynamicToggleGroupProps) {
|
|
223
|
+
const ctx = useDynamicToggle();
|
|
224
|
+
|
|
225
|
+
// Build combined opts text from children
|
|
226
|
+
const optsText = React.useMemo(() => {
|
|
227
|
+
const labels: string[] = [];
|
|
228
|
+
React.Children.forEach(children, (child) => {
|
|
229
|
+
if (React.isValidElement(child)) {
|
|
230
|
+
const p = child.props as { children?: React.ReactNode };
|
|
231
|
+
if (p.children) labels.push(String(p.children));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
return labels.join(' · ');
|
|
235
|
+
}, [children]);
|
|
236
|
+
|
|
237
|
+
// Register group info with root — useLayoutEffect prevents visual flash
|
|
238
|
+
useIsomorphicLayoutEffect(() => {
|
|
239
|
+
const values: string[] = [];
|
|
240
|
+
React.Children.forEach(children, (child) => {
|
|
241
|
+
if (React.isValidElement(child)) {
|
|
242
|
+
const p = child.props as { value?: string };
|
|
243
|
+
if (p.value) values.push(p.value);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
ctx.registerGroup(label, values, labelPosition, collapsedMode);
|
|
247
|
+
}, [label, labelPosition, collapsedMode, children, ctx.registerGroup]);
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
<div
|
|
251
|
+
data-slot="dt-group"
|
|
252
|
+
data-collapsed={collapsedMode}
|
|
253
|
+
data-label={label}
|
|
254
|
+
data-opts={collapsedMode !== 'title' ? optsText : undefined}
|
|
255
|
+
className={cn(dynamicToggleStyles.group, className)}
|
|
256
|
+
>
|
|
257
|
+
<div
|
|
258
|
+
data-slot="dt-group-indicator"
|
|
259
|
+
className={dynamicToggleStyles.groupIndicator}
|
|
260
|
+
/>
|
|
261
|
+
{children}
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Display names
|
|
267
|
+
DynamicToggle.displayName = 'DynamicToggle';
|
|
268
|
+
DynamicToggleOption.displayName = 'DynamicToggleOption';
|
|
269
|
+
DynamicToggleGroup.displayName = 'DynamicToggleGroup';
|
|
270
|
+
|
|
271
|
+
// ---------------------------------------------------------------------------
|
|
272
|
+
// Exports
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
|
|
275
|
+
export {
|
|
276
|
+
DynamicToggle,
|
|
277
|
+
DynamicToggleOption,
|
|
278
|
+
DynamicToggleGroup,
|
|
279
|
+
useDynamicToggle,
|
|
280
|
+
dynamicToggleVariants,
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
export type {
|
|
284
|
+
IDynamicToggleProps,
|
|
285
|
+
IDynamicToggleOptionProps,
|
|
286
|
+
IDynamicToggleGroupProps,
|
|
287
|
+
IDynamicToggleConfig,
|
|
288
|
+
DynamicToggleContextType,
|
|
289
|
+
DynamicToggleCollapsedMode,
|
|
290
|
+
DynamicToggleMorphMode,
|
|
291
|
+
} from './DynamicToggle.types';
|
|
292
|
+
|
|
293
|
+
export type { DynamicToggleSlot, DynamicToggleVariantProps } from './DynamicToggle.styles';
|
|
294
|
+
export { dynamicToggleStyles } from './DynamicToggle.styles';
|