@molecule/app-ui 1.2.1 → 1.3.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/README.md +72 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/spinner.d.ts +109 -0
- package/dist/spinner.d.ts.map +1 -0
- package/dist/spinner.js +228 -0
- package/dist/spinner.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-09-
|
|
6
|
+
Generated: 2026-09-27T09:13:41.545Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-ui
|
|
@@ -1046,6 +1046,64 @@ interface ModalProps extends HTMLElementProps {
|
|
|
1046
1046
|
}
|
|
1047
1047
|
```
|
|
1048
1048
|
|
|
1049
|
+
#### `MoleculeSpinnerColors`
|
|
1050
|
+
|
|
1051
|
+
Gradient-mode colors. Any CSS color string, including `var()` forms.
|
|
1052
|
+
|
|
1053
|
+
```typescript
|
|
1054
|
+
interface MoleculeSpinnerColors {
|
|
1055
|
+
/** Bond base / glint tail color. */
|
|
1056
|
+
blue?: string
|
|
1057
|
+
/** Flow highlight / glint head color at rest. */
|
|
1058
|
+
light?: string
|
|
1059
|
+
/** Glint ignition color while an atom is in flight. */
|
|
1060
|
+
peach?: string
|
|
1061
|
+
}
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
#### `MoleculeSpinnerMarkOptions`
|
|
1065
|
+
|
|
1066
|
+
Options for {@link moleculeSpinnerMarkSvg}.
|
|
1067
|
+
|
|
1068
|
+
```typescript
|
|
1069
|
+
interface MoleculeSpinnerMarkOptions {
|
|
1070
|
+
/** Motion timings; defaults to the shipped design (2.5s / 5s / 3s). */
|
|
1071
|
+
timings?: Partial<MoleculeSpinnerTimings>
|
|
1072
|
+
/** `gradient` (default) or `mono` — plain `currentColor` outline, no defs. */
|
|
1073
|
+
paint?: 'gradient' | 'mono'
|
|
1074
|
+
/** Gradient-mode colors; default the `var(--mol-spin-*, fallback)` set. */
|
|
1075
|
+
colors?: MoleculeSpinnerColors
|
|
1076
|
+
/**
|
|
1077
|
+
* Gradient id for url() references. Must be unique per rendered instance
|
|
1078
|
+
* on a page. Defaults to `mol-spinner-gradient`.
|
|
1079
|
+
*/
|
|
1080
|
+
gradientId?: string
|
|
1081
|
+
/** Pixel size baked into width/height; omit when CSS sizes the svg. */
|
|
1082
|
+
size?: number
|
|
1083
|
+
/** Class attribute for the svg element. */
|
|
1084
|
+
className?: string
|
|
1085
|
+
/** Inline style attribute (already serialized, e.g. `color:re$d`). */
|
|
1086
|
+
style?: string
|
|
1087
|
+
/** Announce as `role="status"` with this label; omit for `aria-hidden`. */
|
|
1088
|
+
ariaLabel?: string
|
|
1089
|
+
}
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
#### `MoleculeSpinnerTimings`
|
|
1093
|
+
|
|
1094
|
+
The mark's timings, in CSS duration strings. Swap cycle → glint cycle.
|
|
1095
|
+
|
|
1096
|
+
```typescript
|
|
1097
|
+
interface MoleculeSpinnerTimings {
|
|
1098
|
+
/** One full 3-phase atom-swap cycle (also drives bond fades + glints). */
|
|
1099
|
+
dur: string
|
|
1100
|
+
/** Whole-figure rotation. Keep at two swap cycles for the intended feel. */
|
|
1101
|
+
spin: string
|
|
1102
|
+
/** Bond gradient flow period (one full translate across the figure). */
|
|
1103
|
+
flow: string
|
|
1104
|
+
}
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1049
1107
|
#### `PageHeaderProps`
|
|
1050
1108
|
|
|
1051
1109
|
Props for the PageHeader component — consistent page title area.
|
|
@@ -2968,6 +3026,19 @@ function hasProvider(): boolean
|
|
|
2968
3026
|
|
|
2969
3027
|
**Returns:** `true` if a UI provider is bonded.
|
|
2970
3028
|
|
|
3029
|
+
#### `moleculeSpinnerMarkSvg(options)`
|
|
3030
|
+
|
|
3031
|
+
The molecule spinner mark as a complete SVG element string (SMIL-animated,
|
|
3032
|
+
framework-agnostic). See the module docblock for usage and gotchas.
|
|
3033
|
+
|
|
3034
|
+
```typescript
|
|
3035
|
+
function moleculeSpinnerMarkSvg(options?: MoleculeSpinnerMarkOptions): string
|
|
3036
|
+
```
|
|
3037
|
+
|
|
3038
|
+
- `options` — Paint, timings, size, gradient id and a11y shape.
|
|
3039
|
+
|
|
3040
|
+
**Returns:** A `<svg>…</svg>` markup string.
|
|
3041
|
+
|
|
2971
3042
|
#### `molId(component, context, qualifier)`
|
|
2972
3043
|
|
|
2973
3044
|
Generate a semantic automation ID for a component.
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The molecule spinner mark — the platform's animated loading glyph, as one
|
|
3
|
+
* framework-agnostic SVG string.
|
|
4
|
+
*
|
|
5
|
+
* This module is the SINGLE source of truth for the mark's geometry, motion
|
|
6
|
+
* and paint. Every surface that spins it — the IDE app's `MoleculeSpinner`,
|
|
7
|
+
* the AI streaming indicator (`@molecule/app-ide-react`), and the "Built with
|
|
8
|
+
* Molecule.dev" attribution badge injected into deployed apps — renders
|
|
9
|
+
* {@link moleculeSpinnerMarkSvg} output rather than keeping a copy. Before
|
|
10
|
+
* this existed, four hand-maintained copies drifted into three different
|
|
11
|
+
* looks; if you are tempted to inline this SVG somewhere, import this instead.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* **What it renders** — a complete `<svg>…</svg>` element string driven by
|
|
15
|
+
* SMIL (no JS runtime, no CSS keyframes), safe to inject with
|
|
16
|
+
* `innerHTML`/`insertAdjacentHTML` in any framework or none:
|
|
17
|
+
* - a 3-phase atom-swap cycle (one outer atom exchanges with the hub per
|
|
18
|
+
* phase; the connecting bond fades for the swap);
|
|
19
|
+
* - a slow hub-centered whole-figure rotation;
|
|
20
|
+
* - paint: a seamless one-way blue gradient flow on the bonds plus per-atom
|
|
21
|
+
* "glint" gradients whose light end warms exactly while that atom is in
|
|
22
|
+
* flight (keyed to the same keyTimes/easing as the motion), or a plain
|
|
23
|
+
* `currentColor` outline via `paint: 'mono'`.
|
|
24
|
+
*
|
|
25
|
+
* **Gotchas a weak executor gets wrong:**
|
|
26
|
+
* - `gradientId` must be unique per rendered instance on a page — two svgs
|
|
27
|
+
* sharing one id cross-reference each other's gradients. React wrappers
|
|
28
|
+
* should pass something derived from `useId()` (strip `:` first).
|
|
29
|
+
* - Default colors are CSS-var-with-fallback strings
|
|
30
|
+
* (`var(--mol-spin-blue, #4f86f0)`), which theme via `--mol-spin-*` where
|
|
31
|
+
* they exist (e.g. the molecule.dev landing page) and fall back to the
|
|
32
|
+
* literal palette elsewhere. Injected into third-party pages (the
|
|
33
|
+
* attribution badge) they must be overridden with literal hexes — the vars
|
|
34
|
+
* do not exist there.
|
|
35
|
+
* - The glyph matrix x-translate (`-.78879`) deliberately differs from the
|
|
36
|
+
* static favicon's (`.81594`): it puts the molecule's hub exactly on the
|
|
37
|
+
* rotation center (16,16) so the spin never wobbles. Do not "fix" it.
|
|
38
|
+
* - `ariaLabel` produces `role="status"`; omit it for decorative uses, which
|
|
39
|
+
* get `aria-hidden="true"` instead. Never emit both.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { moleculeSpinnerMarkSvg } from '@molecule/app-ui'
|
|
44
|
+
*
|
|
45
|
+
* // themed, unique per instance
|
|
46
|
+
* const svg = moleculeSpinnerMarkSvg({ size: 24, gradientId: 'spin-1', ariaLabel: 'Loading' })
|
|
47
|
+
*
|
|
48
|
+
* // monochrome, inherits the surrounding text color
|
|
49
|
+
* const mono = moleculeSpinnerMarkSvg({ size: 16, paint: 'mono' })
|
|
50
|
+
*
|
|
51
|
+
* // third-party page (no --mol-spin-* vars): literal colors, CSS-sized
|
|
52
|
+
* const badge = moleculeSpinnerMarkSvg({
|
|
53
|
+
* gradientId: 'mol-badge-grad',
|
|
54
|
+
* className: 'mol-badge-mark',
|
|
55
|
+
* colors: { blue: '#4f86f0', light: '#6e9bf5', peach: '#e0975a' },
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @module
|
|
60
|
+
*/
|
|
61
|
+
/** The mark's timings, in CSS duration strings. Swap cycle → glint cycle. */
|
|
62
|
+
export interface MoleculeSpinnerTimings {
|
|
63
|
+
/** One full 3-phase atom-swap cycle (also drives bond fades + glints). */
|
|
64
|
+
dur: string;
|
|
65
|
+
/** Whole-figure rotation. Keep at two swap cycles for the intended feel. */
|
|
66
|
+
spin: string;
|
|
67
|
+
/** Bond gradient flow period (one full translate across the figure). */
|
|
68
|
+
flow: string;
|
|
69
|
+
}
|
|
70
|
+
/** Gradient-mode colors. Any CSS color string, including `var()` forms. */
|
|
71
|
+
export interface MoleculeSpinnerColors {
|
|
72
|
+
/** Bond base / glint tail color. */
|
|
73
|
+
blue?: string;
|
|
74
|
+
/** Flow highlight / glint head color at rest. */
|
|
75
|
+
light?: string;
|
|
76
|
+
/** Glint ignition color while an atom is in flight. */
|
|
77
|
+
peach?: string;
|
|
78
|
+
}
|
|
79
|
+
/** Options for {@link moleculeSpinnerMarkSvg}. */
|
|
80
|
+
export interface MoleculeSpinnerMarkOptions {
|
|
81
|
+
/** Motion timings; defaults to the shipped design (2.5s / 5s / 3s). */
|
|
82
|
+
timings?: Partial<MoleculeSpinnerTimings>;
|
|
83
|
+
/** `gradient` (default) or `mono` — plain `currentColor` outline, no defs. */
|
|
84
|
+
paint?: 'gradient' | 'mono';
|
|
85
|
+
/** Gradient-mode colors; default the `var(--mol-spin-*, fallback)` set. */
|
|
86
|
+
colors?: MoleculeSpinnerColors;
|
|
87
|
+
/**
|
|
88
|
+
* Gradient id for url() references. Must be unique per rendered instance
|
|
89
|
+
* on a page. Defaults to `mol-spinner-gradient`.
|
|
90
|
+
*/
|
|
91
|
+
gradientId?: string;
|
|
92
|
+
/** Pixel size baked into width/height; omit when CSS sizes the svg. */
|
|
93
|
+
size?: number;
|
|
94
|
+
/** Class attribute for the svg element. */
|
|
95
|
+
className?: string;
|
|
96
|
+
/** Inline style attribute (already serialized, e.g. `color:re$d`). */
|
|
97
|
+
style?: string;
|
|
98
|
+
/** Announce as `role="status"` with this label; omit for `aria-hidden`. */
|
|
99
|
+
ariaLabel?: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The molecule spinner mark as a complete SVG element string (SMIL-animated,
|
|
103
|
+
* framework-agnostic). See the module docblock for usage and gotchas.
|
|
104
|
+
*
|
|
105
|
+
* @param options - Paint, timings, size, gradient id and a11y shape.
|
|
106
|
+
* @returns A `<svg>…</svg>` markup string.
|
|
107
|
+
*/
|
|
108
|
+
export declare function moleculeSpinnerMarkSvg(options?: MoleculeSpinnerMarkOptions): string;
|
|
109
|
+
//# sourceMappingURL=spinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../src/spinner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAA;IACX,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;CACb;AAED,2EAA2E;AAC3E,MAAM,WAAW,qBAAqB;IACpC,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,kDAAkD;AAClD,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACzC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;IAC3B,2EAA2E;IAC3E,MAAM,CAAC,EAAE,qBAAqB,CAAA;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA0HD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,0BAA+B,GAAG,MAAM,CA+DvF"}
|
package/dist/spinner.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The molecule spinner mark — the platform's animated loading glyph, as one
|
|
3
|
+
* framework-agnostic SVG string.
|
|
4
|
+
*
|
|
5
|
+
* This module is the SINGLE source of truth for the mark's geometry, motion
|
|
6
|
+
* and paint. Every surface that spins it — the IDE app's `MoleculeSpinner`,
|
|
7
|
+
* the AI streaming indicator (`@molecule/app-ide-react`), and the "Built with
|
|
8
|
+
* Molecule.dev" attribution badge injected into deployed apps — renders
|
|
9
|
+
* {@link moleculeSpinnerMarkSvg} output rather than keeping a copy. Before
|
|
10
|
+
* this existed, four hand-maintained copies drifted into three different
|
|
11
|
+
* looks; if you are tempted to inline this SVG somewhere, import this instead.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* **What it renders** — a complete `<svg>…</svg>` element string driven by
|
|
15
|
+
* SMIL (no JS runtime, no CSS keyframes), safe to inject with
|
|
16
|
+
* `innerHTML`/`insertAdjacentHTML` in any framework or none:
|
|
17
|
+
* - a 3-phase atom-swap cycle (one outer atom exchanges with the hub per
|
|
18
|
+
* phase; the connecting bond fades for the swap);
|
|
19
|
+
* - a slow hub-centered whole-figure rotation;
|
|
20
|
+
* - paint: a seamless one-way blue gradient flow on the bonds plus per-atom
|
|
21
|
+
* "glint" gradients whose light end warms exactly while that atom is in
|
|
22
|
+
* flight (keyed to the same keyTimes/easing as the motion), or a plain
|
|
23
|
+
* `currentColor` outline via `paint: 'mono'`.
|
|
24
|
+
*
|
|
25
|
+
* **Gotchas a weak executor gets wrong:**
|
|
26
|
+
* - `gradientId` must be unique per rendered instance on a page — two svgs
|
|
27
|
+
* sharing one id cross-reference each other's gradients. React wrappers
|
|
28
|
+
* should pass something derived from `useId()` (strip `:` first).
|
|
29
|
+
* - Default colors are CSS-var-with-fallback strings
|
|
30
|
+
* (`var(--mol-spin-blue, #4f86f0)`), which theme via `--mol-spin-*` where
|
|
31
|
+
* they exist (e.g. the molecule.dev landing page) and fall back to the
|
|
32
|
+
* literal palette elsewhere. Injected into third-party pages (the
|
|
33
|
+
* attribution badge) they must be overridden with literal hexes — the vars
|
|
34
|
+
* do not exist there.
|
|
35
|
+
* - The glyph matrix x-translate (`-.78879`) deliberately differs from the
|
|
36
|
+
* static favicon's (`.81594`): it puts the molecule's hub exactly on the
|
|
37
|
+
* rotation center (16,16) so the spin never wobbles. Do not "fix" it.
|
|
38
|
+
* - `ariaLabel` produces `role="status"`; omit it for decorative uses, which
|
|
39
|
+
* get `aria-hidden="true"` instead. Never emit both.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { moleculeSpinnerMarkSvg } from '@molecule/app-ui'
|
|
44
|
+
*
|
|
45
|
+
* // themed, unique per instance
|
|
46
|
+
* const svg = moleculeSpinnerMarkSvg({ size: 24, gradientId: 'spin-1', ariaLabel: 'Loading' })
|
|
47
|
+
*
|
|
48
|
+
* // monochrome, inherits the surrounding text color
|
|
49
|
+
* const mono = moleculeSpinnerMarkSvg({ size: 16, paint: 'mono' })
|
|
50
|
+
*
|
|
51
|
+
* // third-party page (no --mol-spin-* vars): literal colors, CSS-sized
|
|
52
|
+
* const badge = moleculeSpinnerMarkSvg({
|
|
53
|
+
* gradientId: 'mol-badge-grad',
|
|
54
|
+
* className: 'mol-badge-mark',
|
|
55
|
+
* colors: { blue: '#4f86f0', light: '#6e9bf5', peach: '#e0975a' },
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @module
|
|
60
|
+
*/
|
|
61
|
+
const DEFAULT_TIMINGS = {
|
|
62
|
+
dur: '2.5s',
|
|
63
|
+
spin: '5s',
|
|
64
|
+
flow: '3s',
|
|
65
|
+
};
|
|
66
|
+
const DEFAULT_COLORS = {
|
|
67
|
+
blue: 'var(--mol-spin-blue, #4f86f0)',
|
|
68
|
+
light: 'var(--mol-spin-blue-light, #6e9bf5)',
|
|
69
|
+
peach: 'var(--mol-spin-peach, #e0975a)',
|
|
70
|
+
};
|
|
71
|
+
const EASE = '0.42 0 0.58 1';
|
|
72
|
+
const LIN = '0 0 1 1';
|
|
73
|
+
/** Bond fade keyframes, one per phase, phase-locked to the swap they serve. */
|
|
74
|
+
const BONDS = [
|
|
75
|
+
{
|
|
76
|
+
// Center–Left — fades during Phase 1
|
|
77
|
+
x1: 16.494,
|
|
78
|
+
x2: 8.563,
|
|
79
|
+
y1: 16,
|
|
80
|
+
y2: 16,
|
|
81
|
+
values: '1;0;0;1;1',
|
|
82
|
+
keyTimes: '0;0.033;0.167;0.217;1',
|
|
83
|
+
keySplines: [EASE, LIN, EASE, LIN].join(';'),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
// Center–Bottom-right — fades during Phase 2
|
|
87
|
+
x1: 20.959,
|
|
88
|
+
x2: 24.924,
|
|
89
|
+
y1: 18.579,
|
|
90
|
+
y2: 25.446,
|
|
91
|
+
values: '1;1;0;0;1;1',
|
|
92
|
+
keyTimes: '0;0.333;0.367;0.500;0.550;1',
|
|
93
|
+
keySplines: [LIN, EASE, LIN, EASE, LIN].join(';'),
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
// Center–Top-right — fades during Phase 3
|
|
97
|
+
x1: 20.959,
|
|
98
|
+
x2: 24.924,
|
|
99
|
+
y1: 13.422,
|
|
100
|
+
y2: 6.555,
|
|
101
|
+
values: '1;1;0;0;1;1',
|
|
102
|
+
keyTimes: '0;0.667;0.700;0.833;0.883;1',
|
|
103
|
+
keySplines: [LIN, EASE, LIN, EASE, LIN].join(';'),
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
/**
|
|
107
|
+
* Atom swap trajectories: cx/cy keyframe lists per atom, plus the glint pulse
|
|
108
|
+
* for its gradient (LIGHT at rest, peach at each flight's midpoint — the same
|
|
109
|
+
* anchors and easing the position animation uses, so the glint is frame-locked
|
|
110
|
+
* to every swap). Atoms are visually identical, so the loop-boundary jump is
|
|
111
|
+
* imperceptible.
|
|
112
|
+
*/
|
|
113
|
+
const ATOMS = [
|
|
114
|
+
{
|
|
115
|
+
// Center → Left (Phase 1), holds
|
|
116
|
+
cx: 19.47,
|
|
117
|
+
cy: 16,
|
|
118
|
+
cxValues: '19.47;19.47;5.587;5.587',
|
|
119
|
+
cyValues: null,
|
|
120
|
+
keyTimes: '0;0.033;0.167;1',
|
|
121
|
+
keySplines: [LIN, EASE, LIN].join(';'),
|
|
122
|
+
glintValues: [1, 1, 0, 1, 1], // indexes into [light, peach]
|
|
123
|
+
glintKeyTimes: '0;0.033;0.1;0.167;1',
|
|
124
|
+
glintSplines: [LIN, EASE, EASE, LIN].join(';'),
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
// Left → Center (Phase 1), Center → BR (Phase 2), holds
|
|
128
|
+
cx: 5.587,
|
|
129
|
+
cy: 16,
|
|
130
|
+
cxValues: '5.587;5.587;19.47;19.47;26.412;26.412',
|
|
131
|
+
cyValues: '16;16;16;16;28.023;28.023',
|
|
132
|
+
keyTimes: '0;0.033;0.167;0.367;0.500;1',
|
|
133
|
+
keySplines: [LIN, EASE, LIN, EASE, LIN].join(';'),
|
|
134
|
+
glintValues: [1, 1, 0, 1, 1, 0, 1, 1],
|
|
135
|
+
glintKeyTimes: '0;0.033;0.1;0.167;0.367;0.434;0.5;1',
|
|
136
|
+
glintSplines: [LIN, EASE, EASE, LIN, EASE, EASE, LIN].join(';'),
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
// BR → Center (Phase 2), Center → TR (Phase 3), holds
|
|
140
|
+
cx: 26.412,
|
|
141
|
+
cy: 28.023,
|
|
142
|
+
cxValues: '26.412;26.412;19.47;19.47;26.412;26.412',
|
|
143
|
+
cyValues: '28.023;28.023;16;16;3.977;3.977',
|
|
144
|
+
keyTimes: '0;0.367;0.500;0.700;0.833;1',
|
|
145
|
+
keySplines: [LIN, EASE, LIN, EASE, LIN].join(';'),
|
|
146
|
+
glintValues: [1, 1, 0, 1, 1, 0, 1, 1],
|
|
147
|
+
glintKeyTimes: '0;0.367;0.434;0.5;0.7;0.767;0.833;1',
|
|
148
|
+
glintSplines: [LIN, EASE, EASE, LIN, EASE, EASE, LIN].join(';'),
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
// TR → Center (Phase 3), holds
|
|
152
|
+
cx: 26.412,
|
|
153
|
+
cy: 3.977,
|
|
154
|
+
cxValues: '26.412;26.412;19.47;19.47',
|
|
155
|
+
cyValues: '3.977;3.977;16;16',
|
|
156
|
+
keyTimes: '0;0.700;0.833;1',
|
|
157
|
+
keySplines: [LIN, EASE, LIN].join(';'),
|
|
158
|
+
glintValues: [1, 1, 0, 1, 1],
|
|
159
|
+
glintKeyTimes: '0;0.7;0.767;0.833;1',
|
|
160
|
+
glintSplines: [LIN, EASE, EASE, LIN].join(';'),
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
/**
|
|
164
|
+
* Minimal attribute-value escaping for {@link MoleculeSpinnerMarkOptions.ariaLabel}
|
|
165
|
+
* — the one option that can carry free text. Developer-supplied options
|
|
166
|
+
* (`className`, `style`, `gradientId`, colors) are interpolated verbatim.
|
|
167
|
+
*/
|
|
168
|
+
function escapeAttr(value) {
|
|
169
|
+
return value
|
|
170
|
+
.replace(/&/g, '&')
|
|
171
|
+
.replace(/"/g, '"')
|
|
172
|
+
.replace(/</g, '<')
|
|
173
|
+
.replace(/>/g, '>');
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The molecule spinner mark as a complete SVG element string (SMIL-animated,
|
|
177
|
+
* framework-agnostic). See the module docblock for usage and gotchas.
|
|
178
|
+
*
|
|
179
|
+
* @param options - Paint, timings, size, gradient id and a11y shape.
|
|
180
|
+
* @returns A `<svg>…</svg>` markup string.
|
|
181
|
+
*/
|
|
182
|
+
export function moleculeSpinnerMarkSvg(options = {}) {
|
|
183
|
+
const timings = { ...DEFAULT_TIMINGS, ...options.timings };
|
|
184
|
+
const colors = { ...DEFAULT_COLORS, ...options.colors };
|
|
185
|
+
const gradientId = options.gradientId ?? 'mol-spinner-gradient';
|
|
186
|
+
const gradient = (options.paint ?? 'gradient') === 'gradient';
|
|
187
|
+
const sizeAttrs = options.size !== undefined ? ` width="${options.size}" height="${options.size}"` : '';
|
|
188
|
+
const classAttrs = options.className ? ` class="${options.className}"` : '';
|
|
189
|
+
const styleAttr = options.style ? ` style="${options.style}"` : '';
|
|
190
|
+
const a11yAttrs = options.ariaLabel
|
|
191
|
+
? ` role="status" aria-label="${escapeAttr(options.ariaLabel)}"`
|
|
192
|
+
: ' aria-hidden="true"';
|
|
193
|
+
const defs = gradient
|
|
194
|
+
? '<defs>' +
|
|
195
|
+
`<linearGradient id="${gradientId}" gradientUnits="userSpaceOnUse" x1="0" y1="16" x2="32" y2="16" spreadMethod="repeat">` +
|
|
196
|
+
`<stop offset="0" stop-color="${colors.blue}"/>` +
|
|
197
|
+
`<stop offset="0.5" stop-color="${colors.light}"/>` +
|
|
198
|
+
`<stop offset="1" stop-color="${colors.blue}"/>` +
|
|
199
|
+
`<animateTransform attributeName="gradientTransform" type="translate" values="0 0; 32 0" dur="${timings.flow}" repeatCount="indefinite"/>` +
|
|
200
|
+
'</linearGradient>' +
|
|
201
|
+
ATOMS.map((atom, i) => `<linearGradient id="${gradientId}-a${i}" x1="0" y1="0" x2="1" y2="1">` +
|
|
202
|
+
`<stop offset="0" stop-color="${colors.light}">` +
|
|
203
|
+
`<animate attributeName="stop-color" dur="${timings.dur}" repeatCount="indefinite" values="${atom.glintValues.map((v) => (v ? colors.light : colors.peach)).join(';')}" keyTimes="${atom.glintKeyTimes}" calcMode="spline" keySplines="${atom.glintSplines}"/>` +
|
|
204
|
+
'</stop>' +
|
|
205
|
+
`<stop offset="1" stop-color="${colors.blue}"/>` +
|
|
206
|
+
'</linearGradient>').join('') +
|
|
207
|
+
'</defs>'
|
|
208
|
+
: '';
|
|
209
|
+
const groupStroke = gradient ? `url(#${gradientId})` : 'currentColor';
|
|
210
|
+
const bonds = BONDS.map((bond) => `<line x1="${bond.x1}" x2="${bond.x2}" y1="${bond.y1}" y2="${bond.y2}">` +
|
|
211
|
+
`<animate attributeName="opacity" dur="${timings.dur}" repeatCount="indefinite" values="${bond.values}" keyTimes="${bond.keyTimes}" calcMode="spline" keySplines="${bond.keySplines}"/>` +
|
|
212
|
+
'</line>').join('');
|
|
213
|
+
const atoms = ATOMS.map((atom, i) => `<circle cx="${atom.cx}" cy="${atom.cy}" r="2.976"${gradient ? ` stroke="url(#${gradientId}-a${i})"` : ''}>` +
|
|
214
|
+
`<animate attributeName="cx" dur="${timings.dur}" repeatCount="indefinite" values="${atom.cxValues}" keyTimes="${atom.keyTimes}" calcMode="spline" keySplines="${atom.keySplines}"/>` +
|
|
215
|
+
(atom.cyValues
|
|
216
|
+
? `<animate attributeName="cy" dur="${timings.dur}" repeatCount="indefinite" values="${atom.cyValues}" keyTimes="${atom.keyTimes}" calcMode="spline" keySplines="${atom.keySplines}"/>`
|
|
217
|
+
: '') +
|
|
218
|
+
'</circle>').join('');
|
|
219
|
+
return (`<svg xmlns="http://www.w3.org/2000/svg"${sizeAttrs}${classAttrs}${styleAttr}` +
|
|
220
|
+
` viewBox="0 0 32 32"${a11yAttrs} focusable="false">` +
|
|
221
|
+
defs +
|
|
222
|
+
`<g><animateTransform attributeName="transform" type="rotate" from="0 16 16" to="360 16 16" dur="${timings.spin}" repeatCount="indefinite"/>` +
|
|
223
|
+
`<g transform="matrix(.86229 0 0 .86229 -.78879 2.2034)" stroke="${groupStroke}" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.4737" fill="none">` +
|
|
224
|
+
bonds +
|
|
225
|
+
atoms +
|
|
226
|
+
'</g></g></svg>');
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../src/spinner.ts"],"names":[],"mappings":"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"}
|