@kubex/zinc 1.0.113 → 1.0.114

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.
Files changed (95) hide show
  1. package/.github/workflows/eleventy_build.yml +5 -5
  2. package/.github/workflows/js_build_and_deploy.yaml +1 -1
  3. package/dist/custom-elements.json +2636 -421
  4. package/dist/vscode.html-custom-data.json +96 -16
  5. package/dist/web-types.json +268 -31
  6. package/dist/zn.d.ts +517 -340
  7. package/dist/zn.min.css +1 -1
  8. package/dist/zn.min.js +942 -863
  9. package/docs/eleventy.config.cjs +4 -2
  10. package/docs/pages/components/header.md +13 -0
  11. package/docs/pages/components/inline-edit.md +20 -0
  12. package/docs/pages/components/item.md +12 -1
  13. package/docs/pages/components/page.md +149 -0
  14. package/docs/pages/components/progress-bar.md +16 -0
  15. package/docs/pages/components/select.md +25 -0
  16. package/docs/pages/components/split-pane.md +6 -7
  17. package/docs/pages/components/tabs.md +59 -9
  18. package/package.json +8 -5
  19. package/scripts/build.js +40 -19
  20. package/scss/_global-spacing.scss +12 -1
  21. package/scss/_root.scss +34 -2
  22. package/scss/shared/layout.scss +15 -2
  23. package/scss/themes/_light.scss +1 -1
  24. package/src/components/absolute-container/absolute-container.component.ts +9 -25
  25. package/src/components/animated-button/animated-button.test.ts +8 -8
  26. package/src/components/button/button.component.ts +3 -1
  27. package/src/components/button/button.scss +5 -0
  28. package/src/components/button-menu/button-menu.component.ts +36 -21
  29. package/src/components/button-menu/button-menu.test.ts +55 -1
  30. package/src/components/chart/chart.component.ts +7 -7
  31. package/src/components/collapsible/collapsible.component.ts +7 -14
  32. package/src/components/cols/cols.scss +1 -1
  33. package/src/components/content-block/content-block.component.ts +11 -33
  34. package/src/components/data-select/data-select.component.ts +7 -11
  35. package/src/components/data-table/data-table.component.ts +10 -14
  36. package/src/components/editor/modules/toolbar/toolbar.component.ts +5 -9
  37. package/src/components/expanding-action/expanding-action.component.ts +37 -43
  38. package/src/components/form-group/form-group.component.ts +8 -3
  39. package/src/components/header/header.component.ts +6 -5
  40. package/src/components/header/header.scss +31 -25
  41. package/src/components/inline-edit/inline-edit.component.ts +13 -1
  42. package/src/components/inline-edit/inline-edit.test.ts +50 -0
  43. package/src/components/input/input.test.ts +77 -0
  44. package/src/components/input-group/input-group.test.ts +2 -10
  45. package/src/components/item/item.component.ts +12 -6
  46. package/src/components/item/item.scss +1 -1
  47. package/src/components/item/item.test.ts +8 -0
  48. package/src/components/navbar/navbar.component.ts +222 -48
  49. package/src/components/navbar/navbar.scss +134 -21
  50. package/src/components/navbar/navbar.test.ts +114 -9
  51. package/src/components/option/option.scss +5 -7
  52. package/src/components/option/option.test.ts +30 -0
  53. package/src/components/page/index.ts +13 -0
  54. package/src/components/page/page.component.ts +406 -0
  55. package/src/components/page/page.scss +325 -0
  56. package/src/components/page/page.test.ts +397 -0
  57. package/src/components/page-nav/page-nav.scss +7 -5
  58. package/src/components/pane/pane.component.ts +2 -2
  59. package/src/components/pane/pane.scss +0 -1
  60. package/src/components/pane/pane.test.ts +31 -0
  61. package/src/components/panel/panel.scss +1 -0
  62. package/src/components/progress-bar/progress-bar.component.ts +5 -2
  63. package/src/components/progress-bar/progress-bar.scss +17 -1
  64. package/src/components/progress-bar/progress-bar.test.ts +12 -0
  65. package/src/components/scroll-container/scroll-container.component.ts +22 -21
  66. package/src/components/select/select.component.ts +240 -38
  67. package/src/components/select/select.scss +15 -0
  68. package/src/components/select/select.test.ts +477 -0
  69. package/src/components/settings-container/settings-container.component.ts +15 -19
  70. package/src/components/settings-container/settings-container.scss +8 -8
  71. package/src/components/sidebar/sidebar.component.ts +11 -11
  72. package/src/components/simple-chart/simple-chart.component.ts +6 -7
  73. package/src/components/sp/sp.scss +46 -15
  74. package/src/components/sp/sp.test.ts +15 -0
  75. package/src/components/split-pane/split-pane.component.ts +153 -26
  76. package/src/components/split-pane/split-pane.scss +89 -13
  77. package/src/components/split-pane/split-pane.test.ts +187 -0
  78. package/src/components/style/style.component.ts +8 -0
  79. package/src/components/tab/index.ts +13 -0
  80. package/src/components/tab/tab.component.ts +25 -0
  81. package/src/components/tab/tab.scss +7 -0
  82. package/src/components/table/table.component.ts +7 -2
  83. package/src/components/tabs/tabs.component.ts +75 -70
  84. package/src/components/tabs/tabs.scss +1 -1
  85. package/src/components/textarea/textarea.component.ts +5 -8
  86. package/src/components/translation-group/translation-group.component.ts +15 -14
  87. package/src/components/translations/translations.component.ts +18 -17
  88. package/src/components/translations/translations.scss +1 -0
  89. package/src/components/translations/translations.test.ts +3 -2
  90. package/src/internal/form.ts +234 -0
  91. package/src/internal/theme.ts +26 -46
  92. package/src/internal/zinc-element.ts +12 -7
  93. package/src/utilities/form.ts +1 -0
  94. package/src/wc.scss +1 -1
  95. package/src/zinc.ts +3 -0
