@kubex/zinc 1.1.74 → 1.1.76

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": "@kubex/zinc",
3
- "version": "1.1.74",
3
+ "version": "1.1.76",
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",
@@ -4,7 +4,6 @@ import {HasSlotController} from "../../internal/slot";
4
4
  import {html, unsafeCSS} from 'lit';
5
5
  import {MutationController} from '@lit-labs/observers/mutation-controller.js';
6
6
  import {property, queryAssignedNodes, queryAsync, state} from 'lit/decorators.js';
7
- import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
8
7
  import ZincElement from "../../internal/zinc-element";
9
8
  import type {PropertyValues} from 'lit';
10
9
  import type ZnTile from "../tile";
@@ -280,7 +279,7 @@ export default class ContentBlock extends ZincElement {
280
279
  'text-section--text': section.type === 'text',
281
280
  'hidden': section.type === 'reply'
282
281
  })}>
283
- ${section.lines.map((line) => html`${unsafeHTML(line)}<br>`)}
282
+ ${section.lines.map((line) => html`${line}<br>`)}
284
283
  </div>
285
284
  `)}
286
285
  </div>
@@ -375,7 +374,7 @@ export default class ContentBlock extends ZincElement {
375
374
  const textRows: TextRow[] = [];
376
375
 
377
376
  if (textContent) {
378
- const text = textContent.innerText;
377
+ const text = textContent.innerText.replace(/<br\s*\/?>/gi, '\n');
379
378
  const rows = text.split('\n');
380
379
  let previousType: TextRow['type'] | null = null;
381
380
  let forceReply = false;
@@ -1,10 +1,34 @@
1
1
  import '../../../dist/zn.min.js';
2
- import { expect, fixture, html } from '@open-wc/testing';
2
+ import { expect, fixture } from '@open-wc/testing';
3
+ import type { LitElement } from 'lit';
4
+
5
+ const textSection = async (body: string) => {
6
+ const el = await fixture<LitElement>(
7
+ `<zn-content-block><div slot="text">${body}</div></zn-content-block>`
8
+ );
9
+ await el.updateComplete;
10
+ return el.shadowRoot!.querySelector<HTMLDivElement>('.text-content')!;
11
+ };
3
12
 
4
13
  describe('<zn-content-block>', () => {
5
14
  it('should render a component', async () => {
6
- const el = await fixture(html` <zn-content-block></zn-content-block> `);
15
+ const el = await fixture('<zn-content-block></zn-content-block>');
7
16
 
8
17
  expect(el).to.exist;
9
18
  });
19
+
20
+ it('should render markup in the text body as text', async () => {
21
+ const content = await textSection('&lt;img src="x" onerror="window.__xss = true"&gt; hello');
22
+
23
+ expect(content.querySelector('img')).to.be.null;
24
+ expect(content.textContent).to.contain('<img src="x" onerror="window.__xss = true"> hello');
25
+ expect((window as unknown as Record<string, unknown>).__xss).to.be.undefined;
26
+ });
27
+
28
+ it('should treat escaped breaks in the text body as line breaks', async () => {
29
+ const content = await textSection('line1&lt;br /&gt;line2');
30
+
31
+ expect(content.textContent).to.not.contain('<br');
32
+ expect(content.querySelectorAll('br').length).to.be.greaterThan(1);
33
+ });
10
34
  });
@@ -325,8 +325,10 @@ export default class ZnExpandingAction extends ZincElement {
325
325
  plain
326
326
  notification="${this.count || nothing}">
327
327
  </zn-button>
328
- <div id="content" class="expanding-action__content">
329
- <slot></slot>
328
+ <div class="expanding-action__frame">
329
+ <div id="content" class="expanding-action__content">
330
+ <slot></slot>
331
+ </div>
330
332
  </div>
331
333
  </zn-dropdown>`
332
334
  }
@@ -72,13 +72,18 @@
72
72
  height: 100%;
73
73
  }
74
74
 
