@splendidlabz/styles 4.9.0 → 4.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splendidlabz/styles",
3
- "version": "4.9.0",
3
+ "version": "4.11.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "homepage": "https://splendidlabz.com/docs/styles",
package/scripts/all.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { masonry, scrollableHorizontal, sticky } from './index.js'
2
+ import { start as spotlight } from './spotlight.js'
2
3
 
3
4
  const defaultOptions = {
4
5
  masonry: true,
5
6
  sticky: true,
6
7
  scrollable: true,
8
+ spotlight: true,
7
9
  }
8
10
 
9
11
  export function all(options = {}) {
@@ -11,4 +13,5 @@ export function all(options = {}) {
11
13
  if (options.masonry) masonry(options.element)
12
14
  if (options.sticky) sticky(options.element)
13
15
  if (options.scrollable) scrollableHorizontal(options.element)
16
+ if (options.spotlight) spotlight()
14
17
  }
package/scripts/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './masonry.js'
2
2
  export * from './scrollable.js'
3
3
  export * from './sticky.js'
4
+ export * from './spotlight.js'
@@ -0,0 +1,93 @@
1
+ /* eslint-env browser */
2
+ /*
3
+ * Spotlight tracker — vanilla cursor-position writer for `.spotlight` cards.
4
+ *
5
+ * Pairs with the `bezel` + `.spotlight` utilities in this package.
6
+ * Lives alongside the styles it powers so the script + CSS ship together.
7
+ *
8
+ * Behavior:
9
+ * • One global `pointermove` listener on `window`.
10
+ * • Discovery via live `HTMLCollection` — DOM updates membership for free.
11
+ * • Rects cached in a `WeakMap` so departed nodes GC.
12
+ * • rAF-coalesced writes: `--x`, `--y` (px, padding-box-origin) and `--dist` (px).
13
+ * • No proximity math in JS — CSS owns falloff via
14
+ * `max(0, 1 - --dist / max(--inner-size, --outer-size))`.
15
+ * • On `mouseleave` from document.body, all cards' `--dist` is reset to a large
16
+ * value so proximities collapse to 0.
17
+ *
18
+ * Call `start()` to begin tracking; `stop()` to tear down. Both are idempotent
19
+ * and SSR-safe.
20
+ *
21
+ * Spec: 2026-05-10-fancybox-spotlight.md
22
+ */
23
+
24
+ // SSR guard — module must be import-safe in non-browser contexts.
25
+ const isBrowser =
26
+ typeof window !== 'undefined' && typeof document !== 'undefined'
27
+
28
+ let cards
29
+ let rects
30
+ let pending = false
31
+ let started = false
32
+ let mx = 0
33
+ let my = 0
34
+
35
+ function rectOf(card) {
36
+ let r = rects.get(card)
37
+ if (!r) {
38
+ r = card.getBoundingClientRect()
39
+ rects.set(card, r)
40
+ }
41
+ return r
42
+ }
43
+
44
+ function recache() {
45
+ for (const c of cards) rects.set(c, c.getBoundingClientRect())
46
+ }
47
+
48
+ function update() {
49
+ pending = false
50
+ for (const card of cards) {
51
+ const r = rectOf(card)
52
+ const dx = Math.max(r.left - mx, 0, mx - r.right)
53
+ const dy = Math.max(r.top - my, 0, my - r.bottom)
54
+ const dist = Math.hypot(dx, dy)
55
+
56
+ card.style.setProperty('--x', `${mx - r.left}px`)
57
+ card.style.setProperty('--y', `${my - r.top}px`)
58
+ card.style.setProperty('--dist', `${dist}px`)
59
+ }
60
+ }
61
+
62
+ function onMove(e) {
63
+ mx = e.clientX
64
+ my = e.clientY
65
+ if (pending) return
66
+ pending = true
67
+ requestAnimationFrame(update)
68
+ }
69
+
70
+ function onLeave() {
71
+ for (const c of cards) c.style.setProperty('--dist', '9999px')
72
+ }
73
+
74
+ export function start() {
75
+ if (!isBrowser || started) return
76
+ started = true
77
+ cards = document.getElementsByClassName('spotlight') // live HTMLCollection
78
+ rects = new WeakMap()
79
+
80
+ window.addEventListener('pointermove', onMove)
81
+ window.addEventListener('resize', recache)
82
+ window.addEventListener('scroll', recache, { passive: true })
83
+ document.body.addEventListener('mouseleave', onLeave)
84
+ }
85
+
86
+ export function stop() {
87
+ if (!isBrowser || !started) return
88
+ started = false
89
+ window.removeEventListener('pointermove', onMove)
90
+ window.removeEventListener('resize', recache)
91
+ window.removeEventListener('scroll', recache)
92
+ document.body.removeEventListener('mouseleave', onLeave)
93
+ }
@@ -15,21 +15,18 @@
15
15
  *********************/
16
16
  /* prettier-ignore */
17
17
  @utility spl-stroke-* {
18
- & {
19
- --stroke-width: --value([length]);
20
- --stroke-color: --value(--color-*, [color]);
21
- --stroke-color: oklch(from --value(--color-*, [color]) l c h / --modifier(integer)%);
22
- }
18
+ --stroke-width: --spacing(--value(number));
19
+ --stroke-width: --value([length]);
20
+ --stroke-color: --value(--color-*, [color]);
21
+ --stroke-color: oklch(
22
+ from --value(--color-*, [color]) l c h / --modifier(number)%
23
+ );
23
24
  }
24
25
 
25
- /*********************
26
- * Fill *
27
- * Allows spl-fill-<color>/<modifier> to create --fill-color
28
- *********************/
29
26
  /* prettier-ignore */
30
27
  @utility spl-fill-* {
31
- & {
32
- --fill-color: --value(--color-*, [color]);
33
- --fill-color: oklch(from --value(--color-*, [color]) l c h / --modifier(integer)%);
34
- }
28
+ --fill-color: --value(--color-*, [color]);
29
+ --fill-color: oklch(
30
+ from --value(--color-*, [color]) l c h / --modifier(number)%
31
+ );
35
32
  }
@@ -1,3 +1,5 @@
1
+ /* stylelint-disable declaration-block-no-duplicate-custom-properties */
2
+
1
3
  @utility strikethrough {
2
4
  position: relative;
3
5
  display: inline-block;
@@ -15,3 +17,26 @@
15
17
  transform-origin: center;
16
18
  }
17
19
  }
