@crowdstrike/glide-core 0.29.1 → 0.30.0
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/accordion.js +240 -1
- package/dist/accordion.styles.js +13 -7
- package/dist/button-group.button.js +143 -1
- package/dist/button-group.button.styles.js +43 -15
- package/dist/button-group.js +249 -1
- package/dist/button-group.styles.js +10 -5
- package/dist/button.js +206 -1
- package/dist/button.styles.js +12 -7
- package/dist/checkbox-group.js +479 -14
- package/dist/checkbox-group.styles.js +5 -2
- package/dist/checkbox.js +519 -32
- package/dist/checkbox.styles.js +10 -5
- package/dist/drawer.js +168 -1
- package/dist/drawer.styles.js +5 -2
- package/dist/dropdown.js +2423 -123
- package/dist/dropdown.option.js +536 -1
- package/dist/dropdown.option.styles.js +5 -2
- package/dist/dropdown.styles.js +14 -7
- package/dist/form-controls-layout.js +102 -1
- package/dist/form-controls-layout.styles.js +5 -2
- package/dist/icon-button.js +139 -1
- package/dist/icon-button.styles.js +19 -7
- package/dist/icons/checked.js +28 -1
- package/dist/icons/chevron.js +21 -1
- package/dist/icons/magnifying-glass.js +23 -1
- package/dist/icons/pencil.js +21 -1
- package/dist/icons/severity-critical.js +20 -1
- package/dist/icons/severity-informational.js +20 -1
- package/dist/icons/severity-medium.js +20 -1
- package/dist/icons/x.js +21 -1
- package/dist/inline-alert.js +118 -1
- package/dist/inline-alert.styles.js +5 -2
- package/dist/input.d.ts +8 -2
- package/dist/input.js +505 -41
- package/dist/input.styles.js +25 -4
- package/dist/label.js +303 -1
- package/dist/label.styles.js +11 -5
- package/dist/library/assert-slot.js +136 -1
- package/dist/library/expect-unhandled-rejection.js +14 -1
- package/dist/library/expect-window-error.js +26 -1
- package/dist/library/final.js +18 -1
- package/dist/library/form-control.js +1 -1
- package/dist/library/localize.js +10 -1
- package/dist/library/mouse.js +35 -1
- package/dist/library/on-resize.js +24 -1
- package/dist/library/required.js +35 -1
- package/dist/library/shadow-root-mode.js +4 -1
- package/dist/library/unique-id.js +3 -1
- package/dist/link.js +92 -1
- package/dist/link.styles.js +10 -5
- package/dist/menu.d.ts +3 -2
- package/dist/menu.js +1259 -1
- package/dist/menu.styles.js +34 -17
- package/dist/modal.d.ts +4 -0
- package/dist/modal.icon-button.js +60 -1
- package/dist/modal.icon-button.styles.js +5 -2
- package/dist/modal.js +473 -1
- package/dist/modal.styles.js +71 -22
- package/dist/option.d.ts +74 -0
- package/dist/option.js +498 -0
- package/dist/option.styles.js +140 -0
- package/dist/{menu.options.d.ts → options.d.ts} +5 -6
- package/dist/options.js +130 -0
- package/dist/options.styles.js +21 -0
- package/dist/popover.js +620 -1
- package/dist/popover.styles.js +11 -5
- package/dist/radio-group.js +624 -17
- package/dist/radio-group.radio.js +211 -1
- package/dist/radio-group.radio.styles.js +9 -4
- package/dist/radio-group.styles.js +5 -2
- package/dist/slider.js +1040 -61
- package/dist/slider.styles.js +9 -4
- package/dist/spinner.js +60 -1
- package/dist/spinner.styles.js +5 -2
- package/dist/split-button.js +116 -1
- package/dist/split-button.primary-button.js +100 -1
- package/dist/split-button.primary-button.styles.js +13 -6
- package/dist/split-button.primary-link.js +102 -1
- package/dist/split-button.secondary-button.d.ts +2 -3
- package/dist/split-button.secondary-button.js +121 -1
- package/dist/split-button.secondary-button.styles.js +12 -7
- package/dist/split-button.styles.js +9 -4
- package/dist/styles/focus-outline.js +9 -3
- package/dist/styles/fonts.css +6 -1
- package/dist/styles/opacity-and-scale-animation.js +6 -3
- package/dist/styles/skeleton.js +6 -3
- package/dist/styles/variables.css +410 -1
- package/dist/styles/visually-hidden.js +6 -3
- package/dist/tab.group.js +386 -1
- package/dist/tab.group.styles.js +5 -2
- package/dist/tab.js +133 -1
- package/dist/tab.panel.js +93 -1
- package/dist/tab.panel.styles.js +11 -5
- package/dist/tab.styles.js +9 -4
- package/dist/tag.js +207 -1
- package/dist/tag.styles.js +10 -5
- package/dist/textarea.js +353 -19
- package/dist/textarea.styles.js +23 -4
- package/dist/toast.js +130 -1
- package/dist/toast.toasts.js +248 -25
- package/dist/toast.toasts.styles.js +9 -4
- package/dist/toggle.js +178 -1
- package/dist/toggle.styles.js +25 -5
- package/dist/tooltip.container.d.ts +2 -0
- package/dist/tooltip.container.js +130 -1
- package/dist/tooltip.container.styles.js +18 -4
- package/dist/tooltip.d.ts +6 -0
- package/dist/tooltip.js +484 -1
- package/dist/tooltip.styles.js +21 -5
- package/dist/translations/en.js +36 -1
- package/dist/translations/fr.js +37 -1
- package/dist/translations/ja.js +37 -1
- package/package.json +8 -12
- package/dist/menu.button.d.ts +0 -42
- package/dist/menu.button.js +0 -1
- package/dist/menu.button.styles.js +0 -32
- package/dist/menu.link.d.ts +0 -44
- package/dist/menu.link.js +0 -1
- package/dist/menu.link.styles.js +0 -35
- package/dist/menu.options.js +0 -1
- package/dist/menu.options.styles.d.ts +0 -2
- package/dist/menu.options.styles.js +0 -20
- /package/dist/{menu.button.styles.d.ts → option.styles.d.ts} +0 -0
- /package/dist/{menu.link.styles.d.ts → options.styles.d.ts} +0 -0
package/dist/input.styles.js
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
import{css}from
|
2
|
-
|
3
|
-
|
1
|
+
import { css } from 'lit';
|
2
|
+
import visuallyHidden from './styles/visually-hidden.js';
|
3
|
+
export default [
|
4
|
+
css `
|
5
|
+
${visuallyHidden('.character-count .hidden')}
|
6
|
+
`,
|
7
|
+
css `
|
4
8
|
.meta {
|
5
9
|
column-gap: var(--glide-core-spacing-base-xs);
|
6
10
|
display: flex;
|
@@ -118,6 +122,22 @@ import{css}from"lit";import visuallyHidden from"./styles/visually-hidden.js";exp
|
|
118
122
|
outline: 2px solid var(--glide-core-color-interactive-stroke-focus);
|
119
123
|
}
|
120
124
|
}
|
125
|
+
|
126
|
+
&[type='color']::-webkit-color-swatch {
|
127
|
+
border: none;
|
128
|
+
border-radius: var(--glide-core-rounding-base-radius-xxs);
|
129
|
+
}
|
130
|
+
|
131
|
+
/*
|
132
|
+
Unfortunately Firefox requires a different selector. It also
|
133
|
+
sets the element to 100% height of its container, so we set
|
134
|
+
a fixed block-size to match the other browsers.
|
135
|
+
*/
|
136
|
+
&[type='color']::-moz-color-swatch {
|
137
|
+
block-size: 1.5rem;
|
138
|
+
border: none;
|
139
|
+
border-radius: var(--glide-core-rounding-base-radius-xxs);
|
140
|
+
}
|
121
141
|
}
|
122
142
|
|
123
143
|
.suffix-icon {
|
@@ -152,4 +172,5 @@ import{css}from"lit";import visuallyHidden from"./styles/visually-hidden.js";exp
|
|
152
172
|
.empty .clear-icon-button {
|
153
173
|
visibility: hidden;
|
154
174
|
}
|
155
|
-
|
175
|
+
`,
|
176
|
+
];
|
package/dist/label.js
CHANGED
@@ -1 +1,303 @@
|
|
1
|
-
var __decorate
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
import './tooltip.js';
|
8
|
+
import { html, LitElement } from 'lit';
|
9
|
+
import { classMap } from 'lit/directives/class-map.js';
|
10
|
+
import { createRef, ref } from 'lit/directives/ref.js';
|
11
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
12
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
13
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
14
|
+
import { when } from 'lit/directives/when.js';
|
15
|
+
import styles from './label.styles.js';
|
16
|
+
import { LocalizeController } from './library/localize.js';
|
17
|
+
import assertSlot from './library/assert-slot.js';
|
18
|
+
import onResize from './library/on-resize.js';
|
19
|
+
import shadowRootMode from './library/shadow-root-mode.js';
|
20
|
+
import final from './library/final.js';
|
21
|
+
/**
|
22
|
+
* @attr {boolean} [disabled=false]
|
23
|
+
* @attr {boolean} [error=false]
|
24
|
+
* @attr {boolean} [hide=false]
|
25
|
+
* @attr {string} [label]
|
26
|
+
* @attr {'horizontal'|'vertical'} [orientation='horizontal']
|
27
|
+
* @attr {boolean} [required=false]
|
28
|
+
* @attr {'left'|'middle'|'right'} [split]
|
29
|
+
* @attr {string} [tooltip]
|
30
|
+
*
|
31
|
+
* @slot {HTMLLabelElement}
|
32
|
+
* @slot {Element} [control] - The element with which the label is associated
|
33
|
+
* @slot {Element | string} [description] - Additional information or context
|
34
|
+
* @slot {Element | string} [summary] - Additional information or context
|
35
|
+
*/
|
36
|
+
let Label = class Label extends LitElement {
|
37
|
+
constructor() {
|
38
|
+
super(...arguments);
|
39
|
+
this.disabled = false;
|
40
|
+
this.error = false;
|
41
|
+
this.hide = false;
|
42
|
+
this.orientation = 'horizontal';
|
43
|
+
this.required = false;
|
44
|
+
this.hasDescription = false;
|
45
|
+
this.hasSummarySlot = false;
|
46
|
+
this.isLabelTooltip = false;
|
47
|
+
this.#defaultSlotElementRef = createRef();
|
48
|
+
this.#descriptionSlotElementRef = createRef();
|
49
|
+
this.#labelElementRef = createRef();
|
50
|
+
this.#localize = new LocalizeController(this);
|
51
|
+
this.#summarySlotElementRef = createRef();
|
52
|
+
}
|
53
|
+
static { this.shadowRootOptions = {
|
54
|
+
...LitElement.shadowRootOptions,
|
55
|
+
mode: shadowRootMode,
|
56
|
+
}; }
|
57
|
+
static { this.styles = styles; }
|
58
|
+
render() {
|
59
|
+
// `aria-hidden` is used on the tooltip so the contents of the label aren't
|
60
|
+
// read twice to screen readers. The label is truncated using CSS. So the full
|
61
|
+
// text of the label is always available to them.
|
62
|
+
// Lit-a11y doesn't know that we're only using a "mouseover" event to hide and
|
63
|
+
// show Tooltip, which is hidden from screenreaders because the truncated text
|
64
|
+
// is available to them without a tooltip.
|
65
|
+
//
|
66
|
+
/* eslint-disable lit-a11y/mouse-events-have-key-events */
|
67
|
+
return html `<div
|
68
|
+
class=${classMap({
|
69
|
+
component: true,
|
70
|
+
horizontal: this.orientation === 'horizontal',
|
71
|
+
vertical: this.orientation === 'vertical',
|
72
|
+
left: this.split === 'left',
|
73
|
+
middle: this.split === 'middle',
|
74
|
+
right: this.split === 'right',
|
75
|
+
'hidden-label': this.hide,
|
76
|
+
})}
|
77
|
+
>
|
78
|
+
<div
|
79
|
+
class=${classMap({
|
80
|
+
tooltips: true,
|
81
|
+
hidden: this.hide,
|
82
|
+
left: this.split === 'left',
|
83
|
+
middle: this.split === 'middle',
|
84
|
+
right: this.split === 'right',
|
85
|
+
vertical: this.orientation === 'vertical',
|
86
|
+
})}
|
87
|
+
part="private-tooltips"
|
88
|
+
>
|
89
|
+
${when(this.tooltip, () => html `<glide-core-tooltip
|
90
|
+
class=${classMap({
|
91
|
+
'optional-tooltip': true,
|
92
|
+
vertical: this.orientation === 'vertical',
|
93
|
+
visible: this.tooltip ? true : false,
|
94
|
+
})}
|
95
|
+
label=${ifDefined(this.tooltip)}
|
96
|
+
placement=${this.orientation === 'vertical' ? 'right' : 'bottom'}
|
97
|
+
>
|
98
|
+
<button
|
99
|
+
aria-label=${this.#localize.term('tooltip')}
|
100
|
+
class="optional-tooltip-target"
|
101
|
+
slot="target"
|
102
|
+
type="button"
|
103
|
+
>
|
104
|
+
${icons.information}
|
105
|
+
</button>
|
106
|
+
</glide-core-tooltip>`)}
|
107
|
+
|
108
|
+
<glide-core-tooltip
|
109
|
+
class="label-tooltip"
|
110
|
+
data-test="label-tooltip"
|
111
|
+
label=${this.label ?? ''}
|
112
|
+
placement="right"
|
113
|
+
?disabled=${!this.isLabelTooltip}
|
114
|
+
screenreader-hidden
|
115
|
+
>
|
116
|
+
<div
|
117
|
+
class=${classMap({
|
118
|
+
label: true,
|
119
|
+
disabled: this.disabled,
|
120
|
+
})}
|
121
|
+
data-test="label"
|
122
|
+
slot="target"
|
123
|
+
@mouseover=${this.#onLabelMouseOver}
|
124
|
+
${ref(this.#labelElementRef)}
|
125
|
+
>
|
126
|
+
<slot ${assertSlot()} ${ref(this.#defaultSlotElementRef)}>
|
127
|
+
<!-- @type {HTMLLabelElement} -->
|
128
|
+
</slot>
|
129
|
+
</div>
|
130
|
+
</glide-core-tooltip>
|
131
|
+
|
132
|
+
${this.required
|
133
|
+
? html `<span
|
134
|
+
aria-hidden="true"
|
135
|
+
class="required-symbol"
|
136
|
+
data-test="required-symbol"
|
137
|
+
>
|
138
|
+
*
|
139
|
+
</span>`
|
140
|
+
: ''}
|
141
|
+
</div>
|
142
|
+
|
143
|
+
<div class="control-and-summary" part="private-control-and-summary">
|
144
|
+
<slot
|
145
|
+
class=${classMap({
|
146
|
+
control: true,
|
147
|
+
error: this.error,
|
148
|
+
disabled: this.disabled,
|
149
|
+
vertical: this.orientation === 'vertical',
|
150
|
+
summaryless: !this.hasSummarySlot,
|
151
|
+
'hidden-label': this.hide,
|
152
|
+
})}
|
153
|
+
name="control"
|
154
|
+
${assertSlot()}
|
155
|
+
>
|
156
|
+
<!--
|
157
|
+
The element with which the label is associated
|
158
|
+
@type {Element}
|
159
|
+
-->
|
160
|
+
</slot>
|
161
|
+
|
162
|
+
<slot
|
163
|
+
class=${classMap({
|
164
|
+
summary: true,
|
165
|
+
error: this.error,
|
166
|
+
})}
|
167
|
+
name="summary"
|
168
|
+
@slotchange=${this.#onSummarySlotChange}
|
169
|
+
${ref(this.#summarySlotElementRef)}
|
170
|
+
>
|
171
|
+
<!--
|
172
|
+
Additional information or context
|
173
|
+
@type {Element | string}
|
174
|
+
-->
|
175
|
+
</slot>
|
176
|
+
</div>
|
177
|
+
|
178
|
+
<slot
|
179
|
+
class=${classMap({
|
180
|
+
description: true,
|
181
|
+
content: this.hasDescription,
|
182
|
+
error: this.error,
|
183
|
+
tooltip: this.tooltip ? true : false,
|
184
|
+
})}
|
185
|
+
id="description"
|
186
|
+
name="description"
|
187
|
+
${onResize(this.#onDescriptionSlotResize.bind(this))}
|
188
|
+
${ref(this.#descriptionSlotElementRef)}
|
189
|
+
>
|
190
|
+
<!--
|
191
|
+
Additional information or context
|
192
|
+
@type {Element | string}
|
193
|
+
-->
|
194
|
+
</slot>
|
195
|
+
</div>`;
|
196
|
+
}
|
197
|
+
#defaultSlotElementRef;
|
198
|
+
#descriptionSlotElementRef;
|
199
|
+
#labelElementRef;
|
200
|
+
#localize;
|
201
|
+
#summarySlotElementRef;
|
202
|
+
#onDescriptionSlotResize() {
|
203
|
+
// The "description" slot has a top margin that needs to be conditionally
|
204
|
+
// applied only if content is slotted so there's not stray whitespace
|
205
|
+
// when there's no description.
|
206
|
+
//
|
207
|
+
// Normally, we'd listen for "slotchange" and set `this.hasDescription`
|
208
|
+
// in the event handler. But form controls always slot content. We need
|
209
|
+
// to know if any text has been slotted instead.
|
210
|
+
//
|
211
|
+
// A Resize Observer is the best proxy for that. If the slot has a height,
|
212
|
+
// then we know it has text.
|
213
|
+
this.hasDescription = Boolean(this.#descriptionSlotElementRef.value &&
|
214
|
+
this.#descriptionSlotElementRef.value.offsetHeight > 0);
|
215
|
+
}
|
216
|
+
#onLabelMouseOver() {
|
217
|
+
const defaultSlotAssignedElement = this.#defaultSlotElementRef.value
|
218
|
+
?.assignedElements()
|
219
|
+
.at(0);
|
220
|
+
if (defaultSlotAssignedElement && this.#labelElementRef.value) {
|
221
|
+
// `getBoundingClientRect()` is used so we're comparing apples to apples.
|
222
|
+
//
|
223
|
+
// `clientWidth` on `defaultSlotAssignedElement` is zero if the element is
|
224
|
+
// `display: inline`. The label, on the other hand, isn't inline.
|
225
|
+
//
|
226
|
+
// But `clientWidth` returns an integer and `getBoundingClientRect().width`
|
227
|
+
// return a float. So using `clientWidth` with `#labelElementRef.value` would
|
228
|
+
// mean the width of `defaultSlotAssignedElement` is always fractionally
|
229
|
+
// greater than that of `#labelElementRef.value`.
|
230
|
+
this.isLabelTooltip =
|
231
|
+
defaultSlotAssignedElement.getBoundingClientRect().width >
|
232
|
+
this.#labelElementRef.value.getBoundingClientRect().width;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
#onSummarySlotChange() {
|
236
|
+
const assignedNodes = this.#summarySlotElementRef.value?.assignedNodes({
|
237
|
+
flatten: true,
|
238
|
+
});
|
239
|
+
this.hasSummarySlot = Boolean(assignedNodes && assignedNodes.length > 0);
|
240
|
+
}
|
241
|
+
};
|
242
|
+
__decorate([
|
243
|
+
property({ reflect: true, type: Boolean })
|
244
|
+
], Label.prototype, "disabled", void 0);
|
245
|
+
__decorate([
|
246
|
+
property({ reflect: true, type: Boolean })
|
247
|
+
], Label.prototype, "error", void 0);
|
248
|
+
__decorate([
|
249
|
+
property({ reflect: true, type: Boolean })
|
250
|
+
], Label.prototype, "hide", void 0);
|
251
|
+
__decorate([
|
252
|
+
property({ reflect: true, useDefault: true })
|
253
|
+
], Label.prototype, "orientation", void 0);
|
254
|
+
__decorate([
|
255
|
+
property({ reflect: true, type: Boolean })
|
256
|
+
], Label.prototype, "required", void 0);
|
257
|
+
__decorate([
|
258
|
+
property()
|
259
|
+
], Label.prototype, "split", void 0);
|
260
|
+
__decorate([
|
261
|
+
property()
|
262
|
+
], Label.prototype, "tooltip", void 0);
|
263
|
+
__decorate([
|
264
|
+
property()
|
265
|
+
], Label.prototype, "label", void 0);
|
266
|
+
__decorate([
|
267
|
+
state()
|
268
|
+
], Label.prototype, "hasDescription", void 0);
|
269
|
+
__decorate([
|
270
|
+
state()
|
271
|
+
], Label.prototype, "hasSummarySlot", void 0);
|
272
|
+
__decorate([
|
273
|
+
state()
|
274
|
+
], Label.prototype, "isLabelTooltip", void 0);
|
275
|
+
Label = __decorate([
|
276
|
+
customElement('glide-core-private-label'),
|
277
|
+
final
|
278
|
+
], Label);
|
279
|
+
export default Label;
|
280
|
+
const icons = {
|
281
|
+
information: html `
|
282
|
+
<svg
|
283
|
+
aria-hidden="true"
|
284
|
+
style=${styleMap({
|
285
|
+
height: '1rem',
|
286
|
+
width: '1rem',
|
287
|
+
})}
|
288
|
+
viewBox="0 0 24 24"
|
289
|
+
fill="none"
|
290
|
+
>
|
291
|
+
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" />
|
292
|
+
|
293
|
+
<path
|
294
|
+
d="M12 16L12 12"
|
295
|
+
stroke="currentColor"
|
296
|
+
stroke-width="2"
|
297
|
+
stroke-linecap="round"
|
298
|
+
/>
|
299
|
+
|
300
|
+
<circle cx="12" cy="8" r="1" fill="currentColor" />
|
301
|
+
</svg>
|
302
|
+
`,
|
303
|
+
};
|
package/dist/label.styles.js
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
-
import{css}
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
import { css } from 'lit';
|
2
|
+
import focusOutline from './styles/focus-outline.js';
|
3
|
+
import visuallyHidden from './styles/visually-hidden.js';
|
4
|
+
export default [
|
5
|
+
css `
|
6
|
+
${focusOutline('.optional-tooltip-target:focus-visible ')}
|
7
|
+
${visuallyHidden('.tooltips.hidden')}
|
8
|
+
`,
|
9
|
+
css `
|
5
10
|
.component {
|
6
11
|
&.horizontal {
|
7
12
|
--private-column-gap: var(--glide-core-spacing-base-sm);
|
@@ -184,4 +189,5 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import
|
|
184
189
|
color: var(--glide-core-color-advisory-text-error);
|
185
190
|
}
|
186
191
|
}
|
187
|
-
|
192
|
+
`,
|
193
|
+
];
|
@@ -1 +1,136 @@
|
|
1
|
-
import
|
1
|
+
import { LitElement, noChange } from 'lit';
|
2
|
+
import { Directive, directive, PartType, } from 'lit/directive.js';
|
3
|
+
const isThrow = ['localhost', '127.0.0.1'].some((host) => {
|
4
|
+
return window.location.host.includes(host);
|
5
|
+
});
|
6
|
+
class AssertSlot extends Directive {
|
7
|
+
render(
|
8
|
+
// This method is required, both by `Directive` and so the directive's
|
9
|
+
// options are typed at `assertSlot()` callsite.
|
10
|
+
//
|
11
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
12
|
+
slotted, isOptional) {
|
13
|
+
return noChange;
|
14
|
+
}
|
15
|
+
update(part, [slotted, isOptional]) {
|
16
|
+
if (part.options?.host instanceof LitElement && isThrow) {
|
17
|
+
const host = part.options.host;
|
18
|
+
if (part.options?.host instanceof LitElement &&
|
19
|
+
!part.options.host.hasUpdated &&
|
20
|
+
isThrow) {
|
21
|
+
// Equivalent to `firstUpdated()`. We need this in addition to the "slotchange"
|
22
|
+
// handler because the handler won't be called if the slot is empty.
|
23
|
+
part.options.host.updateComplete.then(() => {
|
24
|
+
if (!isOptional &&
|
25
|
+
part.element instanceof HTMLSlotElement &&
|
26
|
+
part.element.assignedNodes().length === 0 &&
|
27
|
+
slotted?.length) {
|
28
|
+
const message = part.element.name
|
29
|
+
? `Expected the "${part.element.name}" slot of ${host.constructor.name} to have a slotted element that extends ${slotted
|
30
|
+
.map(({ name }) => name)
|
31
|
+
.join(' or ')}.`
|
32
|
+
: `Expected ${host.constructor.name} to have a slotted element that extends ${slotted
|
33
|
+
.map(({ name }) => name)
|
34
|
+
.join(' or ')}.`;
|
35
|
+
throw new TypeError(message);
|
36
|
+
}
|
37
|
+
if (!isOptional &&
|
38
|
+
part.element instanceof HTMLSlotElement &&
|
39
|
+
part.element.assignedNodes().length === 0) {
|
40
|
+
const message = part.element.name
|
41
|
+
? `Expected ${host.constructor.name} to have a "${part.element.name}" slot.`
|
42
|
+
: `Expected ${host.constructor.name} to have a default slot.`;
|
43
|
+
throw new TypeError(message);
|
44
|
+
}
|
45
|
+
});
|
46
|
+
if (part.options?.host instanceof LitElement &&
|
47
|
+
!part.options.host.hasUpdated) {
|
48
|
+
part.element?.addEventListener('slotchange', () => {
|
49
|
+
if (isOptional &&
|
50
|
+
part.element instanceof HTMLSlotElement &&
|
51
|
+
part.element.assignedNodes().length === 0) {
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
if (part.element instanceof HTMLSlotElement &&
|
55
|
+
part.element.assignedNodes().length === 0) {
|
56
|
+
if (slotted && slotted.length > 0) {
|
57
|
+
const message = part.element.name
|
58
|
+
? `Expected the "${part.element.name}" slot of ${host.constructor.name} to have a slotted element that extends ${slotted
|
59
|
+
.map(({ name }) => name)
|
60
|
+
.join(' or ')}.`
|
61
|
+
: `Expected ${host.constructor.name} to have a slotted element that extends ${slotted
|
62
|
+
.map(({ name }) => name)
|
63
|
+
.join(' or ')}.`;
|
64
|
+
throw new TypeError(message);
|
65
|
+
}
|
66
|
+
const message = part.element.name
|
67
|
+
? `Expected a "${part.element.name}" slot.`
|
68
|
+
: 'Expected a default slot.';
|
69
|
+
throw new TypeError(message);
|
70
|
+
}
|
71
|
+
if (slotted?.length && part.element instanceof HTMLSlotElement) {
|
72
|
+
const nodes = part.element
|
73
|
+
.assignedNodes({ flatten: true })
|
74
|
+
.filter((node) => {
|
75
|
+
// If `assignedNodes()` includes a `Text` node but `Text` isn't included in
|
76
|
+
// `slotted`, then it's filtered out so `isAllowed` doesn't result in a false
|
77
|
+
// positive. This doesn't mean that a slot can't contain `Text` node. It just
|
78
|
+
// means the presence of a `Text` node isn't enough to satisfy the requirements.
|
79
|
+
return node instanceof Text && slotted.includes(Text)
|
80
|
+
? true
|
81
|
+
: node instanceof Text
|
82
|
+
? false
|
83
|
+
: true;
|
84
|
+
});
|
85
|
+
// If `nodes` is empty after filtering, then the slot only contains `Text`
|
86
|
+
// nodes and `types` does not include `Text`. This is usually a case where
|
87
|
+
// the slot only contains whitespace.
|
88
|
+
if (nodes.length === 0) {
|
89
|
+
// "node" is technically correct because a consumer could have slotted text,
|
90
|
+
// and "node" covers both text and elements. But "element" probably gets
|
91
|
+
// the point across better for most developers.
|
92
|
+
const message = `Expected ${host.constructor.name} to have a slotted element that extends ${slotted
|
93
|
+
.map(({ name }) => name)
|
94
|
+
.join(' or ')}.`;
|
95
|
+
throw new TypeError(message);
|
96
|
+
}
|
97
|
+
for (const node of nodes) {
|
98
|
+
const isAllowed = slotted.some((Constructor) => node instanceof Constructor);
|
99
|
+
if (!isAllowed) {
|
100
|
+
const message = part.element.name
|
101
|
+
? `Expected the "${part.element.name}" slot of ${host.constructor.name} to have a slotted element that extends ${slotted
|
102
|
+
.map(({ name }) => name)
|
103
|
+
.join(' or ')}. Extends ${node.constructor.name} instead.`
|
104
|
+
: `Expected ${host.constructor.name} to have a slotted element that extends ${slotted
|
105
|
+
.map(({ name }) => name)
|
106
|
+
.join(' or ')}. Extends ${node.constructor.name} instead.`;
|
107
|
+
throw new TypeError(message);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
});
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
// Purely for test coverage purposes. If `update()` doesn't call `render()`,
|
116
|
+
// nothing will because `update()` exists.
|
117
|
+
return this.render();
|
118
|
+
}
|
119
|
+
constructor(partInfo) {
|
120
|
+
super(partInfo);
|
121
|
+
if (partInfo.type !== PartType.ELEMENT) {
|
122
|
+
throw new TypeError("Directive must be inside the element's opening tag.");
|
123
|
+
}
|
124
|
+
if ('element' in partInfo) {
|
125
|
+
const isSlot = partInfo.element instanceof HTMLSlotElement;
|
126
|
+
if (!isSlot) {
|
127
|
+
throw new TypeError('Directive can only be used on slots.');
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
/**
|
133
|
+
* @param {(Element | Text)[] | null } nodes - An array of node constructors allowed in the slot or `null` is any constructor is allowed
|
134
|
+
* @param {boolean} [isOptional] - `false` by default. Set to `true` if the slot is optional
|
135
|
+
*/
|
136
|
+
export default directive(AssertSlot);
|
@@ -1 +1,14 @@
|
|
1
|
-
import{expect,waitUntil}from
|
1
|
+
import { expect, waitUntil } from '@open-wc/testing';
|
2
|
+
import sinon from 'sinon';
|
3
|
+
export default async function (callback) {
|
4
|
+
const stub = sinon.stub(console, 'error');
|
5
|
+
const spy = sinon.spy();
|
6
|
+
window.addEventListener('unhandledrejection', spy, { once: true });
|
7
|
+
await callback.call(context);
|
8
|
+
await waitUntil(() => spy.callCount);
|
9
|
+
expect(spy.callCount).to.equal(1);
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
11
|
+
expect(spy.args.at(0)?.at(0) instanceof PromiseRejectionEvent).to.be.true;
|
12
|
+
window.removeEventListener('unhandledrejection', spy);
|
13
|
+
stub.restore();
|
14
|
+
}
|
@@ -1 +1,26 @@
|
|
1
|
-
import{expect,waitUntil}from
|
1
|
+
import { expect, waitUntil } from '@open-wc/testing';
|
2
|
+
import sinon from 'sinon';
|
3
|
+
export default async function (callback) {
|
4
|
+
const stub = sinon.stub(console, 'error');
|
5
|
+
const spy = sinon.spy();
|
6
|
+
const onerror = window.onerror;
|
7
|
+
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
8
|
+
window.onerror = spy;
|
9
|
+
await callback.call(context);
|
10
|
+
await waitUntil(() => spy.callCount);
|
11
|
+
// Some components assert against a slot that is itself slotted content for
|
12
|
+
// a component. For example, Split Button Secondary Button and its default slot.
|
13
|
+
//
|
14
|
+
// Split Button Secondary Button passes its default slot into Menu's default slot,
|
15
|
+
// and Menu asserts against its default slot. So Split Button Secondary Button's
|
16
|
+
// default slot test produces two errors: one from itself and one from Menu.
|
17
|
+
//
|
18
|
+
// Rather than account for cases like that in each test, we simply use
|
19
|
+
// `to.be.greaterThan()` instead of `to.equal(1)`.
|
20
|
+
expect(spy.callCount).to.be.greaterThan(0);
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
22
|
+
expect(spy.args.at(0)?.at(4) instanceof Error).to.be.true;
|
23
|
+
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
24
|
+
window.onerror = onerror;
|
25
|
+
stub.restore();
|
26
|
+
}
|
package/dist/library/final.js
CHANGED
@@ -1 +1,18 @@
|
|
1
|
-
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
2
|
+
export default function (constructor) {
|
3
|
+
class Final extends constructor {
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
5
|
+
constructor(...arguments_) {
|
6
|
+
if (new.target !== Final) {
|
7
|
+
throw new TypeError(`${constructor.name} doesn't allow extension. Please talk to us if a component doesn't meet your needs.`);
|
8
|
+
}
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
10
|
+
super(...arguments_);
|
11
|
+
}
|
12
|
+
}
|
13
|
+
// Particularly helpful when dealing with `event.target`. Consumers
|
14
|
+
// expect that property's name to be that of the original constructor
|
15
|
+
// and not "Final".
|
16
|
+
Object.defineProperty(Final, 'name', { value: constructor.name });
|
17
|
+
return Final;
|
18
|
+
}
|
@@ -1 +1 @@
|
|
1
|
-
export{};
|
1
|
+
export {};
|
package/dist/library/localize.js
CHANGED
@@ -1 +1,10 @@
|
|
1
|
-
import{LocalizeController as DefaultLocalizationController,registerTranslation}from
|
1
|
+
import { LocalizeController as DefaultLocalizationController, registerTranslation, } from '@shoelace-style/localize';
|
2
|
+
import en from '../translations/en.js'; // Register English as the default/fallback language
|
3
|
+
import fr from '../translations/fr.js';
|
4
|
+
import ja from '../translations/ja.js';
|
5
|
+
// Extend the controller and apply our own translation interface for better typings
|
6
|
+
export class LocalizeController extends DefaultLocalizationController {
|
7
|
+
static {
|
8
|
+
registerTranslation(en, ja, fr);
|
9
|
+
}
|
10
|
+
}
|
package/dist/library/mouse.js
CHANGED
@@ -1 +1,35 @@
|
|
1
|
-
import{assert}from
|
1
|
+
import { assert } from '@open-wc/testing';
|
2
|
+
import { resetMouse, sendMouse } from '@web/test-runner-commands';
|
3
|
+
export function click(element, position = 'center') {
|
4
|
+
return mouse(element, position, 'click');
|
5
|
+
}
|
6
|
+
export function hover(element, position = 'center') {
|
7
|
+
return mouse(element, position, 'move');
|
8
|
+
}
|
9
|
+
async function mouse(element, position = 'center', type) {
|
10
|
+
assert(element);
|
11
|
+
const { height, width, x, y } = element.getBoundingClientRect();
|
12
|
+
await sendMouse({
|
13
|
+
type,
|
14
|
+
position: position === 'top'
|
15
|
+
? [Math.ceil(x + width / 2), Math.ceil(y)]
|
16
|
+
: position === 'right'
|
17
|
+
? [Math.floor(x + width), Math.ceil(y + height / 2)]
|
18
|
+
: position === 'bottom'
|
19
|
+
? [Math.ceil(x + width / 2), Math.floor(y + height)]
|
20
|
+
: position === 'left'
|
21
|
+
? [Math.ceil(x), Math.ceil(y + height / 2)]
|
22
|
+
: position === 'outside'
|
23
|
+
? [Math.floor(x - 1), Math.floor(y - 1)]
|
24
|
+
: // Center
|
25
|
+
[Math.ceil(x + width / 2), Math.ceil(y + height / 2)],
|
26
|
+
});
|
27
|
+
// You'd think you'd be able to call `resetMouse()` anywhere. But, for whatever
|
28
|
+
// reason, calling it outside `afterEach()` results in sporadic bouts of the
|
29
|
+
// following error via Playwright:
|
30
|
+
//
|
31
|
+
// "mouse.move: Target page, context or browser has been closed".
|
32
|
+
afterEach(async () => {
|
33
|
+
await resetMouse();
|
34
|
+
});
|
35
|
+
}
|