@mks2508/mks-ui 0.7.0 → 0.8.0
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/css/primitives-DotMatrix-dot.css +364 -0
- package/dist/css/primitives-GooeyMorphingSurface-gooey.css +112 -0
- package/dist/css/ui-GooeyButton-gooey.css +43 -0
- package/dist/index.css +531 -0
- package/dist/react-ui/components/MorphingPopover/MorphingPopover.types.d.ts +8 -3
- package/dist/react-ui/components/MorphingPopover/MorphingPopover.types.d.ts.map +1 -1
- package/dist/react-ui/index.js +24 -1
- package/dist/react-ui/primitives/DotMatrix/DotMatrix.types.d.ts +109 -0
- package/dist/react-ui/primitives/DotMatrix/DotMatrix.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/DotMatrix/dot-matrix.js +0 -0
- package/dist/react-ui/primitives/DotMatrix/dot.css +364 -0
- package/dist/react-ui/primitives/DotMatrix/index.d.ts +7 -0
- package/dist/react-ui/primitives/DotMatrix/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/DotMatrix/index.js +185 -0
- package/dist/react-ui/primitives/DotMatrix/patterns.d.ts +32 -0
- package/dist/react-ui/primitives/DotMatrix/patterns.d.ts.map +1 -0
- package/dist/react-ui/primitives/DotMatrix/patterns.js +175 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/GooeyMorphingSurface.types.d.ts +100 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/GooeyMorphingSurface.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/GooeyMorphingSurface.types.js +20 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/gooey-morphing-surface.js +0 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/gooey-morphing.css +112 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/index.d.ts +36 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/GooeyMorphingSurface/index.js +141 -0
- package/dist/react-ui/primitives/index.d.ts +2 -0
- package/dist/react-ui/primitives/index.d.ts.map +1 -1
- package/dist/react-ui/primitives/index.js +4 -0
- package/dist/react-ui/ui/Badge/Badge.styles.d.ts +1 -1
- package/dist/react-ui/ui/Button/Button.styles.d.ts +1 -1
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts +1 -1
- package/dist/react-ui/ui/FileIcon/FileIcon.styles.d.ts +25 -0
- package/dist/react-ui/ui/FileIcon/FileIcon.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/FileIcon/FileIcon.styles.js +31 -0
- package/dist/react-ui/ui/FileIcon/FileIcon.types.d.ts +89 -0
- package/dist/react-ui/ui/FileIcon/FileIcon.types.d.ts.map +1 -0
- package/dist/react-ui/ui/FileIcon/index.d.ts +46 -0
- package/dist/react-ui/ui/FileIcon/index.d.ts.map +1 -0
- package/dist/react-ui/ui/FileIcon/index.js +138 -0
- package/dist/react-ui/ui/FileItem/FileItem.styles.d.ts +47 -0
- package/dist/react-ui/ui/FileItem/FileItem.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/FileItem/FileItem.styles.js +60 -0
- package/dist/react-ui/ui/FileItem/FileItem.types.d.ts +84 -0
- package/dist/react-ui/ui/FileItem/FileItem.types.d.ts.map +1 -0
- package/dist/react-ui/ui/FileItem/index.d.ts +48 -0
- package/dist/react-ui/ui/FileItem/index.d.ts.map +1 -0
- package/dist/react-ui/ui/FileItem/index.js +124 -0
- package/dist/react-ui/ui/FilePanel/FilePanel.styles.d.ts +34 -0
- package/dist/react-ui/ui/FilePanel/FilePanel.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/FilePanel/FilePanel.styles.js +57 -0
- package/dist/react-ui/ui/FilePanel/FilePanel.types.d.ts +55 -0
- package/dist/react-ui/ui/FilePanel/FilePanel.types.d.ts.map +1 -0
- package/dist/react-ui/ui/FilePanel/index.d.ts +55 -0
- package/dist/react-ui/ui/FilePanel/index.d.ts.map +1 -0
- package/dist/react-ui/ui/FilePanel/index.js +107 -0
- package/dist/react-ui/ui/FileTree/FileTree.styles.d.ts +31 -0
- package/dist/react-ui/ui/FileTree/FileTree.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/FileTree/FileTree.styles.js +45 -0
- package/dist/react-ui/ui/FileTree/FileTree.types.d.ts +95 -0
- package/dist/react-ui/ui/FileTree/FileTree.types.d.ts.map +1 -0
- package/dist/react-ui/ui/FileTree/index.d.ts +60 -0
- package/dist/react-ui/ui/FileTree/index.d.ts.map +1 -0
- package/dist/react-ui/ui/FileTree/index.js +226 -0
- package/dist/react-ui/ui/GooeyButton/GooeyButton.types.d.ts +35 -0
- package/dist/react-ui/ui/GooeyButton/GooeyButton.types.d.ts.map +1 -0
- package/dist/react-ui/ui/GooeyButton/gooey-button.js +0 -0
- package/dist/react-ui/ui/GooeyButton/gooey.css +43 -0
- package/dist/react-ui/ui/GooeyButton/index.d.ts +26 -0
- package/dist/react-ui/ui/GooeyButton/index.d.ts.map +1 -0
- package/dist/react-ui/ui/GooeyButton/index.js +109 -0
- package/dist/react-ui/ui/MiddleTruncatePath/MiddleTruncatePath.styles.d.ts +23 -0
- package/dist/react-ui/ui/MiddleTruncatePath/MiddleTruncatePath.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/MiddleTruncatePath/MiddleTruncatePath.styles.js +32 -0
- package/dist/react-ui/ui/MiddleTruncatePath/MiddleTruncatePath.types.d.ts +43 -0
- package/dist/react-ui/ui/MiddleTruncatePath/MiddleTruncatePath.types.d.ts.map +1 -0
- package/dist/react-ui/ui/MiddleTruncatePath/index.d.ts +33 -0
- package/dist/react-ui/ui/MiddleTruncatePath/index.d.ts.map +1 -0
- package/dist/react-ui/ui/MiddleTruncatePath/index.js +60 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.context.d.ts +17 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.context.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.context.js +27 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.styles.d.ts +19 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.styles.js +39 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.types.d.ts +188 -0
- package/dist/react-ui/ui/OperationCard/OperationCard.types.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/index.d.ts +45 -0
- package/dist/react-ui/ui/OperationCard/index.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/index.js +118 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardActions.d.ts +3 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardActions.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardActions.js +86 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardHeader.d.ts +14 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardHeader.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardHeader.js +62 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardProgress.d.ts +3 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardProgress.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardProgress.js +37 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardStats.d.ts +3 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardStats.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardStats.js +42 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardVisualizer.d.ts +3 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardVisualizer.d.ts.map +1 -0
- package/dist/react-ui/ui/OperationCard/parts/OperationCardVisualizer.js +53 -0
- package/dist/react-ui/ui/Tabs/Tabs.styles.d.ts +3 -3
- package/dist/react-ui/ui/index.d.ts +7 -0
- package/dist/react-ui/ui/index.d.ts.map +1 -1
- package/dist/react-ui/ui/index.js +19 -0
- package/package.json +1 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type surface for the DotMatrix primitive.
|
|
3
|
+
*
|
|
4
|
+
* DotMatrix is a pattern-driven rows×cols grid inspired by the
|
|
5
|
+
* 3-pixel-grid concept (MetaHeavies). A `pattern` generates per-cell
|
|
6
|
+
* delays; the engine runs a continuous cycle (fade-in staggered →
|
|
7
|
+
* hold → fade-out staggered → hold-off → repeat) so the matrix reads
|
|
8
|
+
* as a living indicator.
|
|
9
|
+
*
|
|
10
|
+
* `status` is a *lifecycle event* — not a variant. It captures the
|
|
11
|
+
* cycle where it is:
|
|
12
|
+
* - `running` → cycle plays (default)
|
|
13
|
+
* - `idle` → cycle paused, all cells off
|
|
14
|
+
* - `success` → cycle stopped, all cells forced on
|
|
15
|
+
* - `failed` → cycle frozen; ON cells → destructive, OFF cells
|
|
16
|
+
* stay as cancelled-muted
|
|
17
|
+
* - `cancelled`→ cycle frozen; ON cells fade to muted
|
|
18
|
+
*
|
|
19
|
+
* Colour + bloom + accent overlays are orthogonal.
|
|
20
|
+
*
|
|
21
|
+
* @module @mks2508/mks-ui/react/primitives/DotMatrix
|
|
22
|
+
*/
|
|
23
|
+
import type { SlotOverrides } from '../../../core/types';
|
|
24
|
+
import type { DotMatrixPattern } from './patterns';
|
|
25
|
+
export type { DotMatrixPattern } from './patterns';
|
|
26
|
+
/** Lifecycle status. Applied as a CSS data-attr on the root. */
|
|
27
|
+
export type DotMatrixStatus = 'idle' | 'running' | 'success' | 'failed' | 'cancelled';
|
|
28
|
+
/**
|
|
29
|
+
* Colour palette. `foreground` / `primary` / `destructive` / `warning`
|
|
30
|
+
* map to theme tokens (mks-ui RULE 0). The others are opinionated
|
|
31
|
+
* neon/industrial hues ported from 3-pixel-grid in OKLCH for contrast
|
|
32
|
+
* stability across themes.
|
|
33
|
+
*/
|
|
34
|
+
export type DotMatrixColor = 'foreground' | 'primary' | 'destructive' | 'warning' | 'cyan' | 'magenta' | 'yellow' | 'green' | 'orange' | 'blue' | 'red' | 'purple' | 'teal' | 'pink' | 'lime' | 'white';
|
|
35
|
+
/** Where accent highlights live. */
|
|
36
|
+
export type DotMatrixAccentRow = 'top' | 'bottom' | 'both';
|
|
37
|
+
/** Slots consumers can override with className overrides. */
|
|
38
|
+
export type DotMatrixSlot = 'root' | 'cell';
|
|
39
|
+
/** Visual variant. `glow` adds a soft box-shadow on ON cells. */
|
|
40
|
+
export type DotMatrixVariant = 'solid' | 'glow';
|
|
41
|
+
/**
|
|
42
|
+
* @deprecated Superseded by the progressive-fill model. Kept as an empty
|
|
43
|
+
* alias so older call sites compile; the prop is no longer read.
|
|
44
|
+
*/
|
|
45
|
+
export type DotMatrixSweepStyle = 'stepped' | 'wave' | 'trail' | 'pulse';
|
|
46
|
+
export interface IDotMatrixProps {
|
|
47
|
+
/** Rows. Default: 6. */
|
|
48
|
+
rows?: number;
|
|
49
|
+
/** Cols. Default: 18. */
|
|
50
|
+
cols?: number;
|
|
51
|
+
/** Pattern name that determines per-cell delay distribution. */
|
|
52
|
+
pattern?: DotMatrixPattern;
|
|
53
|
+
/** Milliseconds per cell during the fill sweep. Default: 120. */
|
|
54
|
+
patternStep?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Steps the grid stays fully lit after the fill completes, before
|
|
57
|
+
* the reset. Larger values give a longer "fully loaded" pause.
|
|
58
|
+
* Default: 6.
|
|
59
|
+
*/
|
|
60
|
+
holdSteps?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Empty steps between the reset and the next fill (silence period).
|
|
63
|
+
* Default: 4.
|
|
64
|
+
*/
|
|
65
|
+
restSteps?: number;
|
|
66
|
+
/**
|
|
67
|
+
* How sharp the transition is when a cell's threshold is crossed.
|
|
68
|
+
* Higher = crisper snap. 50 is nearly-stepped with a tiny
|
|
69
|
+
* anti-aliased edge; 5-10 gives a warm fade-in that overlaps across
|
|
70
|
+
* neighbouring cells. Default: 50.
|
|
71
|
+
*/
|
|
72
|
+
edgeSharpness?: number;
|
|
73
|
+
/** @deprecated Replaced by the progressive-fill model. No longer read. */
|
|
74
|
+
sweepStyle?: DotMatrixSweepStyle;
|
|
75
|
+
/** @deprecated Replaced by the progressive-fill model. No longer read. */
|
|
76
|
+
patternHold?: number;
|
|
77
|
+
/**
|
|
78
|
+
* External progress in 0..1. When provided, freezes the internal
|
|
79
|
+
* fill animation and drives `--dm-phase` directly from this value
|
|
80
|
+
* — cells light up exactly up to the threshold. Useful for real
|
|
81
|
+
* progress indicators (file transfers, loading bars) where the
|
|
82
|
+
* matrix should reflect a known percentage rather than cycling.
|
|
83
|
+
*/
|
|
84
|
+
progress?: number;
|
|
85
|
+
/** Lifecycle status. Default: `running`. */
|
|
86
|
+
status?: DotMatrixStatus;
|
|
87
|
+
/** Palette colour. Default: `foreground`. */
|
|
88
|
+
color?: DotMatrixColor;
|
|
89
|
+
/**
|
|
90
|
+
* Enable the bloom SVG filter. `true` uses the default intensity (4),
|
|
91
|
+
* a number sets the blur radius.
|
|
92
|
+
*/
|
|
93
|
+
bloom?: boolean | number;
|
|
94
|
+
/** Visual variant. Default: `solid`. */
|
|
95
|
+
variant?: DotMatrixVariant;
|
|
96
|
+
/** Number of accent cells highlighted (e.g. "3 new commits"). Default: 0. */
|
|
97
|
+
accentCount?: number;
|
|
98
|
+
/** Where accent cells sit. Default: `top`. */
|
|
99
|
+
accentRow?: DotMatrixAccentRow;
|
|
100
|
+
/** Explicit accent positions — overrides `accentCount` / `accentRow`. */
|
|
101
|
+
accentPositions?: ReadonlyArray<readonly [row: number, col: number]>;
|
|
102
|
+
/** Per-slot className overrides. */
|
|
103
|
+
slots?: SlotOverrides<DotMatrixSlot>;
|
|
104
|
+
/** Extra className for the root grid container. */
|
|
105
|
+
className?: string;
|
|
106
|
+
/** aria-label for the decorative grid. */
|
|
107
|
+
'aria-label'?: string;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=DotMatrix.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DotMatrix.types.d.ts","sourceRoot":"","sources":["../../../../src/react-ui/primitives/DotMatrix/DotMatrix.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,gEAAgE;AAChE,MAAM,MAAM,eAAe,GACxB,MAAM,GACN,SAAS,GACT,SAAS,GACT,QAAQ,GACR,WAAW,CAAC;AAEf;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GACvB,YAAY,GACZ,SAAS,GACT,aAAa,GACb,SAAS,GACT,MAAM,GACN,SAAS,GACT,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,MAAM,GACN,KAAK,GACL,QAAQ,GACR,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEX,oCAAoC;AACpC,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,iEAAiE;AACjE,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEzE,MAAM,WAAW,eAAe;IAC/B,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,gEAAgE;IAChE,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,eAAe,CAAC;IAEzB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAEzB,wCAAwC;IACxC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAE3B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,yEAAyE;IACzE,eAAe,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAErE,oCAAoC;IACpC,KAAK,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACrC,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB"}
|
|
File without changes
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/* =============================================================================
|
|
2
|
+
* DotMatrix — progressive fill model.
|
|
3
|
+
*
|
|
4
|
+
* Cells light up one at a time in `pattern` order, stay lit until the
|
|
5
|
+
* cycle resets, then repeat. Implementation uses ONE CSS animation per
|
|
6
|
+
* matrix that drives a registered custom property `--dm-phase` from
|
|
7
|
+
* 0 → 1 (fill), holds it at 1 (hold), then snaps back to 0 (reset)
|
|
8
|
+
* for a rest period.
|
|
9
|
+
*
|
|
10
|
+
* Each cell carries a `--dm-threshold` (its position in the fill
|
|
11
|
+
* sequence, 0..1) and computes its own `::before` opacity as a step
|
|
12
|
+
* across `phase - threshold`, multiplied by `--dm-edge-sharpness` so
|
|
13
|
+
* the edge can range from "instant snap" to "warm fade".
|
|
14
|
+
*
|
|
15
|
+
* Perf shape: N matrices = N animations total (not N × cells). Cell
|
|
16
|
+
* opacity is computed at paint time by calc(); the compositor batches
|
|
17
|
+
* updates via the shared phase var. With `contain: layout style paint`
|
|
18
|
+
* each cell is isolated so work doesn't cascade.
|
|
19
|
+
* ============================================================================= */
|
|
20
|
+
|
|
21
|
+
@property --dm-phase {
|
|
22
|
+
syntax: '<number>';
|
|
23
|
+
initial-value: 0;
|
|
24
|
+
inherits: true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.dm-root {
|
|
28
|
+
display: grid;
|
|
29
|
+
width: 100%;
|
|
30
|
+
gap: var(--dm-gap, 5px);
|
|
31
|
+
padding: var(--dm-pad, 0.25rem);
|
|
32
|
+
border-radius: 0.5rem;
|
|
33
|
+
background-color: transparent;
|
|
34
|
+
|
|
35
|
+
/* Skip render work when the matrix is offscreen. */
|
|
36
|
+
content-visibility: auto;
|
|
37
|
+
contain-intrinsic-size: auto 200px;
|
|
38
|
+
transform: translateZ(0);
|
|
39
|
+
|
|
40
|
+
--dm-on: var(--foreground);
|
|
41
|
+
--dm-off: color-mix(in oklch, var(--foreground) 12%, transparent);
|
|
42
|
+
--dm-glow: color-mix(in oklch, var(--foreground) 50%, transparent);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* ─── Cell: base OFF layer — neutral dim ──────────────────────────────── */
|
|
46
|
+
|
|
47
|
+
.dm-cell {
|
|
48
|
+
position: relative;
|
|
49
|
+
aspect-ratio: 1 / 1;
|
|
50
|
+
min-width: 4px;
|
|
51
|
+
min-height: 4px;
|
|
52
|
+
border-radius: var(--dm-radius, 32%);
|
|
53
|
+
background-color: color-mix(in oklch, var(--foreground) 10%, transparent);
|
|
54
|
+
opacity: var(--dm-off-opacity, 0.45);
|
|
55
|
+
transform: scale(var(--dm-off-scale, 0.9));
|
|
56
|
+
contain: layout style paint;
|
|
57
|
+
|
|
58
|
+
--dm-threshold: 0;
|
|
59
|
+
--dm-stagger-delay: 0ms;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ─── Pseudo: ON layer — LED look, fades in as phase crosses threshold ─ */
|
|
63
|
+
|
|
64
|
+
.dm-cell::before {
|
|
65
|
+
content: '';
|
|
66
|
+
position: absolute;
|
|
67
|
+
inset: 0;
|
|
68
|
+
border-radius: inherit;
|
|
69
|
+
background-color: var(--dm-on);
|
|
70
|
+
background-image:
|
|
71
|
+
radial-gradient(
|
|
72
|
+
circle at 32% 26%,
|
|
73
|
+
rgb(255 255 255 / 0.35) 0%,
|
|
74
|
+
rgb(255 255 255 / 0.12) 18%,
|
|
75
|
+
transparent 48%
|
|
76
|
+
),
|
|
77
|
+
radial-gradient(
|
|
78
|
+
circle at 70% 78%,
|
|
79
|
+
rgb(0 0 0 / 0.22) 0%,
|
|
80
|
+
transparent 60%
|
|
81
|
+
);
|
|
82
|
+
box-shadow:
|
|
83
|
+
inset 0 0 1px rgb(255 255 255 / 0.55),
|
|
84
|
+
inset 0 0 0 1px color-mix(in oklch, var(--dm-on) 65%, transparent),
|
|
85
|
+
inset 0 -1px 2px color-mix(in oklch, var(--dm-on) 40%, black 20%);
|
|
86
|
+
opacity: 0;
|
|
87
|
+
pointer-events: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.dm-root[data-variant='glow'] .dm-cell::before {
|
|
91
|
+
box-shadow:
|
|
92
|
+
inset 0 0 1px rgb(255 255 255 / 0.55),
|
|
93
|
+
inset 0 0 0 1px color-mix(in oklch, var(--dm-on) 65%, transparent),
|
|
94
|
+
inset 0 -1px 2px color-mix(in oklch, var(--dm-on) 40%, black 20%),
|
|
95
|
+
0 0 2px var(--dm-glow),
|
|
96
|
+
0 0 6px var(--dm-glow),
|
|
97
|
+
0 0 12px color-mix(in oklch, var(--dm-glow) 55%, transparent);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* ─── Running: phase animates on root, cells derive state from it ────── */
|
|
101
|
+
|
|
102
|
+
.dm-root[data-status='running'] {
|
|
103
|
+
animation-name: var(--dm-anim-phase);
|
|
104
|
+
animation-duration: var(--dm-cycle-total, 2600ms);
|
|
105
|
+
animation-iteration-count: infinite;
|
|
106
|
+
animation-timing-function: linear;
|
|
107
|
+
animation-fill-mode: both;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Lit fraction for THIS cell — 0 when off, 1 when fully filled, ramped
|
|
111
|
+
* near the threshold by `--dm-edge-sharpness`. Reused by both the pseudo
|
|
112
|
+
* opacity (the LED glow) and the cell's scale (grows when lit). */
|
|
113
|
+
.dm-root[data-status='running'] .dm-cell {
|
|
114
|
+
opacity: 1;
|
|
115
|
+
transform: scale(
|
|
116
|
+
calc(
|
|
117
|
+
var(--dm-off-scale, 0.88) +
|
|
118
|
+
(var(--dm-on-scale, 1) - var(--dm-off-scale, 0.88)) *
|
|
119
|
+
clamp(
|
|
120
|
+
0,
|
|
121
|
+
(var(--dm-phase) - var(--dm-threshold)) *
|
|
122
|
+
var(--dm-edge-sharpness, 50),
|
|
123
|
+
1
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.dm-root[data-status='running'] .dm-cell::before {
|
|
130
|
+
opacity: clamp(
|
|
131
|
+
0,
|
|
132
|
+
calc(
|
|
133
|
+
(var(--dm-phase) - var(--dm-threshold)) *
|
|
134
|
+
var(--dm-edge-sharpness, 50)
|
|
135
|
+
),
|
|
136
|
+
1
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ─── Accent cells ────────────────────────────────────────────────────── */
|
|
141
|
+
|
|
142
|
+
.dm-cell[data-accent='true'] {
|
|
143
|
+
opacity: 1;
|
|
144
|
+
transform: scale(1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.dm-cell[data-accent='true']::before {
|
|
148
|
+
background-color: var(--primary);
|
|
149
|
+
background-image: none;
|
|
150
|
+
box-shadow:
|
|
151
|
+
inset 0 0 1px rgb(255 255 255 / 0.5),
|
|
152
|
+
0 0 3px color-mix(in oklch, var(--primary) 70%, transparent),
|
|
153
|
+
0 0 7px color-mix(in oklch, var(--primary) 50%, transparent);
|
|
154
|
+
opacity: 1 !important;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ─── Lifecycle FINAL animations ──────────────────────────────────────── */
|
|
158
|
+
|
|
159
|
+
@keyframes dm-success-pop {
|
|
160
|
+
0% {
|
|
161
|
+
transform: scale(0.94);
|
|
162
|
+
filter: brightness(0.7);
|
|
163
|
+
}
|
|
164
|
+
45% {
|
|
165
|
+
transform: scale(1.18);
|
|
166
|
+
filter: brightness(1.4);
|
|
167
|
+
}
|
|
168
|
+
100% {
|
|
169
|
+
transform: scale(1);
|
|
170
|
+
filter: brightness(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@keyframes dm-fail-strobe {
|
|
175
|
+
0% {
|
|
176
|
+
transform: scale(1);
|
|
177
|
+
filter: brightness(1);
|
|
178
|
+
}
|
|
179
|
+
22% {
|
|
180
|
+
transform: scale(1.22);
|
|
181
|
+
filter: brightness(1.55) saturate(1.4);
|
|
182
|
+
}
|
|
183
|
+
55% {
|
|
184
|
+
transform: scale(0.92);
|
|
185
|
+
filter: brightness(0.75);
|
|
186
|
+
}
|
|
187
|
+
100% {
|
|
188
|
+
transform: scale(0.97);
|
|
189
|
+
filter: brightness(1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@keyframes dm-cancelled-dim {
|
|
194
|
+
0% {
|
|
195
|
+
transform: scale(1);
|
|
196
|
+
opacity: 1;
|
|
197
|
+
}
|
|
198
|
+
100% {
|
|
199
|
+
transform: scale(0.9);
|
|
200
|
+
opacity: 0.55;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.dm-root[data-status='success'] {
|
|
205
|
+
animation: none;
|
|
206
|
+
}
|
|
207
|
+
.dm-root[data-status='success'] .dm-cell {
|
|
208
|
+
opacity: 1;
|
|
209
|
+
transform: scale(1);
|
|
210
|
+
animation: dm-success-pop 520ms cubic-bezier(0.2, 0, 0.2, 1) both;
|
|
211
|
+
animation-delay: var(--dm-stagger-delay, 0ms);
|
|
212
|
+
}
|
|
213
|
+
.dm-root[data-status='success'] .dm-cell::before {
|
|
214
|
+
opacity: 1;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.dm-root[data-status='failed'] {
|
|
218
|
+
animation: none;
|
|
219
|
+
}
|
|
220
|
+
.dm-root[data-status='failed'] .dm-cell {
|
|
221
|
+
opacity: 1;
|
|
222
|
+
animation: dm-fail-strobe 560ms cubic-bezier(0.2, 0, 0.2, 1) both;
|
|
223
|
+
animation-delay: var(--dm-stagger-delay, 0ms);
|
|
224
|
+
}
|
|
225
|
+
.dm-root[data-status='failed'] .dm-cell::before {
|
|
226
|
+
background-color: var(--destructive);
|
|
227
|
+
box-shadow:
|
|
228
|
+
inset 0 0 1px rgb(255 255 255 / 0.5),
|
|
229
|
+
inset 0 0 0 1px color-mix(in oklch, var(--destructive) 55%, transparent),
|
|
230
|
+
inset 0 -1px 2px color-mix(in oklch, var(--destructive) 40%, black 20%);
|
|
231
|
+
opacity: 1;
|
|
232
|
+
}
|
|
233
|
+
.dm-root[data-status='failed'][data-variant='glow'] .dm-cell::before {
|
|
234
|
+
box-shadow:
|
|
235
|
+
inset 0 0 1px rgb(255 255 255 / 0.55),
|
|
236
|
+
inset 0 0 0 1px color-mix(in oklch, var(--destructive) 55%, transparent),
|
|
237
|
+
inset 0 -1px 2px color-mix(in oklch, var(--destructive) 40%, black 20%),
|
|
238
|
+
0 0 3px color-mix(in oklch, var(--destructive) 70%, transparent),
|
|
239
|
+
0 0 9px color-mix(in oklch, var(--destructive) 55%, transparent);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.dm-root[data-status='cancelled'] {
|
|
243
|
+
animation: none;
|
|
244
|
+
}
|
|
245
|
+
.dm-root[data-status='cancelled'] .dm-cell {
|
|
246
|
+
background-color: color-mix(in oklch, var(--foreground) 22%, transparent);
|
|
247
|
+
opacity: 0.65;
|
|
248
|
+
animation: dm-cancelled-dim 380ms cubic-bezier(0.4, 0, 0.8, 0.6) both;
|
|
249
|
+
animation-delay: var(--dm-stagger-delay, 0ms);
|
|
250
|
+
}
|
|
251
|
+
.dm-root[data-status='cancelled'] .dm-cell::before {
|
|
252
|
+
opacity: 0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.dm-root[data-status='idle'] {
|
|
256
|
+
animation: none;
|
|
257
|
+
}
|
|
258
|
+
.dm-root[data-status='idle'] .dm-cell::before {
|
|
259
|
+
opacity: 0;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* ─── Theme-token palettes ────────────────────────────────────────────── */
|
|
263
|
+
|
|
264
|
+
.dm--foreground {
|
|
265
|
+
--dm-on: var(--foreground);
|
|
266
|
+
--dm-off: color-mix(in oklch, var(--foreground) 12%, transparent);
|
|
267
|
+
--dm-glow: color-mix(in oklch, var(--foreground) 55%, transparent);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.dm--primary {
|
|
271
|
+
--dm-on: var(--primary);
|
|
272
|
+
--dm-off: color-mix(in oklch, var(--primary) 14%, transparent);
|
|
273
|
+
--dm-glow: color-mix(in oklch, var(--primary) 65%, transparent);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.dm--destructive {
|
|
277
|
+
--dm-on: var(--destructive);
|
|
278
|
+
--dm-off: color-mix(in oklch, var(--destructive) 14%, transparent);
|
|
279
|
+
--dm-glow: color-mix(in oklch, var(--destructive) 65%, transparent);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.dm--warning {
|
|
283
|
+
--dm-on: var(--warning);
|
|
284
|
+
--dm-off: color-mix(in oklch, var(--warning) 14%, transparent);
|
|
285
|
+
--dm-glow: color-mix(in oklch, var(--warning) 65%, transparent);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* ─── Named palettes (OKLCH for stability) ────────────────────────────── */
|
|
289
|
+
|
|
290
|
+
.dm--cyan {
|
|
291
|
+
--dm-on: oklch(90% 0.2 195);
|
|
292
|
+
--dm-off: oklch(40% 0.08 195 / 0.4);
|
|
293
|
+
--dm-glow: oklch(80% 0.25 195 / 0.95);
|
|
294
|
+
}
|
|
295
|
+
.dm--magenta {
|
|
296
|
+
--dm-on: oklch(85% 0.25 330);
|
|
297
|
+
--dm-off: oklch(40% 0.08 330 / 0.4);
|
|
298
|
+
--dm-glow: oklch(75% 0.3 330 / 0.95);
|
|
299
|
+
}
|
|
300
|
+
.dm--yellow {
|
|
301
|
+
--dm-on: oklch(95% 0.2 90);
|
|
302
|
+
--dm-off: oklch(50% 0.08 90 / 0.4);
|
|
303
|
+
--dm-glow: oklch(90% 0.25 90 / 0.95);
|
|
304
|
+
}
|
|
305
|
+
.dm--green {
|
|
306
|
+
--dm-on: oklch(90% 0.25 145);
|
|
307
|
+
--dm-off: oklch(40% 0.08 145 / 0.4);
|
|
308
|
+
--dm-glow: oklch(80% 0.3 145 / 0.95);
|
|
309
|
+
}
|
|
310
|
+
.dm--orange {
|
|
311
|
+
--dm-on: oklch(85% 0.22 50);
|
|
312
|
+
--dm-off: oklch(45% 0.08 50 / 0.4);
|
|
313
|
+
--dm-glow: oklch(75% 0.28 50 / 0.95);
|
|
314
|
+
}
|
|
315
|
+
.dm--blue {
|
|
316
|
+
--dm-on: oklch(80% 0.22 260);
|
|
317
|
+
--dm-off: oklch(40% 0.08 260 / 0.4);
|
|
318
|
+
--dm-glow: oklch(70% 0.28 260 / 0.95);
|
|
319
|
+
}
|
|
320
|
+
.dm--red {
|
|
321
|
+
--dm-on: oklch(70% 0.25 25);
|
|
322
|
+
--dm-off: oklch(40% 0.08 25 / 0.4);
|
|
323
|
+
--dm-glow: oklch(60% 0.3 25 / 0.95);
|
|
324
|
+
}
|
|
325
|
+
.dm--purple {
|
|
326
|
+
--dm-on: oklch(75% 0.22 300);
|
|
327
|
+
--dm-off: oklch(40% 0.08 300 / 0.4);
|
|
328
|
+
--dm-glow: oklch(65% 0.28 300 / 0.95);
|
|
329
|
+
}
|
|
330
|
+
.dm--teal {
|
|
331
|
+
--dm-on: oklch(82% 0.18 175);
|
|
332
|
+
--dm-off: oklch(40% 0.08 175 / 0.4);
|
|
333
|
+
--dm-glow: oklch(72% 0.24 175 / 0.95);
|
|
334
|
+
}
|
|
335
|
+
.dm--pink {
|
|
336
|
+
--dm-on: oklch(80% 0.2 350);
|
|
337
|
+
--dm-off: oklch(45% 0.08 350 / 0.4);
|
|
338
|
+
--dm-glow: oklch(70% 0.26 350 / 0.95);
|
|
339
|
+
}
|
|
340
|
+
.dm--lime {
|
|
341
|
+
--dm-on: oklch(88% 0.22 120);
|
|
342
|
+
--dm-off: oklch(45% 0.08 120 / 0.4);
|
|
343
|
+
--dm-glow: oklch(80% 0.28 120 / 0.95);
|
|
344
|
+
}
|
|
345
|
+
.dm--white {
|
|
346
|
+
--dm-on: oklch(98% 0 0);
|
|
347
|
+
--dm-off: oklch(50% 0 0 / 0.3);
|
|
348
|
+
--dm-glow: oklch(95% 0 0 / 0.85);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* ─── Reduced motion — freeze animations ─────────────────────────────── */
|
|
352
|
+
|
|
353
|
+
@media (prefers-reduced-motion: reduce) {
|
|
354
|
+
.dm-root[data-status='running'],
|
|
355
|
+
.dm-root[data-status='success'] .dm-cell,
|
|
356
|
+
.dm-root[data-status='failed'] .dm-cell,
|
|
357
|
+
.dm-root[data-status='cancelled'] .dm-cell {
|
|
358
|
+
animation: none !important;
|
|
359
|
+
}
|
|
360
|
+
.dm-cell {
|
|
361
|
+
transform: none;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import './dot-matrix.css';
|
|
2
|
+
import type { IDotMatrixProps } from './DotMatrix.types';
|
|
3
|
+
export * from './DotMatrix.types';
|
|
4
|
+
export { DOT_MATRIX_PATTERNS, buildDelays } from './patterns';
|
|
5
|
+
export type { DotMatrixPattern } from './patterns';
|
|
6
|
+
export declare function DotMatrix({ rows, cols, pattern, patternStep, holdSteps, restSteps, edgeSharpness, progress, status, color, bloom, variant, accentCount, accentRow, accentPositions, slots, className, 'aria-label': ariaLabel, }: IDotMatrixProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/react-ui/primitives/DotMatrix/index.tsx"],"names":[],"mappings":"AA0BA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAIX,eAAe,EACf,MAAM,mBAAmB,CAAC;AAE3B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA6GnD,wBAAgB,SAAS,CAAC,EACzB,IAAQ,EACR,IAAS,EACT,OAAiB,EACjB,WAAiB,EACjB,SAAa,EACb,SAAa,EACb,aAAkB,EAClB,QAAQ,EACR,MAAkB,EAClB,KAAoB,EACpB,KAAY,EACZ,OAAgB,EAChB,WAAe,EACf,SAAiB,EACjB,eAAe,EACf,KAAK,EACL,SAAS,EACT,YAAY,EAAE,SAAS,GACvB,EAAE,eAAe,2CAuJjB"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import "./dot-matrix.js";
|
|
5
|
+
import { DOT_MATRIX_PATTERNS, buildDelays } from "./patterns.js";
|
|
6
|
+
import { useEffect, useId, useMemo } from "react";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
|
|
9
|
+
//#region src/react-ui/primitives/DotMatrix/index.tsx
|
|
10
|
+
/**
|
|
11
|
+
* DotMatrix — pattern-driven rows×cols grid with progressive-fill cycle.
|
|
12
|
+
*
|
|
13
|
+
* - Cells light up one at a time in `pattern` order (`wave-lr` fills
|
|
14
|
+
* left-to-right, `spiral-cw` fills outward-in, etc.). Once lit they
|
|
15
|
+
* stay on until the cycle resets.
|
|
16
|
+
* - While `status='running'` the root runs a single CSS animation
|
|
17
|
+
* that drives `--dm-phase` from 0 → 1 (fill) → held at 1 (hold) →
|
|
18
|
+
* snapped to 0 (reset/rest). Each cell computes its opacity from
|
|
19
|
+
* `(phase − threshold) × edgeSharpness`, where `threshold` is its
|
|
20
|
+
* position in the fill sequence (0..1). One animation per matrix
|
|
21
|
+
* regardless of cell count.
|
|
22
|
+
* - Status flips to `idle / success / failed / cancelled` swap to
|
|
23
|
+
* one-shot final keyframes that force EVERY cell to the status
|
|
24
|
+
* colour (all on for success, all destructive for failed, all
|
|
25
|
+
* muted for cancelled).
|
|
26
|
+
*
|
|
27
|
+
* @module @mks2508/mks-ui/react/primitives/DotMatrix
|
|
28
|
+
*/
|
|
29
|
+
const BLOOM_SVG_ID = "dm-bloom-svg";
|
|
30
|
+
const DEFAULT_BLOOM = 2;
|
|
31
|
+
function ensureBloomSvg() {
|
|
32
|
+
if (typeof document === "undefined") return null;
|
|
33
|
+
let svg = document.getElementById(BLOOM_SVG_ID);
|
|
34
|
+
if (svg) return svg;
|
|
35
|
+
const ns = "http://www.w3.org/2000/svg";
|
|
36
|
+
svg = document.createElementNS(ns, "svg");
|
|
37
|
+
svg.setAttribute("id", BLOOM_SVG_ID);
|
|
38
|
+
svg.setAttribute("aria-hidden", "true");
|
|
39
|
+
svg.setAttribute("style", "position:absolute;width:0;height:0;overflow:hidden");
|
|
40
|
+
svg.appendChild(document.createElementNS(ns, "defs"));
|
|
41
|
+
document.body.appendChild(svg);
|
|
42
|
+
return svg;
|
|
43
|
+
}
|
|
44
|
+
function installBloomFilter(id, amount) {
|
|
45
|
+
const svg = ensureBloomSvg();
|
|
46
|
+
if (!svg) return;
|
|
47
|
+
const defs = svg.firstChild;
|
|
48
|
+
const existing = document.getElementById(id);
|
|
49
|
+
if (existing) existing.parentNode?.removeChild(existing);
|
|
50
|
+
const ns = "http://www.w3.org/2000/svg";
|
|
51
|
+
const filter = document.createElementNS(ns, "filter");
|
|
52
|
+
filter.setAttribute("id", id);
|
|
53
|
+
filter.setAttribute("x", "-100%");
|
|
54
|
+
filter.setAttribute("y", "-100%");
|
|
55
|
+
filter.setAttribute("width", "300%");
|
|
56
|
+
filter.setAttribute("height", "300%");
|
|
57
|
+
const matrix = document.createElementNS(ns, "feColorMatrix");
|
|
58
|
+
matrix.setAttribute("in", "SourceGraphic");
|
|
59
|
+
matrix.setAttribute("type", "matrix");
|
|
60
|
+
matrix.setAttribute("values", "2 0 0 0 -0.5 0 2 0 0 -0.5 0 0 2 0 -0.5 0 0 0 1 0");
|
|
61
|
+
matrix.setAttribute("result", "bright");
|
|
62
|
+
const blur = document.createElementNS(ns, "feGaussianBlur");
|
|
63
|
+
blur.setAttribute("in", "bright");
|
|
64
|
+
blur.setAttribute("stdDeviation", String(amount));
|
|
65
|
+
blur.setAttribute("result", "glow");
|
|
66
|
+
const blend = document.createElementNS(ns, "feBlend");
|
|
67
|
+
blend.setAttribute("in", "SourceGraphic");
|
|
68
|
+
blend.setAttribute("in2", "glow");
|
|
69
|
+
blend.setAttribute("mode", "screen");
|
|
70
|
+
filter.appendChild(matrix);
|
|
71
|
+
filter.appendChild(blur);
|
|
72
|
+
filter.appendChild(blend);
|
|
73
|
+
defs.appendChild(filter);
|
|
74
|
+
}
|
|
75
|
+
function removeBloomFilter(id) {
|
|
76
|
+
if (typeof document === "undefined") return;
|
|
77
|
+
const el = document.getElementById(id);
|
|
78
|
+
if (el) el.parentNode?.removeChild(el);
|
|
79
|
+
}
|
|
80
|
+
function computeAccentSet(rows, cols, count, row, positions) {
|
|
81
|
+
const set = /* @__PURE__ */ new Set();
|
|
82
|
+
if (positions?.length) {
|
|
83
|
+
for (const [r, c] of positions) if (r >= 0 && r < rows && c >= 0 && c < cols) set.add(r * cols + c);
|
|
84
|
+
return set;
|
|
85
|
+
}
|
|
86
|
+
const n = Math.max(0, Math.min(count, cols));
|
|
87
|
+
if (n === 0) return set;
|
|
88
|
+
const startCol = Math.floor((cols - n) / 2);
|
|
89
|
+
if (row === "top" || row === "both") for (let i = 0; i < n; i++) set.add(startCol + i);
|
|
90
|
+
if (row === "bottom" || row === "both") for (let i = 0; i < n; i++) set.add((rows - 1) * cols + startCol + i);
|
|
91
|
+
return set;
|
|
92
|
+
}
|
|
93
|
+
function DotMatrix({ rows = 6, cols = 18, pattern = "snake", patternStep = 120, holdSteps = 6, restSteps = 4, edgeSharpness = 50, progress, status = "running", color = "foreground", bloom = true, variant = "glow", accentCount = 0, accentRow = "top", accentPositions, slots, className, "aria-label": ariaLabel }) {
|
|
94
|
+
const total = rows * cols;
|
|
95
|
+
const reactId = useId().replace(/:/g, "");
|
|
96
|
+
const bloomFilterId = `dm-bloom-${reactId}`;
|
|
97
|
+
const kfPhaseName = `dmph-${reactId}`;
|
|
98
|
+
const accentSet = useMemo(() => computeAccentSet(rows, cols, accentCount, accentRow, accentPositions), [
|
|
99
|
+
rows,
|
|
100
|
+
cols,
|
|
101
|
+
accentCount,
|
|
102
|
+
accentRow,
|
|
103
|
+
accentPositions
|
|
104
|
+
]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!bloom) {
|
|
107
|
+
removeBloomFilter(bloomFilterId);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
installBloomFilter(bloomFilterId, typeof bloom === "number" ? bloom : DEFAULT_BLOOM);
|
|
111
|
+
return () => removeBloomFilter(bloomFilterId);
|
|
112
|
+
}, [bloom, bloomFilterId]);
|
|
113
|
+
const ranks = useMemo(() => buildDelays(pattern, rows, cols, 1), [
|
|
114
|
+
pattern,
|
|
115
|
+
rows,
|
|
116
|
+
cols
|
|
117
|
+
]);
|
|
118
|
+
const maxRank = ranks.length > 0 ? Math.max(...ranks) : 0;
|
|
119
|
+
const fillSteps = maxRank + 1;
|
|
120
|
+
const cycleSteps = Math.max(1, fillSteps + holdSteps + restSteps);
|
|
121
|
+
const cycleTotalMs = cycleSteps * patternStep;
|
|
122
|
+
const fillEndPct = fillSteps / cycleSteps * 100;
|
|
123
|
+
const holdEndPct = (fillSteps + holdSteps) / cycleSteps * 100;
|
|
124
|
+
const resetSnapPct = Math.min(100, holdEndPct + .05);
|
|
125
|
+
const keyframesCSS = useMemo(() => {
|
|
126
|
+
return `
|
|
127
|
+
@keyframes ${kfPhaseName} {
|
|
128
|
+
0% { --dm-phase: 0; }
|
|
129
|
+
${fillEndPct.toFixed(3)}% { --dm-phase: 1; }
|
|
130
|
+
${holdEndPct.toFixed(3)}% { --dm-phase: 1; }
|
|
131
|
+
${resetSnapPct.toFixed(3)}% { --dm-phase: 0; }
|
|
132
|
+
100% { --dm-phase: 0; }
|
|
133
|
+
}`;
|
|
134
|
+
}, [
|
|
135
|
+
kfPhaseName,
|
|
136
|
+
fillEndPct,
|
|
137
|
+
holdEndPct,
|
|
138
|
+
resetSnapPct
|
|
139
|
+
]);
|
|
140
|
+
const finalStagger = useMemo(() => {
|
|
141
|
+
if (maxRank <= 0) return new Array(ranks.length).fill(0);
|
|
142
|
+
const w = 220;
|
|
143
|
+
return ranks.map((r) => Math.round(r / maxRank * w));
|
|
144
|
+
}, [ranks, maxRank]);
|
|
145
|
+
const N = Math.max(1, maxRank + 1);
|
|
146
|
+
const isControlled = typeof progress === "number";
|
|
147
|
+
const clampedProgress = isControlled ? Math.max(0, Math.min(1, progress)) : void 0;
|
|
148
|
+
const effectiveSharpness = isControlled ? N : edgeSharpness;
|
|
149
|
+
const rootStyle = {
|
|
150
|
+
gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
|
|
151
|
+
["--dm-cycle-total"]: `${cycleTotalMs}ms`,
|
|
152
|
+
["--dm-edge-sharpness"]: String(effectiveSharpness),
|
|
153
|
+
...isControlled ? { ["--dm-phase"]: String(clampedProgress) } : { ["--dm-anim-phase"]: kfPhaseName },
|
|
154
|
+
...bloom ? { filter: `url(#${bloomFilterId})` } : {}
|
|
155
|
+
};
|
|
156
|
+
const paletteClass = paletteClassFor(color);
|
|
157
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [!isControlled && /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: keyframesCSS } }), /* @__PURE__ */ jsx("div", {
|
|
158
|
+
className: cn("dm-root", paletteClass, slots?.root, className),
|
|
159
|
+
style: rootStyle,
|
|
160
|
+
role: "img",
|
|
161
|
+
"aria-label": ariaLabel,
|
|
162
|
+
"data-status": status,
|
|
163
|
+
"data-variant": variant,
|
|
164
|
+
"data-pattern": pattern,
|
|
165
|
+
children: Array.from({ length: total }).map((_, i) => {
|
|
166
|
+
const rank = ranks[i] ?? 0;
|
|
167
|
+
const threshold = isControlled ? rank / N : maxRank > 0 ? rank / maxRank : 0;
|
|
168
|
+
return /* @__PURE__ */ jsx("div", {
|
|
169
|
+
"data-accent": accentSet.has(i) ? "true" : void 0,
|
|
170
|
+
className: cn("dm-cell", slots?.cell),
|
|
171
|
+
style: {
|
|
172
|
+
"--dm-threshold": threshold.toFixed(4),
|
|
173
|
+
"--dm-stagger-delay": `${finalStagger[i] ?? 0}ms`
|
|
174
|
+
}
|
|
175
|
+
}, i);
|
|
176
|
+
})
|
|
177
|
+
})] });
|
|
178
|
+
}
|
|
179
|
+
/** @internal */
|
|
180
|
+
function paletteClassFor(color) {
|
|
181
|
+
return `dm--${color}`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
export { DotMatrix };
|