20
+
21
+ /* prettier-ignore */
22
+ @utility strike-angle-* {
23
+ --strike-angle: --value(number)deg;
24
+ }
25
+
26
+ /* prettier-ignore */
27
+ @utility -strike-angle-* {
28
+ --strike-angle: calc(--value(number) * -1deg);
29
+ }
30
+
31
+ /* prettier-ignore */
32
+ @utility strike-* {
33
+ /* strike-width */
34
+ --strike-width: --spacing(--value(number));
35
+ --strike-width: --value([length]);
36
+
37
+ /* strike-color */
38
+ --strike-color: --value(--color-*, [color]);
39
+ --strike-color: oklch(
40
+ from --value(--color-*, [color]) l c h / --modifier(integer)%
41
+ );
42
+ }
@@ -1,41 +1,37 @@
1
1
  @utility writing-normal {
2
+ transition: none;
2
3
  writing-mode: horizontal-tb;
3
4
  }
4
5
 
5
6
  @utility writing-rotate-left {
6
- & {
7
- writing-mode: vertical-rl;
8
- text-orientation: sideways;
7
+ transform: rotate(180deg);
8
+ transition: none;
9
+ writing-mode: vertical-rl;
10
+ }
9
11
 
10
- /* transform: rotate(180deg); */
11
- /* transform: scale(-1, -1); */
12
+ @utility writing-rotate-right {
13
+ transition: none;
14
+ writing-mode: vertical-lr;
15
+ }
12
16
 
13
- /* // This is the alternative if we don't want to use rotate */
14
- }
17
+ @utility writing-rotateleft {
18
+ @apply writing-rotate-left;
15
19
  }