75
- .expanding-action--drop .expanding-action__content {
75
+ .expanding-action--drop .expanding-action__frame {
76
+ @include wc.scrollbars;
77
+
76
78
  --expanding-action-trigger-width: 36px;
77
79
 
78
80
  position: relative;
81
+ display: flex;
82
+ flex-direction: column;
79
83
  min-width: 300px;
80
84
  width: var(--expanding-action-basis, var(--zn-container-smp, 320px));
81
85
  max-width: 80vw;
86
+ max-height: var(--expanding-action-max-height, var(--auto-size-available-height, 80vh));
82
87
  background-color: rgb(var(--zn-panel));
83
88
  box-shadow: 0 8px 16px -6px rgba(33, 33, 33, 0.18);
84
89
  border: solid 1px rgb(var(--zn-border-color));
@@ -98,7 +103,14 @@
98
103
  }
99
104
  }
100
105
 
101
- :host([data-trigger-side="left"]) .expanding-action--drop .expanding-action__content {
106
+ .expanding-action--drop .expanding-action__content {
107
+ flex: 1 1 auto;
108
+ min-height: 0; // Without this the flex item refuses to shrink below its content height
109
+ overflow-y: auto;
110
+ border-radius: inherit;
111
+ }
112
+
113
+ :host([data-trigger-side="left"]) .expanding-action--drop .expanding-action__frame {
102
114
  border-radius: 0 var(--zn-border-radius) var(--zn-border-radius) var(--zn-border-radius);
103
115
 
104
116
  &::before {
@@ -1,5 +1,5 @@
1
1
  import '../../../dist/zn.min.js';
2
- import { expect, fixture, html } from '@open-wc/testing';
2
+ import { expect, fixture, html, waitUntil } from '@open-wc/testing';
3
3
 
4
4
  describe('<zn-expanding-action>', () => {
5
5
  it('should render a component', async () => {
@@ -7,4 +7,47 @@ describe('<zn-expanding-action>', () => {
7
7
 
8
8
  expect(el).to.exist;
9
9
  });
10
+
11
+ describe('drop panel overflow', () => {
12
+ const openPanel = async (el: HTMLElement) => {
13
+ const dropdown = el.shadowRoot!.querySelector('zn-dropdown') as HTMLElement & { show: () => Promise<unknown> };
14
+ await dropdown.show();
15
+ await waitUntil(() => el.hasAttribute('open'));
16
+ await new Promise(resolve => requestAnimationFrame(resolve));
17
+ };
18
+
19
+ const tallContent = html`
20
+ <zn-expanding-action method="drop" icon="note">
21
+ <div style="height: 4000px">tall</div>
22
+ </zn-expanding-action>`;
23
+
24
+ it('should bound the panel height so it cannot run off the screen', async () => {
25
+ const el = await fixture<HTMLElement>(tallContent);
26
+ await openPanel(el);
27
+
28
+ const frame = el.shadowRoot!.querySelector<HTMLElement>('.expanding-action__frame')!;
29
+ expect(frame).to.exist;
30
+ expect(frame.getBoundingClientRect().height).to.be.at.most(window.innerHeight);
31
+ });
32
+
33
+ it('should scroll overflowing content rather than clipping it', async () => {
34
+ const el = await fixture<HTMLElement>(tallContent);
35
+ await openPanel(el);
36
+
37
+ const content = el.shadowRoot!.querySelector<HTMLElement>('#content')!;
38
+ expect(getComputedStyle(content).overflowY).to.equal('auto');
39
+ expect(content.scrollHeight).to.be.greaterThan(content.clientHeight);
40
+ });
41
+
42
+ it('should honour an explicit max-height', async () => {
43
+ const el = await fixture<HTMLElement>(html`
44
+ <zn-expanding-action method="drop" icon="note" max-height="250">
45
+ <div style="height: 4000px">tall</div>
46
+ </zn-expanding-action>`);
47
+ await openPanel(el);
48
+
49
+ const frame = el.shadowRoot!.querySelector<HTMLElement>('.expanding-action__frame')!;
50
+ expect(Math.round(frame.getBoundingClientRect().height)).to.equal(250);
51
+ });
52
+ });
10
53
  });