@lion/ui 0.0.3 → 0.0.5
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/components/calendar/src/LionCalendar.js +10 -4
- package/components/combobox/src/LionCombobox.js +6 -4
- package/components/core/src/DisabledMixin.js +6 -4
- package/components/core/src/DisabledWithTabIndexMixin.js +6 -4
- package/components/core/src/SlotMixin.js +180 -42
- package/components/core/test/SlotMixin.test.js +341 -138
- package/components/core/types/SlotMixinTypes.ts +13 -2
- package/components/form-core/src/FormatMixin.js +10 -8
- package/components/form-core/src/InteractionStateMixin.js +8 -6
- package/components/form-core/src/choice-group/ChoiceInputMixin.js +6 -4
- package/components/form-core/src/utils/SyncUpdatableMixin.js +9 -4
- package/components/form-core/test/utils/SyncUpdatableMixin.test.js +6 -4
- package/components/form-core/test-suites/ValidateMixin.suite.js +1 -1
- package/components/form-core/test-suites/form-group/FormGroupMixin.suite.js +2 -2
- package/components/input/src/LionInput.js +6 -4
- package/components/input-datepicker/src/LionInputDatepicker.js +6 -4
- package/components/input-tel/src/LionInputTel.js +7 -22
- package/components/input-tel/src/PhoneUtilManager.js +9 -5
- package/components/input-tel/src/formatters.js +8 -10
- package/components/input-tel/src/parsers.js +3 -4
- package/components/input-tel/src/preprocessors.js +2 -4
- package/components/input-tel/src/validators.js +4 -6
- package/components/input-tel/test/validators.test.js +8 -5
- package/components/input-tel-dropdown/src/LionInputTelDropdown.js +41 -32
- package/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js +5 -6
- package/components/listbox/src/LionOption.js +6 -4
- package/components/localize/types/LocalizeMixinTypes.ts +1 -1
- package/components/overlays/src/OverlayMixin.js +6 -5
- package/components/overlays/src/OverlaysManager.js +21 -4
- package/components/overlays/src/globalOverlaysStyle.js +10 -0
- package/components/overlays/test/OverlaysManager.test.js +76 -0
- package/components/overlays/test-suites/OverlayMixin.suite.js +20 -14
- package/components/select-rich/src/LionSelectRich.js +6 -4
- package/components/switch/src/LionSwitchButton.js +6 -7
- package/custom-elements.json +2002 -291
- package/dist-types/components/accordion/src/LionAccordion.d.ts +1 -1
- package/dist-types/components/button/src/LionButton.d.ts +1 -1
- package/dist-types/components/calendar/src/LionCalendar.d.ts +7 -41
- package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
- package/dist-types/components/checkbox-group/src/LionCheckboxGroup.d.ts +1 -1
- package/dist-types/components/checkbox-group/src/LionCheckboxIndeterminate.d.ts +0 -4
- package/dist-types/components/checkbox-group/src/LionCheckboxIndeterminate.d.ts.map +1 -1
- package/dist-types/components/collapsible/src/LionCollapsible.d.ts +1 -1
- package/dist-types/components/combobox/src/LionCombobox.d.ts +5 -3
- package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
- package/dist-types/components/core/src/DisabledMixin.d.ts.map +1 -1
- package/dist-types/components/core/src/DisabledWithTabIndexMixin.d.ts.map +1 -1
- package/dist-types/components/core/src/SlotMixin.d.ts +3 -1
- package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
- package/dist-types/components/core/test/SlotMixin.test.d.ts +1 -1
- package/dist-types/components/core/test/SlotMixin.test.d.ts.map +1 -1
- package/dist-types/components/core/types/SlotMixinTypes.d.ts +10 -2
- package/dist-types/components/core/types/SlotMixinTypes.d.ts.map +1 -1
- package/dist-types/components/dialog/src/LionDialog.d.ts +1 -1
- package/dist-types/components/fieldset/src/LionFieldset.d.ts +1 -1
- package/dist-types/components/form-core/src/FormatMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/InteractionStateMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/LionField.d.ts +1 -1
- package/dist-types/components/form-core/src/choice-group/ChoiceInputMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/utils/SyncUpdatableMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/validate/LionValidationFeedback.d.ts +1 -1
- package/dist-types/components/form-core/test-suites/FormRegistrationMixins.suite.d.ts +1 -1
- package/dist-types/components/form-integrations/test/helpers/umbrella-form.d.ts +1 -1
- package/dist-types/components/helpers/src/SbActionLogger.d.ts +1 -1
- package/dist-types/components/helpers/src/SbLocaleSwitcher.d.ts +1 -1
- package/dist-types/components/icon/src/LionIcon.d.ts +1 -1
- package/dist-types/components/input/src/LionInput.d.ts +5 -3
- package/dist-types/components/input/src/LionInput.d.ts.map +1 -1
- package/dist-types/components/input-amount/src/LionInputAmount.d.ts +1 -37
- package/dist-types/components/input-amount/src/LionInputAmount.d.ts.map +1 -1
- package/dist-types/components/input-date/src/LionInputDate.d.ts +1 -37
- package/dist-types/components/input-date/src/LionInputDate.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts +2 -38
- package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +0 -5
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
- package/dist-types/components/input-email/src/LionInputEmail.d.ts +1 -37
- package/dist-types/components/input-email/src/LionInputEmail.d.ts.map +1 -1
- package/dist-types/components/input-iban/src/LionInputIban.d.ts +1 -37
- package/dist-types/components/input-iban/src/LionInputIban.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/LionInputTel.d.ts +3 -63
- package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts +8 -4
- package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/formatters.d.ts +0 -2
- package/dist-types/components/input-tel/src/formatters.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/parsers.d.ts +0 -2
- package/dist-types/components/input-tel/src/parsers.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/preprocessors.d.ts +0 -2
- package/dist-types/components/input-tel/src/preprocessors.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/validators.d.ts +0 -1
- package/dist-types/components/input-tel/src/validators.d.ts.map +1 -1
- package/dist-types/components/input-tel/test/validators.test.d.ts +1 -1
- package/dist-types/components/input-tel/test/validators.test.d.ts.map +1 -1
- package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts +20 -16
- package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts.map +1 -1
- package/dist-types/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.d.ts.map +1 -1
- package/dist-types/components/listbox/src/LionListbox.d.ts +1 -1
- package/dist-types/components/listbox/src/LionOption.d.ts +6 -4
- package/dist-types/components/listbox/src/LionOption.d.ts.map +1 -1
- package/dist-types/components/listbox/src/LionOptions.d.ts +1 -1
- package/dist-types/components/localize/src/LocalizeMixin.d.ts +1 -37
- package/dist-types/components/localize/src/LocalizeMixin.d.ts.map +1 -1
- package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts +1 -1
- package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlaysManager.d.ts +4 -0
- package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
- package/dist-types/components/overlays/src/globalOverlaysStyle.d.ts.map +1 -1
- package/dist-types/components/overlays/test/OverlaysManager.test.d.ts.map +1 -1
- package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
- package/dist-types/components/pagination/src/LionPagination.d.ts +2 -38
- package/dist-types/components/pagination/src/LionPagination.d.ts.map +1 -1
- package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts +2 -38
- package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts.map +1 -1
- package/dist-types/components/radio-group/src/LionRadioGroup.d.ts +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +5 -3
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
- package/dist-types/components/steps/src/LionStep.d.ts +1 -1
- package/dist-types/components/steps/src/LionSteps.d.ts +1 -1
- package/dist-types/components/switch/src/LionSwitchButton.d.ts +6 -7
- package/dist-types/components/switch/src/LionSwitchButton.d.ts.map +1 -1
- package/dist-types/components/tabs/src/LionTabs.d.ts +1 -1
- package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
- package/dist-types/exports/types/core.d.ts +2 -0
- package/dist-types/exports/types/core.d.ts.map +1 -0
- package/dist-types/exports/types/form-core.d.ts +3 -0
- package/dist-types/exports/types/form-core.d.ts.map +1 -0
- package/dist-types/exports/types/input-tel-dropdown.d.ts +3 -0
- package/dist-types/exports/types/input-tel-dropdown.d.ts.map +1 -0
- package/dist-types/exports/types/input-tel.d.ts +2 -0
- package/dist-types/exports/types/input-tel.d.ts.map +1 -0
- package/dist-types/exports/types/localize.d.ts +4 -0
- package/dist-types/exports/types/localize.d.ts.map +1 -0
- package/dist-types/exports/types/overlays.d.ts +5 -0
- package/dist-types/exports/types/overlays.d.ts.map +1 -0
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- package/docs/components/icon/use-cases.md +1 -1
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/overview.md +1 -1
- package/docs/components/input-tel/use-cases.md +6 -6
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/tabs/examples.md +1 -1
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
- package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
- package/docs/fundamentals/systems/core/overview.md +1 -1
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
- package/docs/fundamentals/systems/form/model-value.md +1 -1
- package/docs/fundamentals/systems/form/overview.md +28 -28
- package/docs/fundamentals/systems/form/validate.md +1 -1
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/configuration.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
- package/docs/guides/how-to/create-a-custom-field.md +5 -5
- package/docs/guides/how-to/extend-a-native-input.md +2 -2
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/styling.md +1 -1
- package/exports/types/core.ts +1 -0
- package/exports/types/form-core.ts +2 -0
- package/exports/types/input-tel-dropdown.ts +2 -0
- package/exports/types/input-tel.ts +1 -0
- package/exports/types/localize.ts +3 -0
- package/exports/types/overlays.ts +4 -0
- package/package.json +8 -5
|
@@ -4,6 +4,10 @@ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
|
|
|
4
4
|
import { SlotMixin } from '@lion/ui/core.js';
|
|
5
5
|
import { LitElement } from 'lit';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('../types/SlotMixinTypes.js').SlotHost} SlotHost
|
|
9
|
+
*/
|
|
10
|
+
|
|
7
11
|
const mockedRenderTarget = document.createElement('div');
|
|
8
12
|
function mockScopedRegistry() {
|
|
9
13
|
const outputObj = { createElementCallCount: 0 };
|
|
@@ -26,7 +30,7 @@ function unMockScopedRegistry() {
|
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
describe('SlotMixin', () => {
|
|
29
|
-
it('inserts provided element into
|
|
33
|
+
it('inserts provided element into light dom and sets slot', async () => {
|
|
30
34
|
const tag = defineCE(
|
|
31
35
|
class extends SlotMixin(LitElement) {
|
|
32
36
|
get slots() {
|
|
@@ -41,7 +45,7 @@ describe('SlotMixin', () => {
|
|
|
41
45
|
expect(el.children[0].slot).to.equal('feedback');
|
|
42
46
|
});
|
|
43
47
|
|
|
44
|
-
it("supports
|
|
48
|
+
it("supports default slot with ''", async () => {
|
|
45
49
|
const tag = defineCE(
|
|
46
50
|
class extends SlotMixin(LitElement) {
|
|
47
51
|
get slots() {
|
|
@@ -57,7 +61,7 @@ describe('SlotMixin', () => {
|
|
|
57
61
|
expect(el.children[0]).dom.to.equal('<div></div>');
|
|
58
62
|
});
|
|
59
63
|
|
|
60
|
-
it('supports
|
|
64
|
+
it('supports default slot in conjunction with named slots', async () => {
|
|
61
65
|
const tag = defineCE(
|
|
62
66
|
class extends SlotMixin(LitElement) {
|
|
63
67
|
get slots() {
|
|
@@ -111,63 +115,6 @@ describe('SlotMixin', () => {
|
|
|
111
115
|
expect(slot.innerText).to.equal('');
|
|
112
116
|
});
|
|
113
117
|
|
|
114
|
-
it('supports complex dom trees as element', async () => {
|
|
115
|
-
const tag = defineCE(
|
|
116
|
-
class extends SlotMixin(LitElement) {
|
|
117
|
-
constructor() {
|
|
118
|
-
super();
|
|
119
|
-
this.foo = 'bar';
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
get slots() {
|
|
123
|
-
return {
|
|
124
|
-
...super.slots,
|
|
125
|
-
feedback: () => {
|
|
126
|
-
const el = document.createElement('div');
|
|
127
|
-
el.setAttribute('foo', this.foo);
|
|
128
|
-
const subEl = document.createElement('p');
|
|
129
|
-
subEl.innerText = 'cat';
|
|
130
|
-
el.appendChild(subEl);
|
|
131
|
-
return el;
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
);
|
|
137
|
-
const el = await fixture(`<${tag}></${tag}>`);
|
|
138
|
-
expect(el.children[0].slot).to.equal('feedback');
|
|
139
|
-
expect(el.children[0].getAttribute('foo')).to.equal('bar');
|
|
140
|
-
expect(/** @type HTMLParagraphElement */ (el.children[0].children[0]).innerText).to.equal(
|
|
141
|
-
'cat',
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('supports conditional slots', async () => {
|
|
146
|
-
let renderSlot = true;
|
|
147
|
-
const tag = defineCE(
|
|
148
|
-
class extends SlotMixin(LitElement) {
|
|
149
|
-
get slots() {
|
|
150
|
-
return {
|
|
151
|
-
...super.slots,
|
|
152
|
-
conditional: () => {
|
|
153
|
-
if (renderSlot) {
|
|
154
|
-
const el = document.createElement('div');
|
|
155
|
-
el.id = 'someSlot';
|
|
156
|
-
return el;
|
|
157
|
-
}
|
|
158
|
-
return undefined;
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
);
|
|
164
|
-
const elSlot = await fixture(`<${tag}><${tag}>`);
|
|
165
|
-
expect(elSlot.querySelector('#someSlot')).to.exist;
|
|
166
|
-
renderSlot = false;
|
|
167
|
-
const elNoSlot = await fixture(`<${tag}><${tag}>`);
|
|
168
|
-
expect(elNoSlot.querySelector('#someSlot')).to.not.exist;
|
|
169
|
-
});
|
|
170
|
-
|
|
171
118
|
it("allows to check which slots have been created via this._isPrivateSlot('slotname')", async () => {
|
|
172
119
|
let renderSlot = true;
|
|
173
120
|
class SlotPrivateText extends SlotMixin(LitElement) {
|
|
@@ -195,102 +142,358 @@ describe('SlotMixin', () => {
|
|
|
195
142
|
expect(elNoSlot.didCreateConditionalSlot()).to.be.false;
|
|
196
143
|
});
|
|
197
144
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
template: () => html`<span>text</span>`,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
145
|
+
describe('Rerender', () => {
|
|
146
|
+
it('supports rerender when SlotRerenderObject provided', async () => {
|
|
147
|
+
const tag = defineCE(
|
|
148
|
+
// @ts-expect-error
|
|
149
|
+
class extends SlotMixin(LitElement) {
|
|
150
|
+
static properties = { currentValue: Number };
|
|
207
151
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
);
|
|
213
|
-
const el = await fixture(`<${tag}></${tag}>`);
|
|
214
|
-
const slot = /** @type HTMLSpanElement */ (
|
|
215
|
-
Array.from(el.children).find(elm => elm.slot === 'template')
|
|
216
|
-
);
|
|
217
|
-
expect(slot.slot).to.equal('template');
|
|
218
|
-
expect(slot.tagName).to.equal('SPAN');
|
|
219
|
-
});
|
|
152
|
+
constructor() {
|
|
153
|
+
super();
|
|
154
|
+
this.currentValue = 0;
|
|
155
|
+
}
|
|
220
156
|
|
|
221
|
-
|
|
222
|
-
|
|
157
|
+
get slots() {
|
|
158
|
+
return {
|
|
159
|
+
...super.slots,
|
|
160
|
+
template: () => ({ template: html`<span>${this.currentValue}</span> ` }),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
223
163
|
|
|
224
|
-
|
|
164
|
+
render() {
|
|
165
|
+
return html`<slot name="template"></slot>`;
|
|
166
|
+
}
|
|
225
167
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
168
|
+
get _templateNode() {
|
|
169
|
+
return /** @type HTMLSpanElement */ (
|
|
170
|
+
Array.from(this.children).find(elm => elm.slot === 'template')
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
const el = /** @type {* & SlotHost} */ (await fixture(`<${tag}></${tag}>`));
|
|
176
|
+
await el.updateComplete;
|
|
177
|
+
|
|
178
|
+
expect(el._templateNode.slot).to.equal('template');
|
|
179
|
+
expect(el._templateNode.textContent?.trim()).to.equal('0');
|
|
180
|
+
|
|
181
|
+
el.currentValue = 1;
|
|
182
|
+
await el.updateComplete;
|
|
183
|
+
|
|
184
|
+
expect(el._templateNode.textContent?.trim()).to.equal('1');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('keeps focus after rerender', async () => {
|
|
188
|
+
const tag = defineCE(
|
|
189
|
+
// @ts-expect-error
|
|
190
|
+
class extends SlotMixin(LitElement) {
|
|
191
|
+
static properties = { currentValue: Number };
|
|
192
|
+
|
|
193
|
+
constructor() {
|
|
194
|
+
super();
|
|
195
|
+
this.currentValue = 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
get slots() {
|
|
199
|
+
return {
|
|
200
|
+
...super.slots,
|
|
201
|
+
'focusable-node': () => ({
|
|
202
|
+
template: html`<input /> `,
|
|
203
|
+
}),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
render() {
|
|
208
|
+
return html`<slot name="focusable-node"></slot>`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
get _focusableNode() {
|
|
212
|
+
return /** @type HTMLSpanElement */ (
|
|
213
|
+
Array.from(this.children).find(elm => elm.slot === 'focusable-node')
|
|
214
|
+
?.firstElementChild
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
);
|
|
219
|
+
const el = /** @type {* & SlotHost} */ (await fixture(`<${tag}></${tag}>`));
|
|
220
|
+
|
|
221
|
+
el._focusableNode.focus();
|
|
222
|
+
expect(document.activeElement).to.equal(el._focusableNode);
|
|
223
|
+
|
|
224
|
+
el.currentValue = 1;
|
|
225
|
+
await el.updateComplete;
|
|
226
|
+
|
|
227
|
+
expect(document.activeElement).to.equal(el._focusableNode);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('keeps focus after rerendering complex shadow root into slot', async () => {
|
|
231
|
+
const complexSlotTagName = defineCE(
|
|
232
|
+
class extends LitElement {
|
|
233
|
+
render() {
|
|
234
|
+
return html`
|
|
235
|
+
<input />
|
|
236
|
+
<button>I will be focused</button>
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
get _buttonNode() {
|
|
230
241
|
// @ts-expect-error
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
242
|
+
return this.shadowRoot.querySelector('button');
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
);
|
|
235
246
|
|
|
236
|
-
|
|
237
|
-
return {
|
|
238
|
-
...super.slots,
|
|
239
|
-
template: () => html`<scoped-el></scoped-el>`,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
247
|
+
const complexSlotTag = unsafeStatic(complexSlotTagName);
|
|
242
248
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
249
|
+
const tagName = defineCE(
|
|
250
|
+
// @ts-expect-error
|
|
251
|
+
class extends SlotMixin(LitElement) {
|
|
252
|
+
static properties = { currentValue: Number };
|
|
248
253
|
|
|
249
|
-
|
|
250
|
-
|
|
254
|
+
constructor() {
|
|
255
|
+
super();
|
|
256
|
+
this.currentValue = 0;
|
|
257
|
+
}
|
|
251
258
|
|
|
252
|
-
|
|
259
|
+
get slots() {
|
|
260
|
+
return {
|
|
261
|
+
...super.slots,
|
|
262
|
+
'focusable-node': () => ({
|
|
263
|
+
template: html`<${complexSlotTag}> </${complexSlotTag}> `,
|
|
264
|
+
}),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
253
267
|
|
|
254
|
-
|
|
268
|
+
render() {
|
|
269
|
+
return html`<slot name="focusable-node"></slot>`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
get _focusableNode() {
|
|
273
|
+
return /** @type HTMLSpanElement */ (
|
|
274
|
+
Array.from(this.children).find(elm => elm.slot === 'focusable-node')
|
|
275
|
+
?.firstElementChild
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
);
|
|
280
|
+
const el = /** @type {* & SlotHost} */ (await fixture(`<${tagName}></${tagName}>`));
|
|
281
|
+
|
|
282
|
+
el._focusableNode._buttonNode.focus();
|
|
283
|
+
|
|
284
|
+
expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
|
|
285
|
+
|
|
286
|
+
el.currentValue = 1;
|
|
287
|
+
await el.updateComplete;
|
|
288
|
+
|
|
289
|
+
expect(document.activeElement).to.equal(el._focusableNode);
|
|
290
|
+
expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
|
|
291
|
+
});
|
|
255
292
|
});
|
|
256
293
|
|
|
257
|
-
|
|
258
|
-
|
|
294
|
+
describe('SlotFunctionResult types', () => {
|
|
295
|
+
it('supports complex dom trees as element (type "Element")', async () => {
|
|
296
|
+
const tag = defineCE(
|
|
297
|
+
class extends SlotMixin(LitElement) {
|
|
298
|
+
constructor() {
|
|
299
|
+
super();
|
|
300
|
+
this.foo = 'bar';
|
|
301
|
+
}
|
|
259
302
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
303
|
+
get slots() {
|
|
304
|
+
return {
|
|
305
|
+
...super.slots,
|
|
306
|
+
feedback: () => {
|
|
307
|
+
const el = document.createElement('div');
|
|
308
|
+
el.setAttribute('foo', this.foo);
|
|
309
|
+
const subEl = document.createElement('p');
|
|
310
|
+
subEl.innerText = 'cat';
|
|
311
|
+
el.appendChild(subEl);
|
|
312
|
+
return el;
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
);
|
|
318
|
+
const el = await fixture(`<${tag}></${tag}>`);
|
|
319
|
+
expect(el.children[0].slot).to.equal('feedback');
|
|
320
|
+
expect(el.children[0].getAttribute('foo')).to.equal('bar');
|
|
321
|
+
expect(/** @type HTMLParagraphElement */ (el.children[0].children[0]).innerText).to.equal(
|
|
322
|
+
'cat',
|
|
323
|
+
);
|
|
324
|
+
});
|
|
269
325
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
326
|
+
it('supports conditional slots (type "undefined")', async () => {
|
|
327
|
+
let renderSlot = true;
|
|
328
|
+
const tag = defineCE(
|
|
329
|
+
class extends SlotMixin(LitElement) {
|
|
330
|
+
get slots() {
|
|
331
|
+
return {
|
|
332
|
+
...super.slots,
|
|
333
|
+
conditional: () => {
|
|
334
|
+
if (renderSlot) {
|
|
335
|
+
const el = document.createElement('div');
|
|
336
|
+
el.id = 'someSlot';
|
|
337
|
+
return el;
|
|
338
|
+
}
|
|
339
|
+
return undefined;
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
);
|
|
345
|
+
const elSlot = await fixture(`<${tag}><${tag}>`);
|
|
346
|
+
expect(elSlot.querySelector('#someSlot')).to.exist;
|
|
347
|
+
renderSlot = false;
|
|
348
|
+
const elNoSlot = await fixture(`<${tag}><${tag}>`);
|
|
349
|
+
expect(elNoSlot.querySelector('#someSlot')).to.not.exist;
|
|
350
|
+
});
|
|
276
351
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
352
|
+
it('supports templates (type "TemplateResult")', async () => {
|
|
353
|
+
const tag = defineCE(
|
|
354
|
+
class extends SlotMixin(LitElement) {
|
|
355
|
+
get slots() {
|
|
356
|
+
return {
|
|
357
|
+
...super.slots,
|
|
358
|
+
template: () => html`<span>text</span>`,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
render() {
|
|
363
|
+
return html`<slot name="template"></slot>`;
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
);
|
|
367
|
+
const el = await fixture(`<${tag}></${tag}>`);
|
|
368
|
+
const slot = /** @type HTMLSpanElement */ (
|
|
369
|
+
Array.from(el.children).find(elm => elm.slot === 'template')
|
|
370
|
+
);
|
|
371
|
+
expect(slot.slot).to.equal('template');
|
|
372
|
+
expect(slot.tagName).to.equal('SPAN');
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('supports afterRender logic (type "{ template:TemplateResults; afterRender: Function}" )', async () => {
|
|
376
|
+
let varThatProvesAfterRenderIsCalled = 'not called';
|
|
377
|
+
|
|
378
|
+
const tag = defineCE(
|
|
379
|
+
// @ts-expect-error
|
|
380
|
+
class extends SlotMixin(LitElement) {
|
|
381
|
+
static properties = { currentValue: Number };
|
|
382
|
+
|
|
383
|
+
constructor() {
|
|
384
|
+
super();
|
|
385
|
+
this.currentValue = 0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
get slots() {
|
|
389
|
+
return {
|
|
390
|
+
...super.slots,
|
|
391
|
+
template: () => ({
|
|
392
|
+
template: html`<span>${this.currentValue}</span>, `,
|
|
393
|
+
afterRender: () => {
|
|
394
|
+
varThatProvesAfterRenderIsCalled = 'called';
|
|
395
|
+
},
|
|
396
|
+
}),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
render() {
|
|
401
|
+
return html`<slot name="template"></slot>`;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
get _templateNode() {
|
|
405
|
+
return /** @type HTMLSpanElement */ (
|
|
406
|
+
Array.from(this.children).find(elm => elm.slot === 'template')?.firstElementChild
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
);
|
|
411
|
+
const el = /** @type {* & SlotHost} */ (await fixture(`<${tag}></${tag}>`));
|
|
412
|
+
expect(el._templateNode.textContent).to.equal('0');
|
|
413
|
+
|
|
414
|
+
el.currentValue = 1;
|
|
415
|
+
await el.updateComplete;
|
|
416
|
+
|
|
417
|
+
expect(varThatProvesAfterRenderIsCalled).to.equal('called');
|
|
418
|
+
expect(el._templateNode.textContent).to.equal('1');
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
describe('Scoped Registries', () => {
|
|
423
|
+
it('supports scoped elements when polyfill loaded', async () => {
|
|
424
|
+
const outputObj = mockScopedRegistry();
|
|
425
|
+
|
|
426
|
+
class ScopedEl extends LitElement {}
|
|
427
|
+
|
|
428
|
+
const tagName = defineCE(
|
|
429
|
+
class extends ScopedElementsMixin(SlotMixin(LitElement)) {
|
|
430
|
+
static get scopedElements() {
|
|
431
|
+
return {
|
|
432
|
+
// @ts-expect-error
|
|
433
|
+
...super.scopedElements,
|
|
434
|
+
'scoped-elm': ScopedEl,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
get slots() {
|
|
439
|
+
return {
|
|
440
|
+
...super.slots,
|
|
441
|
+
template: () => html`<scoped-elm></scoped-elm>`,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
render() {
|
|
446
|
+
return html`<slot name="template"></slot>`;
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
const tag = unsafeStatic(tagName);
|
|
452
|
+
await fixture(html`<${tag}></${tag}>`);
|
|
453
|
+
|
|
454
|
+
expect(outputObj.createElementCallCount).to.equal(1);
|
|
455
|
+
|
|
456
|
+
unMockScopedRegistry();
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('does not scope elements when polyfill not loaded', async () => {
|
|
460
|
+
class ScopedEl extends LitElement {}
|
|
461
|
+
|
|
462
|
+
const tagName = defineCE(
|
|
463
|
+
class extends ScopedElementsMixin(SlotMixin(LitElement)) {
|
|
464
|
+
static get scopedElements() {
|
|
465
|
+
return {
|
|
466
|
+
// @ts-expect-error
|
|
467
|
+
...super.scopedElements,
|
|
468
|
+
'scoped-el': ScopedEl,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
get slots() {
|
|
473
|
+
return {
|
|
474
|
+
...super.slots,
|
|
475
|
+
template: () => html`<scoped-el></scoped-el>`,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
render() {
|
|
480
|
+
return html`<slot name="template"></slot>`;
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
);
|
|
282
484
|
|
|
283
|
-
|
|
284
|
-
|
|
485
|
+
const renderTarget = document.createElement('div');
|
|
486
|
+
const el = document.createElement(tagName);
|
|
285
487
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
488
|
+
// We don't use fixture, so we limit the amount of calls to document.createElement
|
|
489
|
+
const docSpy = sinon.spy(document, 'createElement');
|
|
490
|
+
document.body.appendChild(renderTarget);
|
|
491
|
+
renderTarget.appendChild(el);
|
|
290
492
|
|
|
291
|
-
|
|
493
|
+
expect(docSpy.callCount).to.equal(2);
|
|
292
494
|
|
|
293
|
-
|
|
294
|
-
|
|
495
|
+
document.body.removeChild(renderTarget);
|
|
496
|
+
docSpy.restore();
|
|
497
|
+
});
|
|
295
498
|
});
|
|
296
499
|
});
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { Constructor } from '@open-wc/dedupe-mixin';
|
|
2
2
|
import { TemplateResult, LitElement } from 'lit';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Implicitly creates a wrapper node that allows for rerenders
|
|
6
|
+
*/
|
|
7
|
+
export type SlotRerenderObject = {
|
|
8
|
+
template: TemplateResult;
|
|
9
|
+
/* Add logic that will be performed after the render */
|
|
10
|
+
afterRender?: Function;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type SlotFunctionResult = TemplateResult | Element | SlotRerenderObject | undefined;
|
|
14
|
+
|
|
15
|
+
declare function slotFunction(): SlotFunctionResult;
|
|
5
16
|
|
|
6
17
|
export type SlotsMap = {
|
|
7
18
|
[key: string]: typeof slotFunction;
|
|
@@ -49,7 +60,7 @@ export declare class SlotHost {
|
|
|
49
60
|
* };
|
|
50
61
|
* }
|
|
51
62
|
*/
|
|
52
|
-
|
|
63
|
+
declare function SlotMixinImplementation<T extends Constructor<LitElement>>(
|
|
53
64
|
superclass: T,
|
|
54
65
|
): T &
|
|
55
66
|
Constructor<SlotHost> &
|
|
@@ -70,19 +70,21 @@ const FormatMixinImplementation = superclass =>
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
* @param {string} name
|
|
74
|
-
* @param {
|
|
73
|
+
* @param {string} [name]
|
|
74
|
+
* @param {unknown} [oldValue]
|
|
75
|
+
* @param {import('lit').PropertyDeclaration} [options]
|
|
76
|
+
* @returns {void}
|
|
75
77
|
*/
|
|
76
|
-
requestUpdate(name,
|
|
77
|
-
super.requestUpdate(name,
|
|
78
|
+
requestUpdate(name, oldValue, options) {
|
|
79
|
+
super.requestUpdate(name, oldValue, options);
|
|
78
80
|
|
|
79
|
-
if (name === 'modelValue' && this.modelValue !==
|
|
80
|
-
this._onModelValueChanged({ modelValue: this.modelValue }, { modelValue:
|
|
81
|
+
if (name === 'modelValue' && this.modelValue !== oldValue) {
|
|
82
|
+
this._onModelValueChanged({ modelValue: this.modelValue }, { modelValue: oldValue });
|
|
81
83
|
}
|
|
82
|
-
if (name === 'serializedValue' && this.serializedValue !==
|
|
84
|
+
if (name === 'serializedValue' && this.serializedValue !== oldValue) {
|
|
83
85
|
this._calculateValues({ source: 'serialized' });
|
|
84
86
|
}
|
|
85
|
-
if (name === 'formattedValue' && this.formattedValue !==
|
|
87
|
+
if (name === 'formattedValue' && this.formattedValue !== oldValue) {
|
|
86
88
|
this._calculateValues({ source: 'formatted' });
|
|
87
89
|
}
|
|
88
90
|
}
|
|
@@ -33,12 +33,14 @@ const InteractionStateMixinImplementation = superclass =>
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* @param {
|
|
37
|
-
* @param {
|
|
36
|
+
* @param {string} [name]
|
|
37
|
+
* @param {unknown} [oldValue]
|
|
38
|
+
* @param {import('lit').PropertyDeclaration} [options]
|
|
39
|
+
* @returns {void}
|
|
38
40
|
*/
|
|
39
|
-
requestUpdate(name,
|
|
40
|
-
super.requestUpdate(name,
|
|
41
|
-
if (name === 'touched' && this.touched !==
|
|
41
|
+
requestUpdate(name, oldValue, options) {
|
|
42
|
+
super.requestUpdate(name, oldValue, options);
|
|
43
|
+
if (name === 'touched' && this.touched !== oldValue) {
|
|
42
44
|
this._onTouchedChanged();
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -48,7 +50,7 @@ const InteractionStateMixinImplementation = superclass =>
|
|
|
48
50
|
this.filled = !this._isEmpty();
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
if (name === 'dirty' && this.dirty !==
|
|
53
|
+
if (name === 'dirty' && this.dirty !== oldValue) {
|
|
52
54
|
this._onDirtyChanged();
|
|
53
55
|
}
|
|
54
56
|
}
|
|
@@ -52,11 +52,13 @@ const ChoiceInputMixinImplementation = superclass =>
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* @param {string} name
|
|
56
|
-
* @param {
|
|
55
|
+
* @param {string} [name]
|
|
56
|
+
* @param {unknown} [oldValue]
|
|
57
|
+
* @param {import('lit').PropertyDeclaration} [options]
|
|
58
|
+
* @returns {void}
|
|
57
59
|
*/
|
|
58
|
-
requestUpdate(name, oldValue) {
|
|
59
|
-
super.requestUpdate(name, oldValue);
|
|
60
|
+
requestUpdate(name, oldValue, options) {
|
|
61
|
+
super.requestUpdate(name, oldValue, options);
|
|
60
62
|
|
|
61
63
|
if (name === 'modelValue') {
|
|
62
64
|
if (this.modelValue.checked !== this.checked) {
|
|
@@ -93,11 +93,16 @@ const SyncUpdatableMixinImplementation = superclass =>
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
|
-
* @param {string} name
|
|
97
|
-
* @param {
|
|
96
|
+
* @param {string} [name]
|
|
97
|
+
* @param {unknown} [oldValue]
|
|
98
|
+
* @param {import('lit').PropertyDeclaration} [options]
|
|
99
|
+
* @returns {void}
|
|
98
100
|
*/
|
|
99
|
-
requestUpdate(name, oldValue) {
|
|
100
|
-
super.requestUpdate(name, oldValue);
|
|
101
|
+
requestUpdate(name, oldValue, options) {
|
|
102
|
+
super.requestUpdate(name, oldValue, options);
|
|
103
|
+
if (name === undefined) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
101
106
|
|
|
102
107
|
this.__SyncUpdatableNamespace = this.__SyncUpdatableNamespace || {};
|
|
103
108
|
const ns = this.__SyncUpdatableNamespace;
|
|
@@ -147,11 +147,13 @@ describe('SyncUpdatableMixin', () => {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
|
-
* @param {string} name
|
|
151
|
-
* @param {
|
|
150
|
+
* @param {string} [name]
|
|
151
|
+
* @param {unknown} [oldValue]
|
|
152
|
+
* @param {import('lit').PropertyDeclaration} [options]
|
|
153
|
+
* @returns {void}
|
|
152
154
|
*/
|
|
153
|
-
requestUpdate(name, oldValue) {
|
|
154
|
-
super.requestUpdate(name, oldValue);
|
|
155
|
+
requestUpdate(name, oldValue, options) {
|
|
156
|
+
super.requestUpdate(name, oldValue, options);
|
|
155
157
|
if (name === 'prop') {
|
|
156
158
|
propChangedCount += 1;
|
|
157
159
|
}
|