@kubex/zinc 1.1.174 → 1.1.176

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.
@@ -35,7 +35,7 @@ Use the `active` attribute to highlight the current step in the process. The act
35
35
 
36
36
  ### With Custom Icons
37
37
 
38
- Use the `icon` slot to add custom icons or indicators for each step.
38
+ Use the `icon` slot to add custom icons or indicators for each step. The icon is centred in the step's 32px circle, so keep it at the default 24px size or smaller.
39
39
 
40
40
  ```html:preview
41
41
  <zn-vertical-stepper caption="Personal Details" description="Enter your name and contact information" first active>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubex/zinc",
3
- "version": "1.1.174",
3
+ "version": "1.1.176",
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,7 +2,7 @@ import {classMap} from "lit/directives/class-map.js";
2
2
  import {deepQuerySelectorAll} from "../../utilities/query";
3
3
  import {HasSlotController} from "../../internal/slot";
4
4
  import {html, unsafeCSS} from 'lit';
5
- import {looksLikeHtml, sanitizeHtml} from './sanitize-html';
5
+ import {htmlToText, looksLikeHtml, sanitizeHtml} from './sanitize-html';
6
6
  import {MutationController} from '@lit-labs/observers/mutation-controller.js';
7
7
  import {property, queryAssignedNodes, queryAsync, state} from 'lit/decorators.js';
8
8
  import {unsafeHTML} from 'lit/directives/unsafe-html.js';
@@ -292,7 +292,7 @@ export default class ContentBlock extends ZincElement {
292
292
  protected truncateText() {
293
293
  const textContent = this.querySelector('[slot="text"]') as HTMLDivElement | null;
294
294
  if (!textContent) return '';
295
- const trimmed = textContent.innerText.replace(/<[^>]*>/g, '').trim();
295
+ const trimmed = htmlToText(textContent.innerText);
296
296
  return trimmed.length > 32 ? trimmed.substring(0, 32) + '...' : trimmed;
297
297
  }
298
298
 
@@ -63,4 +63,18 @@ describe('<zn-content-block>', () => {
63
63
  expect(content.textContent).to.not.contain('<br');
64
64
  expect(content.querySelectorAll('br').length).to.be.greaterThan(1);
65
65
  });
66
+
67
+ it('should decode entities and strip markup in the header preview', async () => {
68
+ const preview = async (body: string) => {
69
+ const el = await fixture<LitElement>(
70
+ `<zn-content-block><div slot="text">${body}</div></zn-content-block>`
71
+ );
72
+ await el.updateComplete;
73
+ return el.shadowRoot!.querySelector('.content-block-header__description')!.textContent;
74
+ };
75
+
76
+ expect(await preview('test&amp;nbsp;send')).to.equal('test send');
77
+ expect(await preview('&lt;p&gt;Hello&lt;/p&gt;&lt;p&gt;there&lt;/p&gt;')).to.equal('Hello there');
78
+ expect(await preview('From: Bob &lt;bob@example.com&gt;')).to.equal('From: Bob <bob@example.com>');
79
+ });
66
80
  });
@@ -83,3 +83,14 @@ export function sanitizeHtml(source: string): string {
83
83
  copyChildren(parsed.body, root, out);
84
84
  return root.innerHTML;
85
85
  }
86
+
87
+ /** Plain text of a body that may be HTML source or text holding encoded entities like `&nbsp;`. */
88
+ export function htmlToText(source: string): string {
89
+ // Plain text is escaped so an address like `<bob@example.com>` isn't parsed as a tag
90
+ const markup = looksLikeHtml(source)
91
+ ? sanitizeHtml(source)
92
+ : source.replace(/<br\s*\/?>/gi, ' ').replace(/</g, '&lt;');
93
+ const parsed = new DOMParser().parseFromString(markup, 'text/html');
94
+ parsed.body.querySelectorAll('br, p, li').forEach((el) => el.after(' '));
95
+ return (parsed.body.textContent ?? '').replace(/\s+/g, ' ').trim();
96
+ }
@@ -18,6 +18,10 @@
18
18
  &__icon {
19
19
  width: var(--zn-spacing-large);
20
20
  height: var(--zn-spacing-large);
21
+ display: flex;
22
+ flex-shrink: 0;
23
+ align-items: center;
24
+ justify-content: center;
21
25
  background-color: rgb(var(--zn-input-bg));
22
26
  border-width: 1px;
23
27
  border-radius: 100%;