@kubex/zinc 1.1.161 → 1.1.163

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.
@@ -44,7 +44,7 @@ table {
44
44
  border-bottom: 1px solid rgb(var(--zn-border-color)) !important;
45
45
  }
46
46
 
47
- &.with-hover tbody tr.table__row--data:not(.table__row--selected):hover td {
47
+ &.with-hover tbody tr.table__row--data:hover td {
48
48
  background-color: rgba(var(--zn-primary), 0.05) !important;
49
49
  cursor: pointer;
50
50
  }
@@ -414,68 +414,24 @@ zn-menu::part(base) {
414
414
  background-color: rgb(var(--zn-panel, 255, 255, 255));
415
415
  }
416
416
 
417
- /* Table Select Styles */
418
- table tbody tr.table__row--selected {
419
- background-color: var(--zn-color-purple-100);
420
-
421
- &:hover {
422
- background-color: var(--zn-color-purple-200) !important;
423
- }
424
-
425
- td {
426
- border-top: 1px solid var(--zn-color-purple-600) !important;
427
- border-bottom: 1px solid var(--zn-color-purple-600) !important;
428
- }
429
-
430
- td:first-of-type {
431
- border-left: 1px solid var(--zn-color-purple-600);
432
- }
433
-
434
- td:last-of-type {
435
- border-right: 1px solid var(--zn-color-purple-600);
436
- }
437
-
438
- &:last-of-type td:first-of-type {
439
- border-bottom-left-radius: var(--zn-border-radius);
440
- }
441
-
442
- &:last-of-type td:last-of-type {
443
- border-bottom-right-radius: var(--zn-border-radius);
444
- }
445
-
446
- & + tr.table__row--selected td {
447
- border-top: 0 !important;
448
-
449
- &:first-of-type {
450
- border-top-left-radius: 0;
451
- }
452
-
453
- &:last-of-type {
454
- border-top-right-radius: 0;
455
- }
456
- }
457
-
458
- &:has(+ tr.table__row--selected) td {
459
- border-bottom: 0 !important;
460
- }
461
-
462
- &:first-of-type td {
463
- border-top: 0 !important;
464
- }
465
-
466
- &:has(+ tr.table__row--selected) {
467
- td:first-of-type {
468
- border-bottom-left-radius: 0;
469
- }
417
+ .table tr .table__head[tabindex]:focus-visible {
418
+ outline: var(--zn-focus-ring);
419
+ outline-offset: calc(-1 * var(--zn-focus-ring-width));
420
+ }
470
421
 
471
- td:last-of-type {
472
- border-bottom-right-radius: 0;
473
- }
474
- }
422
+ .table tr .table__head--checkbox,
423
+ .table tr .table__cell--checkbox {
424
+ width: 1px;
425
+ min-width: 0;
426
+ padding-right: 0;
475
427
  }
476
428
 
477
- table:has(tbody tr:first-of-type.table__row--selected) thead tr th {
478
- border-bottom-color: var(--zn-color-purple-600) !important;
429
+ // Visually hidden rather than display: none, which would stop a slotted zn-confirm's dialog rendering
430
+ .table__actions-source {
431
+ position: absolute;
432
+ width: 0;
433
+ height: 0;
434
+ overflow: hidden;
479
435
  }
480
436
 
481
437
  tbody tr.table__row--group th {
@@ -182,7 +182,7 @@ export default class ZnDropdown extends ZincElement {
182
182
  }
183
183
 
184
184
  private async handleTriggerKeyDown(event: KeyboardEvent) {
185
- if ([' ', 'Enter', 'Tab'].includes(event.key)) {
185
+ if ([' ', 'Enter'].includes(event.key)) {
186
186
  event.preventDefault();
187
187
  await this.handleTriggerClick();
188
188
  return;
@@ -252,9 +252,12 @@ export default class ZnDropdown extends ZincElement {
252
252
 
253
253
  if (event.key === 'Tab') {
254
254
  if (this.open) {
255
- event.preventDefault();
256
255
  this.hide().then(r => r);
257
- this.focusOnTrigger();
256
+ // Tabbing out of the menu resumes from the trigger; from the trigger, Tab moves on as usual
257
+ if (this.panel?.assignedElements({flatten: true}).some(el => el.matches(':focus-within'))) {
258
+ event.preventDefault();
259
+ this.focusOnTrigger();
260
+ }
258
261
  return;
259
262
  }
260
263
 
@@ -141,11 +141,34 @@
141
141
  }
142
142
  }
143
143
 
144
+ // Nothing visible to clip to, so leave room for the focus ring of a control sitting flush against the edge.
145
+ // The body scrolls, so it can't take a clip margin — it gets a gutter cancelled by a negative margin instead.
144
146
  &--transparent {
145
147
  .panel__header {
146
148
  padding-left: 0;
147
149
  padding-right: 0;
148
150
  }
151
+
152
+ .panel__inner,
153
+ .panel__content {
154
+ overflow: clip;
155
+ overflow-clip-margin: var(--zn-focus-ring-outset);
156
+ }
157
+
158
+ &.panel--flush .panel__body {
159
+ padding: var(--zn-focus-ring-outset);
160
+ margin: calc(var(--zn-focus-ring-outset) * -1);
161
+ }
162
+
163
+ &.panel--flush-x .panel__body {
164
+ padding-inline: var(--zn-focus-ring-outset);
165
+ margin-inline: calc(var(--zn-focus-ring-outset) * -1);
166
+ }
167
+
168
+ &.panel--flush-y .panel__body {
169
+ padding-block: var(--zn-focus-ring-outset);
170
+ margin-block: calc(var(--zn-focus-ring-outset) * -1);
171
+ }
149
172
  }
150
173
 
151
174
  &--cosmic {
@@ -386,6 +386,12 @@ export default class ZnPopup extends ZincElement {
386
386
  ? (element: Element) => platform.getOffsetParent(element, offsetParent)
387
387
  : platform.getOffsetParent;
388
388
 
389
+ // A closed popover has no size to measure, so it would first land on top of its anchor
390
+ if (this.popup.isConnected && !this.popup.matches(':popover-open')) {
391
+ this.popup.style.visibility = 'hidden';
392
+ this.popup.showPopover();
393
+ }
394
+
389
395
  computePosition(this.anchorEl, this.popup, {
390
396
  placement: this.placement,
391
397
  middleware,
@@ -402,7 +408,8 @@ export default class ZnPopup extends ZincElement {
402
408
 
403
409
  Object.assign(this.popup.style, {
404
410
  left: `${x}px`,
405
- top: `${y}px`
411
+ top: `${y}px`,
412
+ visibility: ''
406
413
  });
407
414
 
408
415
  if (!this.popup?.isConnected) return;
@@ -279,7 +279,8 @@ function renderConditionalParts(parts: ConditionalPart[]): TemplateResult {
279
279
  ${parts.map(part => {
280
280
  if (part.kind === 'nested') return renderConditionalWrapper(part.label, part.parts);
281
281
  const text = part.lines.join('\n').trim();
282
- return text ? html`<div class="remarkd-editor__rendered--parsed">${unsafeHTML(safeParse(text))}</div>` : '';
282
+ return text ? html`
283
+ <div class="remarkd-editor__rendered--parsed">${unsafeHTML(safeParse(text))}</div>` : '';
283
284
  })}
284
285
  </div>`;
285
286
  }
@@ -1232,7 +1233,7 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1232
1233
  fetch(url, {headers: {Accept: 'application/json'}})
1233
1234
  .then(res => {
1234
1235
  if (!res.ok) throw new Error(`link search failed: ${res.status}`);
1235
- return res.json() as Promise<{items?: LinkOption[]}>;
1236
+ return res.json() as Promise<{ items?: LinkOption[] }>;
1236
1237
  })
1237
1238
  .then(data => {
1238
1239
  if (token !== this.linkSearchToken) return;
@@ -1329,7 +1330,7 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1329
1330
  this.includeRequest = fetch(this.includeUrl, {headers: {Accept: 'application/json'}})
1330
1331
  .then(res => {
1331
1332
  if (!res.ok) throw new Error(`include list request failed: ${res.status}`);
1332
- return res.json() as Promise<{items?: IncludeOption[]}>;
1333
+ return res.json() as Promise<{ items?: IncludeOption[] }>;
1333
1334
  })
1334
1335
  .then(data => {
1335
1336
  const items = data.items ?? [];
@@ -1367,7 +1368,7 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1367
1368
  fetch(url, {headers: {Accept: 'application/json'}})
1368
1369
  .then(res => {
1369
1370
  if (!res.ok) throw new Error(`link resolve failed: ${res.status}`);
1370
- return res.json() as Promise<{items?: LinkOption[]}>;
1371
+ return res.json() as Promise<{ items?: LinkOption[] }>;
1371
1372
  })
1372
1373
  .then(data => {
1373
1374
  const known = new Map((data.items ?? []).map(item => [item.ref, item]));
@@ -1529,7 +1530,7 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1529
1530
  private renderImageControls() {
1530
1531
  const data = this.imageEdit;
1531
1532
  if (!data) return '';
1532
- const aligns: {value: ImageBlockData['align']; icon: string; label: string}[] = [
1533
+ const aligns: { value: ImageBlockData['align']; icon: string; label: string }[] = [
1533
1534
  {value: '', icon: 'align-left@lu', label: 'Align left'},
1534
1535
  {value: 'center', icon: 'align-center@lu', label: 'Align center'},
1535
1536
  {value: 'right', icon: 'align-right@lu', label: 'Align right'},
@@ -1558,7 +1559,8 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1558
1559
  <span>Alignment</span>
1559
1560
  <zn-button-group>
1560
1561
  ${aligns.map(align => html`
1561
- <zn-button type="button" icon-button="small" icon=${align.icon}
1562
+ <zn-button icon-button="small"
1563
+ icon=${align.icon}
1562
1564
  ?plain=${data.align !== align.value}
1563
1565
  tooltip=${align.label}
1564
1566
  @click=${() => this.updateImageEdit({align: align.value})}></zn-button>`)}
@@ -1581,12 +1583,15 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1581
1583
  </label>
1582
1584
  </div>
1583
1585
  <div class="remarkd-editor__image-buttons">
1584
- <zn-button type="button" color="primary" size="small" @click=${this.saveImageEdit}>Save</zn-button>
1585
- <zn-button type="button" color="secondary" size="small" @click=${this.closeImageEdit}>Cancel</zn-button>
1586
+ <zn-button color="primary" size="small" @click=${this.saveImageEdit}>Save</zn-button>
1587
+ <zn-button color="secondary" size="small" @click=${this.closeImageEdit}>Cancel</zn-button>
1586
1588
  <span class="remarkd-editor__image-buttons-spacer"></span>
1587
- <zn-button type="button" icon-button="small" plain icon="code@lu"
1588
- tooltip="Edit source" @click=${this.editImageSource}></zn-button>
1589
- <zn-button type="button" icon-button="small" plain icon="trash-2@lu" color="error"
1589
+ <zn-button icon-button="small"
1590
+ plain
1591
+ icon="code@lu"
1592
+ tooltip="Edit source"
1593
+ @click=${this.editImageSource}></zn-button>
1594
+ <zn-button icon-button="small" plain icon="trash-2@lu" color="error"
1590
1595
  tooltip="Delete image" @click=${this.deleteImageBlock}></zn-button>
1591
1596
  </div>
1592
1597
  </div>`;
@@ -1744,12 +1749,19 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1744
1749
  @pointerdown=${this.handleHandlePointerDown}>
1745
1750
  <zn-icon src="grip-vertical@lu" size="16"></zn-icon>
1746
1751
  </span>
1747
- <zn-button type="button" icon-button="small" plain icon="plus@lu" icon-size="16"
1752
+ <zn-button icon-button="small"
1753
+ plain
1754
+ icon="plus@lu"
1755
+ icon-size="16"
1748
1756
  tooltip="Add block below"
1749
1757
  @click=${() => this.insertDraftBlock(index + 1)}></zn-button>
1750
1758
  </div>
1751
1759
  <zn-button class="remarkd-editor__delete"
1752
- type="button" icon-button="small" plain icon="x@lu" icon-size="16" color="error"
1760
+ icon-button="small"
1761
+ plain
1762
+ icon="x@lu"
1763
+ icon-size="16"
1764
+ color="error"
1753
1765
  tooltip="Delete block"
1754
1766
  @click=${() => this.deleteBlock(index)}></zn-button>`}
1755
1767
  <div part="rendered"
@@ -1808,7 +1820,10 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1808
1820
  /** A single toolbar action button, shared by the toolbar bar and the overflow menu. */
1809
1821
  private renderAction(action: EditorAction) {
1810
1822
  return html`
1811
- <zn-button type="button" icon-button plain icon=${action.icon} icon-size="18"
1823
+ <zn-button icon-button="small"
1824
+ plain
1825
+ icon=${action.icon}
1826
+ icon-size="18"
1812
1827
  tooltip=${action.label}
1813
1828
  ?disabled=${this.isActionDisabled(action)}
1814
1829
  @mousedown=${(e: MouseEvent) => e.preventDefault()}
@@ -1869,8 +1884,12 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1869
1884
  // the textarea out from under it.
1870
1885
  if (!this.linkPickerOpen) this.suppressBlurCommit = false;
1871
1886
  }}>
1872
- <zn-button slot="trigger" type="button" icon-button plain icon="ellipsis@lu"
1873
- icon-size="18" tooltip="More"
1887
+ <zn-button slot="trigger"
1888
+ icon-button="small"
1889
+ plain
1890
+ icon="ellipsis@lu"
1891
+ icon-size="18"
1892
+ tooltip="More"
1874
1893
  @mousedown=${(e: MouseEvent) => e.preventDefault()}></zn-button>
1875
1894
  <zn-menu>
1876
1895
  ${overflowed.flatMap(entry => entry.actions).map(action => this.renderMenuAction(action))}
@@ -1878,8 +1897,11 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1878
1897
  </zn-dropdown>` : ''}`;
1879
1898
  })()}
1880
1899
  ${this.allowRaw ? html`
1881
- <zn-button part="raw-toggle" class="remarkd-editor__raw-toggle"
1882
- type="button" icon-button icon="code-xml@lu" icon-size="18"
1900
+ <zn-button part="raw-toggle"
1901
+ class="remarkd-editor__raw-toggle"
1902
+ icon-button="small"
1903
+ icon="code-xml@lu"
1904
+ icon-size="18"
1883
1905
  ?plain=${!this.rawMode}
1884
1906
  tooltip=${this.rawMode ? 'Show blocks' : 'Show raw source'}
1885
1907
  @click=${this.toggleRawMode}></zn-button>` : ''}
@@ -1944,12 +1966,17 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1944
1966
  @input=${(e: Event) => {
1945
1967
  this.includeQuery = (e.target as HTMLInputElement).value;
1946
1968
  }}>
1947
- <zn-button type="button" icon-button="small" plain icon="x@lu"
1948
- tooltip="Cancel" @click=${this.closeIncludePicker}></zn-button>
1969
+ <zn-button icon-button="small"
1970
+ plain
1971
+ icon="x@lu"
1972
+ tooltip="Cancel"
1973
+ @click=${this.closeIncludePicker}></zn-button>
1949
1974
  </div>
1950
1975
  ${this.includeOptions === null
1951
- ? html`<div class="remarkd-editor__include-picker-empty">${
1952
- this.includeLoadFailed ? 'Could not load Includes' : 'Loading…'}</div>`
1976
+ ? html`
1977
+ <div class="remarkd-editor__include-picker-empty">${
1978
+ this.includeLoadFailed ? 'Could not load Includes' : 'Loading…'}
1979
+ </div>`
1953
1980
  : items.length
1954
1981
  ? items.map(item => html`
1955
1982
  <button type="button" class="remarkd-editor__include-option"
@@ -1959,7 +1986,8 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1959
1986
  <span class="remarkd-editor__include-option-meta">${item.scope ?? ''}${
1960
1987
  item.languages ? ` · ${item.languages}` : ' · No content'}</span>
1961
1988
  </button>`)
1962
- : html`<div class="remarkd-editor__include-picker-empty">No Includes found</div>`}
1989
+ : html`
1990
+ <div class="remarkd-editor__include-picker-empty">No Includes found</div>`}
1963
1991
  </div>`;
1964
1992
  }
1965
1993
 
@@ -1975,12 +2003,17 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1975
2003
  this.linkQuery = (e.target as HTMLInputElement).value;
1976
2004
  this.searchLinks(this.linkQuery);
1977
2005
  }}>
1978
- <zn-button type="button" icon-button="small" plain icon="x@lu"
1979
- tooltip="Cancel" @click=${this.closeLinkPicker}></zn-button>
2006
+ <zn-button icon-button="small"
2007
+ plain
2008
+ icon="x@lu"
2009
+ tooltip="Cancel"
2010
+ @click=${this.closeLinkPicker}></zn-button>
1980
2011
  </div>
1981
2012
  ${this.linkResults === null
1982
- ? html`<div class="remarkd-editor__link-picker-empty">${
1983
- this.linkSearchFailed ? 'Could not search for articles' : 'Searching…'}</div>`
2013
+ ? html`
2014
+ <div class="remarkd-editor__link-picker-empty">${
2015
+ this.linkSearchFailed ? 'Could not search for articles' : 'Searching…'}
2016
+ </div>`
1984
2017
  : this.linkResults.length
1985
2018
  ? this.linkResults.map(item => html`
1986
2019
  <button type="button" class="remarkd-editor__link-option"
@@ -1990,7 +2023,8 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
1990
2023
  [kinds[item.kind] ?? item.kind, item.context, item.status === 'published' ? '' : item.status]
1991
2024
  .filter(Boolean).join(' · ')}</span>
1992
2025
  </button>`)
1993
- : html`<div class="remarkd-editor__link-picker-empty">No articles found</div>`}
2026
+ : html`
2027
+ <div class="remarkd-editor__link-picker-empty">No articles found</div>`}
1994
2028
  </div>`;
1995
2029
  }
1996
2030
 
@@ -2024,7 +2058,9 @@ export default class ZnRemarkdEditor extends ZincElement implements ZincFormCont
2024
2058
  accept="image/*"
2025
2059
  droparea
2026
2060
  @zn-change=${this.handleImagePicked}></zn-file>
2027
- <zn-button type="button" icon-button="small" plain icon="x@lu"
2061
+ <zn-button icon-button="small"
2062
+ plain
2063
+ icon="x@lu"
2028
2064
  tooltip="Cancel"
2029
2065
  @click=${this.closeImagePicker}></zn-button>
2030
2066
  </div>`;
@@ -191,6 +191,14 @@ export default class ZnTooltip extends ZincElement {
191
191
  waitForEvent(this, 'zn-after-hide');
192
192
  }
193
193
 
194
+ // The bubble renders inside its anchor's host (e.g. zn-button), so its clicks would reach the host's
195
+ // listeners. Anchor clicks target the slotted element, so only bubble clicks target the popup.
196
+ private handlePopupClick = (event: MouseEvent) => {
197
+ if (event.target === event.currentTarget) {
198
+ event.stopPropagation();
199
+ }
200
+ };
201
+
194
202
  render() {
195
203
  return html`
196
204
  <zn-popup
@@ -207,7 +215,8 @@ export default class ZnTooltip extends ZincElement {
207
215
  flip
208
216
  shift
209
217
  arrow
210
- hover-bridge>
218
+ hover-bridge
219
+ @click="${this.handlePopupClick}">
211
220
  <slot slot="anchor"></slot>
212
221
  <div part="body" id="tooltip" class="tooltip__body"
213
222
  role="tooltip"
@@ -9,6 +9,11 @@
9
9
  --arrow-size: 6px;
10
10
  }
11
11
 
12
+ .tooltip::part(popup),
13
+ .tooltip::part(hover-bridge) {
14
+ cursor: default;
15
+ }
16
+
12
17
  .tooltip[placement^='top']::part(popup) {
13
18
  transform-origin: bottom;
14
19
  }