vireuikit 0.4.0 → 0.6.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/NOTICE +2 -5
- package/README.md +54 -79
- package/dist/a11y-D3SS74I3.d.cts +25 -0
- package/dist/a11y-D3SS74I3.d.ts +25 -0
- package/dist/chunk-I3BD3XGC.js +392 -0
- package/dist/chunk-I3BD3XGC.js.map +1 -0
- package/dist/index.cjs +226 -1137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +115 -92
- package/dist/index.d.ts +115 -92
- package/dist/index.js +1 -186
- package/dist/index.js.map +1 -1
- package/dist/web.cjs +826 -0
- package/dist/web.cjs.map +1 -0
- package/dist/web.d.cts +27 -0
- package/dist/web.d.ts +27 -0
- package/dist/web.js +567 -0
- package/dist/web.js.map +1 -0
- package/package.json +16 -16
- package/dist/chunk-VY22O2II.js +0 -1148
- package/dist/chunk-VY22O2II.js.map +0 -1
- package/dist/dynamics-DqGk_f1n.d.cts +0 -415
- package/dist/dynamics-DqGk_f1n.d.ts +0 -415
- package/dist/web/index.cjs +0 -1865
- package/dist/web/index.cjs.map +0 -1
- package/dist/web/index.d.cts +0 -152
- package/dist/web/index.d.ts +0 -152
- package/dist/web/index.js +0 -899
- package/dist/web/index.js.map +0 -1
package/NOTICE
CHANGED
|
@@ -4,8 +4,5 @@ Copyright 2026 Danil Kotlaev
|
|
|
4
4
|
This product includes software developed as part of the vireSpace platform
|
|
5
5
|
(https://github.com/pruffit/vire).
|
|
6
6
|
|
|
7
|
-
Built on VireGlass (https://github.com/pruffit/vireglass).
|
|
8
|
-
|
|
9
|
-
The MacCormack advection scheme implements the method described in Selle, Fedkiw, Kim, Liu and
|
|
10
|
-
Rossignac, "An Unconditionally Stable MacCormack Method" (2007). No third-party code or assets
|
|
11
|
-
are included in or distributed with this software; these are citations, not redistribution.
|
|
7
|
+
Built on VireGlass (https://github.com/pruffit/vireglass). No third-party code or assets are
|
|
8
|
+
included in or distributed with this software.
|
package/README.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# VireUIKit
|
|
2
2
|
|
|
3
3
|
A UI kit built on top of [VireGlass](https://github.com/pruffit/vireglass)'s physically-derived
|
|
4
|
-
glass material: atom state and press/hover/selection behavior for controls, a
|
|
5
|
-
growth morph
|
|
6
|
-
condensation tracks — that plugs into VireGlass's WebGL2 renderer as a backdrop pass.
|
|
4
|
+
glass material: atom state and press/hover/selection behavior for controls, and a
|
|
5
|
+
capsule-to-target growth morph.
|
|
7
6
|
|
|
8
7
|
**Status: 0.x.** The API can still change between minor versions.
|
|
9
8
|
|
|
@@ -13,8 +12,8 @@ condensation tracks — that plugs into VireGlass's WebGL2 renderer as a backdro
|
|
|
13
12
|
npm install vireuikit vireglass
|
|
14
13
|
```
|
|
15
14
|
|
|
16
|
-
`vireglass` is a peer dependency — this package draws on its material model
|
|
17
|
-
|
|
15
|
+
`vireglass` (3.x) is a peer dependency — this package draws on its material model rather than
|
|
16
|
+
shipping its own.
|
|
18
17
|
|
|
19
18
|
## Atom state and morph
|
|
20
19
|
|
|
@@ -44,84 +43,60 @@ const frame = growthFrame(sourceShape, targetShape, anchorPoint, growthPhase(sta
|
|
|
44
43
|
// frame.body: the shape to draw as glass this frame.
|
|
45
44
|
```
|
|
46
45
|
|
|
47
|
-
##
|
|
48
|
-
|
|
49
|
-
`
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
spotlight has no drawn edge: its beam is a soft lobe with static shafts fanning out from the lamp,
|
|
58
|
-
dimmed by the gas between the lamp and each point (a grid-resolution shadow pass,
|
|
59
|
-
`shadowExtinction`), so beams show where there is vapor to scatter them. `lightRigForCover`/
|
|
60
|
-
`lightRigForCharacter` tint the spotlights toward a cover's hue like colored gels and leave the
|
|
61
|
-
strip near neutral. Vapor species (`channelColors`) fold into a near-neutral ambient base;
|
|
62
|
-
`channelScatter` is how strongly each species scatters light.
|
|
63
|
-
|
|
64
|
-
Tracks come in three kinds (`MEDIUM_TRACK_PRESETS`): `alpha` (short, thick, thickening toward its
|
|
65
|
-
end — the playing source sprays a burst of them from the cover's position, a few on the beat and
|
|
66
|
-
the rest over the next 1.6 s), `electron` (thin, wiggly) and `muon` (long, straight,
|
|
67
|
-
thin). The calm state schedules a lone electron or muon every 8–20 s from no source at all. Each track is drawn twice: as a soft residue stamped into the simulation grid, and
|
|
68
|
-
as a crisp droplet chain in content pixels (`trackLayerAmount`, `MEDIUM_TRACK_LAYER_LOOK`) that
|
|
69
|
-
appears at full length, then broadens, sags and fades over one to two seconds. Tracks are lit by
|
|
70
|
-
the same lights, plus `trackLightFloor` so one is never fully dark.
|
|
46
|
+
## Web elements
|
|
47
|
+
|
|
48
|
+
`vireuikit/web` upgrades native controls with custom elements. The control inside works before the
|
|
49
|
+
upgrade; afterwards the element drives its states from the model. Glass is opt-in: put `glass` on pieces
|
|
50
|
+
of the navigation layer, and leave it off for content.
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<vire-button><button>Play</button></vire-button>
|
|
54
|
+
<vire-icon-button glass><button aria-label="Share">…</button></vire-icon-button>
|
|
55
|
+
```
|
|
71
56
|
|
|
72
57
|
```ts
|
|
73
|
-
import {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const renderer = createVireGlassRenderer(canvas);
|
|
78
|
-
renderer.resize(canvas.width, canvas.height);
|
|
79
|
-
|
|
80
|
-
let last = performance.now();
|
|
81
|
-
function frame(now: number) {
|
|
82
|
-
const dt = (now - last) / 1000;
|
|
83
|
-
last = now;
|
|
84
|
-
renderer.render({
|
|
85
|
-
density: window.devicePixelRatio,
|
|
86
|
-
debug: 'normal',
|
|
87
|
-
pieces,
|
|
88
|
-
backdrop: medium.pass({ gridWidth: 128, gridHeight: 72, dt }),
|
|
89
|
-
});
|
|
90
|
-
requestAnimationFrame(frame);
|
|
91
|
-
}
|
|
58
|
+
import { defineVireElements, setA11yOverride } from 'vireuikit/web';
|
|
59
|
+
|
|
60
|
+
defineVireElements({ nonce: cspNonce });
|
|
61
|
+
setA11yOverride({ reduceTransparency: true });
|
|
92
62
|
```
|
|
93
63
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
64
|
+
- `<vire-button>` is an action: it sinks and grows slightly under press, and nothing opens out of it.
|
|
65
|
+
- `<vire-icon-button>` lifts into the glass under the finger; the lens response is visible while the
|
|
66
|
+
press is held.
|
|
67
|
+
- Attributes: `glass` (empty or `present`: a lens at rest; `touch`: a lens only under the finger; absent: no
|
|
68
|
+
glass), `size` (`touch`, `small`, `medium`, `large`, `xlarge`; by default `touch` on a coarse pointer and
|
|
69
|
+
`medium` otherwise), `disabled`.
|
|
70
|
+
- On a coarse pointer every size keeps a hit area of at least 44 dp without changing layout.
|
|
71
|
+
- The lens reads the backdrop from declared colours and cannot see an image, a video or a canvas. A host that knows
|
|
72
|
+
what lies under the control sets the element's `sample` (a `BackdropSample` from `vireglass`), at any time; `null`
|
|
73
|
+
hands it back to the probe.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { statsFromSamples } from 'vireglass/dom';
|
|
77
|
+
|
|
78
|
+
playButton.sample = statsFromSamples(coverColours); // [{ r, g, b }, …] in 0–255
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- The element dispatches `vire-glass-ready` once its lens is attached. If the lens cannot be loaded or attached,
|
|
82
|
+
the control stays a complete one on its plain (or, under reduced transparency, opaque frosted) surface, and the next
|
|
83
|
+
setting change tries again.
|
|
84
|
+
- Set `disabled` on the host element: it is mirrored onto the inner `<button>` and wins over it. Clearing it on
|
|
85
|
+
the host re-enables the button.
|
|
86
|
+
- Under `forced-colors` the elements keep the system colours and drop their own tints and blur.
|
|
87
|
+
- Accessibility follows the system `prefers-*` settings; `setA11yOverride` or the element's `a11y`
|
|
88
|
+
property overrides them. Reduced transparency keeps the lens and frosts it: a blurrier lens and a denser body, with the
|
|
89
|
+
ink following the body. Text takes the page's colour; the frosted fallback and the high-contrast bodies assume
|
|
90
|
+
the page's `color-scheme` matches it.
|
|
91
|
+
- The elements inject one stylesheet. Under a strict CSP pass `nonce` to `defineVireElements`, or ship the
|
|
92
|
+
exported `STYLES` string yourself.
|
|
93
|
+
- Importing the module touches no DOM, so it is safe on a server; `defineVireElements()` is the only call
|
|
94
|
+
that registers anything. An element defined before its markup is parsed waits for its button.
|
|
95
|
+
|
|
96
|
+
Sizes, behaviour state machines and accessibility modes are exported from `vireuikit` and shared by every
|
|
97
|
+
target. How an atom is accepted:
|
|
98
|
+
[design](https://github.com/pruffit/vireuikit/blob/main/docs/design.md),
|
|
99
|
+
[acceptance](https://github.com/pruffit/vireuikit/blob/main/docs/acceptance.md).
|
|
125
100
|
|
|
126
101
|
## License
|
|
127
102
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type A11yMode = {
|
|
2
|
+
reduceTransparency: boolean;
|
|
3
|
+
increaseContrast: boolean;
|
|
4
|
+
reduceMotion: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare const A11Y_NONE: A11yMode;
|
|
7
|
+
/** `undefined` follows the system; a boolean overrides it. */
|
|
8
|
+
type A11yOverride = {
|
|
9
|
+
[K in keyof A11yMode]?: boolean | undefined;
|
|
10
|
+
};
|
|
11
|
+
declare function resolveA11y(system: A11yMode, override?: A11yOverride): A11yMode;
|
|
12
|
+
/** `plain`: no glass was asked for. `frosted`: the stand-in when glass under reduced transparency cannot attach. */
|
|
13
|
+
type Surface = 'plain' | 'frosted' | 'glass';
|
|
14
|
+
type Presentation = {
|
|
15
|
+
glass: boolean;
|
|
16
|
+
/** Reduced transparency: the glass stays and frosts. */
|
|
17
|
+
frost: boolean;
|
|
18
|
+
surface: Surface;
|
|
19
|
+
contrastBorder: boolean;
|
|
20
|
+
instantSprings: boolean;
|
|
21
|
+
};
|
|
22
|
+
declare function presentationFor(mode: A11yMode, wantsGlass: boolean): Presentation;
|
|
23
|
+
declare function sameA11y(a: A11yMode, b: A11yMode): boolean;
|
|
24
|
+
|
|
25
|
+
export { A11Y_NONE as A, type Presentation as P, type Surface as S, type A11yMode as a, type A11yOverride as b, presentationFor as p, resolveA11y as r, sameA11y as s };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type A11yMode = {
|
|
2
|
+
reduceTransparency: boolean;
|
|
3
|
+
increaseContrast: boolean;
|
|
4
|
+
reduceMotion: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare const A11Y_NONE: A11yMode;
|
|
7
|
+
/** `undefined` follows the system; a boolean overrides it. */
|
|
8
|
+
type A11yOverride = {
|
|
9
|
+
[K in keyof A11yMode]?: boolean | undefined;
|
|
10
|
+
};
|
|
11
|
+
declare function resolveA11y(system: A11yMode, override?: A11yOverride): A11yMode;
|
|
12
|
+
/** `plain`: no glass was asked for. `frosted`: the stand-in when glass under reduced transparency cannot attach. */
|
|
13
|
+
type Surface = 'plain' | 'frosted' | 'glass';
|
|
14
|
+
type Presentation = {
|
|
15
|
+
glass: boolean;
|
|
16
|
+
/** Reduced transparency: the glass stays and frosts. */
|
|
17
|
+
frost: boolean;
|
|
18
|
+
surface: Surface;
|
|
19
|
+
contrastBorder: boolean;
|
|
20
|
+
instantSprings: boolean;
|
|
21
|
+
};
|
|
22
|
+
declare function presentationFor(mode: A11yMode, wantsGlass: boolean): Presentation;
|
|
23
|
+
declare function sameA11y(a: A11yMode, b: A11yMode): boolean;
|
|
24
|
+
|
|
25
|
+
export { A11Y_NONE as A, type Presentation as P, type Surface as S, type A11yMode as a, type A11yOverride as b, presentationFor as p, resolveA11y as r, sameA11y as s };
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { activeMaterial, applyAccessibility, resolveOptics, halfMinDp, concentricRadius } from 'vireglass';
|
|
2
|
+
|
|
3
|
+
// src/kit/a11y.ts
|
|
4
|
+
var A11Y_NONE = {
|
|
5
|
+
reduceTransparency: false,
|
|
6
|
+
increaseContrast: false,
|
|
7
|
+
reduceMotion: false
|
|
8
|
+
};
|
|
9
|
+
function resolveA11y(system, override = {}) {
|
|
10
|
+
return {
|
|
11
|
+
reduceTransparency: override.reduceTransparency ?? system.reduceTransparency,
|
|
12
|
+
increaseContrast: override.increaseContrast ?? system.increaseContrast,
|
|
13
|
+
reduceMotion: override.reduceMotion ?? system.reduceMotion
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function presentationFor(mode, wantsGlass) {
|
|
17
|
+
return {
|
|
18
|
+
glass: wantsGlass,
|
|
19
|
+
frost: wantsGlass && mode.reduceTransparency,
|
|
20
|
+
surface: wantsGlass ? "glass" : "plain",
|
|
21
|
+
contrastBorder: mode.increaseContrast,
|
|
22
|
+
instantSprings: mode.reduceMotion
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function sameA11y(a, b) {
|
|
26
|
+
return a.reduceTransparency === b.reduceTransparency && a.increaseContrast === b.increaseContrast && a.reduceMotion === b.reduceMotion;
|
|
27
|
+
}
|
|
28
|
+
var ATOM_AT_REST = {
|
|
29
|
+
pressed: 0,
|
|
30
|
+
hovered: 0,
|
|
31
|
+
selected: 0,
|
|
32
|
+
disabled: false
|
|
33
|
+
};
|
|
34
|
+
function atomLift(kind) {
|
|
35
|
+
switch (kind) {
|
|
36
|
+
case "iconButton":
|
|
37
|
+
case "switch":
|
|
38
|
+
case "slider":
|
|
39
|
+
return 1;
|
|
40
|
+
default:
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
var DISABLED_PRESENCE = 0.25;
|
|
45
|
+
var HOVER_GAIN = 0.35;
|
|
46
|
+
function activation(state) {
|
|
47
|
+
if (state.disabled) return 0;
|
|
48
|
+
const clamp = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
|
|
49
|
+
return Math.max(clamp(state.selected), clamp(state.pressed), clamp(state.hovered) * HOVER_GAIN);
|
|
50
|
+
}
|
|
51
|
+
function atomMaterial(base, kind, state = ATOM_AT_REST) {
|
|
52
|
+
const out = activeMaterial(base, activation(state));
|
|
53
|
+
if (!state.disabled) return out;
|
|
54
|
+
return { ...out, presence: out.presence * DISABLED_PRESENCE };
|
|
55
|
+
}
|
|
56
|
+
function atomAtRest(state) {
|
|
57
|
+
return state.pressed === 0 && state.hovered === 0 && state.selected === 0 && state.disabled === false;
|
|
58
|
+
}
|
|
59
|
+
var REST_BODY = { alpha: 0.25, white: 0.15, lift: 0.1 };
|
|
60
|
+
var PRESSED_BODY = { alpha: 0.34, white: 0.35, lift: 0 };
|
|
61
|
+
var FROST_LIFT = 0.26;
|
|
62
|
+
function atomBody(base, state = ATOM_AT_REST, frost = false) {
|
|
63
|
+
const on = activation(state);
|
|
64
|
+
const mix2 = (key) => REST_BODY[key] + (PRESSED_BODY[key] - REST_BODY[key]) * on;
|
|
65
|
+
let alpha = mix2("alpha");
|
|
66
|
+
let white = mix2("white");
|
|
67
|
+
let lift = mix2("lift");
|
|
68
|
+
if (state.disabled) alpha *= DISABLED_PRESENCE;
|
|
69
|
+
if (frost) {
|
|
70
|
+
const density = applyAccessibility(resolveOptics(base), {
|
|
71
|
+
reduceTransparency: true,
|
|
72
|
+
increaseContrast: false,
|
|
73
|
+
reduceMotion: false
|
|
74
|
+
}).bodyDensity;
|
|
75
|
+
alpha = Math.max(alpha, density);
|
|
76
|
+
white = 0;
|
|
77
|
+
lift = FROST_LIFT;
|
|
78
|
+
}
|
|
79
|
+
return { alpha, white, lift };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/kit/behavior/focus.ts
|
|
83
|
+
function stepFocus(event) {
|
|
84
|
+
return event.type === "focus" && event.visible;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/kit/behavior/hover.ts
|
|
88
|
+
function stepHover(event, canHover) {
|
|
89
|
+
return canHover && event.type === "enter";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/kit/behavior/press.ts
|
|
93
|
+
var PRESS_IDLE = { by: null };
|
|
94
|
+
function stepPress(state, event, enabled) {
|
|
95
|
+
switch (event.type) {
|
|
96
|
+
case "down":
|
|
97
|
+
if (!enabled || state.by !== null) return { state, activated: false };
|
|
98
|
+
return { state: { by: event.source }, activated: false };
|
|
99
|
+
case "up":
|
|
100
|
+
if (state.by !== event.source) return { state, activated: false };
|
|
101
|
+
return { state: PRESS_IDLE, activated: enabled };
|
|
102
|
+
case "cancel":
|
|
103
|
+
return { state: PRESS_IDLE, activated: false };
|
|
104
|
+
case "leave":
|
|
105
|
+
return state.by === "pointer" ? { state: PRESS_IDLE, activated: false } : { state, activated: false };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/kit/behavior/control.ts
|
|
110
|
+
var TOUCH_INPUT = { hover: false };
|
|
111
|
+
var POINTER_INPUT = { hover: true };
|
|
112
|
+
var CONTROL_IDLE = {
|
|
113
|
+
press: PRESS_IDLE,
|
|
114
|
+
hovered: false,
|
|
115
|
+
focused: false,
|
|
116
|
+
disabled: false
|
|
117
|
+
};
|
|
118
|
+
function stepControl(state, event, caps) {
|
|
119
|
+
switch (event.type) {
|
|
120
|
+
case "down":
|
|
121
|
+
case "up":
|
|
122
|
+
case "cancel": {
|
|
123
|
+
const next = stepPress(state.press, event, !state.disabled);
|
|
124
|
+
return { state: { ...state, press: next.state }, activated: next.activated };
|
|
125
|
+
}
|
|
126
|
+
case "leave": {
|
|
127
|
+
const next = stepPress(state.press, event, !state.disabled);
|
|
128
|
+
return { state: { ...state, press: next.state, hovered: false }, activated: false };
|
|
129
|
+
}
|
|
130
|
+
case "enter":
|
|
131
|
+
return {
|
|
132
|
+
state: { ...state, hovered: !state.disabled && stepHover(event, caps.hover) },
|
|
133
|
+
activated: false
|
|
134
|
+
};
|
|
135
|
+
case "focus":
|
|
136
|
+
case "blur": {
|
|
137
|
+
const press = event.type === "blur" && state.press.by === "keyboard" ? PRESS_IDLE : state.press;
|
|
138
|
+
return {
|
|
139
|
+
state: { ...state, press, focused: !state.disabled && stepFocus(event) },
|
|
140
|
+
activated: false
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
case "disable":
|
|
144
|
+
return {
|
|
145
|
+
state: event.disabled ? { press: PRESS_IDLE, hovered: false, focused: false, disabled: true } : { ...state, disabled: false },
|
|
146
|
+
activated: false
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function controlTargets(state) {
|
|
151
|
+
return {
|
|
152
|
+
pressed: state.press.by !== null ? 1 : 0,
|
|
153
|
+
hovered: state.hovered ? 1 : 0,
|
|
154
|
+
focus: state.focused ? 1 : 0,
|
|
155
|
+
disabled: state.disabled
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function stepSpring(s, dt, response, damping, instant = false) {
|
|
159
|
+
if (instant) {
|
|
160
|
+
const moved = s.x !== s.target || s.v !== 0;
|
|
161
|
+
s.x = s.target;
|
|
162
|
+
s.v = 0;
|
|
163
|
+
return moved;
|
|
164
|
+
}
|
|
165
|
+
const stiffness = (2 * Math.PI / response) ** 2;
|
|
166
|
+
const friction = 4 * Math.PI * damping / response;
|
|
167
|
+
const h = 1 / 240;
|
|
168
|
+
for (let left = Math.min(dt, 0.05); left > 0; left -= h) {
|
|
169
|
+
const step = Math.min(left, h);
|
|
170
|
+
s.v += (stiffness * (s.target - s.x) - friction * s.v) * step;
|
|
171
|
+
s.x += s.v * step;
|
|
172
|
+
}
|
|
173
|
+
if (Math.abs(s.target - s.x) < 1e-3 && Math.abs(s.v) < 0.01) {
|
|
174
|
+
s.x = s.target;
|
|
175
|
+
s.v = 0;
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
var smoothstep = (e0, e1, x) => {
|
|
181
|
+
const t = Math.min(Math.max((x - e0) / (e1 - e0), 0), 1);
|
|
182
|
+
return t * t * (3 - 2 * t);
|
|
183
|
+
};
|
|
184
|
+
var mix = (a, b, t) => a + (b - a) * t;
|
|
185
|
+
var DROP_DIAMETER = 1.1;
|
|
186
|
+
var DROP_LIFT = 0.5;
|
|
187
|
+
var NECK_GAIN = 0.3;
|
|
188
|
+
var NECK_RAMP = 4;
|
|
189
|
+
var CORNER_EASE_START = 0.55;
|
|
190
|
+
var INK_OUT_END = 0.4;
|
|
191
|
+
var INK_IN_START = 0.45;
|
|
192
|
+
var INK_IN_END = 0.95;
|
|
193
|
+
function growthInk(phase) {
|
|
194
|
+
const a = Math.min(Math.max(phase.shrink, 0), 1);
|
|
195
|
+
const b = Math.max(phase.grow, 0);
|
|
196
|
+
return {
|
|
197
|
+
outgoing: 1 - smoothstep(0, INK_OUT_END, a),
|
|
198
|
+
incoming: smoothstep(INK_IN_START, INK_IN_END, b)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function largerOf(a, b) {
|
|
202
|
+
return halfMinDp(a.geometry) >= halfMinDp(b.geometry) ? { main: a, other: b } : { main: b, other: a };
|
|
203
|
+
}
|
|
204
|
+
function growthFrame(source, target, anchor, phase) {
|
|
205
|
+
const dx = target.center.x - source.center.x;
|
|
206
|
+
const dy = target.center.y - source.center.y;
|
|
207
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
208
|
+
const sourceSize = halfMinDp(source.geometry) * 2;
|
|
209
|
+
const lift = DROP_LIFT * sourceSize;
|
|
210
|
+
const drop = {
|
|
211
|
+
x: source.center.x + dx / len * lift,
|
|
212
|
+
y: source.center.y + dy / len * lift
|
|
213
|
+
};
|
|
214
|
+
const a = Math.min(Math.max(phase.shrink, 0), 1);
|
|
215
|
+
const b = Math.max(phase.grow, 0);
|
|
216
|
+
const keep = Math.max(1 - b, 0);
|
|
217
|
+
const d = DROP_DIAMETER * sourceSize;
|
|
218
|
+
const shrunkGeometry = {
|
|
219
|
+
width: mix(source.geometry.width, 0.6 * d, a) * keep,
|
|
220
|
+
height: mix(source.geometry.height, 0.6 * d, a) * keep,
|
|
221
|
+
cornerRadius: 0
|
|
222
|
+
};
|
|
223
|
+
shrunkGeometry.cornerRadius = Math.min(
|
|
224
|
+
mix(source.geometry.cornerRadius, halfMinDp(shrunkGeometry), a),
|
|
225
|
+
halfMinDp(shrunkGeometry)
|
|
226
|
+
);
|
|
227
|
+
const shrunk = {
|
|
228
|
+
geometry: shrunkGeometry,
|
|
229
|
+
center: { x: mix(source.center.x, drop.x, a), y: mix(source.center.y, drop.y, a) }
|
|
230
|
+
};
|
|
231
|
+
const seed = d * Math.sqrt(a);
|
|
232
|
+
const cornerX = Math.sign(anchor.x - source.center.x);
|
|
233
|
+
const cornerY = Math.sign(anchor.y - source.center.y);
|
|
234
|
+
const edgeX = mix(drop.x + cornerX * (seed / 2), anchor.x, Math.min(b, 1));
|
|
235
|
+
const edgeY = mix(drop.y + cornerY * (seed / 2), anchor.y, Math.min(b, 1));
|
|
236
|
+
const width = mix(seed, target.geometry.width, b);
|
|
237
|
+
const height = mix(seed, target.geometry.height, b);
|
|
238
|
+
const grownGeometry = { width, height, cornerRadius: 0 };
|
|
239
|
+
grownGeometry.cornerRadius = Math.min(
|
|
240
|
+
mix(halfMinDp(grownGeometry), target.geometry.cornerRadius, smoothstep(CORNER_EASE_START, 1, b)),
|
|
241
|
+
halfMinDp(grownGeometry)
|
|
242
|
+
);
|
|
243
|
+
const grown = {
|
|
244
|
+
geometry: grownGeometry,
|
|
245
|
+
center: { x: edgeX - cornerX * (width / 2), y: edgeY - cornerY * (height / 2) }
|
|
246
|
+
};
|
|
247
|
+
const { main, other } = largerOf(grown, shrunk);
|
|
248
|
+
const neck = NECK_GAIN * sourceSize * Math.min(a * NECK_RAMP, 1) * keep;
|
|
249
|
+
const united = neck > 0.01 && other.geometry.width > 0.5 && other.geometry.height > 0.5;
|
|
250
|
+
return {
|
|
251
|
+
body: main,
|
|
252
|
+
grown,
|
|
253
|
+
merge: united ? {
|
|
254
|
+
offsetX: other.center.x - main.center.x,
|
|
255
|
+
offsetY: other.center.y - main.center.y,
|
|
256
|
+
width: other.geometry.width,
|
|
257
|
+
height: other.geometry.height,
|
|
258
|
+
cornerRadius: other.geometry.cornerRadius,
|
|
259
|
+
smoothing: neck
|
|
260
|
+
} : void 0,
|
|
261
|
+
ink: growthInk(phase)
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
var createGrowthState = () => ({
|
|
265
|
+
shrink: { x: 0, v: 0, target: 0 },
|
|
266
|
+
grow: { x: 0, v: 0, target: 0 }
|
|
267
|
+
});
|
|
268
|
+
var growthPhase = (state) => ({
|
|
269
|
+
shrink: state.shrink.x,
|
|
270
|
+
grow: state.grow.x
|
|
271
|
+
});
|
|
272
|
+
var DEFAULT_GROWTH_TIMING = {
|
|
273
|
+
shrinkOpen: 0.38,
|
|
274
|
+
shrinkClose: 0.3,
|
|
275
|
+
growOpen: 0.46,
|
|
276
|
+
growClose: 0.4,
|
|
277
|
+
growDampingOpen: 0.72
|
|
278
|
+
};
|
|
279
|
+
var GROW_DAMPING_CLOSE = 1;
|
|
280
|
+
var SHRINK_DAMPING = 1;
|
|
281
|
+
var GROW_STARTS_AT = 0.8;
|
|
282
|
+
var SHRINK_RETURNS_AT = 0.12;
|
|
283
|
+
function stepGrowth(state, dt, open, reduceMotion = false, timing = DEFAULT_GROWTH_TIMING) {
|
|
284
|
+
const { shrink, grow } = state;
|
|
285
|
+
if (reduceMotion) {
|
|
286
|
+
shrink.target = open ? 1 : 0;
|
|
287
|
+
grow.target = open ? 1 : 0;
|
|
288
|
+
} else if (open) {
|
|
289
|
+
shrink.target = 1;
|
|
290
|
+
if (shrink.x > GROW_STARTS_AT) grow.target = 1;
|
|
291
|
+
} else {
|
|
292
|
+
grow.target = 0;
|
|
293
|
+
if (grow.x < SHRINK_RETURNS_AT) shrink.target = 0;
|
|
294
|
+
}
|
|
295
|
+
const movedShrink = stepSpring(
|
|
296
|
+
shrink,
|
|
297
|
+
dt,
|
|
298
|
+
open ? timing.shrinkOpen : timing.shrinkClose,
|
|
299
|
+
SHRINK_DAMPING,
|
|
300
|
+
reduceMotion
|
|
301
|
+
);
|
|
302
|
+
const movedGrow = stepSpring(
|
|
303
|
+
grow,
|
|
304
|
+
dt,
|
|
305
|
+
open ? timing.growOpen : timing.growClose,
|
|
306
|
+
open ? timing.growDampingOpen : GROW_DAMPING_CLOSE,
|
|
307
|
+
reduceMotion
|
|
308
|
+
);
|
|
309
|
+
return movedShrink || movedGrow;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// src/kit/behavior/visual.ts
|
|
313
|
+
var createControlVisual = () => ({
|
|
314
|
+
pressed: { x: 0, v: 0, target: 0 },
|
|
315
|
+
hovered: { x: 0, v: 0, target: 0 },
|
|
316
|
+
focus: { x: 0, v: 0, target: 0 }
|
|
317
|
+
});
|
|
318
|
+
var PRESS = { response: 0.18, damping: 0.78 };
|
|
319
|
+
var HOVER = { response: 0.22, damping: 1 };
|
|
320
|
+
var FOCUS = { response: 0.16, damping: 1 };
|
|
321
|
+
function stepControlVisual(visual, dt, state, instant = false) {
|
|
322
|
+
const t = controlTargets(state);
|
|
323
|
+
visual.pressed.target = t.pressed;
|
|
324
|
+
visual.hovered.target = t.hovered;
|
|
325
|
+
visual.focus.target = t.focus;
|
|
326
|
+
const a = stepSpring(visual.pressed, dt, PRESS.response, PRESS.damping, instant);
|
|
327
|
+
const b = stepSpring(visual.hovered, dt, HOVER.response, HOVER.damping, instant);
|
|
328
|
+
const c = stepSpring(visual.focus, dt, FOCUS.response, FOCUS.damping, instant);
|
|
329
|
+
return a || b || c;
|
|
330
|
+
}
|
|
331
|
+
function visualAtomState(visual, state) {
|
|
332
|
+
return {
|
|
333
|
+
pressed: visual.pressed.x,
|
|
334
|
+
hovered: visual.hovered.x,
|
|
335
|
+
selected: 0,
|
|
336
|
+
disabled: state.disabled
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function settleControlVisual(visual, state) {
|
|
340
|
+
stepControlVisual(visual, 0, state, true);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/kit/response.ts
|
|
344
|
+
var LIFTING = { grow: 0.18, defocus: 1.6 };
|
|
345
|
+
var SINKING = { grow: 0.06, defocus: 1 };
|
|
346
|
+
function pressResponse(kind) {
|
|
347
|
+
return atomLift(kind) === 1 ? LIFTING : SINKING;
|
|
348
|
+
}
|
|
349
|
+
var CONTROL_SIZES = ["touch", "small", "medium", "large", "xlarge"];
|
|
350
|
+
var MIN_TOUCH_TARGET_DP = 44;
|
|
351
|
+
var MIN_POINTER_TARGET_DP = 24;
|
|
352
|
+
var capsule = (height, paddingX) => ({
|
|
353
|
+
height,
|
|
354
|
+
paddingX,
|
|
355
|
+
icon: Math.round(height / 2),
|
|
356
|
+
radius: height / 2,
|
|
357
|
+
shape: "capsule"
|
|
358
|
+
});
|
|
359
|
+
var rounded = (height, paddingX) => ({
|
|
360
|
+
height,
|
|
361
|
+
paddingX,
|
|
362
|
+
icon: Math.round(height / 2),
|
|
363
|
+
radius: height / 4,
|
|
364
|
+
shape: "rounded"
|
|
365
|
+
});
|
|
366
|
+
var BUTTON_SIZES = {
|
|
367
|
+
touch: capsule(44, 20),
|
|
368
|
+
small: rounded(24, 10),
|
|
369
|
+
medium: rounded(32, 14),
|
|
370
|
+
large: capsule(40, 18),
|
|
371
|
+
xlarge: capsule(48, 22)
|
|
372
|
+
};
|
|
373
|
+
function iconButtonSize(size) {
|
|
374
|
+
const spec = BUTTON_SIZES[size];
|
|
375
|
+
return { ...spec, width: spec.height, paddingX: 0 };
|
|
376
|
+
}
|
|
377
|
+
function nestedRadius(outerRadius, inset, minimum = 0) {
|
|
378
|
+
return concentricRadius(outerRadius, inset, minimum);
|
|
379
|
+
}
|
|
380
|
+
function defaultSize(input) {
|
|
381
|
+
return input.touch ? "touch" : "medium";
|
|
382
|
+
}
|
|
383
|
+
function hitSlop(bodyDp, minTargetDp) {
|
|
384
|
+
return bodyDp >= minTargetDp ? 0 : (minTargetDp - bodyDp) / 2;
|
|
385
|
+
}
|
|
386
|
+
function minTarget(input) {
|
|
387
|
+
return input.touch ? MIN_TOUCH_TARGET_DP : MIN_POINTER_TARGET_DP;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export { A11Y_NONE, ATOM_AT_REST, BUTTON_SIZES, CONTROL_IDLE, CONTROL_SIZES, DEFAULT_GROWTH_TIMING, MIN_POINTER_TARGET_DP, MIN_TOUCH_TARGET_DP, POINTER_INPUT, PRESS_IDLE, TOUCH_INPUT, atomAtRest, atomBody, atomLift, atomMaterial, controlTargets, createControlVisual, createGrowthState, defaultSize, growthFrame, growthInk, growthPhase, hitSlop, iconButtonSize, minTarget, nestedRadius, presentationFor, pressResponse, resolveA11y, sameA11y, settleControlVisual, smoothstep, stepControl, stepControlVisual, stepFocus, stepGrowth, stepHover, stepPress, stepSpring, visualAtomState };
|
|
391
|
+
//# sourceMappingURL=chunk-I3BD3XGC.js.map
|
|
392
|
+
//# sourceMappingURL=chunk-I3BD3XGC.js.map
|