@kubex/zinc 1.0.107 → 1.0.108

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.
@@ -7,6 +7,7 @@
7
7
  <li><a href="/getting-started/table-examples">Table Examples</a></li>
8
8
  <li><a href="/getting-started/example-layout">Example Layout</a></li>
9
9
  <li><a href="/getting-started/example-page">Example Page</a></li>
10
+ <li><a href="/getting-started/shimmer-text">Shimmer Text</a></li>
10
11
  </ul>
11
12
  </li>
12
13
  <li>
@@ -0,0 +1,81 @@
1
+ ---
2
+ meta:
3
+ title: Shimmer Text
4
+ description: A global utility class that applies an animated shimmer sweep to text, suitable for loading, processing, or "thinking" states.
5
+ ---
6
+
7
+ # Shimmer Text
8
+
9
+ `shimmer-text` is a global utility class that animates a horizontal highlight sweep across text colour. Use it to convey an in-progress state — AI generation, background processing, or any "working on it" indicator.
10
+
11
+ The class works on any element with text content, including inside Zinc components. Colour variants mirror the standard Zinc palette: `zn-primary`, `zn-accent`, `zn-info`, `zn-success`, `zn-warning`, `zn-error`.
12
+
13
+ When `prefers-reduced-motion: reduce` is set, the animation is suppressed and the text falls back to a solid colour matching the chosen variant.
14
+
15
+ ## Examples
16
+
17
+ ### Default
18
+
19
+ ```html:preview
20
+ <span class="shimmer-text">Thinking…</span>
21
+ ```
22
+
23
+ ### Colour Variants
24
+
25
+ ```html:preview
26
+ <div style="display: flex; flex-direction: column; gap: 8px;">
27
+ <span class="shimmer-text">Default</span>
28
+ <span class="shimmer-text zn-primary">Primary</span>
29
+ <span class="shimmer-text zn-accent">Accent</span>
30
+ <span class="shimmer-text zn-info">Info</span>
31
+ <span class="shimmer-text zn-success">Success</span>
32
+ <span class="shimmer-text zn-warning">Warning</span>
33
+ <span class="shimmer-text zn-error">Error</span>
34
+ </div>
35
+ ```
36
+
37
+ ### Headings and Larger Text
38
+
39
+ The shimmer scales with whatever `font-size` is on the element, so it can be applied to headings or inline within prose.
40
+
41
+ ```html:preview
42
+ <h2 class="shimmer-text zn-primary" style="margin: 0;">Generating summary…</h2>
43
+ <p style="margin: 8px 0 0;">
44
+ Please wait while we <span class="shimmer-text zn-info">analyse your data</span>.
45
+ </p>
46
+ ```
47
+
48
+ ### Inside Zinc Components
49
+
50
+ Because `shimmer-text` is a plain class, it composes with any Zinc component that renders slotted text.
51
+
52
+ ```html:preview
53
+ <zn-chip class="shimmer-text zn-accent">Processing</zn-chip>
54
+ ```
55
+
56
+ ### Tuning the Sweep
57
+
58
+ The effect mirrors the Claude CLI's character-level shimmer: a narrow, sharper highlight slides across text rather than a soft gradient wash. The class exposes these CSS custom properties — all sized in `ch` so they scale with the current font size.
59
+
60
+ | Variable | Default | Purpose |
61
+ |---|---|---|
62
+ | `--shimmer-base` | `rgb(var(--zn-text))` | Resting text colour. |
63
+ | `--shimmer-highlight` | `rgb(var(--zn-text-heading))` | Colour of the spotlight. |
64
+ | `--shimmer-core` | `0.5ch` | Half-width of the solid-colour core of the spotlight. |
65
+ | `--shimmer-spread` | `1.5ch` | Half-width of the full highlight including its fade-out edges. |
66
+ | `--shimmer-duration` | `2s` | Time for one full sweep cycle. |
67
+
68
+ ```html:preview
69
+ <div style="display: flex; flex-direction: column; gap: 6px;">
70
+ <span class="shimmer-text">Default sweep</span>
71
+ <span class="shimmer-text" style="--shimmer-duration: 1s;">Faster sweep</span>
72
+ <span class="shimmer-text" style="--shimmer-duration: 4s;">Slower, gentler sweep</span>
73
+ <span class="shimmer-text" style="--shimmer-core: 1ch; --shimmer-spread: 3ch;">Wider spotlight</span>
74
+ </div>
75
+ ```
76
+
77
+ The Claude CLI scales its sweep with message length (50ms per character plus 10 characters of offscreen pause on each side). To match that feel in CSS, set `--shimmer-duration` to roughly `(messageCharacters + 20) × 50ms`.
78
+
79
+ ### Reduced Motion
80
+
81
+ The animation is wrapped in `@media (prefers-reduced-motion: no-preference)`. Users who have requested reduced motion see the static colour variant instead — no configuration required.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubex/zinc",
3
- "version": "1.0.107",
3
+ "version": "1.0.108",
4
4
  "description": "A collection of web components for building web applications based off of @shoelace-style/Shoelace",
