@threadlabs/looma 0.38.0 → 0.39.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.
@@ -25,6 +25,8 @@ const markdown = stringify(ast);
25
25
  const restoredEditorJson = expressmarkToEditorDocument(parse(markdown));
26
26
  ```
27
27
 
28
+ Editor Markdown import and export explicitly select Expressmark’s `compatible` syntax (CommonMark/GFM with expressive extensions), preserving the existing interchange format as Expressmark’s defaults evolve. Pass `syntax` in conversion options when selecting another supported reading; content outside the editor schema still raises a conversion error.
29
+
28
30
  The editor continues to save Tiptap JSON. Expressive Markdown is an interchange
29
31
  format; it does not replace your saved document, history or application metadata.
30
32
  See the [proposal and syntax](https://nextwebwg.org/expressive-markdown/) and
package/README.md CHANGED
@@ -67,7 +67,7 @@ The package includes the documentation generator and theme customizer used by Lo
67
67
  Install the optional documentation tools, then initialize your project:
68
68
 
69
69
  ```sh
70
- pnpm add -D markupress @nextwebwg/htmlkit@1.0.0-alpha.69 vite
70
+ pnpm add -D markupress @threadlabs/markupkit@0.2.0 vite
71
71
  pnpm exec looma-docs init
72
72
  pnpm exec looma-docs dev
73
73
  ```
@@ -1,4 +1,4 @@
1
- <template component="ui-skeleton">
1
+ <template component="ui-skeleton" module="./ui-skeleton.js">
2
2
  <defs>
3
3
  <prop name="shape" type="keyword" values="text, circle, rectangle" default="text"
4
4
  >The content's silhouette. text reserves one inherited line box with a shorter bar inside it; circle matches a medium Avatar; rectangle reserves a media
@@ -8,8 +8,12 @@
8
8
  Avatar's outer size for circles.</prop>
9
9
  <prop name="height" type="string" default=""
10
10
  >Block size as a CSS length. Empty reserves one line for text, a square for circles, or 8rem for rectangles. Set only width to keep a circle square.</prop>
11
- <prop name="animated" type="boolean" default="false"
12
- >Gently pulses the placeholder. Off by default, and always still when the reader requests reduced motion.</prop>
11
+ <prop
12
+ name="animated"
13
+ type="boolean"
14
+ default="true"
15
+ default-true-reason="A travelling highlight identifies pending content by default; reduced-motion preferences always keep it static."
16
+ >Moves a subtle highlight from left to right. On by default; pass false to keep it static. Reduced-motion preferences always disable the shimmer.</prop>
13
17
  </defs>
14
18
  <span aria-hidden="true" style:--ui-skeleton-width="$width" style:--ui-skeleton-height="$height"></span>
15
19
  <style>
@@ -22,8 +26,20 @@
22
26
  syntax: "*";
23
27
  inherits: false;
24
28
  }
29
+ @property --_ui-skeleton-viewport-x {
30
+ syntax: "<length>";
31
+ inherits: false;
32
+ initial-value: 0px;
33
+ }
34
+ @property --_ui-skeleton-viewport-scale {
35
+ syntax: "<number>";
36
+ inherits: false;
37
+ initial-value: 1;
38
+ }
25
39
 
26
40
  :host {
41
+ --_ui-skeleton-paint-x: var(--_ui-skeleton-viewport-x);
42
+ --_ui-skeleton-paint-scale: var(--_ui-skeleton-viewport-scale);
27
43
  display: block !important;
28
44
  position: relative;
29
45
  box-sizing: border-box !important;
@@ -65,23 +81,36 @@
65
81
  }
66
82
 
67
83
  :host([animated])::before {
68
- animation: ui-skeleton-pulse 1.6s ease-in-out infinite;
84
+ background-image: linear-gradient(
85
+ 90deg,
86
+ transparent,
87
+ light-dark(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.14)) 50%,
88
+ transparent
89
+ );
90
+ background-size: calc(100vw / var(--_ui-skeleton-paint-scale)) 100%;
91
+ background-position: calc(0vw - var(--_ui-skeleton-paint-x)) 0;
92
+ background-repeat: repeat-x;
93
+ animation: ui-skeleton-shimmer 3s linear infinite;
69
94
  }
70
- @keyframes ui-skeleton-pulse {
71
- 50% {
72
- opacity: 0.45;
95
+ @keyframes ui-skeleton-shimmer {
96
+ to {
97
+ background-position: calc(100vw / var(--_ui-skeleton-paint-scale) - var(--_ui-skeleton-paint-x)) 0;
73
98
  }
74
99
  }
75
100
  @media (prefers-reduced-motion: reduce) {
76
101
  :host([animated])::before {
77
102
  animation: none;
103
+ background-image: none;
78
104
  }
79
105
  }
80
106
  @media (forced-colors: active) {
81
107
  :host::before {
82
108
  background: CanvasText;
83
109
  opacity: 0.2;
110
+ }
111
+ :host([animated])::before {
84
112
  animation: none;
113
+ background-image: none;
85
114
  }
86
115
  }
87
116
  :host[hidden] {
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Keep one viewport gradient aligned through mounting, scrolling and transformed surfaces.
3
+ * @lifecycle CSS owns motion preferences; geometry tracking stops with the animation or disconnect.
4
+ */
5
+ export function connect(host) {
6
+ const element = host.element;
7
+ const view = element.ownerDocument.defaultView;
8
+ let motion;
9
+ let frame = 0;
10
+ let previousPosition = "";
11
+ let previousScale = "";
12
+ const trackPosition = () => {
13
+ frame = 0;
14
+ if (motion?.playState !== "running") return;
15
+ const bounds = element.getBoundingClientRect();
16
+ const width = parseFloat(view.getComputedStyle(element).width);
17
+ const scale = bounds.width > 0 && width > 0 ? bounds.width / width : 1;
18
+ const position = `${bounds.left / scale}px`;
19
+ const scaleValue = String(scale);
20
+ if (position !== previousPosition) {
21
+ element.style.setProperty("--_ui-skeleton-viewport-x", position);
22
+ previousPosition = position;
23
+ }
24
+ if (scaleValue !== previousScale) {
25
+ element.style.setProperty("--_ui-skeleton-viewport-scale", scaleValue);
26
+ previousScale = scaleValue;
27
+ }
28
+ frame = view.requestAnimationFrame(trackPosition);
29
+ };
30
+ const synchronize = () => {
31
+ const names = view.getComputedStyle(element, "::before").animationName.split(",").map(name => name.trim());
32
+ for (const animation of element.getAnimations({ subtree: true })) {
33
+ if (names.includes(animation.animationName)) {
34
+ motion = animation;
35
+ motion.startTime = 0;
36
+ }
37
+ }
38
+ if (!frame) trackPosition();
39
+ };
40
+ element.addEventListener("animationstart", synchronize);
41
+ synchronize();
42
+ return () => {
43
+ element.removeEventListener("animationstart", synchronize);
44
+ view.cancelAnimationFrame(frame);
45
+ };
46
+ }