@splendidlabz/styles 4.8.2 → 4.10.1

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.8.2",
3
+ "version": "4.10.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "homepage": "https://splendidlabz.com/docs/styles",
@@ -14,7 +14,7 @@
14
14
  ".": "./src/styles.css",
15
15
  "./components": "./src/components/index.css",
16
16
  "./layouts": "./src/layouts/direct.css",
17
- "./layouts/no-tw": "./dist/no-tw/styles.css",
17
+ "./pigment": "./src/tools/pigment.css",
18
18
  "./scripts": "./scripts/index.js",
19
19
  "./scripts/*": "./scripts/*.js"
20
20
  },
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
+ }
@@ -1,86 +1,78 @@
1
1
  @utility prose {
2
- & {
3
- display: flex;
4
- flex-flow: column;
5
- gap: 1lh;
6
- hanging-punctuation: first allow-end last;
7
-
8
- /* Using padding instead of margin, so #targets will leave some whitespace above when scrolling to the component. */
9
- > * + :where(h2),
10
- > * + :where(astro-island, astro-slot) > :where(h2):first-child {
11
- margin-top: calc(var(--spacing) * 6);
12
- scroll-margin-block: calc(var(--spacing) * 6);
13
- }
14
-
15
- > * + :where(h3),
16
- > * + :where(astro-island, astro-slot) > :where(h3):first-child {
17
- margin-top: calc(var(--spacing) * 4);
18
- margin-bottom: calc(var(--spacing) * -2);
19
- scroll-margin-block: calc(var(--spacing) * 4);
20
- }
21
-
22
- > * + :where(h4, h5, h6),
23
- > * + :where(astro-island, astro-slot) > :where(h4, h5, h6):first-child {
24
- margin-top: calc(var(--spacing) * 4);
25
- margin-bottom: calc(var(--spacing) * -4);
26
- scroll-margin-block: calc(var(--spacing) * 4);
27
- }
28
-
29
- :where(ul) {
30
- list-style-type: initial;
31
- }
32
-
33
- /* Basic list styles */
34
- :where(ul, ol),
35
- > :where(astro-island, astro-slot) :where(ul, ol) {
36
- list-style-position: outside;
37
- margin-left: 2em;
2
+ display: flex;
3
+ flex-flow: column;
4
+ gap: 1lh;
5
+ hanging-punctuation: first allow-end last;
6
+
7
+ /* Using padding instead of margin, so #targets will leave some whitespace above when scrolling to the component. */
8
+ > * + :where(h2),
9
+ > * + :where(astro-island, astro-slot) > :where(h2):first-child {
10
+ margin-top: calc(var(--spacing) * 6);
11
+ scroll-margin-block: calc(var(--spacing) * 6);
12
+ }
38
13
 
39
- :where(ul, ol) {
40
- margin-left: 0;
41
- padding-left: 2em;
42
- }
14
+ > * + :where(h3),
15
+ > * + :where(astro-island, astro-slot) > :where(h3):first-child {
16
+ margin-top: calc(var(--spacing) * 4);
17
+ scroll-margin-block: calc(var(--spacing) * 4);
18
+ }
43
19
 
44
- li {
45
- font-variant-numeric: lining-nums;
46
- }
20
+ > * + :where(h4, h5, h6),
21
+ > * + :where(astro-island, astro-slot) > :where(h4, h5, h6):first-child {
22
+ margin-top: calc(var(--spacing) * 2);
23
+ scroll-margin-block: calc(var(--spacing) * 2);
24
+ }
47
25
 
48
- li + li {
49
- margin-top: calc(var(--spacing));
50
- }
26
+ :where(ul) {
27
+ list-style-type: initial;
28
+ }
51
29
 
52
- li:has(li) + li {
53
- margin-top: calc(var(--spacing) * 2);
54
- }
30
+ /* Basic list styles */
31
+ :where(ul, ol),
32
+ > :where(astro-island, astro-slot) :where(ul, ol) {
33
+ list-style-position: outside;
34
+ margin-left: 2em;
55
35
 
56
- li > :where(ul, ol) {
57
- margin-top: calc(var(--spacing));
58
- }
36
+ :where(ul, ol) {
37
+ margin-left: 0;
38
+ padding-left: 1em;
59
39
  }
60
40
 
61
- :where(a) {
62
- text-decoration-line: underline;
41
+ li {
42
+ font-variant-numeric: lining-nums;
63
43
  }
64
44
 
65
- :where(> img),
66
- :where(> figure img) {
67
- border: 1px solid oklch(90% 0 0deg);
68
- border-radius: var(--radius);
45
+ li + li {
46
+ margin-top: calc(var(--spacing));
69
47
  }
70
48
 
71
- :where(> figure) {
72
- inline-size: fit-content;
73
- margin-inline: auto;
49
+ li > :where(ul, ol) {
50
+ margin-top: calc(var(--spacing));
74
51
  }
52
+ }
75
53
 
76
- :where(> figure figcaption) {
77
- contain: inline-size;
78
- }
54
+ :where(a) {
55
+ text-decoration-line: underline;
56
+ }
79
57
 
80
- :where(.fancylist) {
81
- margin-left: 1em;
82
- padding-left: 0;
83
- }
58
+ :where(> img),
59
+ :where(> figure img) {
60
+ border: 1px solid oklch(90% 0 0deg);
61
+ border-radius: var(--radius);
62
+ }
63
+
64
+ :where(> figure) {
65
+ inline-size: fit-content;
66
+ margin-inline: auto;
67
+ }
68
+
69
+ :where(> figure figcaption) {
70
+ contain: inline-size;
71
+ }
72
+
73
+ :where(.fancylist) {
74
+ margin-left: 1em;
75
+ padding-left: 0;
84
76
  }
85
77
  }
86
78
 
@@ -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%;