5
5
  "keywords": [
6
6
  "web components",
@@ -2,6 +2,7 @@
2
2
  @forward "layout";
3
3
  @forward "divide";
4
4
  @forward "nav";
5
+ @forward "shimmer";
5
6
 
6
7
 
7
8
  // Need to remove the below from zinc, or have nice defaults that don't mess everything up
@@ -0,0 +1,98 @@
1
+
2
+ @keyframes shimmer-text-sweep {
3
+ 0% {
4
+ background-position: 100% center;
5
+ }
6
+ 100% {
7
+ background-position: 0% center;
8
+ }
9
+ }
10
+
11
+ @media (prefers-reduced-motion: no-preference) {
12
+ .shimmer-text {
13
+ --shimmer-base: rgb(var(--zn-text));
14
+ --shimmer-highlight: rgb(var(--zn-text-heading));
15
+ --shimmer-core: 0.5ch;
16
+ --shimmer-spread: 1.5ch;
17
+ --shimmer-duration: 1.5s;
18
+
19
+ display: inline-block;
20
+ width: fit-content;
21
+ max-width: 100%;
22
+ background-image:
23
+ linear-gradient(
24
+ 90deg,
25
+ transparent calc(50% - var(--shimmer-spread)),
26
+ var(--shimmer-highlight) calc(50% - var(--shimmer-core)),
27
+ var(--shimmer-highlight) calc(50% + var(--shimmer-core)),
28
+ transparent calc(50% + var(--shimmer-spread))
29
+ ),
30
+ linear-gradient(var(--shimmer-base), var(--shimmer-base));
31
+ background-size: 250% 100%, auto;
32
+ background-clip: text;
33
+ -webkit-background-clip: text;
34
+ -webkit-text-fill-color: transparent !important;
35
+ color: transparent !important;
36
+ animation: var(--shimmer-duration) linear infinite shimmer-text-sweep;
37
+
38
+ &.zn-error {
39
+ --shimmer-base: rgb(var(--zn-color-error));
40
+ --shimmer-highlight: color-mix(in srgb, rgb(var(--zn-color-error)) 55%, white);
41
+ }
42
+
43
+ &.zn-success {
44
+ --shimmer-base: rgb(var(--zn-color-success));
45
+ --shimmer-highlight: color-mix(in srgb, rgb(var(--zn-color-success)) 55%, white);
46
+ }
47
+
48
+ &.zn-info {
49
+ --shimmer-base: rgb(var(--zn-color-info));
50
+ --shimmer-highlight: color-mix(in srgb, rgb(var(--zn-color-info)) 55%, white);
51
+ }
52
+
53
+ &.zn-warning {
54
+ --shimmer-base: rgb(var(--zn-color-warning));
55
+ --shimmer-highlight: color-mix(in srgb, rgb(var(--zn-color-warning)) 55%, white);
56
+ }
57
+
58
+ &.zn-primary {
59
+ --shimmer-base: rgb(var(--zn-primary));
60
+ --shimmer-highlight: color-mix(in srgb, rgb(var(--zn-primary)) 55%, white);
61
+ }
62
+
63
+ &.zn-accent {
64
+ --shimmer-base: rgb(var(--zn-accent));
65
+ --shimmer-highlight: color-mix(in srgb, rgb(var(--zn-accent)) 55%, white);
66
+ }
67
+ }
68
+ }
69
+
70
+ @media (prefers-reduced-motion: reduce) {
71
+ .shimmer-text {
72
+ color: rgb(var(--zn-text));
73
+
74
+ &.zn-error {
75
+ color: rgb(var(--zn-color-error)) !important;
76
+ }
77
+
78
+ &.zn-success {
79
+ color: rgb(var(--zn-color-success)) !important;
80
+ }
81
+
82
+ &.zn-info {
83
+ color: rgb(var(--zn-color-info)) !important;
84
+ }
85
+
86
+ &.zn-warning {
87
+ color: rgb(var(--zn-color-warning)) !important;
88
+ }
89
+
90
+ &.zn-primary {
91
+ color: rgb(var(--zn-primary)) !important;
92
+ }
93
+
94
+ &.zn-accent {
95
+ color: rgb(var(--zn-accent)) !important;
96
+ }
97
+ }
98
+ }
@@ -269,6 +269,8 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
269
269
  'panel--cosmic': this.cosmic,
270
270
  'panel--shadow': this.shadow,
271
271
  })}>
