@kubex/zinc 1.0.108 → 1.0.110
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 +110 -75
- package/dist/vscode.html-custom-data.json +11 -11
- package/dist/web-types.json +23 -23
- package/dist/zn.d.ts +9 -4
- package/dist/zn.min.js +183 -181
- package/docs/pages/components/icon.md +5 -1
- package/package.json +1 -1
- package/src/components/button/button.scss +2 -3
- package/src/components/datepicker/datepicker.component.ts +6 -0
- package/src/components/datepicker/datepicker.test.ts +32 -1
- package/src/components/form-group/form-group.component.ts +7 -7
- package/src/components/icon/icon.component.ts +51 -30
- package/src/components/icon/icon.test.ts +23 -0
- package/src/components/input/input.component.ts +6 -0
- package/src/components/input/input.test.ts +34 -1
- package/src/components/select/select.component.ts +7 -0
- package/src/components/select/select.test.ts +24 -0
- package/src/components/textarea/textarea.component.ts +8 -0
- package/src/components/textarea/textarea.test.ts +36 -3
- package/src/components/tile-property/tile-property.scss +11 -5
- package/src/utilities/sha256.ts +114 -0
|
@@ -333,6 +333,8 @@ Explicit library specification:
|
|
|
333
333
|
<zn-icon src="test1@example.com" library="gravatar" size="48"></zn-icon>
|
|
334
334
|
```
|
|
335
335
|
|
|
336
|
+
Email addresses are trimmed, lowercased, and hashed with SHA-256 before the Gravatar request is made.
|
|
337
|
+
|
|
336
338
|
Using shorthand notation:
|
|
337
339
|
|
|
338
340
|
```html:preview
|
|
@@ -348,6 +350,8 @@ Libravatar is an open-source alternative to Gravatar. Use it for federated avata
|
|
|
348
350
|
<zn-icon src="user@example.com" library="libravatar" size="48" round></zn-icon>
|
|
349
351
|
```
|
|
350
352
|
|
|
353
|
+
Email addresses are trimmed, lowercased, and hashed with SHA-256 before the Libravatar request is made.
|
|
354
|
+
|
|
351
355
|
Similar to Gravatar, you can specify fallback options:
|
|
352
356
|
|
|
353
357
|
```html:preview
|
|
@@ -727,4 +731,4 @@ your HTML like this:
|
|
|
727
731
|
grid-template-columns: repeat(4, 1fr);
|
|
728
732
|
}
|
|
729
733
|
}
|
|
730
|
-
</style>
|
|
734
|
+
</style>
|
package/package.json
CHANGED
|
@@ -139,14 +139,13 @@
|
|
|
139
139
|
|
|
140
140
|
&:hover:not([disabled]), &:active:not([disabled]) {
|
|
141
141
|
background-color: rgb(var(--btn-color));
|
|
142
|
-
color: white;
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
&.button--secondary {
|
|
146
|
-
border-color:
|
|
145
|
+
border-color: var(--zn-color-neutral-100);
|
|
147
146
|
|
|
148
147
|
&:hover:not([disabled]), &:active:not([disabled]) {
|
|
149
|
-
background-color:
|
|
148
|
+
background-color: var(--zn-color-neutral-100);
|
|
150
149
|
}
|
|
151
150
|
}
|
|
152
151
|
}
|
|
@@ -321,6 +321,12 @@ export default class ZnDatepicker extends ZincElement implements ZincFormControl
|
|
|
321
321
|
return;
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
+
if (event.key === 'Escape') {
|
|
325
|
+
this.input.blur();
|
|
326
|
+
event.stopPropagation();
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
324
330
|
// Allow navigation and control keys
|
|
325
331
|
const allowedKeys = [
|
|
326
332
|
'Backspace', 'Delete', 'Tab', 'Escape', 'Enter',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
|
-
import {
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type ZnDatepicker from './datepicker.component';
|
|
3
4
|
|
|
4
5
|
describe('<zn-datepicker>', () => {
|
|
5
6
|
it('should render a component', async () => {
|
|
@@ -7,4 +8,34 @@ describe('<zn-datepicker>', () => {
|
|
|
7
8
|
|
|
8
9
|
expect(el).to.exist;
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
describe('Escape key', () => {
|
|
13
|
+
it('blurs the inner input when focused and the calendar is closed', async () => {
|
|
14
|
+
const el = await fixture<ZnDatepicker>(html`<zn-datepicker></zn-datepicker>`);
|
|
15
|
+
await el.updateComplete;
|
|
16
|
+
|
|
17
|
+
// Focus shows AirDatepicker's calendar (showEvent: 'focus'). Per spec, Escape
|
|
18
|
+
// while calendar is open is handled by AirDatepicker; our handler engages once
|
|
19
|
+
// the calendar is closed. Hide it explicitly to simulate the calendar-closed
|
|
20
|
+
// state, then press Escape.
|
|
21
|
+
el.focus();
|
|
22
|
+
await el.updateComplete;
|
|
23
|
+
const dp = (el as unknown as { _instance?: { hide: () => void; visible: boolean } })._instance;
|
|
24
|
+
dp?.hide();
|
|
25
|
+
await el.updateComplete;
|
|
26
|
+
el.input.focus();
|
|
27
|
+
await el.updateComplete;
|
|
28
|
+
expect(el.shadowRoot!.activeElement).to.equal(el.input);
|
|
29
|
+
|
|
30
|
+
el.input.dispatchEvent(new KeyboardEvent('keydown', {
|
|
31
|
+
key: 'Escape',
|
|
32
|
+
bubbles: true,
|
|
33
|
+
composed: true,
|
|
34
|
+
cancelable: true
|
|
35
|
+
}));
|
|
36
|
+
await el.updateComplete;
|
|
37
|
+
|
|
38
|
+
expect(el.shadowRoot!.activeElement, 'inner input should be blurred').to.not.equal(el.input);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
10
41
|
});
|
|
@@ -74,14 +74,14 @@ export default class ZnFormGroup extends ZincElement {
|
|
|
74
74
|
</zn-tooltip>`
|
|
75
75
|
: ''}
|
|
76
76
|
</label>
|
|
77
|
+
</div>` : html``}
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
</div>` : html``}
|
|
79
|
+
${hasHelpText ? html`
|
|
80
|
+
<div
|
|
81
|
+
part="form-control-help-text"
|
|
82
|
+
id="help-text"
|
|
83
|
+
class="form-control__help-text">
|
|
84
|
+
<slot name="help-text">${this.helpText}</slot>
|
|
85
85
|
</div>` : html``}
|
|
86
86
|
|
|
87
87
|
<div part="form-control-input" class="form-control-input">
|
|
@@ -1,8 +1,8 @@
|
|
|
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 {md5} from '../../utilities/md5';
|
|
5
4
|
import {property} from 'lit/decorators.js';
|
|
5
|
+
import {sha256} from '../../utilities/sha256';
|
|
6
6
|
import {styleMap} from "lit/directives/style-map.js";
|
|
7
7
|
import ZincElement from '../../internal/zinc-element';
|
|
8
8
|
|
|
@@ -30,7 +30,7 @@ export type IconColor =
|
|
|
30
30
|
| "violet"
|
|
31
31
|
| "pink"
|
|
32
32
|
| "grey"
|
|
33
|
-
| (string &
|
|
33
|
+
| (string & Record<never, never>);
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* @summary Short summary of the component's intended use.
|
|
@@ -127,40 +127,37 @@ export default class ZnIcon extends ZincElement {
|
|
|
127
127
|
connectedCallback() {
|
|
128
128
|
super.connectedCallback();
|
|
129
129
|
|
|
130
|
+
let hashFragment = '';
|
|
130
131
|
|
|
131
132
|
if (this.src && this.src.includes('#')) {
|
|
132
|
-
const split = this.src.split('#');
|
|
133
|
+
const split = this.src.split('#', 2);
|
|
133
134
|
this.src = split[0];
|
|
134
|
-
|
|
135
|
-
attributes.forEach(attr => {
|
|
136
|
-
if (attr === "round") {
|
|
137
|
-
this.round = true;
|
|
138
|
-
}
|
|
139
|
-
if (attr === "tile") {
|
|
140
|
-
this.tile = true;
|
|
141
|
-
}
|
|
142
|
-
if (attr === "depth") {
|
|
143
|
-
this.depth = true;
|
|
144
|
-
}
|
|
145
|
-
});
|
|
135
|
+
hashFragment = split[1] ?? '';
|
|
146
136
|
}
|
|
147
137
|
|
|
148
138
|
if (this.src && this.src.includes('@')) {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
139
|
+
const atIndex = this.src.lastIndexOf('@');
|
|
140
|
+
const libraryOrDomain = this.src.slice(atIndex + 1);
|
|
141
|
+
|
|
142
|
+
if (libraryOrDomain.includes('.')) {
|
|
143
|
+
this.library = this.library ?? "gravatar";
|
|
144
|
+
} else if ((this.library === undefined) && libraryOrDomain !== "") {
|
|
153
145
|
// if split[1] is a valid library name, set it
|
|
154
|
-
this.library = this.convertToLibrary(
|
|
155
|
-
this.src =
|
|
146
|
+
this.library = this.convertToLibrary(libraryOrDomain);
|
|
147
|
+
this.src = this.src.slice(0, atIndex);
|
|
156
148
|
}
|
|
157
149
|
|
|
158
150
|
if (this.library === "gravatar" || this.library === "libravatar") {
|
|
159
|
-
this.
|
|
160
|
-
this.src =
|
|
151
|
+
this.applyHashFragment(hashFragment);
|
|
152
|
+
this.src = sha256(this.normalizeRavatarEmail(this.src));
|
|
153
|
+
} else {
|
|
154
|
+
this.applyHashFragment(hashFragment);
|
|
161
155
|
}
|
|
162
156
|
} else if (!this.library && this.src && !this.src.includes('/')) {
|
|
157
|
+
this.applyHashFragment(hashFragment);
|
|
163
158
|
this.library = this.defaultLibrary;
|
|
159
|
+
} else {
|
|
160
|
+
this.applyHashFragment(hashFragment);
|
|
164
161
|
}
|
|
165
162
|
|
|
166
163
|
// load the material icons font if the library is set to material
|
|
@@ -174,18 +171,42 @@ export default class ZnIcon extends ZincElement {
|
|
|
174
171
|
<link
|
|
175
172
|
href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined|Material+Icons|Material+Icons+Round|Material+Icons+Sharp|Material+Icons+Two+Tone|Material+Icons+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200"
|
|
176
173
|
rel="stylesheet">`, document.head);
|
|
177
|
-
|
|
178
|
-
this.ravatarOptions();
|
|
179
174
|
}
|
|
180
175
|
|
|
181
|
-
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
176
|
+
private applyHashFragment(hashFragment: string) {
|
|
177
|
+
if (!hashFragment) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const attributes = hashFragment.split(',');
|
|
182
|
+
|
|
183
|
+
attributes.forEach(attr => {
|
|
184
|
+
if (attr === 'round') {
|
|
185
|
+
this.round = true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (attr === 'tile') {
|
|
189
|
+
this.tile = true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (attr === 'depth') {
|
|
193
|
+
this.depth = true;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
if ((this.library === 'gravatar' || this.library === 'libravatar')) {
|
|
198
|
+
const defaultOption = attributes.find(attr => !['round', 'tile', 'depth'].includes(attr));
|
|
199
|
+
|
|
200
|
+
if (defaultOption) {
|
|
201
|
+
this.gravatarOptions = `&d=${defaultOption}`;
|
|
202
|
+
}
|
|
186
203
|
}
|
|
187
204
|
}
|
|
188
205
|
|
|
206
|
+
private normalizeRavatarEmail(email: string) {
|
|
207
|
+
return email.trim().toLowerCase();
|
|
208
|
+
}
|
|
209
|
+
|
|
189
210
|
render() {
|
|
190
211
|
return html`
|
|
191
212
|
<div class="icon-wrapper">
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
2
|
import { expect, fixture, html } from '@open-wc/testing';
|
|
3
|
+
import type ZnIcon from './icon.component';
|
|
3
4
|
|
|
4
5
|
describe('<zn-icon>', () => {
|
|
5
6
|
it('should render a component', async () => {
|
|
@@ -7,4 +8,26 @@ describe('<zn-icon>', () => {
|
|
|
7
8
|
|
|
8
9
|
expect(el).to.exist;
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
it('should build Gravatar URLs with a normalized SHA-256 hash', async () => {
|
|
13
|
+
const el = await fixture<ZnIcon>(html`
|
|
14
|
+
<zn-icon src="MyEmailAddress@example.com " library="gravatar" size="48"></zn-icon>
|
|
15
|
+
`);
|
|
16
|
+
|
|
17
|
+
const image = el.shadowRoot?.querySelector('img');
|
|
18
|
+
expect(image?.getAttribute('src')).to.equal(
|
|
19
|
+
'https://www.gravatar.com/avatar/84059b07d4be67b806386c0aad8070a23f18836bbaae342275dc0a83414c32ee?s=48'
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should pass fallback options through to Libravatar', async () => {
|
|
24
|
+
const el = await fixture<ZnIcon>(html`
|
|
25
|
+
<zn-icon src="nonexistent@example.com#identicon" library="libravatar" size="48"></zn-icon>
|
|
26
|
+
`);
|
|
27
|
+
|
|
28
|
+
const image = el.shadowRoot?.querySelector('img');
|
|
29
|
+
expect(image?.getAttribute('src')).to.equal(
|
|
30
|
+
'https://seccdn.libravatar.org/avatar/04e8703fcfb60849fb5c596abc8f3d7547c7e0099c3806a3ffec77a95dc02e25?s=48&d=identicon'
|
|
31
|
+
);
|
|
32
|
+
});
|
|
10
33
|
});
|
|
@@ -547,6 +547,12 @@ export default class ZnInput extends ZincElement implements ZincFormControl {
|
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
private handleKeyDown(event: KeyboardEvent) {
|
|
550
|
+
if (event.key === 'Escape') {
|
|
551
|
+
this.input.blur();
|
|
552
|
+
event.stopPropagation();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
550
556
|
const hasModifier = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
551
557
|
|
|
552
558
|
// Pressing enter when focused on the input should submit the form like a native input, be we wait a tick before
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
|
-
import {
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type ZnInput from './input.component';
|
|
3
4
|
|
|
4
5
|
describe('<zn-input>', () => {
|
|
5
6
|
it('should render a component', async () => {
|
|
@@ -7,4 +8,36 @@ describe('<zn-input>', () => {
|
|
|
7
8
|
|
|
8
9
|
expect(el).to.exist;
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
describe('Escape key', () => {
|
|
13
|
+
it('blurs the inner input and stops propagation when focused', async () => {
|
|
14
|
+
const wrapper = await fixture<HTMLDivElement>(html`
|
|
15
|
+
<div>
|
|
16
|
+
<zn-input></zn-input>
|
|
17
|
+
</div>
|
|
18
|
+
`);
|
|
19
|
+
const el = wrapper.querySelector('zn-input') as ZnInput;
|
|
20
|
+
await el.updateComplete;
|
|
21
|
+
|
|
22
|
+
let wrapperEscapes = 0;
|
|
23
|
+
wrapper.addEventListener('keydown', (e) => {
|
|
24
|
+
if ((e as KeyboardEvent).key === 'Escape') wrapperEscapes++;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
el.focus();
|
|
28
|
+
await el.updateComplete;
|
|
29
|
+
expect(el.shadowRoot!.activeElement).to.equal(el.input);
|
|
30
|
+
|
|
31
|
+
el.input.dispatchEvent(new KeyboardEvent('keydown', {
|
|
32
|
+
key: 'Escape',
|
|
33
|
+
bubbles: true,
|
|
34
|
+
composed: true,
|
|
35
|
+
cancelable: true
|
|
36
|
+
}));
|
|
37
|
+
await el.updateComplete;
|
|
38
|
+
|
|
39
|
+
expect(el.shadowRoot!.activeElement, 'inner input should be blurred').to.not.equal(el.input);
|
|
40
|
+
expect(wrapperEscapes, 'wrapper should not see Escape on press 1').to.equal(0);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
10
43
|
});
|
|
@@ -484,6 +484,13 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
484
484
|
this.displayInput.focus({preventScroll: true});
|
|
485
485
|
}
|
|
486
486
|
|
|
487
|
+
// Blur the display input when Escape is pressed and the dropdown is closed,
|
|
488
|
+
// so a second Escape press can bubble (e.g. close a containing dialog).
|
|
489
|
+
if (event.key === 'Escape' && !this.open) {
|
|
490
|
+
event.stopPropagation();
|
|
491
|
+
this.displayInput.blur();
|
|
492
|
+
}
|
|
493
|
+
|
|
487
494
|
// Handle enter and space. When pressing space, we allow for type to select behaviors so if there's anything in the
|
|
488
495
|
// buffer we _don't_ close it. When search is enabled, space should type into the input, not toggle.
|
|
489
496
|
if (event.key === 'Enter' || (event.key === ' ' && !this.search && this.typeToSelectString === '')) {
|
|
@@ -152,4 +152,28 @@ describe('<zn-select>', () => {
|
|
|
152
152
|
expect(visibleOptions[0].value).to.equal('apple');
|
|
153
153
|
});
|
|
154
154
|
});
|
|
155
|
+
|
|
156
|
+
describe('Escape key', () => {
|
|
157
|
+
it('blurs the display input when dropdown is closed and Escape is pressed', async () => {
|
|
158
|
+
const el = await fixture<ZnSelect>(html`<zn-select></zn-select>`);
|
|
159
|
+
await el.updateComplete;
|
|
160
|
+
|
|
161
|
+
const displayInput = el.shadowRoot!.querySelector<HTMLInputElement>('.select__display-input')!;
|
|
162
|
+
el.focus();
|
|
163
|
+
await el.updateComplete;
|
|
164
|
+
expect(el.shadowRoot!.activeElement).to.equal(displayInput);
|
|
165
|
+
expect(el.open).to.be.false;
|
|
166
|
+
|
|
167
|
+
displayInput.dispatchEvent(new KeyboardEvent('keydown', {
|
|
168
|
+
key: 'Escape',
|
|
169
|
+
bubbles: true,
|
|
170
|
+
composed: true,
|
|
171
|
+
cancelable: true
|
|
172
|
+
}));
|
|
173
|
+
await el.updateComplete;
|
|
174
|
+
|
|
175
|
+
expect(el.shadowRoot!.activeElement, 'display input should be blurred').to.not.equal(displayInput);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
});
|
|
155
179
|
});
|
|
@@ -233,6 +233,13 @@ export default class ZnTextarea extends ZincElement implements ZincFormControl {
|
|
|
233
233
|
this.formControlController.emitInvalidEvent(event);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
private handleKeyDown(event: KeyboardEvent) {
|
|
237
|
+
if (event.key === 'Escape') {
|
|
238
|
+
this.input.blur();
|
|
239
|
+
event.stopPropagation();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
236
243
|
private setTextareaHeight() {
|
|
237
244
|
if (this.resize === 'auto') {
|
|
238
245
|
this.input.style.height = 'auto';
|
|
@@ -436,6 +443,7 @@ export default class ZnTextarea extends ZincElement implements ZincFormControl {
|
|
|
436
443
|
@change=${this.handleChange}
|
|
437
444
|
@input=${this.handleInput}
|
|
438
445
|
@invalid=${this.handleInvalid}
|
|
446
|
+
@keydown=${this.handleKeyDown}
|
|
439
447
|
@focus=${this.handleFocus}
|
|
440
448
|
@blur=${this.handleBlur}
|
|
441
449
|
></textarea>
|
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
|
-
import {
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type ZnTextarea from './textarea.component';
|
|
3
4
|
|
|
4
|
-
describe('<zn-
|
|
5
|
+
describe('<zn-textarea>', () => {
|
|
5
6
|
it('should render a component', async () => {
|
|
6
|
-
const el = await fixture(html` <zn-
|
|
7
|
+
const el = await fixture(html` <zn-textarea></zn-textarea> `);
|
|
7
8
|
|
|
8
9
|
expect(el).to.exist;
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
describe('Escape key', () => {
|
|
13
|
+
it('blurs the inner textarea and stops propagation when focused', async () => {
|
|
14
|
+
const wrapper = await fixture<HTMLDivElement>(html`
|
|
15
|
+
<div>
|
|
16
|
+
<zn-textarea></zn-textarea>
|
|
17
|
+
</div>
|
|
18
|
+
`);
|
|
19
|
+
const el = wrapper.querySelector('zn-textarea') as ZnTextarea;
|
|
20
|
+
await el.updateComplete;
|
|
21
|
+
|
|
22
|
+
let wrapperEscapes = 0;
|
|
23
|
+
wrapper.addEventListener('keydown', (e) => {
|
|
24
|
+
if ((e as KeyboardEvent).key === 'Escape') wrapperEscapes++;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
el.focus();
|
|
28
|
+
await el.updateComplete;
|
|
29
|
+
expect(el.shadowRoot!.activeElement).to.equal(el.input);
|
|
30
|
+
|
|
31
|
+
el.input.dispatchEvent(new KeyboardEvent('keydown', {
|
|
32
|
+
key: 'Escape',
|
|
33
|
+
bubbles: true,
|
|
34
|
+
composed: true,
|
|
35
|
+
cancelable: true
|
|
36
|
+
}));
|
|
37
|
+
await el.updateComplete;
|
|
38
|
+
|
|
39
|
+
expect(el.shadowRoot!.activeElement, 'inner textarea should be blurred').to.not.equal(el.input);
|
|
40
|
+
expect(wrapperEscapes, 'wrapper should not see Escape on press 1').to.equal(0);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
10
43
|
});
|
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
@use "../../wc";
|
|
2
2
|
|
|
3
|
+
:host {
|
|
4
|
+
display: flex;
|
|
5
|
+
min-width: 0;
|
|
6
|
+
max-width: 240px;
|
|
7
|
+
}
|
|
3
8
|
|
|
4
9
|
.tile__property {
|
|
5
10
|
display: flex;
|
|
6
11
|
align-items: center;
|
|
7
12
|
flex-direction: row;
|
|
8
|
-
width:
|
|
9
|
-
|
|
10
|
-
max-width: 200px;
|
|
13
|
+
min-width: 0;
|
|
14
|
+
width: 100%;
|
|
11
15
|
|
|
12
16
|
.tile__property_container {
|
|
13
17
|
display: flex;
|
|
14
18
|
flex-direction: column;
|
|
15
19
|
overflow: hidden;
|
|
16
|
-
|
|
17
|
-
text-overflow: ellipsis;
|
|
20
|
+
min-width: 0;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
.tile__icon {
|
|
21
24
|
margin-right: 15px;
|
|
25
|
+
flex-shrink: 0;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
.tile__caption {
|
|
@@ -29,6 +33,7 @@
|
|
|
29
33
|
color: rgb(var(--zn-text-heading));
|
|
30
34
|
text-overflow: ellipsis;
|
|
31
35
|
overflow: hidden;
|
|
36
|
+
white-space: nowrap;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
.tile__description {
|
|
@@ -39,5 +44,6 @@
|
|
|
39
44
|
color: rgb(var(--zn-text-color));
|
|
40
45
|
text-overflow: ellipsis;
|
|
41
46
|
overflow: hidden;
|
|
47
|
+
white-space: nowrap;
|
|
42
48
|
}
|
|
43
49
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
export function sha256(input: string): string {
|
|
3
|
+
function rightRotate(value: number, amount: number) {
|
|
4
|
+
return (value >>> amount) | (value << (32 - amount));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function utf8Encode(string: string) {
|
|
8
|
+
string = string.replace(/\r\n/g, '\n');
|
|
9
|
+
let utfText = '';
|
|
10
|
+
|
|
11
|
+
for (let index = 0; index < string.length; index++) {
|
|
12
|
+
const charCode = string.charCodeAt(index);
|
|
13
|
+
|
|
14
|
+
if (charCode < 128) {
|
|
15
|
+
utfText += String.fromCharCode(charCode);
|
|
16
|
+
} else if (charCode < 2048) {
|
|
17
|
+
utfText += String.fromCharCode((charCode >> 6) | 192);
|
|
18
|
+
utfText += String.fromCharCode((charCode & 63) | 128);
|
|
19
|
+
} else {
|
|
20
|
+
utfText += String.fromCharCode((charCode >> 12) | 224);
|
|
21
|
+
utfText += String.fromCharCode(((charCode >> 6) & 63) | 128);
|
|
22
|
+
utfText += String.fromCharCode((charCode & 63) | 128);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return utfText;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const mathPow = Math.pow;
|
|
30
|
+
const maxWord = mathPow(2, 32);
|
|
31
|
+
const words: number[] = [];
|
|
32
|
+
const hash: number[] = [];
|
|
33
|
+
const roundConstants: number[] = [];
|
|
34
|
+
const isComposite: Record<number, boolean> = {};
|
|
35
|
+
let primeCounter = 0;
|
|
36
|
+
let message = utf8Encode(input);
|
|
37
|
+
const messageBitLength = message.length * 8;
|
|
38
|
+
|
|
39
|
+
for (let candidate = 2; primeCounter < 64; candidate++) {
|
|
40
|
+
if (!isComposite[candidate]) {
|
|
41
|
+
for (let index = 0; index < 313; index += candidate) {
|
|
42
|
+
isComposite[index] = true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (primeCounter < 8) {
|
|
46
|
+
hash[primeCounter] = (mathPow(candidate, 0.5) * maxWord) | 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
roundConstants[primeCounter] = (mathPow(candidate, 1 / 3) * maxWord) | 0;
|
|
50
|
+
primeCounter++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
message += '\x80';
|
|
55
|
+
|
|
56
|
+
while (message.length % 64 !== 56) {
|
|
57
|
+
message += '\x00';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (let index = 0; index < message.length; index++) {
|
|
61
|
+
words[index >> 2] |= message.charCodeAt(index) << ((3 - (index % 4)) * 8);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
words[words.length] = (messageBitLength / maxWord) | 0;
|
|
65
|
+
words[words.length] = messageBitLength;
|
|
66
|
+
|
|
67
|
+
for (let chunkStart = 0; chunkStart < words.length; chunkStart += 16) {
|
|
68
|
+
const workingHash = hash.slice(0, 8);
|
|
69
|
+
const schedule = words.slice(chunkStart, chunkStart + 16);
|
|
70
|
+
|
|
71
|
+
for (let round = 16; round < 64; round++) {
|
|
72
|
+
const word15 = schedule[round - 15];
|
|
73
|
+
const word2 = schedule[round - 2];
|
|
74
|
+
const sigma0 = rightRotate(word15, 7) ^ rightRotate(word15, 18) ^ (word15 >>> 3);
|
|
75
|
+
const sigma1 = rightRotate(word2, 17) ^ rightRotate(word2, 19) ^ (word2 >>> 10);
|
|
76
|
+
|
|
77
|
+
schedule[round] = (schedule[round - 16] + sigma0 + schedule[round - 7] + sigma1) | 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (let round = 0; round < 64; round++) {
|
|
81
|
+
const a = workingHash[0];
|
|
82
|
+
const b = workingHash[1];
|
|
83
|
+
const c = workingHash[2];
|
|
84
|
+
const d = workingHash[3];
|
|
85
|
+
const e = workingHash[4];
|
|
86
|
+
const f = workingHash[5];
|
|
87
|
+
const g = workingHash[6];
|
|
88
|
+
const h = workingHash[7];
|
|
89
|
+
const sigma1 = rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25);
|
|
90
|
+
const choose = (e & f) ^ (~e & g);
|
|
91
|
+
const temp1 = (h + sigma1 + choose + roundConstants[round] + schedule[round]) | 0;
|
|
92
|
+
const sigma0 = rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22);
|
|
93
|
+
const majority = (a & b) ^ (a & c) ^ (b & c);
|
|
94
|
+
const temp2 = (sigma0 + majority) | 0;
|
|
95
|
+
|
|
96
|
+
workingHash[7] = g;
|
|
97
|
+
workingHash[6] = f;
|
|
98
|
+
workingHash[5] = e;
|
|
99
|
+
workingHash[4] = (d + temp1) | 0;
|
|
100
|
+
workingHash[3] = c;
|
|
101
|
+
workingHash[2] = b;
|
|
102
|
+
workingHash[1] = a;
|
|
103
|
+
workingHash[0] = (temp1 + temp2) | 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (let index = 0; index < 8; index++) {
|
|
107
|
+
hash[index] = (hash[index] + workingHash[index]) | 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return hash
|
|
112
|
+
.map(value => (value >>> 0).toString(16).padStart(8, '0'))
|
|
113
|
+
.join('');
|
|
114
|
+
}
|