@kubex/zinc 1.0.115 → 1.0.117
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/dist/custom-elements.json +476 -287
- package/dist/vscode.html-custom-data.json +52 -52
- package/dist/web-types.json +116 -86
- package/dist/zn.d.ts +63 -11
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +1096 -1087
- package/docs/_includes/default.njk +3 -4
- package/docs/assets/styles/docs.css +13 -13
- package/docs/pages/components/absolute-container.md +2 -2
- package/docs/pages/components/alert.md +5 -5
- package/docs/pages/components/audio-select.md +4 -4
- package/docs/pages/components/button-group.md +1 -31
- package/docs/pages/components/button.md +13 -12
- package/docs/pages/components/checkbox.md +4 -4
- package/docs/pages/components/chip.md +14 -14
- package/docs/pages/components/data-table.md +4 -4
- package/docs/pages/components/datepicker.md +5 -5
- package/docs/pages/components/dialog.md +2 -2
- package/docs/pages/components/file.md +81 -9
- package/docs/pages/components/header.md +4 -6
- package/docs/pages/components/hover-container.md +1 -1
- package/docs/pages/components/icon.md +14 -0
- package/docs/pages/components/inline-edit.md +4 -4
- package/docs/pages/components/item.md +2 -2
- package/docs/pages/components/menu.md +2 -2
- package/docs/pages/components/note.md +12 -12
- package/docs/pages/components/page.md +3 -3
- package/docs/pages/components/pagination.md +6 -6
- package/docs/pages/components/pane.md +3 -6
- package/docs/pages/components/panel.md +10 -12
- package/docs/pages/components/priority-list.md +3 -3
- package/docs/pages/components/radio-group.md +4 -4
- package/docs/pages/components/radio.md +4 -4
- package/docs/pages/components/scroll-container.md +10 -10
- package/docs/pages/components/select.md +5 -5
- package/docs/pages/components/split-button.md +4 -4
- package/docs/pages/components/tabs.md +3 -3
- package/docs/pages/components/tile.md +13 -13
- package/docs/pages/components/toggle.md +4 -4
- package/docs/pages/components/translations.md +5 -5
- package/docs/pages/components/vertical-stepper.md +3 -3
- package/docs/pages/components/well.md +19 -19
- package/docs/pages/getting-started/example-layout.md +16 -16
- package/docs/pages/getting-started/example-page.md +1 -3
- package/package.json +2 -1
- package/scss/_root.scss +87 -60
- package/scss/shared/_button.scss +6 -1
- package/scss/shared/_form-elements.scss +1 -0
- package/scss/shared/_table.scss +1 -1
- package/scss/shared/layout.scss +5 -4
- package/scss/themes/_dark.scss +4 -4
- package/scss/themes/_light.scss +70 -287
- package/src/components/bulk-actions/bulk-actions.component.ts +0 -1
- package/src/components/button/button.component.ts +40 -10
- package/src/components/button/button.scss +67 -103
- package/src/components/button-menu/button-menu.component.ts +2 -6
- package/src/components/collapsible/collapsible.scss +1 -1
- package/src/components/cols/cols.scss +1 -1
- package/src/components/content-block/content-block.component.ts +1 -2
- package/src/components/data-table/data-table.component.ts +4 -8
- package/src/components/data-table/data-table.test.ts +7 -0
- package/src/components/data-table-filter/data-table-filter.component.ts +1 -1
- package/src/components/data-table-sort/data-table-sort.component.ts +2 -2
- package/src/components/dialog/dialog.component.ts +0 -1
- package/src/components/editor/modules/dialog/dialog.component.ts +0 -1
- package/src/components/editor/modules/dialog/dialog.scss +1 -1
- package/src/components/editor/modules/toolbar/toolbar.component.ts +0 -1
- package/src/components/expanding-action/expanding-action.component.ts +0 -3
- package/src/components/expanding-action/expanding-action.scss +0 -5
- package/src/components/file/file.component.ts +158 -17
- package/src/components/file/file.scss +122 -29
- package/src/components/header/header.component.ts +2 -8
- package/src/components/header/header.scss +4 -25
- package/src/components/icon/icon.component.ts +80 -1
- package/src/components/icon/icon.scss +8 -0
- package/src/components/icon/icon.test.ts +24 -0
- package/src/components/icon-picker/icon-picker.component.ts +0 -1
- package/src/components/inline-edit/inline-edit.component.ts +3 -4
- package/src/components/input/input.scss +21 -6
- package/src/components/input-group/input-group.scss +2 -1
- package/src/components/markdown-editor/markdown-editor.component.ts +1 -5
- package/src/components/menu/menu.scss +1 -1
- package/src/components/menu-item/menu-item.scss +4 -4
- package/src/components/navbar/navbar.component.ts +20 -0
- package/src/components/navbar/navbar.scss +31 -17
- package/src/components/navbar/navbar.test.ts +72 -0
- package/src/components/note/note.component.ts +0 -1
- package/src/components/page/page.component.ts +43 -12
- package/src/components/page/page.scss +21 -17
- package/src/components/page/page.test.ts +18 -1
- package/src/components/page-nav/page-nav.scss +6 -6
- package/src/components/panel/panel.component.ts +3 -5
- package/src/components/panel/panel.scss +3 -3
- package/src/components/panel/panel.test.ts +14 -0
- package/src/components/query-builder/query-builder.component.ts +0 -1
- package/src/components/slideout/slideout.component.ts +0 -1
- package/src/components/sp/sp.scss +2 -2
- package/src/components/tab/tab.component.ts +2 -0
- package/src/components/tabs/tabs.component.ts +1 -1
- package/src/components/tile/tile.scss +1 -1
- package/src/components/translation-group/translation-group.component.ts +0 -3
- package/src/components/translations/translations.component.ts +0 -3
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import {choose} from 'lit/directives/choose.js';
|
|
2
2
|
import {classMap} from "lit/directives/class-map.js";
|
|
3
3
|
import {type CSSResultGroup, html, render, unsafeCSS} from 'lit';
|
|
4
|
+
import {icons} from 'lucide';
|
|
4
5
|
import {property} from 'lit/decorators.js';
|
|
5
6
|
import {sha256} from '../../utilities/sha256';
|
|
6
7
|
import {styleMap} from "lit/directives/style-map.js";
|
|
8
|
+
import {unsafeSVG} from 'lit/directives/unsafe-svg.js';
|
|
7
9
|
import ZincElement from '../../internal/zinc-element';
|
|
10
|
+
import type {IconNode, SVGProps} from 'lucide';
|
|
8
11
|
|
|
9
12
|
import styles from './icon.scss';
|
|
10
13
|
|
|
11
14
|
type IconLibrary = "src" | "material" | "material-outlined" | "material-round" | "material-sharp" |
|
|
12
|
-
"material-two-tone" | "material-symbols-outlined" | "gravatar" | "libravatar" | "avatar" | "brands" | "line"
|
|
15
|
+
"material-two-tone" | "material-symbols-outlined" | "gravatar" | "libravatar" | "avatar" | "brands" | "line" |
|
|
16
|
+
"lucide";
|
|
13
17
|
|
|
14
18
|
export type IconColor =
|
|
15
19
|
"default"
|
|
@@ -116,6 +120,9 @@ export default class ZnIcon extends ZincElement {
|
|
|
116
120
|
return "avatar";
|
|
117
121
|
case "line":
|
|
118
122
|
return "line";
|
|
123
|
+
case "lucide":
|
|
124
|
+
case "lu":
|
|
125
|
+
return "lucide";
|
|
119
126
|
case 'brand':
|
|
120
127
|
case 'brands':
|
|
121
128
|
return "brands";
|
|
@@ -251,6 +258,7 @@ export default class ZnIcon extends ZincElement {
|
|
|
251
258
|
["material-two-tone", () => html`<i part="icon" class="mi mi--two-tone">${this.src}</i>`],
|
|
252
259
|
["brands", () => html`<i part="icon" class="kb">${this.src}</i>`],
|
|
253
260
|
["line", () => html`<i part="icon" class="lni lni-${this.src}"></i>`],
|
|
261
|
+
["lucide", () => this.renderLucideIcon()],
|
|
254
262
|
["material-symbols-outlined", () => html`<i part="icon" class="mi mi--symbol-outlined">${this.src}</i>`],
|
|
255
263
|
["gravatar", () => html`<img part="icon" alt="${this.alt}"
|
|
256
264
|
src="https://www.gravatar.com/avatar/${this.src}?s=${this.size}${this.gravatarOptions}"/>`],
|
|
@@ -285,6 +293,77 @@ export default class ZnIcon extends ZincElement {
|
|
|
285
293
|
return avatar.slice(0, 2).toUpperCase()
|
|
286
294
|
}
|
|
287
295
|
|
|
296
|
+
private renderLucideIcon() {
|
|
297
|
+
const icon = this.getLucideIcon(this.src);
|
|
298
|
+
|
|
299
|
+
if (!icon) {
|
|
300
|
+
return html`Icon not found: ${this.src ?? ''}`;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return unsafeSVG(this.getLucideSvg(icon));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private getLucideIcon(src = ''): IconNode | undefined {
|
|
307
|
+
if (!src) {
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const candidates = [src, this.toPascalCase(src)];
|
|
312
|
+
const iconSet = icons as Record<string, IconNode>;
|
|
313
|
+
|
|
314
|
+
for (const candidate of candidates) {
|
|
315
|
+
if (Object.prototype.hasOwnProperty.call(iconSet, candidate)) {
|
|
316
|
+
return iconSet[candidate];
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private toPascalCase(input: string) {
|
|
324
|
+
return input
|
|
325
|
+
.split(/[-_\s]+/)
|
|
326
|
+
.filter(Boolean)
|
|
327
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
328
|
+
.join('');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private getLucideSvg(icon: IconNode) {
|
|
332
|
+
const children = icon
|
|
333
|
+
.map(([tag, attrs]) => `<${tag}${this.getSvgAttributes(attrs)} />`)
|
|
334
|
+
.join('');
|
|
335
|
+
|
|
336
|
+
return `
|
|
337
|
+
<svg
|
|
338
|
+
part="icon"
|
|
339
|
+
class="lucide"
|
|
340
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
341
|
+
viewBox="0 0 24 24"
|
|
342
|
+
fill="none"
|
|
343
|
+
stroke="currentColor"
|
|
344
|
+
stroke-width="2"
|
|
345
|
+
stroke-linecap="round"
|
|
346
|
+
stroke-linejoin="round"
|
|
347
|
+
aria-hidden="true"
|
|
348
|
+
>${children}</svg>
|
|
349
|
+
`;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private getSvgAttributes(attrs: SVGProps) {
|
|
353
|
+
return Object.entries(attrs)
|
|
354
|
+
.filter(([, value]) => value !== undefined)
|
|
355
|
+
.map(([name, value]) => ` ${name}="${this.escapeSvgAttribute(String(value))}"`)
|
|
356
|
+
.join('');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
private escapeSvgAttribute(value: string) {
|
|
360
|
+
return value
|
|
361
|
+
.replace(/&/g, '&')
|
|
362
|
+
.replace(/"/g, '"')
|
|
363
|
+
.replace(/</g, '<')
|
|
364
|
+
.replace(/>/g, '>');
|
|
365
|
+
}
|
|
366
|
+
|
|
288
367
|
|
|
289
368
|
protected getColorForAvatar(avatarInitials: string) {
|
|
290
369
|
const colors = [
|
|
@@ -219,6 +219,14 @@
|
|
|
219
219
|
-webkit-font-smoothing: antialiased;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
.lucide {
|
|
223
|
+
display: block;
|
|
224
|
+
width: 100%;
|
|
225
|
+
height: 100%;
|
|
226
|
+
color: currentColor;
|
|
227
|
+
stroke: currentColor;
|
|
228
|
+
}
|
|
229
|
+
|
|
222
230
|
img {
|
|
223
231
|
max-width: 100%;
|
|
224
232
|
vertical-align: middle;
|
|
@@ -30,4 +30,28 @@ describe('<zn-icon>', () => {
|
|
|
30
30
|
'https://seccdn.libravatar.org/avatar/04e8703fcfb60849fb5c596abc8f3d7547c7e0099c3806a3ffec77a95dc02e25?s=48&d=identicon'
|
|
31
31
|
);
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
it('should render Lucide icons as inline SVGs', async () => {
|
|
35
|
+
const el = await fixture<ZnIcon>(html`
|
|
36
|
+
<zn-icon src="cloud-upload" library="lucide" size="48"></zn-icon>
|
|
37
|
+
`);
|
|
38
|
+
|
|
39
|
+
const svg = el.shadowRoot?.querySelector('svg.lucide');
|
|
40
|
+
|
|
41
|
+
expect(svg).to.exist;
|
|
42
|
+
expect(svg?.getAttribute('part')).to.equal('icon');
|
|
43
|
+
expect(svg?.querySelectorAll('path').length).to.be.greaterThan(0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should support Lucide shorthand notation', async () => {
|
|
47
|
+
const el = await fixture<ZnIcon>(html`
|
|
48
|
+
<zn-icon src="circle-alert@lu" size="48"></zn-icon>
|
|
49
|
+
`);
|
|
50
|
+
|
|
51
|
+
const svg = el.shadowRoot?.querySelector('svg.lucide');
|
|
52
|
+
|
|
53
|
+
expect(el.library).to.equal('lucide');
|
|
54
|
+
expect(el.src).to.equal('circle-alert');
|
|
55
|
+
expect(svg).to.exist;
|
|
56
|
+
});
|
|
33
57
|
});
|
|
@@ -261,7 +261,6 @@ export default class ZnIconPicker extends ZincElement implements ZincFormControl
|
|
|
261
261
|
<span class="icon-picker__edit-text">Click to edit</span>
|
|
262
262
|
<zn-button
|
|
263
263
|
class="icon-picker__clear"
|
|
264
|
-
size="x-small"
|
|
265
264
|
color="transparent"
|
|
266
265
|
icon="close"
|
|
267
266
|
icon-size="16"
|
|
@@ -362,20 +362,19 @@ export default class ZnInlineEdit extends ZincElement implements ZincFormControl
|
|
|
362
362
|
${!this.isEditing ?
|
|
363
363
|
html`
|
|
364
364
|
${hasEditText ? html`
|
|
365
|
-
<zn-button @click="${this.disabled ? undefined : this.handleEditClick}"
|
|
365
|
+
<zn-button @click="${this.disabled ? undefined : this.handleEditClick}"
|
|
366
366
|
color="secondary">
|
|
367
367
|
${this.editText}
|
|
368
368
|
</zn-button>` : html`
|
|
369
369
|
<zn-button @click="${this.disabled ? undefined : this.handleEditClick}"
|
|
370
370
|
class="button--edit"
|
|
371
371
|
icon="edit"
|
|
372
|
-
size="x-small"
|
|
373
372
|
icon-size="20"
|
|
374
373
|
color="secondary"></zn-button>`}` :
|
|
375
374
|
html`
|
|
376
|
-
<zn-button type="submit" @click="${this.handleSubmitClick}" icon="check"
|
|
375
|
+
<zn-button type="submit" @click="${this.handleSubmitClick}" icon="check" icon-size="20"
|
|
377
376
|
color="secondary"></zn-button>
|
|
378
|
-
<zn-button type="button" @click="${this.handleCancelClick}" icon="close"
|
|
377
|
+
<zn-button type="button" @click="${this.handleCancelClick}" icon="close" icon-size="20"
|
|
379
378
|
color="secondary"></zn-button>`}
|
|
380
379
|
</div>
|
|
381
380
|
</div>
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
margin: 0;
|
|
92
92
|
cursor: inherit;
|
|
93
93
|
-webkit-appearance: none;
|
|
94
|
+
line-height: 24px;
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
/* Color input text should use monospace font */
|
|
@@ -176,7 +177,7 @@ input[type='text'].input__control[data-color-input] {
|
|
|
176
177
|
|
|
177
178
|
.input--x-small .input__prefix ::slotted(*),
|
|
178
179
|
.input__prefix-default {
|
|
179
|
-
margin-inline-start: var(--zn-
|
|
180
|
+
margin-inline-start: var(--zn-spacing-x-small);
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
.input--x-small .input__suffix ::slotted(*),
|
|
@@ -244,12 +245,12 @@ input[type='text'].input__control[data-color-input] {
|
|
|
244
245
|
|
|
245
246
|
.input--medium .input__prefix ::slotted(*),
|
|
246
247
|
.input__prefix-default {
|
|
247
|
-
margin-inline-start: var(--zn-
|
|
248
|
+
margin-inline-start: var(--zn-spacing-small);
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
.input--medium .input__suffix ::slotted(*),
|
|
251
252
|
.input__suffix-default {
|
|
252
|
-
margin-inline-end: var(--zn-
|
|
253
|
+
margin-inline-end: var(--zn-spacing-small);
|
|
253
254
|
}
|
|
254
255
|
|
|
255
256
|
.input--medium .input__suffix ::slotted(zn-button),
|
|
@@ -260,6 +261,20 @@ input[type='text'].input__control[data-color-input] {
|
|
|
260
261
|
margin-inline-start: 0;
|
|
261
262
|
}
|
|
262
263
|
|
|
264
|
+
.input__suffix ::slotted(zn-button),
|
|
265
|
+
.input__prefix ::slotted(zn-button) {
|
|
266
|
+
--zn-button-border-color: rgb(var(--zn-color-border));
|
|
267
|
+
--zn-button-border-width: 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.input__suffix ::slotted(zn-button) {
|
|
271
|
+
--zn-button-border-left-width: 1px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.input__prefix ::slotted(zn-button) {
|
|
275
|
+
--zn-button-border-right-width: 1px;
|
|
276
|
+
}
|
|
277
|
+
|
|
263
278
|
.input--large {
|
|
264
279
|
border-radius: var(--zn-input-border-radius-large);
|
|
265
280
|
font-size: var(--zn-input-font-size-large);
|
|
@@ -398,15 +413,15 @@ input[type='date']::-webkit-calendar-picker-indicator {
|
|
|
398
413
|
}
|
|
399
414
|
|
|
400
415
|
.input--small .input__color-swatch {
|
|
401
|
-
margin-inline-start: var(--zn-
|
|
416
|
+
margin-inline-start: var(--zn-spacing-x2-small);
|
|
402
417
|
}
|
|
403
418
|
|
|
404
419
|
.input--medium .input__color-swatch {
|
|
405
|
-
margin-inline-start: var(--zn-
|
|
420
|
+
margin-inline-start: var(--zn-spacing-x-small);
|
|
406
421
|
}
|
|
407
422
|
|
|
408
423
|
.input--large .input__color-swatch {
|
|
409
|
-
margin-inline-start: var(--zn-
|
|
424
|
+
margin-inline-start: var(--zn-spacing-small);
|
|
410
425
|
}
|
|
411
426
|
|
|
412
427
|
.input__color-swatch-inner {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
flex-wrap: nowrap;
|
|
11
11
|
align-items: center;
|
|
12
12
|
width: 100%;
|
|
13
|
+
gap: var(--zn-spacing-small);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
/* Gap variants */
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
/* Button overrides - don't join to other inputs */
|
|
90
91
|
::slotted(zn-button[data-zn-input-group__input]) {
|
|
91
92
|
flex: 0 0 auto;
|
|
92
|
-
margin-inline-start:
|
|
93
|
+
margin-inline-start: 0;
|
|
93
94
|
margin-inline-end: 0;
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -3,7 +3,6 @@ import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
|
3
3
|
import {defaultValue} from "../../internal/default-value";
|
|
4
4
|
import {FormControlController} from "../../internal/form";
|
|
5
5
|
import {HasSlotController} from "../../internal/slot";
|
|
6
|
-
import {ifDefined} from "lit/directives/if-defined.js";
|
|
7
6
|
import {marked} from "marked";
|
|
8
7
|
import {property, query} from 'lit/decorators.js';
|
|
9
8
|
import {watch} from "../../internal/watch";
|
|
@@ -275,11 +274,10 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
|
|
|
275
274
|
${hasHeader ? html`
|
|
276
275
|
<zn-header class=${classMap({
|
|
277
276
|
panel__header: true,
|
|
278
|
-
'panel__header--underline': this.
|
|
277
|
+
'panel__header--underline': !this.headerBorderless,
|
|
279
278
|
})}
|
|
280
279
|
icon=${this.icon}
|
|
281
280
|
caption=${this.caption}
|
|
282
|
-
description=${ifDefined(this.description)}
|
|
283
281
|
transparent>
|
|
284
282
|
${hasActionSlot ? html`
|
|
285
283
|
<slot name="actions" slot="actions" class="panel__header__actions"></slot>` : null}
|
|
@@ -306,7 +304,6 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
|
|
|
306
304
|
<zn-button
|
|
307
305
|
class="markdown-editor__expand-btn"
|
|
308
306
|
type="button"
|
|
309
|
-
size="medium"
|
|
310
307
|
color="secondary"
|
|
311
308
|
icon=${this.expanded ? 'close_fullscreen' : 'open_in_full'}
|
|
312
309
|
icon-size="18"
|
|
@@ -379,7 +376,6 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
|
|
|
379
376
|
})}
|
|
380
377
|
data-mode=${mode}
|
|
381
378
|
type="button"
|
|
382
|
-
size="medium"
|
|
383
379
|
color="default"
|
|
384
380
|
?outline=${!isActive}
|
|
385
381
|
square
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
--submenu-offset: -2px;
|
|
5
5
|
--color: rgba(var(--zn-text), var(--zn-text-opacity));
|
|
6
6
|
--hover-color: rgb(var(--zn-primary));
|
|
7
|
-
--hover-bg: rgba(var(--zn-
|
|
7
|
+
--hover-bg: rgba(var(--zn-color-navigation-highlight), var(--zn-panel-highlight-opacity));
|
|
8
8
|
display: block;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -154,9 +154,9 @@
|
|
|
154
154
|
bottom: 0;
|
|
155
155
|
left: 0;
|
|
156
156
|
clip-path: polygon(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
var(--safe-triangle-cursor-x, 0) var(--safe-triangle-cursor-y, 0),
|
|
158
|
+
var(--safe-triangle-submenu-start-x, 0) var(--safe-triangle-submenu-start-y, 0),
|
|
159
|
+
var(--safe-triangle-submenu-end-x, 0) var(--safe-triangle-submenu-end-y, 0)
|
|
160
160
|
);
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -253,6 +253,24 @@ export default class ZnNavbar extends ZincElement {
|
|
|
253
253
|
return moreWidth;
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
private _syncLastVisibleItem() {
|
|
257
|
+
const items = this._navItems?.querySelectorAll<HTMLElement>(':scope > li') || [];
|
|
258
|
+
let lastVisibleItem: HTMLElement | null = null;
|
|
259
|
+
|
|
260
|
+
for (const item of items) {
|
|
261
|
+
item.classList.remove('last-visible');
|
|
262
|
+
|
|
263
|
+
if (item.classList.contains('more') || item.classList.contains('hidden') || item.id === 'dropdown-item') {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
lastVisibleItem = item;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
lastVisibleItem?.classList.add('last-visible');
|
|
271
|
+
this._navItems?.classList.toggle('more-only', !lastVisibleItem && this._navItems.classList.contains('has-hidden'));
|
|
272
|
+
}
|
|
273
|
+
|
|
256
274
|
private _getExpandableWidth(containerWidth: number): number {
|
|
257
275
|
const expandableWidth = this._expandableMargin + (this._expandable?.getBoundingClientRect().width || this._expandable?.offsetWidth || 0);
|
|
258
276
|
let fillWidth = 0;
|
|
@@ -298,6 +316,7 @@ export default class ZnNavbar extends ZincElement {
|
|
|
298
316
|
|
|
299
317
|
if (!hasHidden && this._totalItemWidth <= availableWithoutMore) {
|
|
300
318
|
this._navItems?.classList.toggle('has-hidden', false)
|
|
319
|
+
this._syncLastVisibleItem();
|
|
301
320
|
return
|
|
302
321
|
}
|
|
303
322
|
|
|
@@ -331,6 +350,7 @@ export default class ZnNavbar extends ZincElement {
|
|
|
331
350
|
}
|
|
332
351
|
}
|
|
333
352
|
this._navItems?.classList.toggle('has-hidden', hasHidden && hideRemaining)
|
|
353
|
+
this._syncLastVisibleItem();
|
|
334
354
|
}
|
|
335
355
|
|
|
336
356
|
// Clones in the extended menu are static snapshots, so mirror the active
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
ul.navbar {
|
|
8
8
|
padding: 0;
|
|
9
|
-
margin: 0
|
|
9
|
+
margin: 0 var(--zn-base-gap);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
:host:not([stacked]) .navbar {
|
|
71
|
-
margin: 0 0 0 var(--zn-
|
|
71
|
+
margin: 0 0 0 var(--zn-base-gap);
|
|
72
72
|
padding-left: 0;
|
|
73
73
|
|
|
74
74
|
&--flush {
|
|
@@ -81,6 +81,7 @@ ul.navbar {
|
|
|
81
81
|
padding-top: 0;
|
|
82
82
|
font-size: var(--zn-font-size-medium);
|
|
83
83
|
white-space: nowrap;
|
|
84
|
+
color: rgb(var(--zn-color-muted-text));
|
|
84
85
|
|
|
85
86
|
a {
|
|
86
87
|
text-decoration: none;
|
|
@@ -117,7 +118,7 @@ ul.navbar {
|
|
|
117
118
|
|
|
118
119
|
li {
|
|
119
120
|
border-bottom: 1px solid rgb(var(--zn-border-color));
|
|
120
|
-
padding: var(--zn-
|
|
121
|
+
padding: var(--zn-base-px);
|
|
121
122
|
|
|
122
123
|
&.active:before, &.zn-tb-active:before {
|
|
123
124
|
display: none;
|
|
@@ -133,12 +134,6 @@ ul.navbar {
|
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
&--slim {
|
|
137
|
-
li {
|
|
138
|
-
padding: var(--zn-spacing-small);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
137
|
}
|
|
143
138
|
}
|
|
144
139
|
|
|
@@ -147,8 +142,6 @@ ul.navbar {
|
|
|
147
142
|
&--border {
|
|
148
143
|
border-right: 1px solid rgb(var(--zn-border-color));
|
|
149
144
|
}
|
|
150
|
-
|
|
151
|
-
//margin-right: var(--zn-spacing-medium);
|
|
152
145
|
}
|
|
153
146
|
}
|
|
154
147
|
|
|
@@ -157,8 +150,6 @@ ul.navbar {
|
|
|
157
150
|
&--border {
|
|
158
151
|
border-left: 1px solid rgb(var(--zn-border-color));
|
|
159
152
|
}
|
|
160
|
-
|
|
161
|
-
// margin-left: var(--zn-spacing-medium);
|
|
162
153
|
}
|
|
163
154
|
}
|
|
164
155
|
|
|
@@ -253,12 +244,27 @@ ul.navbar.navbar--stacked.navbar--icon-bar {
|
|
|
253
244
|
|
|
254
245
|
&:first-of-type {
|
|
255
246
|
border-left-width: 1px;
|
|
247
|
+
border-top-left-radius: 6px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
&:last-of-type {
|
|
251
|
+
border-top-right-radius: 6px;
|
|
256
252
|
}
|
|
257
253
|
|
|
258
254
|
&.active, &.zn-tb-active {
|
|
255
|
+
color: rgb(var(--zn-color-text));
|
|
259
256
|
border-bottom: 1px solid rgb(var(--navbar-active-colour));
|
|
260
257
|
}
|
|
261
258
|
}
|
|
259
|
+
|
|
260
|
+
&:not(.has-hidden) > li.last-visible {
|
|
261
|
+
border-top-right-radius: 6px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
&.more-only > li.more {
|
|
265
|
+
border-left-width: 1px;
|
|
266
|
+
border-top-left-radius: 6px;
|
|
267
|
+
}
|
|
262
268
|
}
|
|
263
269
|
}
|
|
264
270
|
|
|
@@ -299,13 +305,21 @@ ul.navbar.navbar--stacked.navbar--icon-bar {
|
|
|
299
305
|
|
|
300
306
|
user-select: none;
|
|
301
307
|
font-weight: 500;
|
|
302
|
-
padding: 0 calc(var(--zn-base-
|
|
303
|
-
background:
|
|
308
|
+
padding: 0 calc(var(--zn-base-px, 8px) * 2);
|
|
309
|
+
background: rgb(var(--zn-color-tab));
|
|
304
310
|
transition: background-color 100ms ease-in-out;
|
|
305
311
|
position: relative;
|
|
306
312
|
|
|
307
313
|
&:hover {
|
|
308
|
-
background: rgba(
|
|
314
|
+
background: rgba(var(--zn-color-tab), 0.5);
|
|
315
|
+
|
|
316
|
+
&::after {
|
|
317
|
+
content: "";
|
|
318
|
+
position: absolute;
|
|
319
|
+
inset: 0;
|
|
320
|
+
background: rgb(var(--navbar-active-colour));
|
|
321
|
+
z-index: -1;
|
|
322
|
+
}
|
|
309
323
|
}
|
|
310
324
|
|
|
311
325
|
display: flex;
|
|
@@ -483,7 +497,7 @@ button[popovertarget] {
|
|
|
483
497
|
display: flex;
|
|
484
498
|
align-items: center;
|
|
485
499
|
width: fit-content;
|
|
486
|
-
height:
|
|
500
|
+
height: 40px;
|
|
487
501
|
gap: var(--zn-spacing-2x-small);
|
|
488
502
|
padding-right: calc(var(--zn-gutter, 0) + var(--zn-base-gap, 0));
|
|
489
503
|
}
|
|
@@ -119,6 +119,78 @@ describe('<zn-navbar>', () => {
|
|
|
119
119
|
expect(nav.classList.contains('has-hidden')).to.equal(true);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
+
it('rounds the last visible nav item when items are hidden behind more', async () => {
|
|
123
|
+
const el = await fixture<ZnNavbar>(html`
|
|
124
|
+
<zn-navbar>
|
|
125
|
+
<li>One</li>
|
|
126
|
+
<li>Two</li>
|
|
127
|
+
<li>Three</li>
|
|
128
|
+
</zn-navbar>
|
|
129
|
+
`);
|
|
130
|
+
await aTimeout(150);
|
|
131
|
+
|
|
132
|
+
const nav = el.shadowRoot!.querySelector<HTMLElement>('ul.navbar')!;
|
|
133
|
+
const more = nav.querySelector<HTMLElement>(':scope > li.more')!;
|
|
134
|
+
const items = Array.from(nav.querySelectorAll<HTMLElement>(':scope > li:not(.more)'));
|
|
135
|
+
|
|
136
|
+
Object.defineProperty(el, 'offsetWidth', {configurable: true, get: () => 250});
|
|
137
|
+
Object.defineProperty(more, 'offsetWidth', {configurable: true, get: () => 60});
|
|
138
|
+
Object.defineProperty(more, 'getBoundingClientRect', {
|
|
139
|
+
configurable: true,
|
|
140
|
+
value: () => ({width: 60})
|
|
141
|
+
});
|
|
142
|
+
items.forEach(item => {
|
|
143
|
+
Object.defineProperty(item, 'offsetWidth', {configurable: true, get: () => 100});
|
|
144
|
+
Object.defineProperty(item, 'getBoundingClientRect', {
|
|
145
|
+
configurable: true,
|
|
146
|
+
value: () => ({width: 100})
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
el.handleResize();
|
|
151
|
+
|
|
152
|
+
expect(nav.classList.contains('has-hidden')).to.equal(true);
|
|
153
|
+
expect(items[0].classList.contains('last-visible')).to.equal(true);
|
|
154
|
+
expect(items[1].classList.contains('hidden')).to.equal(true);
|
|
155
|
+
expect(getComputedStyle(items[0]).borderTopRightRadius).to.equal('6px');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('keeps the left border when only the more button is visible', async () => {
|
|
159
|
+
const el = await fixture<ZnNavbar>(html`
|
|
160
|
+
<zn-navbar>
|
|
161
|
+
<li>One</li>
|
|
162
|
+
<li>Two</li>
|
|
163
|
+
</zn-navbar>
|
|
164
|
+
`);
|
|
165
|
+
await aTimeout(150);
|
|
166
|
+
|
|
167
|
+
const nav = el.shadowRoot!.querySelector<HTMLElement>('ul.navbar')!;
|
|
168
|
+
const more = nav.querySelector<HTMLElement>(':scope > li.more')!;
|
|
169
|
+
const items = Array.from(nav.querySelectorAll<HTMLElement>(':scope > li:not(.more)'));
|
|
170
|
+
|
|
171
|
+
Object.defineProperty(el, 'offsetWidth', {configurable: true, get: () => 100});
|
|
172
|
+
Object.defineProperty(more, 'offsetWidth', {configurable: true, get: () => 60});
|
|
173
|
+
Object.defineProperty(more, 'getBoundingClientRect', {
|
|
174
|
+
configurable: true,
|
|
175
|
+
value: () => ({width: 60})
|
|
176
|
+
});
|
|
177
|
+
items.forEach(item => {
|
|
178
|
+
Object.defineProperty(item, 'offsetWidth', {configurable: true, get: () => 150});
|
|
179
|
+
Object.defineProperty(item, 'getBoundingClientRect', {
|
|
180
|
+
configurable: true,
|
|
181
|
+
value: () => ({width: 150})
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
el.handleResize();
|
|
186
|
+
|
|
187
|
+
expect(nav.classList.contains('has-hidden')).to.equal(true);
|
|
188
|
+
expect(nav.classList.contains('more-only')).to.equal(true);
|
|
189
|
+
expect(items.every(item => item.classList.contains('hidden'))).to.equal(true);
|
|
190
|
+
expect(getComputedStyle(more).borderLeftWidth).to.equal('1px');
|
|
191
|
+
expect(getComputedStyle(more).borderTopLeftRadius).to.equal('6px');
|
|
192
|
+
});
|
|
193
|
+
|
|
122
194
|
describe('hide-one', () => {
|
|
123
195
|
it('hides when only one item is present', async () => {
|
|
124
196
|
const el = await fixture<ZnNavbar>(html`
|
|
@@ -81,7 +81,6 @@ export default class ZnNote extends ZincElement {
|
|
|
81
81
|
${!showExpandableButton ? '' : html`
|
|
82
82
|
<div class="note__toggle">
|
|
83
83
|
<zn-button color="transparent"
|
|
84
|
-
size="content"
|
|
85
84
|
class="note__toggle__btn"
|
|
86
85
|
@click="${this._toggleExpand}"
|
|
87
86
|
aria-expanded="${String(this.expanded)}">
|