package/scss/_root.scss CHANGED
@@ -44,8 +44,40 @@
44
44
 
45
45
  --base: 255, 255, 255;
46
46
  --inverse-base: 0, 0, 0;
47
+
48
+ --zn-base-gap: 12px;
49
+ --zn-gutter: 4px;
50
+ --zn-default-margin: 0 auto 0 0;
51
+ }
52
+
53
+ @media (min-width: 1024px) {
54
+ :root {
55
+ --zn-base-gap: 14px;
56
+ --zn-gutter: 6px;
57
+ }
58
+ }
59
+
60
+ @media (min-width: 1600px) {
61
+ :root {
62
+ --zn-base-gap: 16px;
63
+ --zn-gutter: 8px;
64
+ }
47
65
  }
48
66
 
67
+ @media (min-width: 2000px) {
68
+ :root {
69
+ --zn-base-gap: 18px;
70
+ --zn-gutter: 10px;
71
+ }
72
+ }
73
+
74
+ @media (min-width: 2400px) {
75
+ :root {
76
+ --zn-default-margin: 0 auto;
77
+ }
78
+ }
79
+
80
+
49
81
  .zn-mono {
50
82
  font-family: var(--zn-font-family-mono);
51
83
  }
@@ -201,8 +233,8 @@
201
233
  color: rgb(var(--zn-color-success));
202
234
  }
203
235
 