16
20
 
17
- @utility writing-rotate-right {
18
- & {
19
- writing-mode: vertical-rl;
20
- text-orientation: sideways;
21
- }
21
+ @utility writing-rotateright {
22
+ @apply writing-rotate-right;
22
23
  }
23
24
 
24
25
  @utility writing-downwards {
25
- & {
26
- writing-mode: vertical-lr;
27
- text-orientation: upright;
28
- }
26
+ writing-mode: vertical-lr;
27
+ text-orientation: upright;
29
28
  }
30
29
 
31
- /* Alias for writing-downwards */
32
- @utility writing-downards-lr {
30
+ @utility writing-downwards-lr {
33
31
  @apply writing-downwards;
34
32
  }
35
33
 
36
34
  @utility writing-downwards-rl {
37
- & {
38
- writing-mode: vertical-rl;
39
- text-orientation: upright;
40
- }
35
+ writing-mode: vertical-rl;
36
+ text-orientation: upright;
41
37
  }
@@ -60,6 +60,10 @@ dot-3-color */
60
60
  border-radius: 0 0 var(--radius) var(--radius);
61
61
  background: var(--bg-frame-content);
62
62
 
63
+ > :where(*) {
64
+ border-radius: inherit;
65
+ }
66
+
63
67
  > :where(.background) svg {
64
68
  width: 100%;
65
69
  height: 100%;
@@ -0,0 +1,334 @@
1
+ @utility bezel {
2
+ @apply border-scaffold;
3
+ --x: 50%;
4
+ --y: 50%;
5
+ --dist: 0px;
6
+ --b: var(--border-width);
7
+ --r: var(--radius);
8
+ position: relative;
9
+ border-color: transparent;
10
+ background:
11
+ var(--inner-gradient, none),
12
+ linear-gradient(var(--bg-color, transparent), var(--bg-color, transparent)),
13
+ var(--outer-gradient, none);
14
+ background-origin: padding-box, padding-box, border-box;
15
+ background-clip: padding-box, padding-box, border-box;
16
+ }
17
+
18
+ /*********************
19
+ * Inner & Outer gradients *
20
+ *********************/
21
+ @utility inner-radial {
22
+ --_shape: var(--inner-shape, var(--gradient-shape));
23
+ --_size: var(--inner-size, var(--gradient-size));
24
+ --_position: var(--inner-position, var(--gradient-position));
25
+ --inner-gradient: radial-gradient(
26
+ var(--_shape) var(--_size) at var(--_position) in var(--color-space)
27
+ var(--hue-interpolation),
28
+ var(--inner-stops)
29
+ );
30
+ }
31
+
32
+ @utility outer-radial {
33
+ --_shape: var(--outer-shape, var(--gradient-shape));
34
+ --_size: var(--outer-size, var(--gradient-size));
35
+ --_position: var(--outer-position, var(--gradient-position));
36
+ --outer-gradient: radial-gradient(
37
+ var(--_shape) var(--_size) at var(--_position) in var(--color-space)
38
+ var(--hue-interpolation),
39
+ var(--outer-stops)
40
+ );
41
+ }
42
+
43
+ @utility inner-linear {
44
+ --_angle: var(--inner-angle, var(--gradient-angle));
45
+ --inner-gradient: linear-gradient(
46
+ var(--_angle) in var(--color-space) var(--hue-interpolation),
47
+ var(--inner-stops)
48
+ );
49
+ }
50
+
51
+ @utility outer-linear {
52
+ --_angle: var(--outer-angle, var(--gradient-angle));
53
+ --outer-gradient: linear-gradient(
54
+ var(--_angle) in var(--color-space) var(--hue-interpolation),
55
+ var(--outer-stops)
56
+ );
57
+ }
58
+
59
+ @utility inner-conic {
60
+ --_angle: var(--inner-angle, var(--gradient-angle));
61
+ --_position: var(--inner-position, var(--gradient-position));
62
+ --inner-gradient: conic-gradient(
63
+ from var(--_angle) at var(--_position) in var(--color-space)
64
+ var(--hue-interpolation),
65
+ var(--inner-stops)
66
+ );
67
+ }
68
+
69
+ @utility outer-conic {
70
+ --_angle: var(--outer-angle, var(--gradient-angle));
71
+ --_position: var(--outer-position, var(--gradient-position));
72
+ --outer-gradient: conic-gradient(
73
+ from var(--_angle) at var(--_position) in var(--color-space)
74
+ var(--hue-interpolation),
75
+ var(--outer-stops)
76
+ );
77
+ }
78
+
79
+ /*********************
80
+ * Spotlight *
81
+ *********************/
82
+ @utility spotlight {
83
+ --proximity: max(
84
+ 0,
85
+ 1 - var(--dist, 9999px) /
86
+ max(var(--inner-size, 0px), var(--outer-size, 200px))
87
+ );
88
+ }
89
+
90
+ /*********************
91
+ * Bezel frost *
92
+ * Frosted variant. Ring lives on ::before so the element itself can carry backdrop-filter with no opaque layers in the way.
93
+ *********************/
94
+ /* stylelint-disable nesting-selector-no-missing-scoping-root */
95
+ @utility bezel-frost {
96
+ @apply border-scaffold;
97
+ --b: var(--border-width);
98
+ --r: var(--radius);
99
+ --frost: 16px;
100
+ position: relative;
101
+ border-color: transparent;
102
+ backdrop-filter: blur(var(--frost));
103
+
104
+ &::before {
105
+ content: '';
106
+ pointer-events: none;
107
+ position: absolute;
108
+ inset: calc(-1 * var(--b));
109
+ padding: var(--b);
110
+ border-radius: inherit;
111
+ background: var(--outer-gradient, none);
112
+ mask:
113
+ linear-gradient(#000 0 0) content-box,
114
+ linear-gradient(#000 0 0);
115
+ mask-composite: exclude;
116
+ }
117
+ }
118
+
119
+ /*********************
120
+ * Bezel Arrow *
121
+ * Creates arrows with bezel-arrow-* where * is top|bottom|left|right .
122
+ * Uses both before and pseudo elements.
123
+ *********************/
124
+ @utility bezel-arrow {
125
+ @apply bezel;
126
+ --a: var(--arrow-angle, 90deg);
127
+ --h: var(--arrow-height, 0.75em);
128
+ --p: var(--arrow-position, 50%);
129
+ overflow: visible;
130
+ z-index: 0;
131
+
132
+ &::before,
133
+ &::after {
134
+ content: '';
135
+ position: absolute;
136
+ inset: calc(-1 * var(--b));
137
+ z-index: -1;
138
+ background: inherit;
139
+ }
140
+
141
+ /* Per-layer sizes match the three-layer stack: inner, bg-color, outer.
142
+ * ::before = outer-only (the rim slice over the arrow tail).
143
+ * ::after = card-interior slice (inner + bg-color, no outer). */
144
+ &::before {
145
+ background-size:
146
+ 0 0,
147
+ 0 0,
148
+ 100% 100%;
149
+ }
150
+
151
+ &::after {
152
+ border: inherit;
153
+ background-size:
154
+ 100% 100%,
155
+ 100% 100%,
156
+ 0 0;
157
+ }
158
+ }
159
+
160
+ @utility bezel-arrow-top {
161
+ @apply bezel-arrow;
162
+ border-radius: min(var(--r), var(--p) - var(--h) * tan(var(--a) / 2))
163
+ min(var(--r), 100% - var(--p) - var(--h) * tan(var(--a) / 2)) var(--r)
164
+ var(--r) / var(--r);
165
+ background-position: bottom;
166
+ background-size: 100% calc(100% + var(--h));
167
+
168
+ &::before,
169
+ &::after {
170
+ top: calc(-1 * var(--b) - var(--h));
171
+ }
172
+
173
+ &::before {
174
+ clip-path: polygon(
175
+ min(100%, var(--p) + var(--h) * tan(var(--a) / 2))
176
+ calc(var(--h) + var(--b)),
177
+ min(100%, var(--p) + var(--h) * tan(var(--a) / 2)) var(--h),
178
+ var(--p) 0,
179
+ max(0%, var(--p) - var(--h) * tan(var(--a) / 2)) var(--h),
180
+ max(0%, var(--p) - var(--h) * tan(var(--a) / 2)) calc(var(--h) + var(--b))
181
+ );
182
+ }
183
+
184
+ &::after {
185
+ clip-path: polygon(
186
+ min(
187
+ 100% - var(--b),
188
+ var(--p) + var(--h) * tan(var(--a) / 2) - var(--b) *
189
+ tan(45deg - var(--a) / 4)
190
+ )
191
+ calc(var(--h) + var(--b)),
192
+ var(--p) calc(var(--b) / sin(var(--a) / 2)),
193
+ max(
194
+ var(--b),
195
+ var(--p) - var(--h) * tan(var(--a) / 2) + var(--b) *
196
+ tan(45deg - var(--a) / 4)
197
+ )
198
+ calc(var(--h) + var(--b)),
199
+ 50% 50%
200
+ );
201
+ }
202
+ }
203
+
204
+ @utility bezel-arrow-bottom {
205
+ @apply bezel-arrow;
206
+ border-radius: var(--r) var(--r)
207
+ min(var(--r), 100% - var(--p) - var(--h) * tan(var(--a) / 2))
208
+ min(var(--r), var(--p) - var(--h) * tan(var(--a) / 2)) / var(--r);
209
+ background-size: 100% calc(100% + var(--h));
210
+
211
+ &::before,
212
+ &::after {
213
+ bottom: calc(-1 * var(--b) - var(--h));
214
+ }
215
+
216
+ &::before {
217
+ clip-path: polygon(
218
+ min(100%, var(--p) + var(--h) * tan(var(--a) / 2))
219
+ calc(100% - var(--h) - var(--b)),
220
+ min(100%, var(--p) + var(--h) * tan(var(--a) / 2)) calc(100% - var(--h)),
221
+ var(--p) 100%,
222
+ max(0%, var(--p) - var(--h) * tan(var(--a) / 2)) calc(100% - var(--h)),
223
+ max(0%, var(--p) - var(--h) * tan(var(--a) / 2))
224
+ calc(100% - var(--h) - var(--b))
225
+ );
226
+ }
227
+
228
+ &::after {
229
+ clip-path: polygon(
230
+ min(
231
+ 100% - var(--b),
232
+ var(--p) + var(--h) * tan(var(--a) / 2) - var(--b) *
233
+ tan(45deg - var(--a) / 4)
234
+ )
235
+ calc(100% - var(--h) - var(--b)),
236
+ var(--p) calc(100% - var(--b) / sin(var(--a) / 2)),
237
+ max(
238
+ var(--b),
239
+ var(--p) - var(--h) * tan(var(--a) / 2) + var(--b) *
240
+ tan(45deg - var(--a) / 4)
241
+ )
242
+ calc(100% - var(--h) - var(--b)),
243
+ 50% 50%
244
+ );
245
+ }
246
+ }
247
+
248
+ @utility bezel-arrow-left {
249
+ @apply bezel-arrow;
250
+ border-radius: var(--r) /
251
+ min(var(--r), var(--p) - var(--h) * tan(var(--a) / 2)) var(--r) var(--r)
252
+ min(var(--r), 100% - var(--p) - var(--h) * tan(var(--a) / 2));
253
+ background-position: right;
254
+ background-size: calc(100% + var(--h)) 100%;
255
+
256
+ &::before,
257
+ &::after {
258
+ left: calc(-1 * var(--b) - var(--h));
259
+ }
260
+
261
+ &::before {
262
+ clip-path: polygon(
263
+ calc(var(--h) + var(--b))
264
+ min(100%, var(--p) + var(--h) * tan(var(--a) / 2)),
265
+ var(--h) min(100%, var(--p) + var(--h) * tan(var(--a) / 2)),
266
+ 0 var(--p),
267
+ var(--h) max(0%, var(--p) - var(--h) * tan(var(--a) / 2)),
268
+ calc(var(--h) + var(--b)) max(0%, var(--p) - var(--h) * tan(var(--a) / 2))
269
+ );
270
+ }
271
+
272
+ &::after {
273
+ clip-path: polygon(
274
+ calc(var(--h) + var(--b))
275
+ min(
276
+ 100% - var(--b),
277
+ var(--p) + var(--h) * tan(var(--a) / 2) - var(--b) *
278
+ tan(45deg - var(--a) / 4)
279
+ ),
280
+ calc(var(--b) / sin(var(--a) / 2)) var(--p),
281
+ calc(var(--h) + var(--b))
282
+ max(
283
+ var(--b),
284
+ var(--p) - var(--h) * tan(var(--a) / 2) + var(--b) *
285
+ tan(45deg - var(--a) / 4)
286
+ ),
287
+ 50% 50%
288
+ );
289
+ }
290
+ }
291
+
292
+ @utility bezel-arrow-right {
293
+ @apply bezel-arrow;
294
+ border-radius: var(--r) / var(--r)
295
+ min(var(--r), var(--p) - var(--h) * tan(var(--a) / 2))
296
+ min(var(--r), 100% - var(--p) - var(--h) * tan(var(--a) / 2)) var(--r);
297
+ background-size: calc(100% + var(--h)) 100%;
298
+
299
+ &::before,
300
+ &::after {
301
+ right: calc(-1 * var(--b) - var(--h));
302
+ }
303
+
304
+ &::before {
305
+ clip-path: polygon(
306
+ calc(100% - var(--h) - var(--b))
307
+ min(100%, var(--p) + var(--h) * tan(var(--a) / 2)),
308
+ calc(100% - var(--h)) min(100%, var(--p) + var(--h) * tan(var(--a) / 2)),
309
+ 100% var(--p),
310
+ calc(100% - var(--h)) max(0%, var(--p) - var(--h) * tan(var(--a) / 2)),
311
+ calc(100% - var(--h) - var(--b))
312
+ max(0%, var(--p) - var(--h) * tan(var(--a) / 2))
313
+ );
314
+ }
315
+
316
+ &::after {
317
+ clip-path: polygon(
318
+ calc(100% - var(--h) - var(--b))
319
+ min(
320
+ 100% - var(--b),
321
+ var(--p) + var(--h) * tan(var(--a) / 2) - var(--b) *
322
+ tan(45deg - var(--a) / 4)
323
+ ),
324
+ calc(100% - var(--b) / sin(var(--a) / 2)) var(--p),
325
+ calc(100% - var(--h) - var(--b))
326
+ max(
327
+ var(--b),
328
+ var(--p) - var(--h) * tan(var(--a) / 2) + var(--b) *
329
+ tan(45deg - var(--a) / 4)
330
+ ),
331
+ 50% 50%
332
+ );
333
+ }
334
+ }
@@ -1,7 +1,4 @@
1
1
  :root {
2
- --color-space: oklch;
3
- --hue-interpolation: shorter hue;
4
-
5
2
  /* --inner-gradient: linear-gradient(var(--gradient-angle), #563444, #4ecdc4); */
6
3
  /* --bg-color: transparent;
7
4
  --outer-gradient: linear-gradient(