@hina-ui/vue 1.7.10 → 1.7.11
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/index.js +86 -54
- package/dist/index.js.map +1 -1
- package/dist/shared/behavior/spoiler/painter.ts +87 -60
- package/dist/shared/behavior/spoiler/worklet.ts +7 -9
- package/dist/shared/styles/motion.css +7 -1
- package/dist/shared/styles/spoiler.css +6 -0
- package/dist/shared/styles/typography.css +18 -3
- package/dist/types/shared/src/behavior/spoiler/painter.d.ts +10 -9
- package/dist/types/shared/src/behavior/spoiler/painter.d.ts.map +1 -1
- package/dist/types/shared/src/behavior/spoiler/worklet.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -32,26 +32,50 @@ const DEFAULTS = {
|
|
|
32
32
|
accent: '0 0% 20%',
|
|
33
33
|
} as const
|
|
34
34
|
|
|
35
|
+
export const SPOILER_WORKLET_INPUTS = [
|
|
36
|
+
'--hn-nz-t',
|
|
37
|
+
'--hn-nz-stop',
|
|
38
|
+
'--hn-nz-fade',
|
|
39
|
+
'--hn-nz-gap',
|
|
40
|
+
'--hn-nz-accent',
|
|
41
|
+
'--hn-nz-words',
|
|
42
|
+
'--hn-nz-density',
|
|
43
|
+
] as const
|
|
44
|
+
|
|
35
45
|
const BLOCK_MAX_TILE = 293
|
|
36
46
|
const INLINE_MAX_TILE = 333
|
|
37
47
|
const GAP_RATIO = 8
|
|
38
48
|
const DEFAULT_FADE_S = 1.5
|
|
49
|
+
const CLOCK_S = 3600
|
|
50
|
+
|
|
51
|
+
const painters = new WeakMap<Element, SpoilerPainter>()
|
|
52
|
+
let viewport: IntersectionObserver | undefined
|
|
53
|
+
|
|
54
|
+
function watchViewport() {
|
|
55
|
+
viewport ??= new IntersectionObserver(entries => {
|
|
56
|
+
for (const entry of entries) painters.get(entry.target)?.setInView(entry.isIntersecting)
|
|
57
|
+
})
|
|
58
|
+
return viewport
|
|
59
|
+
}
|
|
39
60
|
|
|
40
61
|
export class SpoilerPainter {
|
|
41
62
|
readonly el: HTMLElement
|
|
42
63
|
maxFPS: number = DEFAULTS.fps
|
|
43
64
|
|
|
44
|
-
private
|
|
45
|
-
private
|
|
46
|
-
private
|
|
47
|
-
private
|
|
48
|
-
private fadeS = 0
|
|
65
|
+
private clock: Animation | null = null
|
|
66
|
+
private settle: ReturnType<typeof setTimeout> | undefined
|
|
67
|
+
private running = false
|
|
68
|
+
private inView = false
|
|
49
69
|
private hidden = false
|
|
50
70
|
private destroyed = false
|
|
51
71
|
|
|
52
72
|
constructor(el: HTMLElement, options: SpoilerPainterOptions = {}) {
|
|
53
73
|
registerSpoilerWorklet()
|
|
54
74
|
this.el = el
|
|
75
|
+
painters.set(el, this)
|
|
76
|
+
watchViewport().observe(el)
|
|
77
|
+
this.setFade(0)
|
|
78
|
+
this.setTstop(null)
|
|
55
79
|
this.update(options)
|
|
56
80
|
}
|
|
57
81
|
|
|
@@ -68,13 +92,19 @@ export class SpoilerPainter {
|
|
|
68
92
|
}: SpoilerPainterOptions = {}) {
|
|
69
93
|
if (this.destroyed) return
|
|
70
94
|
|
|
71
|
-
|
|
95
|
+
const maxFPS = prefersReducedMotion() ? 0 : fps
|
|
96
|
+
if (maxFPS !== this.maxFPS) {
|
|
97
|
+
this.maxFPS = maxFPS
|
|
98
|
+
if (maxFPS > 0) this.clock?.effect?.updateTiming({ easing: this.easing() })
|
|
99
|
+
else this.stopClock()
|
|
100
|
+
}
|
|
72
101
|
|
|
73
102
|
this.el.style.setProperty('--hn-nz-density', String(density))
|
|
74
103
|
this.el.style.setProperty('--hn-nz-accent', accent)
|
|
75
104
|
|
|
76
105
|
const isBlockElement = getComputedStyle(this.el).getPropertyValue('display') !== 'inline'
|
|
77
106
|
this.useBackgroundStyle('auto', 'auto', false)
|
|
107
|
+
this.el.style.setProperty('--hn-nz-gap', '0px 0px')
|
|
78
108
|
|
|
79
109
|
if (isBlockElement) {
|
|
80
110
|
this.el.style.setProperty('--hn-nz-words', 'false')
|
|
@@ -109,23 +139,21 @@ export class SpoilerPainter {
|
|
|
109
139
|
this.el.style.background = `paint(hn-spoiler) ${repeatAndPosition} / ${w} ${h}`
|
|
110
140
|
}
|
|
111
141
|
|
|
112
|
-
private
|
|
113
|
-
|
|
114
|
-
this.el.style.setProperty('--hn-nz-fade', `${value}s`)
|
|
142
|
+
private easing() {
|
|
143
|
+
return `steps(${Math.round(CLOCK_S * this.maxFPS)})`
|
|
115
144
|
}
|
|
116
145
|
|
|
117
|
-
private
|
|
118
|
-
this.
|
|
119
|
-
this.
|
|
146
|
+
private time() {
|
|
147
|
+
const elapsed = Number(this.clock?.currentTime ?? 0) / 1000
|
|
148
|
+
return this.maxFPS > 0 ? Math.floor(elapsed * this.maxFPS) / this.maxFPS : 0
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private setFade(value: number) {
|
|
152
|
+
this.el.style.setProperty('--hn-nz-fade', `${value}s`)
|
|
120
153
|
}
|
|
121
154
|
|
|
122
155
|
private setTstop(value: number | null) {
|
|
123
|
-
this.
|
|
124
|
-
if (value !== null) {
|
|
125
|
-
this.el.style.setProperty('--hn-nz-stop', value.toFixed(3))
|
|
126
|
-
} else {
|
|
127
|
-
this.el.style.removeProperty('--hn-nz-stop')
|
|
128
|
-
}
|
|
156
|
+
this.el.style.setProperty('--hn-nz-stop', value === null ? 'Infinity' : value.toFixed(3))
|
|
129
157
|
}
|
|
130
158
|
|
|
131
159
|
private parseFade(value: number | boolean | undefined) {
|
|
@@ -133,13 +161,40 @@ export class SpoilerPainter {
|
|
|
133
161
|
return value === true || value === undefined ? DEFAULT_FADE_S : Number(value)
|
|
134
162
|
}
|
|
135
163
|
|
|
164
|
+
private sync() {
|
|
165
|
+
if (!this.clock) return
|
|
166
|
+
if (this.running && this.inView) this.clock.play()
|
|
167
|
+
else this.clock.pause()
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private stopClock() {
|
|
171
|
+
clearTimeout(this.settle)
|
|
172
|
+
this.settle = undefined
|
|
173
|
+
this.clock?.cancel()
|
|
174
|
+
this.clock = null
|
|
175
|
+
this.running = false
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
setInView(value: boolean) {
|
|
179
|
+
if (this.destroyed || value === this.inView) return
|
|
180
|
+
this.inView = value
|
|
181
|
+
this.sync()
|
|
182
|
+
}
|
|
183
|
+
|
|
136
184
|
hide(animate?: number | boolean) {
|
|
137
185
|
if (this.destroyed) return
|
|
138
186
|
this.hidden = true
|
|
139
187
|
this.setFade(this.parseFade(animate))
|
|
140
188
|
this.setTstop(null)
|
|
141
|
-
this.
|
|
142
|
-
this.
|
|
189
|
+
this.stopClock()
|
|
190
|
+
if (this.maxFPS <= 0) return
|
|
191
|
+
this.clock = this.el.animate({ '--hn-nz-t': [0, CLOCK_S] } as PropertyIndexedKeyframes, {
|
|
192
|
+
duration: CLOCK_S * 1000,
|
|
193
|
+
easing: this.easing(),
|
|
194
|
+
iterations: Infinity,
|
|
195
|
+
})
|
|
196
|
+
this.running = true
|
|
197
|
+
this.sync()
|
|
143
198
|
}
|
|
144
199
|
|
|
145
200
|
reveal(animate?: number | boolean) {
|
|
@@ -147,51 +202,23 @@ export class SpoilerPainter {
|
|
|
147
202
|
this.hidden = false
|
|
148
203
|
const duration = this.parseFade(animate)
|
|
149
204
|
this.setFade(duration)
|
|
150
|
-
this.setTstop(this.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const shouldStop = this.tstop !== null && this.t > this.tstop + this.fadeS
|
|
157
|
-
|
|
158
|
-
if (this.maxFPS > 0 && !shouldStop) {
|
|
159
|
-
this.raf = requestAnimationFrame(this.frame)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const dt = now - this.t0
|
|
163
|
-
if (dt > 0 && dt < 1000 / this.maxFPS) return
|
|
164
|
-
|
|
165
|
-
this.setT(this.t + dt / 1000)
|
|
166
|
-
this.t0 = now
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private startAnimation() {
|
|
170
|
-
this.t0 = performance.now()
|
|
171
|
-
this.frame(this.t0)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
private stopAnimation() {
|
|
175
|
-
if (this.raf !== null) {
|
|
176
|
-
cancelAnimationFrame(this.raf)
|
|
177
|
-
this.raf = null
|
|
205
|
+
this.setTstop(this.time())
|
|
206
|
+
clearTimeout(this.settle)
|
|
207
|
+
const stop = () => {
|
|
208
|
+
this.settle = undefined
|
|
209
|
+
this.running = false
|
|
210
|
+
this.sync()
|
|
178
211
|
}
|
|
212
|
+
if (duration <= 0) stop()
|
|
213
|
+
else this.settle = setTimeout(stop, duration * 1000 + 1000 / this.maxFPS)
|
|
179
214
|
}
|
|
180
215
|
|
|
181
216
|
destroy() {
|
|
182
217
|
this.destroyed = true
|
|
183
|
-
this.
|
|
218
|
+
this.stopClock()
|
|
219
|
+
viewport?.unobserve(this.el)
|
|
220
|
+
painters.delete(this.el)
|
|
184
221
|
this.el.style.removeProperty('background')
|
|
185
|
-
for (const prop of
|
|
186
|
-
'--hn-nz-t',
|
|
187
|
-
'--hn-nz-stop',
|
|
188
|
-
'--hn-nz-fade',
|
|
189
|
-
'--hn-nz-gap',
|
|
190
|
-
'--hn-nz-words',
|
|
191
|
-
'--hn-nz-density',
|
|
192
|
-
'--hn-nz-accent',
|
|
193
|
-
]) {
|
|
194
|
-
this.el.style.removeProperty(prop)
|
|
195
|
-
}
|
|
222
|
+
for (const prop of SPOILER_WORKLET_INPUTS) this.el.style.removeProperty(prop)
|
|
196
223
|
}
|
|
197
224
|
}
|
|
@@ -11,10 +11,6 @@ const workletMain = () => {
|
|
|
11
11
|
0x7fffffff
|
|
12
12
|
|
|
13
13
|
const pol2vec = (l: number, a = 0) => [l * M.cos(a), l * M.sin(a)] as const
|
|
14
|
-
const vecmag = ([x, y]: readonly number[]) => M.sqrt(x! * x! + y! * y!)
|
|
15
|
-
const vecnorm = ([x, y]: readonly number[], l = vecmag([x!, y!])) =>
|
|
16
|
-
l === 0 ? ([0, 0] as const) : ([x! / l, y! / l] as const)
|
|
17
|
-
|
|
18
14
|
const trapezoidalWave = (l: number, a: number, b: number) => {
|
|
19
15
|
const s = M.max(a, l - b)
|
|
20
16
|
return (t: number) => {
|
|
@@ -144,20 +140,21 @@ const workletMain = () => {
|
|
|
144
140
|
|
|
145
141
|
ctx.clearRect(0, 0, size.width, size.height)
|
|
146
142
|
|
|
143
|
+
const l = parseInt(accent[2] ?? '0')
|
|
144
|
+
const ldir = l > 50 ? -1 : 1
|
|
145
|
+
const hue = `hsl(${accent[0]} ${accent[1]} `
|
|
146
|
+
|
|
147
147
|
for (let i = 0; i < world.n; ++i) {
|
|
148
148
|
const x0 = hgap + wordDist(rand())
|
|
149
149
|
const y0 = rand(vgap, height - vgap)
|
|
150
150
|
const v0mag = rand(vmin, vmax)
|
|
151
151
|
const size0 = rand(1, 1 + sizedev)
|
|
152
152
|
|
|
153
|
-
const l = parseInt(accent[2] ?? '0')
|
|
154
|
-
const ldir = l > 50 ? -1 : 1
|
|
155
153
|
const lightness = M.floor(clamp(0, l + ldir * rand(0, 30), 100))
|
|
156
154
|
|
|
157
155
|
const v0 = pol2vec(v0mag, rand(0, M.PI * 2))
|
|
158
156
|
const vx0 = v0[0]
|
|
159
157
|
const vy0 = v0[1]
|
|
160
|
-
vecnorm(v0)
|
|
161
158
|
|
|
162
159
|
const shape = rand() > 0.5 ? 'square' : 'circle'
|
|
163
160
|
const lifetime = rand(0.3, 1.5)
|
|
@@ -175,12 +172,13 @@ const workletMain = () => {
|
|
|
175
172
|
const y = y0 + vy0 * t
|
|
176
173
|
|
|
177
174
|
const fade = animateFadeInOut(world, i, fadeDuration)
|
|
178
|
-
const alpha = fade * (1 - t / lifetime)
|
|
175
|
+
const alpha = M.round(fade * (1 - t / lifetime) * 100)
|
|
179
176
|
const psize = fade * (size0 * visibilityFn(t))
|
|
177
|
+
if (alpha <= 0 || psize <= 0) continue
|
|
180
178
|
|
|
179
|
+
ctx.fillStyle = `${hue}${lightness}% / ${alpha}%)`
|
|
181
180
|
for (const [wx, wy] of cycleBounds([x, y], [width, height], psize / 2)) {
|
|
182
181
|
ctx.beginPath()
|
|
183
|
-
ctx.fillStyle = `hsl(${accent[0]} ${accent[1]} ${lightness}% / ${M.round(alpha * 100)}%)`
|
|
184
182
|
if (shape === 'square') {
|
|
185
183
|
ctx.rect(wx!, wy!, psize, psize)
|
|
186
184
|
} else {
|
|
@@ -510,8 +510,14 @@
|
|
|
510
510
|
}
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
+
@layer components {
|
|
514
|
+
.hn-anim-collapse {
|
|
515
|
+
display: flow-root;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
513
519
|
@utility hn-anim-collapse {
|
|
514
|
-
overflow:
|
|
520
|
+
overflow: clip;
|
|
515
521
|
&[data-state='open'] {
|
|
516
522
|
animation: hn-collapse-in var(--hn-duration-base) var(--hn-ease-move);
|
|
517
523
|
}
|
|
@@ -6,10 +6,25 @@
|
|
|
6
6
|
letter-spacing: var(--hn-tracking-tight);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
@layer base {
|
|
10
|
+
:where(
|
|
11
|
+
.text-accent-on,
|
|
12
|
+
.text-neutral-solid-on,
|
|
13
|
+
.text-success-on,
|
|
14
|
+
.text-warning-on,
|
|
15
|
+
.text-danger-on,
|
|
16
|
+
.text-info-on
|
|
17
|
+
) {
|
|
18
|
+
--hn-on-solid-fill: transparent;
|
|
19
|
+
--hn-on-solid-border: color-mix(in oklab, currentColor 40%, transparent);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
@utility hn-code {
|
|
10
24
|
font-family: var(--hn-font-mono);
|
|
11
25
|
font-size: 0.875em;
|
|
12
|
-
background-color: var(--hn-bg-inset);
|
|
26
|
+
background-color: var(--hn-on-solid-fill, var(--hn-bg-inset));
|
|
27
|
+
box-shadow: inset 0 0 0 1px var(--hn-on-solid-border, transparent);
|
|
13
28
|
border-radius: var(--hn-radius-sm);
|
|
14
29
|
padding: 0.125em 0.375em;
|
|
15
30
|
}
|
|
@@ -144,8 +159,8 @@
|
|
|
144
159
|
@utility hn-kbd {
|
|
145
160
|
font-family: var(--hn-font-mono);
|
|
146
161
|
font-size: 0.8125em;
|
|
147
|
-
background-color: var(--hn-surface);
|
|
148
|
-
border: 1px solid var(--hn-border);
|
|
162
|
+
background-color: var(--hn-on-solid-fill, var(--hn-surface));
|
|
163
|
+
border: 1px solid var(--hn-on-solid-border, var(--hn-border));
|
|
149
164
|
border-block-end-width: 2px;
|
|
150
165
|
border-radius: var(--hn-radius-sm);
|
|
151
166
|
padding: 0.0625em 0.375em;
|
|
@@ -7,29 +7,30 @@ export interface SpoilerPainterOptions {
|
|
|
7
7
|
mimicWords?: boolean;
|
|
8
8
|
accent?: string;
|
|
9
9
|
}
|
|
10
|
+
export declare const SPOILER_WORKLET_INPUTS: readonly ["--hn-nz-t", "--hn-nz-stop", "--hn-nz-fade", "--hn-nz-gap", "--hn-nz-accent", "--hn-nz-words", "--hn-nz-density"];
|
|
10
11
|
export declare class SpoilerPainter {
|
|
11
12
|
readonly el: HTMLElement;
|
|
12
13
|
maxFPS: number;
|
|
13
|
-
private
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
private
|
|
17
|
-
private fadeS;
|
|
14
|
+
private clock;
|
|
15
|
+
private settle;
|
|
16
|
+
private running;
|
|
17
|
+
private inView;
|
|
18
18
|
private hidden;
|
|
19
19
|
private destroyed;
|
|
20
20
|
constructor(el: HTMLElement, options?: SpoilerPainterOptions);
|
|
21
21
|
get isHidden(): boolean;
|
|
22
22
|
update({ fps, gap, density, mimicWords, accent, }?: SpoilerPainterOptions): void;
|
|
23
23
|
private useBackgroundStyle;
|
|
24
|
+
private easing;
|
|
25
|
+
private time;
|
|
24
26
|
private setFade;
|
|
25
|
-
private setT;
|
|
26
27
|
private setTstop;
|
|
27
28
|
private parseFade;
|
|
29
|
+
private sync;
|
|
30
|
+
private stopClock;
|
|
31
|
+
setInView(value: boolean): void;
|
|
28
32
|
hide(animate?: number | boolean): void;
|
|
29
33
|
reveal(animate?: number | boolean): void;
|
|
30
|
-
private frame;
|
|
31
|
-
private startAnimation;
|
|
32
|
-
private stopAnimation;
|
|
33
34
|
destroy(): void;
|
|
34
35
|
}
|
|
35
36
|
//# sourceMappingURL=painter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"painter.d.ts","sourceRoot":"","sources":["../../../../../../../shared/src/behavior/spoiler/painter.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,uBAAuB,SAC0D,CAAA;AAI9F,wBAAgB,sBAAsB,SAQrC;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;
|
|
1
|
+
{"version":3,"file":"painter.d.ts","sourceRoot":"","sources":["../../../../../../../shared/src/behavior/spoiler/painter.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,uBAAuB,SAC0D,CAAA;AAI9F,wBAAgB,sBAAsB,SAQrC;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAUD,eAAO,MAAM,sBAAsB,6HAQzB,CAAA;AAkBV,qBAAa,cAAc;IACzB,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,MAAM,CAAe;IAE7B,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,MAAM,CAA2C;IACzD,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,SAAS,CAAQ;gBAEb,EAAE,EAAE,WAAW,EAAE,OAAO,GAAE,qBAA0B;IAUhE,IAAI,QAAQ,YAEX;IAED,MAAM,CAAC,EACL,GAAkB,EAClB,GAAkB,EAClB,OAA0B,EAC1B,UAAgC,EAChC,MAAwB,GACzB,GAAE,qBAA0B;IA2C7B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,SAAS;IAQjB,SAAS,CAAC,KAAK,EAAE,OAAO;IAMxB,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IAgB/B,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IAgBjC,OAAO;CAQR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worklet.d.ts","sourceRoot":"","sources":["../../../../../../../shared/src/behavior/spoiler/worklet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"worklet.d.ts","sourceRoot":"","sources":["../../../../../../../shared/src/behavior/spoiler/worklet.ts"],"names":[],"mappings":"AAoMA,eAAO,MAAM,aAAa,QAAkC,CAAA"}
|