204
- ul.gap{
205
- li{
236
+ ul.gap {
237
+ li {
206
238
  margin: 5px 0;
207
239
  }
208
240
  }
@@ -205,9 +205,17 @@
205
205
  }
206
206
 
207
207
  .zn-panel-bg {
208
+ --zn-page-surface-background: var(--zn-panel);
208
209
  background-color: rgba(var(--zn-panel), var(--zn-panel-opacity));
209
210
  }
210
211
 
212
+ .zn-panel {
213
+ background-color: rgba(var(--zn-panel), var(--zn-panel-opacity));
214
+ border: 1px solid rgb(var(--zn-border-color));
215
+ border-radius: var(--zn-border-radius-large);
216
+ --zn-page-surface-background: var(--zn-panel);
217
+ }
218
+
211
219
  .zn-container {
212
220
  display: flex;
213
221
  flex-direction: column;
@@ -279,14 +287,19 @@
279
287
  .zn-panel-bar {
280
288
  border-bottom: 1px solid rgb(var(--zn-border-color));
281
289
  background-color: rgba(var(--zn-panel), 0.9);
282
- padding: 3px;
283
- gap: 3px;
290
+ padding: 4px;
291
+ gap: 4px;
284
292
  display: flex;
285
293
  flex-wrap: wrap;
286
294
  align-items: center;
287
295
  z-index: 1;
288
296
  }
289
297
 
298
+ .zn-panel-bar--pill {
299
+ border-radius: var(--zn-border-radius-large);
300
+ border: 1px solid rgb(var(--zn-border-color));
301
+ }
302
+
290
303
  .zn-panel-bar--large {
291
304
  padding: 6px;
292
305
  gap: 6px;
@@ -372,7 +372,7 @@
372
372
  --zn-transition-x-fast: 50ms;
373
373
 
374
374
  /** Gap */
375
- --zn-gap: var(--zn-spacing-medium, 0);
375
+ --zn-gap: var(--zn-base-gap, var(--zn-spacing-medium, 4px));
376
376
 
377
377
  /**************************************************************
378
378
  * Typography
@@ -1,3 +1,4 @@
1
+ import {MutationController} from '@lit-labs/observers/mutation-controller.js';
1
2
  import ZincElement from '../../internal/zinc-element';
2
3
  import type {PropertyValues} from 'lit';
3
4
 
@@ -14,16 +15,14 @@ import type {PropertyValues} from 'lit';
14
15
  */
15
16
  export default class ZnAbsoluteContainer extends ZincElement {
16
17
 
17
- private domObserver: MutationObserver;
18
-
19
- connectedCallback() {
20
- super.connectedCallback();
21
- this.observerDom();
22
- }
23
-
24
- disconnectedCallback() {
25
- super.disconnectedCallback();
26
- this.domObserver?.disconnect();
18
+ constructor() {
19
+ super();
20
+ // eslint-disable-next-line no-new
21
+ new MutationController(this, {
22
+ config: {childList: true, subtree: true, attributes: true, characterData: true},
23
+ callback: () => this.resize(),
24
+ skipInitial: true,
25
+ });
27
26
  }
28
27
 
29
28
  protected firstUpdated(_changedProperties: PropertyValues) {
@@ -39,21 +38,6 @@ export default class ZnAbsoluteContainer extends ZincElement {
39
38
  this.style.minHeight = newSize + 'px';
40
39
  }
41
40
 
42
- observerDom() {
43
- // observe the DOM for changes
44
- this.domObserver = new MutationObserver(() => {
45
- this.resize();
46
- });
47
-
48
- this.domObserver.observe(this,
49
- {
50
- childList: true,
51
- subtree: true,
52
- attributes: true,
53
- characterData: true
54
- });
55
- }
56
-
57
41
  // the height of this element is set to the height of its children (absolute positioned)
58
42
  // to push the content element down
59
43
  createRenderRoot() {
@@ -56,7 +56,7 @@ describe('<zn-animated-button>', () => {
56
56
  await el.updateComplete;
57
57
 
58
58
  const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
59
- expect(button.classList.contains('purchase-button--success')).to.be.true;
59
+ expect(button.classList.contains('animated-button--success')).to.be.true;
60
60
  });
61
61
 
62
62
  it('should transition to failure state when setFailure is called', async () => {
@@ -66,7 +66,7 @@ describe('<zn-animated-button>', () => {
66
66
  await el.updateComplete;
67
67
 
68
68
  const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
69
- expect(button.classList.contains('purchase-button--failure')).to.be.true;
69
+ expect(button.classList.contains('animated-button--failure')).to.be.true;
70
70
  expect(button.textContent).to.include('Payment failed');
71
71
  });
72
72
 
@@ -79,18 +79,18 @@ describe('<zn-animated-button>', () => {
79
79
  await el.updateComplete;
80
80
 
81
81
  let button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
82
- expect(button.classList.contains('purchase-button--failure')).to.be.true;
82
+ expect(button.classList.contains('animated-button--failure')).to.be.true;
83
83
 
84
84
  await waitUntil(
85
85
  () => {
86
86
  button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
87
- return button.classList.contains('purchase-button--idle');
87
+ return button.classList.contains('animated-button--idle');
88
88
  },
89
89
  '',
90
90
  { timeout: 500 }
91
91
  );
92
92
 
93
- expect(button.classList.contains('purchase-button--idle')).to.be.true;
93
+ expect(button.classList.contains('animated-button--idle')).to.be.true;
94
94
  });
95
95
 
96
96
  it('should show spinner icon in processing state', async () => {
@@ -100,7 +100,7 @@ describe('<zn-animated-button>', () => {
100
100
  button.click();
101
101
  await el.updateComplete;
102
102
 
103
- const spinner = el.shadowRoot?.querySelector('.purchase-button__spinner');
103
+ const spinner = el.shadowRoot?.querySelector('.animated-button__spinner');
104
104
  expect(spinner).to.exist;
105
105
  });
106
106
 
@@ -110,7 +110,7 @@ describe('<zn-animated-button>', () => {
110
110
  el.setSuccess();
111
111
  await el.updateComplete;
112
112
 
113
- const successIcon = el.shadowRoot?.querySelector('.purchase-button__icon--success');
113
+ const successIcon = el.shadowRoot?.querySelector('.animated-button__icon--success');
114
114
  expect(successIcon).to.exist;
115
115
  });
116
116
 
@@ -120,7 +120,7 @@ describe('<zn-animated-button>', () => {
120
120
  el.setFailure();
121
121
  await el.updateComplete;
122
122
 
123
- const failureIcon = el.shadowRoot?.querySelector('.purchase-button__icon--failure');
123
+ const failureIcon = el.shadowRoot?.querySelector('.animated-button__icon--failure');
124
124
  expect(failureIcon).to.exist;
125
125
  });
126
126
 
@@ -66,6 +66,7 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
66
66
  @property({type: Boolean}) disabled = false;
67
67
  @property({type: Boolean}) grow = false;
68
68
  @property({type: Boolean}) square = false;
69
+ @property({type: Boolean, attribute: 'panel-bg'}) panelBackground = false;
69
70
 
70
71
  @property({attribute: 'dropdown-closer', type: Boolean}) dropdownCloser = false;
71
72
 
@@ -329,6 +330,7 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
329
330
  'button': true,
330
331
  'button--default': this.color === 'default',
331
332
  'button--secondary': this.color === 'secondary',
333
+ 'button--panel-bg': this.panelBackground,
332
334
  'button--error': this.color === 'error',
333
335
  'button--info': this.color === 'info',
334
336
  'button--success': this.color === 'success',
@@ -360,7 +362,7 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
360
362
  rel="${ifDefined(isLink ? this.rel : undefined)}"
361
363
  gaid="${ifDefined(this.gaid)}"
362
364
  data-notification="${ifDefined(this.notification)}"
363
- disabled=${this.disabled || nothing}
365
+ disabled="${this.disabled || nothing}"
364
366
  @click="${this.handleClick}">
365
367
  ${this.iconPosition === 'left' ? icon : ''}
366
368
  <slot part="label"
@@ -13,6 +13,7 @@
13
13
  }
14
14
  }
15
15
 
16
+
16
17
  .button {
17
18
  @include shared.button;
18
19
 
@@ -445,3 +446,7 @@
445
446
  border-radius: 0 5px 5px 0 !important;
446
447
  border-left: 0 !important;
447
448
  }
449
+
450
+ .button--panel-bg {
451
+ background: rgb(var(--zn-panel));
452
+ }
@@ -2,6 +2,7 @@ import {classMap} from "lit/directives/class-map.js";
2
2
  import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
3
3
  import {deepQuerySelectorAll} from "../../utilities/query";
4
4
  import {property} from 'lit/decorators.js';
5
+ import {ResizeController} from '@lit-labs/observers/resize-controller.js';
5
6
  import {watch} from "../../internal/watch";
6
7
  import ZincElement from '../../internal/zinc-element';
7
8
  import type ZnButton from "../button";
@@ -51,7 +52,18 @@ export default class ZnButtonMenu extends ZincElement {
51
52
 
52
53
  private _originalButtons: CustomButtonWidths[] = [];
53
54
 
54
- private resizeObserver: ResizeObserver | null = null;
55
+ private _resizeRafId = 0;
56
+
57
+ private readonly resizeObserver = new ResizeController(this, {
58
+ target: null,
59
+ callback: () => {
60
+ if (this._resizeRafId) return;
61
+ this._resizeRafId = requestAnimationFrame(() => {
62
+ this._resizeRafId = 0;
63
+ this.containerWidth = this.offsetWidth;
64
+ });
65
+ },
66
+ });
55
67
 
56
68
  protected async firstUpdated(_changedProperties: PropertyValues) {
57
69
  super.firstUpdated(_changedProperties);
@@ -93,23 +105,11 @@ export default class ZnButtonMenu extends ZincElement {
93
105
  super.connectedCallback();
94
106
  this.containerWidth = this.offsetWidth;
95
107
 
96
- this.resizeObserver = new ResizeObserver(this.handleResize.bind(this));
97
- this.resizeObserver.observe(this.parentNode as HTMLElement); // Observe the parent node
98
- }
99
-
100
- disconnectedCallback() {
101
- super.disconnectedCallback();
102
-
103
- if (this.resizeObserver) {
104
- this.resizeObserver.disconnect();
105
- this.resizeObserver = null;
108
+ if (this.parentNode) {
109
+ this.resizeObserver.observe(this.parentNode as HTMLElement);
106
110
  }
107
111
  }
108
112
 
109
- handleResize = () => {
110
- this.containerWidth = this.offsetWidth;
111
- }
112
-
113
113
  calculateVisibleButtons() {
114
114
  const containerWidth = this.containerWidth;
115
115
 
@@ -203,13 +203,12 @@ export default class ZnButtonMenu extends ZincElement {
203
203
  buttons.forEach((button: CustomButtonWidths, index: number) => {
204
204
  if (index >= visibleButtons) {
205
205
  const menuItem = document.createElement('zn-menu-item');
206
- menuItem.innerText = button.button.innerText;
206
+ menuItem.innerText = this.getButtonLabel(button.button);
207
207
  menuItem.setAttribute('id', button.button.id || `zn-button-menu-item-${index}`);
208
208
  menuItem.setAttribute('role', 'menuitem');
209
209
  const attr = button.button.attributes;
210
210
  // Copy all attributes from the button to the menu item
211
- for (let i = 0; i < attr.length; i++) {
212
- const attribute = attr[i];
211
+ for (const attribute of Array.from(attr)) {
213
212
  if (attribute.name !== 'icon' && attribute.name !== 'category') {
214
213
  menuItem.setAttribute(attribute.name, attribute.value);
215
214
  }
@@ -270,16 +269,32 @@ export default class ZnButtonMenu extends ZincElement {
270
269
  })
271
270
  }
272
271
 
272
+ private getButtonLabel(button: ZnButton) {
273
+ const labelSlot = button.shadowRoot?.querySelector<HTMLSlotElement>('slot[part="label"]');
274
+ const slottedLabel = labelSlot ? [...labelSlot.assignedNodes({flatten: true})]
275
+ .map(node => node.textContent ?? '')
276
+ .join('')
277
+ .trim() : '';
278
+
279
+ return slottedLabel ||
280
+ button.content ||
281
+ button.getAttribute('content') ||
282
+ (button as ZnButton & { caption?: string }).caption ||
283
+ button.getAttribute('caption') ||
284
+ button.button.innerText;
285
+ }
286
+
273
287
  render() {
274
288
  return html`
275
- <div class=${classMap({
289
+ <div class="${classMap({
276
290
  'button-menu': true,
277
291
  'button-menu--no-padding': this.noPadding,
278
292
  'button-menu--no-gap': this.noGap,
279
- })}>
293
+ })}">
280
294
  <div class="button-menu__container"></div>
281
295
  <zn-dropdown placement="bottom-end">
282
- <zn-button slot="trigger" icon="more_vert" icon-size="${this.iconSize}" color="transparent" size="${this.size}"></zn-button>
296
+ <zn-button slot="trigger" icon="more_vert" icon-size="${this.iconSize}" color="transparent"
297
+ size="${this.size}"></zn-button>
283
298
  <zn-menu></zn-menu>
284
299
  </zn-dropdown>
285
300
  <slot></slot>
@@ -1,5 +1,6 @@
1
1
  import '../../../dist/zn.min.js';
2
- import { expect, fixture, html } from '@open-wc/testing';
2
+ import {aTimeout, expect, fixture, html} from '@open-wc/testing';
3
+ import type ZnButtonMenu from './button-menu.component';
3
4
 
4
5
  describe('<zn-button-menu>', () => {
5
6
  it('should render a component', async () => {
@@ -7,4 +8,57 @@ describe('<zn-button-menu>', () => {
7
8
 
8
9
  expect(el).to.exist;
9
10
  });
11
+
12
+ it('uses the slotted button label when creating collapsed menu items', async () => {
13
+ const el = await fixture<ZnButtonMenu>(html`
14
+ <zn-button-menu limit="0">
15
+ <zn-button id="wrapped-label">
16
+ <span>Wrapped Label</span>
17
+ </zn-button>
18
+ </zn-button-menu>
19
+ `);
20
+
21
+ await el.updateComplete;
22
+ await aTimeout(20);
23
+ el.calculateVisibleButtons();
24
+
25
+ const menuItem = el.shadowRoot!.querySelector('zn-menu-item');
26
+
27
+ expect(menuItem).to.exist;
28
+ expect(menuItem!.innerText).to.equal('Wrapped Label');
29
+ });
30
+
31
+ it('uses the button content attribute when creating collapsed menu items', async () => {
32
+ const el = await fixture<ZnButtonMenu>(html`
33
+ <zn-button-menu limit="0">
34
+ <zn-button id="content-label" content="Content Label"></zn-button>
35
+ </zn-button-menu>
36
+ `);
37
+
38
+ await el.updateComplete;
39
+ await aTimeout(20);
40
+ el.calculateVisibleButtons();
41
+
42
+ const menuItem = el.shadowRoot!.querySelector('zn-menu-item');
43
+
44
+ expect(menuItem).to.exist;
45
+ expect(menuItem!.innerText).to.equal('Content Label');
46
+ });
47
+
48
+ it('uses the button caption attribute when creating collapsed menu items', async () => {
49
+ const el = await fixture<ZnButtonMenu>(html`
50
+ <zn-button-menu limit="0">
51
+ <zn-button id="caption-label" caption="Caption Label"></zn-button>
52
+ </zn-button-menu>
53
+ `);
54
+
55
+ await el.updateComplete;
56
+ await aTimeout(20);
57
+ el.calculateVisibleButtons();
58
+
59
+ const menuItem = el.shadowRoot!.querySelector('zn-menu-item');
60
+
61
+ expect(menuItem).to.exist;
62
+ expect(menuItem!.innerText).to.equal('Caption Label');
63
+ });
10
64
  });
@@ -11,6 +11,7 @@ import {
11
11
  } from './builders';
12
12
  import { CanvasRenderer } from 'echarts/renderers';
13
13
  import { type CSSResultGroup, html, type PropertyValues, unsafeCSS } from 'lit';
14
+ import { ResizeController } from '@lit-labs/observers/resize-controller.js';
14
15
  import {
15
16
  DataZoomComponent,
16
17
  GridComponent,
@@ -87,9 +88,14 @@ export default class ZnChart extends ZincElement {
87
88
  }) scale: boolean | number = false;
88
89
 
89
90
  private chart?: ECharts;
90
- private resizeObserver?: ResizeObserver;
91
91
  private liveTimer?: number;
92
92
 
93
+ private readonly resizeObserver = new ResizeController(this, {
94
+ target: null,
95
+ skipInitial: true,
96
+ callback: () => this.chart?.resize(),
97
+ });
98
+
93
99
  protected firstUpdated(_changedProperties: PropertyValues) {
94
100
  this.initChart();
95
101
  super.firstUpdated(_changedProperties);
@@ -150,11 +156,6 @@ export default class ZnChart extends ZincElement {
150
156
  echarts.connect(this.syncGroup);
151
157
  }
152
158
 
153
- let firstResize = true;
154
- this.resizeObserver = new ResizeObserver(() => {
155
- if (firstResize) { firstResize = false; return; }
156
- this.chart?.resize();
157
- });
158
159
  this.resizeObserver.observe(host);
159
160
 
160
161
  if (this.live && this.dataUrl) this.startLive();
@@ -206,7 +207,6 @@ export default class ZnChart extends ZincElement {
206
207
  disconnectedCallback() {
207
208
  super.disconnectedCallback();
208
209
  if (this.liveTimer) clearInterval(this.liveTimer);
209
- this.resizeObserver?.disconnect();
210
210
  this.chart?.dispose();
211
211
  this.chart = undefined;
212
212
  }
@@ -1,6 +1,7 @@
1
1
  import {classMap} from "lit/directives/class-map.js";
2
2
  import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
3
3
  import {HasSlotController} from "../../internal/slot";
4
+ import {MutationController} from '@lit-labs/observers/mutation-controller.js';
4
5
  import {property, state} from 'lit/decorators.js';
5
6
  import {Store} from "../../internal/storage";
6
7
  import ZincElement from '../../internal/zinc-element';
@@ -52,7 +53,11 @@ export default class ZnCollapsible extends ZincElement {
52
53
 
53
54
  private readonly hasSlotController = new HasSlotController(this, '[default]', 'header', 'caption', 'label');
54
55
 
55
- private observer: MutationObserver;
56
+ private readonly observer = new MutationController(this, {
57
+ target: null,
58
+ config: {childList: true, subtree: true},
59
+ callback: () => this.recalculateNumberOfItems(),
60
+ });
56
61
 
57
62
  private showArrow: boolean = true;
58
63
 
@@ -69,12 +74,7 @@ export default class ZnCollapsible extends ZincElement {
69
74
  }
70
75
 
71
76
  if (this.showNumber) {
72
- // add a mutation observer to the default slot to recalculate the number of items when it changes
73
- const slot = this as HTMLElement;
74
- this.observer = new MutationObserver(() => {
75
- this.recalculateNumberOfItems();
76
- });
77
- this.observer.observe(slot, {childList: true, subtree: true});
77
+ this.observer.observe(this);
78
78
  }
79
79
 
80
80
  await this.updateComplete;
@@ -106,13 +106,6 @@ export default class ZnCollapsible extends ZincElement {
106
106
  }
107
107
  }
108
108
 
109
- disconnectedCallback() {
110
- super.disconnectedCallback();
111
- if (this.observer) {
112
- this.observer.disconnect();
113
- }
114
- }
115
-
116
109
  handleCollapse = (e: MouseEvent) => {
117
110
  const target = e.target as HTMLElement;
118
111
  if (target.tagName.toLowerCase() === 'input' && (target as HTMLInputElement).type === 'checkbox') {
@@ -18,7 +18,7 @@
18
18
  width: 100%;
19
19
  container-type: inline-size;
20
20
  overflow: hidden;
21
- gap: var(--zn-spacing-small);
21
+ gap: var(--zn-base-gap, var(--zn-divide-gap, var(--zn-spacing-medium)));
22
22
 
23
23
  max-width: 100%;
24
24
 
@@ -3,6 +3,7 @@ import {deepQuerySelectorAll} from "../../utilities/query";
3
3
  import {HasSlotController} from "../../internal/slot";
4
4
  import type {PropertyValues} from 'lit';
5
5
  import {html, nothing, unsafeCSS} from 'lit';
6
+ import {MutationController} from '@lit-labs/observers/mutation-controller.js';
6
7
  import {property, queryAssignedNodes, queryAsync} from 'lit/decorators.js';
7
8
  import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
8
9
  import ZincElement from "../../internal/zinc-element";
@@ -44,7 +45,11 @@ export default class ContentBlock extends ZincElement {
44
45
 
45
46
  private _textRows: TextRow[] = [];
46
47
 
47
- private _footerObserver?: MutationObserver;
48
+ private readonly _footerObserver = new MutationController(this, {
49
+ target: null,
50
+ config: {subtree: true, childList: true, attributes: true, attributeFilter: ['href', 'download', 'caption']},
51
+ callback: () => this._debouncedReplace(),
52
+ });
48
53
  private _replaceDebounce: number = 0;
49
54
 
50
55
  connectedCallback() {
@@ -71,20 +76,11 @@ export default class ContentBlock extends ZincElement {
71
76
  }
72
77
 
73
78
  disconnectedCallback() {
74
- try {
75
- if (this._footerObserver) {
76
- this._footerObserver.disconnect();
77
- this._footerObserver = undefined;
78
- }
79
- if (this._replaceDebounce) {
80
- clearTimeout(this._replaceDebounce);
81
- this._replaceDebounce = 0;
82
- }
83
- } finally {
84
- // Ensure base class cleanup
85
- // @ts-ignore - base may or may not implement disconnectedCallback
86
- super.disconnectedCallback?.();
79
+ if (this._replaceDebounce) {
80
+ clearTimeout(this._replaceDebounce);
81
+ this._replaceDebounce = 0;
87
82
  }
83
+ super.disconnectedCallback();
88
84
  }
89
85
 
90
86
  private _collapseContent(e: Event) {
@@ -267,25 +263,7 @@ export default class ContentBlock extends ZincElement {
267
263
  const assignedEls: Element[] = slot.assignedElements({flatten: true});
268
264
  if (!assignedEls || assignedEls.length === 0) return;
269
265
 
270
- // Reset and attach a new observer to watch for dynamic content inside the footer subtree
271
- if (this._footerObserver) {
272
- this._footerObserver.disconnect();
273
- this._footerObserver = undefined;
274
- }
275
-
276
- const obs = new MutationObserver(() => {
277
- this._debouncedReplace();
278
- });
279
- this._footerObserver = obs;
280
-
281
- assignedEls.forEach(el => {
282
- obs.observe(el, {
283
- subtree: true,
284
- childList: true,
285
- attributes: true,
286
- attributeFilter: ['href', 'download', 'caption']
287
- });
288
- });
266
+ assignedEls.forEach(el => this._footerObserver.observe(el));
289
267
 
290
268
  // Run now and again shortly after to catch async rendering
291
269
  this._replaceImagePlaceholders();
@@ -10,6 +10,7 @@ import {
10
10
  } from "./providers/provider";
11
11
  import {type CSSResultGroup, html, nothing, type PropertyValues, unsafeCSS} from 'lit';
12
12
  import {FormControlController} from "../../internal/form";
13
+ import {MutationController} from '@lit-labs/observers/mutation-controller.js';
13
14
  import {property, query} from 'lit/decorators.js';
14
15
  import {watch} from "../../internal/watch";
15
16
  import ZincElement from '../../internal/zinc-element';
@@ -134,7 +135,11 @@ export default class ZnDataSelect extends ZincElement implements ZincFormControl
134
135
 
135
136
  protected readonly formControlController = new FormControlController(this);
136
137
 
137
- private selectObserver?: MutationObserver;
138
+ private readonly selectObserver = new MutationController(this, {
139
+ target: null,
140
+ config: {attributes: true, attributeFilter: ['disabled']},
141
+ callback: () => this._syncDisabledState(),
142
+ });
138
143
 
139
144
  get validationMessage() {
140
145
  return this.select.validationMessage;
@@ -159,7 +164,6 @@ export default class ZnDataSelect extends ZincElement implements ZincFormControl
159
164
  disconnectedCallback() {
160
165
  super.disconnectedCallback();
161
166
  window.removeEventListener('keydown', this.closeOnTab);
162
- this.selectObserver?.disconnect();
163
167
  }
164
168
 
165
169
  protected async firstUpdated(_changedProperties: PropertyValues) {
@@ -398,15 +402,7 @@ export default class ZnDataSelect extends ZincElement implements ZincFormControl
398
402
  if (!this.select) return;
399
403
 
400
404
  this._syncDisabledState();
401
-
402
- this.selectObserver = new MutationObserver(() => {
403
- this._syncDisabledState();
404
- });
405
-
406
- this.selectObserver.observe(this.select, {
407
- attributes: true,
408
- attributeFilter: ['disabled']
409
- });
405
+ this.selectObserver.observe(this.select);
410
406
  }
411
407
 
412
408
  private _syncDisabledState() {