@zevra/ui 0.10.0 → 0.12.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/src/motion.js ADDED
@@ -0,0 +1,53 @@
1
+ /* Zevra UI — motion.js : la révélation unique des entrées.
2
+ *
3
+ * Rôle exact, et rien d'autre :
4
+ * 1. poser `zv-motion` sur <html> — c'est cette classe qui ARME les
5
+ * entrées de motion.css (sans elle, la page s'affiche complète) ;
6
+ * 2. poser `zv-in`, UNE fois, sur chaque élément d'entrée quand il
7
+ * touche le viewport — l'animation se joue, s'arrête sur l'état
8
+ * final, et on n'observe plus l'élément : remonter ne défait rien.
9
+ *
10
+ * Un échafaudage de scènes scroll-pilotées (l'expérience épinglée d'une
11
+ * home) pose `data-zv-motion-skip` sur ses scènes : rien n'y est observé,
12
+ * ses timelines nommées gardent la main.
13
+ *
14
+ * S'importe une fois par page : `import '@zevra/ui/motion.js'`. Pour un
15
+ * armement avant première peinture (aucun éclair du contenu), l'app peut
16
+ * AUSSI poser la classe en inline dans <head> :
17
+ * <script>document.documentElement.classList.add('zv-motion')</script>
18
+ * motion.js est idempotent par-dessus.
19
+ */
20
+ (() => {
21
+ if (typeof document === 'undefined' || typeof IntersectionObserver === 'undefined') return;
22
+ if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
23
+
24
+ document.documentElement.classList.add('zv-motion');
25
+
26
+ const ENTREES = '.zv-anim-rise, .zv-anim-glyph-in, .zv-anim-converge, .zv-anim-pop, .zv-anim-filet';
27
+
28
+ const armer = () => {
29
+ const io = new IntersectionObserver(
30
+ (entries) => {
31
+ for (const e of entries) {
32
+ if (!e.isIntersecting) continue;
33
+ e.target.classList.add('zv-in');
34
+ io.unobserve(e.target);
35
+ }
36
+ },
37
+ /* Déclenche un peu AVANT que l'élément soit franchement visible :
38
+ * l'entrée accompagne l'arrivée au lieu de la suivre. */
39
+ { rootMargin: '0px 0px -8% 0px', threshold: 0.01 }
40
+ );
41
+
42
+ for (const el of document.querySelectorAll(ENTREES)) {
43
+ if (el.closest('[data-zv-motion-skip]')) continue;
44
+ io.observe(el);
45
+ }
46
+ };
47
+
48
+ if (document.readyState === 'loading') {
49
+ document.addEventListener('DOMContentLoaded', armer, { once: true });
50
+ } else {
51
+ armer();
52
+ }
53
+ })();
package/src/surfaces.css CHANGED
@@ -138,6 +138,15 @@
138
138
  z-index: 1;
139
139
  }
140
140
 
141
+ /* L'emphase de base.css pose --ink sur les strong de zv-body/zv-lead — sur
142
+ * le navy du manifeste, cette encre disparaît dans le fond. Dans la bande,
143
+ * l'emphase hérite de la couleur ambiante (blanc), et seule la graisse la
144
+ * distingue. */
145
+ .zv-band .zv-body strong,
146
+ .zv-band .zv-lead strong {
147
+ color: inherit;
148
+ }
149
+
141
150
  /* Filigrane : le glyphe, blanchi et presque effacé, débordant du cadre. */
142
151
  .zv-band__watermark {
143
152
  position: absolute;