272
+
273
+
272
274
  <div class="panel__inner">
273
275
  ${hasHeader ? html`
274
276
  <zn-header class=${classMap({
@@ -297,6 +299,7 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
297
299
  </label>` : ''}
298
300
 
299
301
  <div part="toolbar" class="markdown-editor__toolbar">
302
+ ${this.markdownHelperBtn()}
300
303
  <zn-button-group class="markdown-editor__view-toggle" @click=${this.handleViewToggle}>
301
304
  ${VIEW_MODES.map(v => this.renderViewButton(v.mode, v.icon, v.label))}
302
305
  </zn-button-group>
@@ -351,6 +354,21 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
351
354
  `;
352
355
  }
353
356
 
357
+ markdownHelperBtn() {
358
+ return html`
359
+ <a
360
+ class="markdown-editor__markdown-link"
361
+ href="https://www.markdownguide.org/cheat-sheet"
362
+ target="_blank"
363
+ rel="noopener noreferrer"
364
+ title="Markdown is supported"
365
+ >
366
+ <zn-icon src="markdown"></zn-icon>
367
+ <span>Markdown is supported</span>
368
+ </a>
369
+ `;
370
+ }
371
+
354
372
  private renderViewButton(mode: ViewMode, icon: string, label: string) {
355
373
  const isActive = this.viewMode === mode;
356
374
  return html`
@@ -372,4 +390,7 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
372
390
  ></zn-button>
373
391
  `;
374
392
  }
393
+
394
+
395
+
375
396
  }
@@ -44,9 +44,32 @@
44
44
 
45
45
  .markdown-editor__toolbar {
46
46
  display: flex;
47
- align-items: center;
47
+ align-items: end;
48
48
  gap: var(--zn-spacing-small);
49
49
  justify-content: flex-end;
50
+ flex-wrap: wrap;
51
+ }
52
+
53
+ .markdown-editor__markdown-link {
54
+ display: inline-flex;
55
+ align-items: center;
56
+ gap: var(--zn-spacing-x-small);
57
+ margin-right: auto;
58
+ font-size: var(--zn-input-label-font-size-small);
59
+ line-height: 1;
60
+ color: var(--zn-color-neutral-500, #656d76);
61
+ text-decoration: none;
62
+ cursor: pointer;
63
+ transition: color 0.15s ease;
64
+ padding-left: var(--zn-spacing-x-small);
65
+
66
+ &:hover {
67
+ color: var(--zn-color-primary-600, #0969da);
68
+ }
69
+
70
+ span {
71
+ white-space: nowrap;
72
+ }
50
73
  }
51
74
 
52
75
  .markdown-editor__view-toggle {
@@ -37,6 +37,7 @@ export default class ZnTabs extends ZincElement {
37
37
  @property({attribute: 'primary-caption', reflect: true}) primaryCaption = 'Navigation';
38
38
  @property({attribute: 'secondary-caption', reflect: true}) secondaryCaption = 'Content';
39
39
  @property({attribute: 'no-prefetch', type: Boolean, reflect: true}) noPrefetch = false;
40
+ @property({attribute: 'no-cache', type: Boolean, reflect: true}) noCache = false;
40
41
  // session storage if not local
41
42
  @property({attribute: 'local-storage', type: Boolean, reflect: true}) localStorage: boolean;
42
43
  @property({attribute: 'store-key'}) storeKey: string;
@@ -72,7 +73,7 @@ export default class ZnTabs extends ZincElement {
72
73
  this.masterId = this.storeKey || Math.floor(Math.random() * 1000000).toString();
73
74
  }
74
75
 
75
- this.preload = !this.noPrefetch;
76
+ this.preload = !this.noPrefetch && !this.noCache;
76
77
 
77
78
  await this.updateComplete;
78
79
  this._panel = this.shadowRoot?.querySelector('#content');
@@ -272,11 +273,14 @@ export default class ZnTabs extends ZincElement {
272
273
  }
273
274
 
274
275
  clickTab(target: HTMLElement, refresh: boolean) {
276
+ const tabUri = target.getAttribute('tab-uri');
277
+ const wasCached = !!tabUri && this._panels.has(this._uriToId(tabUri));
275
278
  this.fetchUriTab(target);
276
279
 
277
280
  if (target.hasAttribute('tab')) {
281
+ const forceRefresh = refresh || (this.noCache && wasCached);
278
282
  setTimeout(() => {
279
- this.setActiveTab(target.getAttribute('tab') || '', true, refresh, this.getRefTab(target));
283
+ this.setActiveTab(target.getAttribute('tab') || '', true, forceRefresh, this.getRefTab(target));
280
284
  }, 10);
281
285
  }
282
286
  }