chore: format & changeset

This commit is contained in:
Konstantinos Norgias 2021-05-20 12:25:28 +02:00
parent e17f7bdfa6
commit 72067c0d19
35 changed files with 520 additions and 351 deletions

View file

@ -0,0 +1,40 @@
---
'babel-plugin-extend-docs': minor
'providence-analytics': minor
'publish-docs': minor
'remark-extend': minor
'@lion/accordion': minor
'@lion/button': minor
'@lion/calendar': minor
'@lion/checkbox-group': minor
'@lion/collapsible': minor
'@lion/combobox': minor
'@lion/core': minor
'@lion/dialog': minor
'@lion/form': minor
'@lion/form-core': minor
'@lion/form-integrations': minor
'@lion/helpers': minor
'@lion/icon': minor
'@lion/input': minor
'@lion/input-amount': minor
'@lion/input-datepicker': minor
'@lion/input-iban': minor
'@lion/input-stepper': minor
'@lion/listbox': minor
'@lion/localize': minor
'@lion/overlays': minor
'@lion/pagination': minor
'@lion/progress-indicator': minor
'@lion/radio-group': minor
'@lion/select': minor
'@lion/select-rich': minor
'@lion/steps': minor
'@lion/switch': minor
'@lion/tabs': minor
'@lion/textarea': minor
'@lion/tooltip': minor
'@lion/validate-messages': minor
---
**BREAKING** Upgrade to lit version 2

View file

@ -36,9 +36,8 @@ There are the following methods available to control the pagination.
```js preview-story
export const methods = ({ shadowRoot }) => {
setTimeout(() => {
shadowRoot.getElementById('pagination-method-demo').innerText = shadowRoot.getElementById(
'pagination-method',
).current;
shadowRoot.getElementById('pagination-method-demo').innerText =
shadowRoot.getElementById('pagination-method').current;
});
return html`
@ -80,9 +79,8 @@ export const methods = ({ shadowRoot }) => {
```js preview-story
export const event = ({ shadowRoot }) => {
setTimeout(() => {
shadowRoot.getElementById('pagination-event-demo-text').innerText = shadowRoot.getElementById(
'pagination-event-demo',
).current;
shadowRoot.getElementById('pagination-event-demo-text').innerText =
shadowRoot.getElementById('pagination-event-demo').current;
});
return html`

View file

@ -18,9 +18,9 @@ import '@lion/button/define';
export class UmbrellaForm extends LitElement {
get _lionFormNode() {
return /** @type {import('@lion/form').LionForm} */ (this.shadowRoot?.querySelector(
'lion-form',
));
return /** @type {import('@lion/form').LionForm} */ (
this.shadowRoot?.querySelector('lion-form')
);
}
render() {

View file

@ -111,9 +111,10 @@ class PBoard extends DecorateMixin(LitElement) {
checked
@change="${({ target }) => {
// TODO: of course, logic depending on dom is never a good idea
const groupBoxes = target.parentElement.nextElementSibling.querySelectorAll(
'input[type=checkbox]',
);
const groupBoxes =
target.parentElement.nextElementSibling.querySelectorAll(
'input[type=checkbox]',
);
const { checked } = target;
Array.from(groupBoxes).forEach(box => {
// eslint-disable-next-line no-param-reassign

View file

@ -25,11 +25,8 @@ const promptAnalyzerModule = require('../../src/cli/prompt-analyzer-menu.js');
const { toPosixPath } = require('../../src/program/utils/to-posix-path.js');
const { getExtendDocsResults } = require('../../src/cli/launch-providence-with-extend-docs.js');
const {
pathsArrayFromCs,
pathsArrayFromCollectionName,
appendProjectDependencyPaths,
} = cliHelpersModule;
const { pathsArrayFromCs, pathsArrayFromCollectionName, appendProjectDependencyPaths } =
cliHelpersModule;
const queryResults = [];

View file

@ -15,9 +15,8 @@ const {
restoreSuppressNonCriticalLogs,
} = require('../../../test-helpers/mock-log-service-helpers.js');
const findCustomelementsQueryConfig = QueryService.getQueryConfigFromAnalyzer(
'find-customelements',
);
const findCustomelementsQueryConfig =
QueryService.getQueryConfigFromAnalyzer('find-customelements');
const _providenceCfg = {
targetProjectPaths: ['/fictional/project'], // defined in mockProject
};

View file

@ -149,7 +149,8 @@ describe('remarkExtend', () => {
it('throws if an import file does not exist', async () => {
await expectThrowsAsync(() => execute("```js ::import('./fixtures/not-available.md')\n```"), {
errorMatch: /The import "\.\/fixtures\/not-available.md" in "test-file.md" does not exist\. Resolved to ".*"\.$/,
errorMatch:
/The import "\.\/fixtures\/not-available.md" in "test-file.md" does not exist\. Resolved to ".*"\.$/,
});
});
@ -157,7 +158,8 @@ describe('remarkExtend', () => {
const input =
"```js ::import('./fixtures/three-sections-red.md', 'heading:has([value=Does not exit])')\n```";
await expectThrowsAsync(() => execute(input), {
errorMatch: /The start selector "heading:has\(\[value=Does not exit\]\)" could not find a matching node in ".*"\.$/,
errorMatch:
/The start selector "heading:has\(\[value=Does not exit\]\)" could not find a matching node in ".*"\.$/,
});
});
@ -165,7 +167,8 @@ describe('remarkExtend', () => {
const input =
"```js ::import('./fixtures/three-sections-red.md', 'heading:has([value=More Red])', 'heading:has([value=Does not exit])')\n```";
await expectThrowsAsync(() => execute(input), {
errorMatch: /The end selector "heading:has\(\[value=Does not exit\]\)" could not find a matching node in ".*"\./,
errorMatch:
/The end selector "heading:has\(\[value=Does not exit\]\)" could not find a matching node in ".*"\./,
});
});

View file

@ -226,12 +226,12 @@ export class LionAccordion extends LitElement {
* @private
*/
__setupStore() {
const invokers = /** @type {HTMLElement[]} */ (Array.from(
this.querySelectorAll('[slot="invoker"]'),
));
const contents = /** @type {HTMLElement[]} */ (Array.from(
this.querySelectorAll('[slot="content"]'),
));
const invokers = /** @type {HTMLElement[]} */ (
Array.from(this.querySelectorAll('[slot="invoker"]'))
);
const contents = /** @type {HTMLElement[]} */ (
Array.from(this.querySelectorAll('[slot="content"]'))
);
if (invokers.length !== contents.length) {
// eslint-disable-next-line no-console
console.warn(
@ -356,9 +356,11 @@ export class LionAccordion extends LitElement {
if (!(this.__store && this.__store[this.focusedIndex])) {
return;
}
const previousInvoker = /** @type {HTMLElement | undefined} */ (Array.from(this.children).find(
child => child.slot === 'invoker' && child.firstElementChild?.hasAttribute('focused'),
));
const previousInvoker = /** @type {HTMLElement | undefined} */ (
Array.from(this.children).find(
child => child.slot === 'invoker' && child.firstElementChild?.hasAttribute('focused'),
)
);
if (previousInvoker) {
unfocusInvoker(previousInvoker);
}

View file

@ -162,9 +162,9 @@ export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement))
* @protected
*/
get _nativeButtonNode() {
return /** @type {HTMLButtonElement} */ (Array.from(this.children).find(
child => child.slot === '_button',
));
return /** @type {HTMLButtonElement} */ (
Array.from(this.children).find(child => child.slot === '_button')
);
}
get slots() {

View file

@ -813,12 +813,10 @@ describe('<lion-calendar>', () => {
`);
const elObj = new CalendarObject(el);
expect(
elObj.checkForAllDayObjs(/** @param {DayObject} d */ d => d.el.hasAttribute('disabled'), [
1,
2,
30,
31,
]),
elObj.checkForAllDayObjs(
/** @param {DayObject} d */ d => d.el.hasAttribute('disabled'),
[1, 2, 30, 31],
),
).to.equal(true);
clock.restore();

View file

@ -11,9 +11,8 @@ function compareMultipleMonth(obj) {
week.days.forEach((day, dayi) => {
// @ts-expect-error since we are converting Date to ISO string, but that's okay for our test Date comparisons
// eslint-disable-next-line no-param-reassign
obj.months[monthi].weeks[weeki].days[dayi].date = obj.months[monthi].weeks[weeki].days[
dayi
].date.toISOString();
obj.months[monthi].weeks[weeki].days[dayi].date =
obj.months[monthi].weeks[weeki].days[dayi].date.toISOString();
});
});
});

View file

@ -108,9 +108,9 @@ describe('SlotMixin', () => {
const tag = defineCE(SlotPrivateText);
const el = /** @type {SlotPrivateText} */ (await fixture(`<${tag}><${tag}>`));
expect(el.didCreateConditionalSlot()).to.be.true;
const elUserSlot = /** @type {SlotPrivateText} */ (await fixture(
`<${tag}><p slot="conditional">foo</p><${tag}>`,
));
const elUserSlot = /** @type {SlotPrivateText} */ (
await fixture(`<${tag}><p slot="conditional">foo</p><${tag}>`)
);
expect(elUserSlot.didCreateConditionalSlot()).to.be.false;
renderSlot = false;
const elNoSlot = /** @type {SlotPrivateText} */ (await fixture(`<${tag}><${tag}>`));

View file

@ -1,6 +1,7 @@
import { dedupeMixin } from '@lion/core';
const windowWithOptionalPolyfill = /** @type {Window & typeof globalThis & {applyFocusVisiblePolyfill?: function}} */ (window);
const windowWithOptionalPolyfill =
/** @type {Window & typeof globalThis & {applyFocusVisiblePolyfill?: function}} */ (window);
const polyfilledNodes = new WeakMap();
/**

View file

@ -31,13 +31,13 @@ const FormRegistrarPortalMixinImplementation = superclass =>
* @type {(FormRegistrarPortalHost & HTMLElement) | undefined}
*/
this.registrationTarget = undefined;
this.__redispatchEventForFormRegistrarPortalMixin = this.__redispatchEventForFormRegistrarPortalMixin.bind(
this,
);
this.__redispatchEventForFormRegistrarPortalMixin =
this.__redispatchEventForFormRegistrarPortalMixin.bind(this);
this.addEventListener(
'form-element-register',
/** @type {EventListenerOrEventListenerObject} */ (this
.__redispatchEventForFormRegistrarPortalMixin),
/** @type {EventListenerOrEventListenerObject} */ (
this.__redispatchEventForFormRegistrarPortalMixin
),
);
}

View file

@ -39,8 +39,10 @@ export const ValidateMixinImplementation = superclass =>
SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass)))),
) {
static get scopedElements() {
const scopedElementsCtor = /** @type {typeof import('@open-wc/scoped-elements/src/types').ScopedElementsHost} */ (super
.constructor);
const scopedElementsCtor =
/** @type {typeof import('@open-wc/scoped-elements/src/types').ScopedElementsHost} */ (
super.constructor
);
return {
...scopedElementsCtor.scopedElements,
'lion-validation-feedback': LionValidationFeedback,
@ -482,10 +484,12 @@ export const ValidateMixinImplementation = superclass =>
* @private
*/
__executeResultValidators(regularValidationResult) {
const resultValidators = /** @type {ResultValidator[]} */ (this._allValidators.filter(v => {
const vCtor = /** @type {typeof Validator} */ (v.constructor);
return !vCtor.async && v instanceof ResultValidator;
}));
const resultValidators = /** @type {ResultValidator[]} */ (
this._allValidators.filter(v => {
const vCtor = /** @type {typeof Validator} */ (v.constructor);
return !vCtor.async && v instanceof ResultValidator;
})
);
return resultValidators.filter(v =>
v.executeOnResults({
@ -511,8 +515,10 @@ export const ValidateMixinImplementation = superclass =>
this.__validationResult = [...resultOutCome, ...syncAndAsyncOutcome];
// this._storeResultsOnInstance(this.__validationResult);
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
.constructor);
const ctor =
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
this.constructor
);
/** @type {Object.<string, Object.<string, boolean>>} */
const validationStates = ctor.validationTypes.reduce(
@ -582,8 +588,10 @@ export const ValidateMixinImplementation = superclass =>
console.error(errorMessage, this);
throw new Error(errorMessage);
}
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
.constructor);
const ctor =
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
this.constructor
);
if (ctor.validationTypes.indexOf(v.type) === -1) {
const vCtor = /** @type {typeof Validator} */ (v.constructor);
// throws in constructor are not visible to end user so we do both
@ -776,12 +784,16 @@ export const ValidateMixinImplementation = superclass =>
changedProperties.has('shouldShowFeedbackFor') ||
changedProperties.has('hasFeedbackFor')
) {
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
.constructor);
const ctor =
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
this.constructor
);
// Necessary typecast because types aren't smart enough to understand that we filter out undefined
this.showsFeedbackFor = /** @type {string[]} */ (ctor.validationTypes
.map(type => (this._hasFeedbackVisibleFor(type) ? type : undefined))
.filter(Boolean));
this.showsFeedbackFor = /** @type {string[]} */ (
ctor.validationTypes
.map(type => (this._hasFeedbackVisibleFor(type) ? type : undefined))
.filter(Boolean)
);
this._updateFeedbackComponent();
}
@ -791,9 +803,9 @@ export const ValidateMixinImplementation = superclass =>
}
if (changedProperties.has('validationStates')) {
const prevStates = /** @type {{[key: string]: object;}} */ (changedProperties.get(
'validationStates',
));
const prevStates = /** @type {{[key: string]: object;}} */ (
changedProperties.get('validationStates')
);
if (prevStates) {
Object.entries(this.validationStates).forEach(([type, feedbackObj]) => {
if (
@ -811,21 +823,25 @@ export const ValidateMixinImplementation = superclass =>
* @protected
*/
_updateShouldShowFeedbackFor() {
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
.constructor);
const ctor =
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
this.constructor
);
// Necessary typecast because types aren't smart enough to understand that we filter out undefined
const newShouldShowFeedbackFor = /** @type {string[]} */ (ctor.validationTypes
.map(type =>
this.feedbackCondition(
type,
this._feedbackConditionMeta,
this._showFeedbackConditionFor.bind(this),
const newShouldShowFeedbackFor = /** @type {string[]} */ (
ctor.validationTypes
.map(type =>
this.feedbackCondition(
type,
this._feedbackConditionMeta,
this._showFeedbackConditionFor.bind(this),
)
? type
: undefined,
)
? type
: undefined,
)
.filter(Boolean));
.filter(Boolean)
);
if (JSON.stringify(this.shouldShowFeedbackFor) !== JSON.stringify(newShouldShowFeedbackFor)) {
this.shouldShowFeedbackFor = newShouldShowFeedbackFor;
@ -841,8 +857,10 @@ export const ValidateMixinImplementation = superclass =>
* @protected
*/
_prioritizeAndFilterFeedback({ validationResult }) {
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
.constructor);
const ctor =
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
this.constructor
);
const types = ctor.validationTypes;
// Sort all validators based on the type provided.
const res = validationResult

View file

@ -92,7 +92,8 @@ export class MinMaxLength extends Validator {
}
}
const isEmailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const isEmailRegex =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
export class IsEmail extends Validator {
static get validatorName() {
return 'IsEmail';

View file

@ -36,11 +36,13 @@ export const runRegistrationSuite = customConfig => {
const { parentTagString, childTagString } = cfg;
it('can register a formElement', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(html`
const el = /** @type {RegistrarClass} */ (
await fixture(html`
<${parentTag}>
<${childTag}></${childTag}>
</${parentTag}>
`));
`)
);
expect(el.formElements.length).to.equal(1);
});
@ -57,25 +59,29 @@ export const runRegistrationSuite = customConfig => {
});
it('can register a formElement with arbitrary dom tree in between registrar and registering', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(html`
const el = /** @type {RegistrarClass} */ (
await fixture(html`
<${parentTag}>
<div>
<${childTag}></${childTag}>
</div>
</${parentTag}>
`));
`)
);
expect(el.formElements.length).to.equal(1);
});
it('supports nested registration parents', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(html`
const el = /** @type {RegistrarClass} */ (
await fixture(html`
<${parentTag}>
<${parentTag} class="sub-group">
<${childTag}></${childTag}>
<${childTag}></${childTag}>
</${parentTag}>
</${parentTag}>
`));
`)
);
expect(el.formElements.length).to.equal(1);
const subGroup = /** @type {RegistrarClass} */ (el.querySelector('.sub-group'));
@ -95,20 +101,24 @@ export const runRegistrationSuite = customConfig => {
}
const tagWrapperString = defineCE(PerformUpdate);
const tagWrapper = unsafeStatic(tagWrapperString);
const el = /** @type {PerformUpdate} */ (await fixture(html`
const el = /** @type {PerformUpdate} */ (
await fixture(html`
<${tagWrapper}>
<${childTag}></${childTag}>
</${tagWrapper}>
`));
`)
);
expect(el.formElements.length).to.equal(1);
});
it('can dynamically add/remove elements', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(html`
const el = /** @type {RegistrarClass} */ (
await fixture(html`
<${parentTag}>
<${childTag}></${childTag}>
</${parentTag}>
`));
`)
);
const newField = await fixture(html`
<${childTag}></${childTag}>
`);
@ -122,20 +132,24 @@ export const runRegistrationSuite = customConfig => {
});
it('adds elements to formElements in the right order (DOM)', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(html`
const el = /** @type {RegistrarClass} */ (
await fixture(html`
<${parentTag}>
<${childTag} pos="0"></${childTag}>
<${childTag} pos="1"></${childTag}>
<${childTag} pos="2"></${childTag}>
</${parentTag}>
`));
`)
);
/** INSERT field before the pos=1 */
/**
* @typedef {Object.<string, string>} prop
*/
const newField = /** @type {RegisteringClass & prop} */ (await fixture(html`
const newField = /** @type {RegisteringClass & prop} */ (
await fixture(html`
<${childTag}></${childTag}>
`));
`)
);
newField.setAttribute('pos', 'inserted-before-1');
el.insertBefore(newField, el.children[1]);
@ -145,9 +159,11 @@ export const runRegistrationSuite = customConfig => {
expect(el.formElements[1].getAttribute('pos')).to.equal('inserted-before-1');
/** INSERT field before the pos=0 (e.g. at the top) */
const topField = /** @type {RegisteringClass & prop} */ (await fixture(html`
const topField = /** @type {RegisteringClass & prop} */ (
await fixture(html`
<${childTag}></${childTag}>
`));
`)
);
topField.setAttribute('pos', 'inserted-before-0');
el.insertBefore(topField, el.children[0]);
@ -159,9 +175,9 @@ export const runRegistrationSuite = customConfig => {
describe('FormRegistrarPortalMixin', () => {
it('forwards registrations to the .registrationTarget', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(
html`<${parentTag}></${parentTag}>`,
));
const el = /** @type {RegistrarClass} */ (
await fixture(html`<${parentTag}></${parentTag}>`)
);
await fixture(html`
<${portalTag} .registrationTarget=${el}>
<${childTag}></${childTag}>
@ -172,9 +188,9 @@ export const runRegistrationSuite = customConfig => {
});
it('can dynamically add/remove elements', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(
html`<${parentTag}></${parentTag}>`,
));
const el = /** @type {RegistrarClass} */ (
await fixture(html`<${parentTag}></${parentTag}>`)
);
const portal = await fixture(html`
<${portalTag} .registrationTarget=${el}>
<${childTag}></${childTag}>
@ -194,13 +210,15 @@ export const runRegistrationSuite = customConfig => {
});
it('adds elements to formElements in the right order', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(html`
const el = /** @type {RegistrarClass} */ (
await fixture(html`
<${parentTag}>
<${childTag}></${childTag}>
<${childTag}></${childTag}>
<${childTag}></${childTag}>
</${parentTag}>
`));
`)
);
expect(el.formElements.length).to.equal(3);
@ -232,9 +250,9 @@ export const runRegistrationSuite = customConfig => {
});
it('keeps working if moving the portal itself', async () => {
const el = /** @type {RegistrarClass} */ (await fixture(
html`<${parentTag}></${parentTag}>`,
));
const el = /** @type {RegistrarClass} */ (
await fixture(html`<${parentTag}></${parentTag}>`)
);
const portal = await fixture(html`
<${portalTag} .registrationTarget=${el}>
<${childTag}></${childTag}>
@ -270,9 +288,9 @@ export const runRegistrationSuite = customConfig => {
);
const delayedPortalTag = unsafeStatic(delayedPortalString);
const el = /** @type {RegistrarClass} */ (await fixture(
html`<${parentTag}></${parentTag}>`,
));
const el = /** @type {RegistrarClass} */ (
await fixture(html`<${parentTag}></${parentTag}>`)
);
await fixture(html`
<${delayedPortalTag} .registrationTarget=${el}>
<${childTag}></${childTag}>

View file

@ -82,9 +82,9 @@ export function runInteractionStateMixinSuite(customConfig) {
});
it('sets an attribute "filled" if the input has a non-empty modelValue', async () => {
const el = /** @type {IState} */ (await fixture(
html`<${tag} .modelValue=${'hello'}></${tag}>`,
));
const el = /** @type {IState} */ (
await fixture(html`<${tag} .modelValue=${'hello'}></${tag}>`)
);
expect(el.hasAttribute('filled')).to.equal(true);
el.modelValue = '';
await el.updateComplete;
@ -97,9 +97,11 @@ export function runInteractionStateMixinSuite(customConfig) {
it('fires "(touched|dirty)-state-changed" event when state changes', async () => {
const touchedSpy = sinon.spy();
const dirtySpy = sinon.spy();
const el = /** @type {IState} */ (await fixture(
html`<${tag} @touched-changed=${touchedSpy} @dirty-changed=${dirtySpy}></${tag}>`,
));
const el = /** @type {IState} */ (
await fixture(
html`<${tag} @touched-changed=${touchedSpy} @dirty-changed=${dirtySpy}></${tag}>`,
)
);
el.touched = true;
expect(touchedSpy.callCount).to.equal(1);
@ -109,14 +111,18 @@ export function runInteractionStateMixinSuite(customConfig) {
});
it('sets prefilled once instantiated', async () => {
const el = /** @type {IState} */ (await fixture(html`
const el = /** @type {IState} */ (
await fixture(html`
<${tag} .modelValue=${'prefilled'}></${tag}>
`));
`)
);
expect(el.prefilled).to.be.true;
const nonPrefilled = /** @type {IState} */ (await fixture(html`
const nonPrefilled = /** @type {IState} */ (
await fixture(html`
<${tag} .modelValue=${''}></${tag}>
`));
`)
);
expect(nonPrefilled.prefilled).to.be.false;
});
@ -125,9 +131,9 @@ export function runInteractionStateMixinSuite(customConfig) {
(${cfg.allowedModelValueTypes.map(t => t.name).join(', ')})`, async () => {
/** @typedef {{_inputNode: HTMLElement}} inputNodeInterface */
const el = /** @type {IState & inputNodeInterface} */ (await fixture(
html`<${tag}></${tag}>`,
));
const el = /** @type {IState & inputNodeInterface} */ (
await fixture(html`<${tag}></${tag}>`)
);
/**
* @param {*} modelValue
@ -213,9 +219,11 @@ export function runInteractionStateMixinSuite(customConfig) {
describe('Validation integration with states', () => {
it('has .shouldShowFeedbackFor indicating for which type to show messages', async () => {
const el = /** @type {IState} */ (await fixture(html`
const el = /** @type {IState} */ (
await fixture(html`
<${tag}></${tag}>
`));
`)
);
// @ts-ignore [allow-private] in test
expect(el.shouldShowFeedbackFor).to.deep.equal([]);
el.submitted = true;
@ -225,9 +233,11 @@ export function runInteractionStateMixinSuite(customConfig) {
});
it('keeps the feedback component in sync', async () => {
const el = /** @type {IState} */ (await fixture(html`
const el = /** @type {IState} */ (
await fixture(html`
<${tag} .validators=${[new MinLength(3)]}></${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
await el.updateComplete;
@ -257,9 +267,9 @@ export function runInteractionStateMixinSuite(customConfig) {
}
const tagLeaveString = defineCE(IStateCustomBlur);
const tagLeave = unsafeStatic(tagLeaveString);
const el = /** @type {IStateCustomBlur} */ (await fixture(
html`<${tagLeave}></${tagLeave}>`,
));
const el = /** @type {IStateCustomBlur} */ (
await fixture(html`<${tagLeave}></${tagLeave}>`)
);
el.dispatchEvent(new Event('custom-blur'));
expect(el.touched).to.be.true;
});

View file

@ -66,9 +66,11 @@ export function runValidateMixinFeedbackPart() {
});
it('has .showsFeedbackFor indicating for which type it actually shows messages', async () => {
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag} submitted .validators=${[new MinLength(3)]}>${lightDom}</${tag}>
`));
`)
);
el.modelValue = 'a';
await el.feedbackComplete;
@ -87,14 +89,16 @@ export function runValidateMixinFeedbackPart() {
}
const elTagString = defineCE(ValidateElementCustomTypes);
const elTag = unsafeStatic(elTagString);
const el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
const el = /** @type {ValidateElementCustomTypes} */ (
await fixture(html`
<${elTag}
.submitted=${true}
.validators=${[
new MinLength(2, { type: 'x' }),
new MinLength(3, { type: 'error' }),
]}>${lightDom}</${elTag}>
`));
`)
);
el.modelValue = '1';
await el.updateComplete;
@ -116,12 +120,14 @@ export function runValidateMixinFeedbackPart() {
});
it('passes a message to the "._feedbackNode"', async () => {
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.modelValue=${'cat'}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
expect(_feedbackNode.feedbackData).to.deep.equal([]);
@ -132,13 +138,15 @@ export function runValidateMixinFeedbackPart() {
});
it('has configurable feedback visibility hook', async () => {
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.modelValue=${'cat'}
.validators=${[new AlwaysInvalid()]}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
await el.updateComplete;
@ -153,13 +161,15 @@ export function runValidateMixinFeedbackPart() {
});
it('writes prioritized result to "._feedbackNode" based on Validator order', async () => {
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.modelValue=${'cat'}
.validators=${[new AlwaysInvalid(), new MinLength(4)]}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
await el.updateComplete;
@ -179,13 +189,15 @@ export function runValidateMixinFeedbackPart() {
return 'this ends up in "._feedbackNode"';
};
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.modelValue=${'cat'}
.validators=${[new AlwaysInvalid()]}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
expect(_feedbackNode.feedbackData).to.be.undefined;
@ -208,13 +220,15 @@ export function runValidateMixinFeedbackPart() {
return 'this ends up in "._feedbackNode"';
};
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.modelValue=${'cat'}
.validators=${[new AlwaysInvalid()]}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
expect(_feedbackNode.feedbackData).to.be.undefined;
@ -248,8 +262,9 @@ export function runValidateMixinFeedbackPart() {
render() {
let name = '';
if (this.feedbackData && this.feedbackData.length > 0) {
const ctor = /** @type {typeof Validator} */ (this.feedbackData[0]?.validator
?.constructor);
const ctor = /** @type {typeof Validator} */ (
this.feedbackData[0]?.validator?.constructor
);
name = ctor.validatorName;
}
return html`Custom for ${name}`;
@ -257,13 +272,15 @@ export function runValidateMixinFeedbackPart() {
}
const customFeedbackTagString = defineCE(ValidateElementCustomRender);
const customFeedbackTag = unsafeStatic(customFeedbackTagString);
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.validators=${[new ContainsLowercaseA(), new AlwaysInvalid()]}>
<${customFeedbackTag} slot="feedback"><${customFeedbackTag}>
</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
expect(_feedbackNode.localName).to.equal(customFeedbackTagString);
@ -282,12 +299,14 @@ export function runValidateMixinFeedbackPart() {
});
it('supports custom messages in Validator instance configuration object', async () => {
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.validators=${[new MinLength(3, { getMessage: () => 'custom via config' })]}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
el.modelValue = 'a';
@ -297,13 +316,15 @@ export function runValidateMixinFeedbackPart() {
});
it('updates the feedback component when locale changes', async () => {
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.validators=${[new MinLength(3)]}
.modelValue=${'1'}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
await el.feedbackComplete;
@ -323,7 +344,8 @@ export function runValidateMixinFeedbackPart() {
}
const elTagString = defineCE(ValidateElementCustomTypes);
const elTag = unsafeStatic(elTagString);
const el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
const el = /** @type {ValidateElementCustomTypes} */ (
await fixture(html`
<${elTag}
.submitted=${true}
.validators=${[
@ -331,7 +353,8 @@ export function runValidateMixinFeedbackPart() {
new DefaultSuccess(null, { getMessage: () => 'This is a success message' }),
]}
>${lightDom}</${elTag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
el.modelValue = 'a';
@ -347,13 +370,15 @@ export function runValidateMixinFeedbackPart() {
describe('Accessibility', () => {
it('sets [aria-invalid="true"] to "._inputNode" when there is an error', async () => {
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
submitted
.validators=${[new Required()]}
.modelValue=${'a'}
>${lightDom}</${tag}>
`));
`)
);
const { _inputNode } = getFormControlMembers(el);
const inputNode = _inputNode;
@ -386,13 +411,15 @@ export function runValidateMixinFeedbackPart() {
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
const constructorMessageSpy = sinon.spy(ctorValidator, 'getMessage');
el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
el = /** @type {ValidateElementCustomTypes} */ (
await fixture(html`
<${elTag}
.submitted=${true}
.validators=${[constructorValidator]}
.modelValue=${'cat'}
>${lightDom}</${elTag}>
`));
`)
);
await el.updateComplete;
await el.feedbackComplete;
expect(constructorMessageSpy.args[0][0]).to.eql({
@ -408,13 +435,15 @@ export function runValidateMixinFeedbackPart() {
const instanceMessageSpy = sinon.spy();
const instanceValidator = new MinLength(4, { getMessage: instanceMessageSpy });
el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
el = /** @type {ValidateElementCustomTypes} */ (
await fixture(html`
<${elTag}
.submitted=${true}
.validators=${[instanceValidator]}
.modelValue=${'cat'}
>${lightDom}</${elTag}>
`));
`)
);
await el.updateComplete;
await el.feedbackComplete;
expect(instanceMessageSpy.args[0][0]).to.eql({
@ -435,14 +464,16 @@ export function runValidateMixinFeedbackPart() {
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
const spy = sinon.spy(ctorValidator, 'getMessage');
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.validators=${[constructorValidator]}
.modelValue=${'cat'}
.fieldName=${new Promise(resolve => resolve('myField'))}
>${lightDom}</${tag}>
`));
`)
);
await el.updateComplete;
await el.feedbackComplete;
expect(spy.args[0][0]).to.eql({
@ -464,14 +495,16 @@ export function runValidateMixinFeedbackPart() {
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
const spy = sinon.spy(ctorValidator, 'getMessage');
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.validators=${[constructorValidator]}
.modelValue=${'cat'}
.fieldName=${new Promise(resolve => resolve('myField'))}
>${lightDom}</${tag}>
`));
`)
);
await el.updateComplete;
await el.feedbackComplete;
@ -500,13 +533,15 @@ export function runValidateMixinFeedbackPart() {
* The Queue system solves this by queueing the updateFeedbackComponent tasks and
* await them one by one.
*/
const el = /** @type {ValidateElement} */ (await fixture(html`
const el = /** @type {ValidateElement} */ (
await fixture(html`
<${tag}
.submitted=${true}
.validators=${[new MinLength(3)]}
.modelValue=${'1'}
>${lightDom}</${tag}>
`));
`)
);
const { _feedbackNode } = getFormControlMembers(el);
el.modelValue = '12345';

View file

@ -22,9 +22,9 @@ import '@lion/input-stepper/define';
export class UmbrellaForm extends LitElement {
get _lionFormNode() {
return /** @type {import('@lion/form').LionForm} */ (this.shadowRoot?.querySelector(
'lion-form',
));
return /** @type {import('@lion/form').LionForm} */ (
this.shadowRoot?.querySelector('lion-form')
);
}
/**

View file

@ -18,30 +18,34 @@ describe('<lion-input-amount>', () => {
});
it('uses formatAmount for formatting', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount></lion-input-amount>`)
);
expect(el.formatter).to.equal(formatAmount);
});
it('formatAmount uses currency provided on webcomponent', async () => {
// JOD displays 3 fraction digits by default
localize.locale = 'fr-FR';
const el = /** @type {LionInputAmount} */ (await fixture(
html`<lion-input-amount currency="JOD" .modelValue="${123}"></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(
html`<lion-input-amount currency="JOD" .modelValue="${123}"></lion-input-amount>`,
)
);
expect(el.formattedValue).to.equal('123,000');
});
it('formatAmount uses locale provided in formatOptions', async () => {
let el = /** @type {LionInputAmount} */ (await fixture(
html`
<lion-input-amount
.formatOptions="${{ locale: 'en-GB' }}"
.modelValue="${123}"
></lion-input-amount>
`,
));
let el = /** @type {LionInputAmount} */ (
await fixture(
html`
<lion-input-amount
.formatOptions="${{ locale: 'en-GB' }}"
.modelValue="${123}"
></lion-input-amount>
`,
)
);
expect(el.formattedValue).to.equal('123.00');
el = await fixture(
html`
@ -55,9 +59,11 @@ describe('<lion-input-amount>', () => {
});
it('ignores global locale change if property is provided', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(html`
<lion-input-amount .modelValue=${123456.78} .locale="${'en-GB'}"></lion-input-amount>
`));
const el = /** @type {LionInputAmount} */ (
await fixture(html`
<lion-input-amount .modelValue=${123456.78} .locale="${'en-GB'}"></lion-input-amount>
`)
);
expect(el.formattedValue).to.equal('123,456.78'); // British
localize.locale = 'nl-NL';
await aTimeout(0);
@ -65,24 +71,24 @@ describe('<lion-input-amount>', () => {
});
it('uses parseAmount for parsing', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount></lion-input-amount>`)
);
expect(el.parser).to.equal(parseAmount);
});
it('sets inputmode attribute to decimal', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount></lion-input-amount>`)
);
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
expect(_inputNode.getAttribute('inputmode')).to.equal('decimal');
});
it('has type="text" to activate default keyboard on mobile with all necessary symbols', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount></lion-input-amount>`)
);
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
expect(_inputNode.type).to.equal('text');
});
@ -93,9 +99,9 @@ describe('<lion-input-amount>', () => {
});
it('displays currency if provided', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount currency="EUR"></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
);
expect(
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'after')
?.innerText,
@ -104,9 +110,9 @@ describe('<lion-input-amount>', () => {
it('displays correct currency for TRY if locale is tr-TR', async () => {
localize.locale = 'tr-TR';
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount currency="TRY"></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount currency="TRY"></lion-input-amount>`)
);
expect(
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'after')
?.innerText,
@ -114,9 +120,9 @@ describe('<lion-input-amount>', () => {
});
it('can update currency', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount currency="EUR"></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
);
el.currency = 'USD';
await el.updateComplete;
expect(
@ -126,9 +132,11 @@ describe('<lion-input-amount>', () => {
});
it('ignores currency if a suffix is already present', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount currency="EUR"><span slot="suffix">my-currency</span></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(
`<lion-input-amount currency="EUR"><span slot="suffix">my-currency</span></lion-input-amount>`,
)
);
expect(
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'suffix')
?.innerText,
@ -143,18 +151,18 @@ describe('<lion-input-amount>', () => {
describe('Accessibility', () => {
it('adds currency id to aria-labelledby of input', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount currency="EUR"></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
);
expect(el._currencyDisplayNode?.getAttribute('data-label')).to.be.not.null;
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
expect(_inputNode.getAttribute('aria-labelledby')).to.contain(el._currencyDisplayNode?.id);
});
it('adds an aria-label to currency slot', async () => {
const el = /** @type {LionInputAmount} */ (await fixture(
`<lion-input-amount currency="EUR"></lion-input-amount>`,
));
const el = /** @type {LionInputAmount} */ (
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
);
expect(el._currencyDisplayNode?.getAttribute('aria-label')).to.equal('euros');
el.currency = 'USD';
await el.updateComplete;

View file

@ -57,13 +57,15 @@ export class DatepickerInputObject {
}
get overlayHeadingEl() {
return /** @type {HTMLElement} */ (this.overlayEl &&
this.overlayEl.shadowRoot?.querySelector('.calendar-overlay__heading'));
return /** @type {HTMLElement} */ (
this.overlayEl && this.overlayEl.shadowRoot?.querySelector('.calendar-overlay__heading')
);
}
get overlayCloseButtonEl() {
return /** @type {HTMLElement} */ (this.calendarEl &&
this.overlayEl.shadowRoot?.querySelector('#close-button'));
return /** @type {HTMLElement} */ (
this.calendarEl && this.overlayEl.shadowRoot?.querySelector('#close-button')
);
}
get calendarEl() {

View file

@ -235,9 +235,9 @@ export class LocalizeManager {
loadNamespace(namespaceObj, { locale = this.locale } = { locale: this.locale }) {
const isDynamicImport = typeof namespaceObj === 'object';
const namespace = /** @type {string} */ (isDynamicImport
? Object.keys(namespaceObj)[0]
: namespaceObj);
const namespace = /** @type {string} */ (
isDynamicImport ? Object.keys(namespaceObj)[0] : namespaceObj
);
if (this._isNamespaceInCache(locale, namespace)) {
return Promise.resolve();

View file

@ -11,12 +11,14 @@ import { forceCurrencyNameForPHPEnGB } from './utils/normalize-get-currency-name
* @returns {string} currency name like 'US dollar'
*/
export function getCurrencyName(currencyIso, options) {
const parts = /** @type {FormatNumberPart[]} */ (formatNumberToParts(1, {
...options,
style: 'currency',
currency: currencyIso,
currencyDisplay: 'name',
}));
const parts = /** @type {FormatNumberPart[]} */ (
formatNumberToParts(1, {
...options,
style: 'currency',
currency: currencyIso,
currencyDisplay: 'name',
})
);
let currencyName = parts
.filter(p => p.type === 'currency')
.map(o => o.value)

View file

@ -9,10 +9,12 @@ import { formatNumberToParts } from './formatNumberToParts.js';
* @returns {number} fraction for the given currency
*/
export function getFractionDigits(currency = 'EUR') {
const parts = /** @type {FormatNumberPart[]} */ (formatNumberToParts(123, {
style: 'currency',
currency,
}));
const parts = /** @type {FormatNumberPart[]} */ (
formatNumberToParts(123, {
style: 'currency',
currency,
})
);
const [fractionPart] = parts.filter(part => part.type === 'fraction');
return fractionPart ? fractionPart.value.length : 0;
}

View file

@ -11,10 +11,8 @@ import { LocalizeManager } from '../src/LocalizeManager.js';
*/
function getProtectedMembers(localizeManagerEl) {
// @ts-ignore
const {
__storage: storage,
_supportExternalTranslationTools: supportExternalTranslationTools,
} = localizeManagerEl;
const { __storage: storage, _supportExternalTranslationTools: supportExternalTranslationTools } =
localizeManagerEl;
return {
storage,
supportExternalTranslationTools,

View file

@ -9,10 +9,8 @@ import { localize, setLocalize } from '../src/localize.js';
*/
function getProtectedMembers(localizeManagerEl) {
// @ts-ignore
const {
_autoLoadOnLocaleChange: autoLoadOnLocaleChange,
_fallbackLocale: fallbackLocale,
} = localizeManagerEl;
const { _autoLoadOnLocaleChange: autoLoadOnLocaleChange, _fallbackLocale: fallbackLocale } =
localizeManagerEl;
return {
autoLoadOnLocaleChange,
fallbackLocale,

View file

@ -244,8 +244,9 @@ export class OverlayController extends EventTargetShim {
* @type {HTMLElement}
*/
get contentWrapperNode() {
return /** @type {HTMLElement} */ (this.__contentWrapperNode ||
this.config?.contentWrapperNode);
return /** @type {HTMLElement} */ (
this.__contentWrapperNode || this.config?.contentWrapperNode
);
}
/**
@ -262,8 +263,9 @@ export class OverlayController extends EventTargetShim {
* @type {HTMLElement}
*/
get elementToFocusAfterHide() {
return /** @type {HTMLElement} */ (this.__elementToFocusAfterHide ||
this.config?.elementToFocusAfterHide);
return /** @type {HTMLElement} */ (
this.__elementToFocusAfterHide || this.config?.elementToFocusAfterHide
);
}
/**
@ -588,8 +590,9 @@ export class OverlayController extends EventTargetShim {
if (this.__isContentNodeProjected && this.contentWrapperNode.isConnected) {
// We need to keep track of the original local context.
/** config [l2], [l4] */
this.__originalContentParent = /** @type {HTMLElement} */ (this.contentWrapperNode
.parentNode);
this.__originalContentParent = /** @type {HTMLElement} */ (
this.contentWrapperNode.parentNode
);
} else if (cfgToAdd.contentNode && cfgToAdd.contentNode.isConnected) {
// We need to keep track of the original local context.
/** config [l1], [l3], [g1] */
@ -905,8 +908,9 @@ export class OverlayController extends EventTargetShim {
/** @protected */
_restoreFocus() {
const { activeElement } = /** @type {* & ShadowRoot} */ (this
.__contentWrapperNode).getRootNode();
const { activeElement } = /** @type {* & ShadowRoot} */ (
this.__contentWrapperNode
).getRootNode();
// We only are allowed to move focus if we (still) 'own' it.
// Otherwise we assume the 'outside world' has, purposefully, taken over
if (

View file

@ -49,12 +49,14 @@ describe('ArrowMixin', () => {
});
it('shows by default', async () => {
const el = /** @type {ArrowTest} */ (await fixture(html`
<arrow-test>
<div slot="content">This is a tooltip</div>
<button slot="invoker">Tooltip button</button>
</arrow-test>
`));
const el = /** @type {ArrowTest} */ (
await fixture(html`
<arrow-test>
<div slot="content">This is a tooltip</div>
<button slot="invoker">Tooltip button</button>
</arrow-test>
`)
);
expect(el.hasAttribute('has-arrow')).to.be.true;
const arrowNode = /** @type {Element} */ (el._arrowNode);
@ -62,12 +64,14 @@ describe('ArrowMixin', () => {
});
it('hides the arrow when has-arrow is false', async () => {
const el = /** @type {ArrowTest} */ (await fixture(html`
<arrow-test>
<div slot="content">This is a tooltip</div>
<button slot="invoker">Tooltip button</button>
</arrow-test>
`));
const el = /** @type {ArrowTest} */ (
await fixture(html`
<arrow-test>
<div slot="content">This is a tooltip</div>
<button slot="invoker">Tooltip button</button>
</arrow-test>
`)
);
el.hasArrow = false;
await el.updateComplete;
expect(el.hasAttribute('has-arrow')).to.be.false;
@ -76,21 +80,23 @@ describe('ArrowMixin', () => {
});
it('makes sure positioning of the arrow is correct', async () => {
const el = /** @type {ArrowTest} */ (await fixture(html`
<arrow-test
.config="${
/** @type {import('../types/OverlayConfig').OverlayConfig} */ ({
popperConfig: {
placement: 'right',
},
})
}"
style="position: relative; top: 10px;"
>
<div slot="content" style="height: 30px; background-color: red;">Hey there</div>
<button slot="invoker" style="height: 30px;">Tooltip button</button>
</arrow-test>
`));
const el = /** @type {ArrowTest} */ (
await fixture(html`
<arrow-test
.config="${
/** @type {import('../types/OverlayConfig').OverlayConfig} */ ({
popperConfig: {
placement: 'right',
},
})
}"
style="position: relative; top: 10px;"
>
<div slot="content" style="height: 30px; background-color: red;">Hey there</div>
<button slot="invoker" style="height: 30px;">Tooltip button</button>
</arrow-test>
`)
);
el.opened = true;

View file

@ -13,12 +13,14 @@ describe('deepContains()', () => {
<input id="el-3">
`;
const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-1'));
const element = /** @type {HTMLElement} */ (await fixture(html`
<div id="light">
${shadowElement}
<button id="light-el-1"></button>
</div>
`));
const element = /** @type {HTMLElement} */ (
await fixture(html`
<div id="light">
${shadowElement}
<button id="light-el-1"></button>
</div>
`)
);
const lightChildEl = /** @type {HTMLElement} */ (element.querySelector('#light-el-1'));
expect(deepContains(element, element)).to.be.true;
@ -59,12 +61,14 @@ describe('deepContains()', () => {
const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-2'));
const shadowElementChild2 = /** @type {HTMLElement} */ (shadowRoot2.querySelector('#el-2'));
const element = /** @type {HTMLElement} */ (await fixture(html`
<div id="light">
${shadowElement} ${shadowElement2}
<button id="light-el-1"></button>
</div>
`));
const element = /** @type {HTMLElement} */ (
await fixture(html`
<div id="light">
${shadowElement} ${shadowElement2}
<button id="light-el-1"></button>
</div>
`)
);
expect(deepContains(element, shadowElementChild)).to.be.true;
expect(deepContains(shadowElement, shadowElementChild)).to.be.true;
@ -93,21 +97,26 @@ describe('deepContains()', () => {
`;
shadowRoot.insertBefore(shadowNestedElement, shadowRoot.lastElementChild);
const element = /** @type {HTMLElement} */ (await fixture(html`
<div id="light">
${shadowElement}
<button id="light-el-1"></button>
</div>
`));
const element = /** @type {HTMLElement} */ (
await fixture(html`
<div id="light">
${shadowElement}
<button id="light-el-1"></button>
</div>
`)
);
const elementFirstChild = /** @type {HTMLElement} */ (element.firstElementChild);
const elementFirstChildShadow = /** @type {ShadowRoot} */ (elementFirstChild.shadowRoot);
const elementFirstChildShadowChildren = /** @type {HTMLElement[]} */ (Array.from(
elementFirstChildShadow.children,
));
const elementFirstChildShadowChildShadow = /** @type {ShadowRoot} */ (elementFirstChildShadowChildren[1]
.shadowRoot);
const elementFirstChildShadowChildShadowLastChild = /** @type {HTMLElement} */ (elementFirstChildShadowChildShadow.lastElementChild);
const elementFirstChildShadowChildren = /** @type {HTMLElement[]} */ (
Array.from(elementFirstChildShadow.children)
);
const elementFirstChildShadowChildShadow = /** @type {ShadowRoot} */ (
elementFirstChildShadowChildren[1].shadowRoot
);
const elementFirstChildShadowChildShadowLastChild = /** @type {HTMLElement} */ (
elementFirstChildShadowChildShadow.lastElementChild
);
expect(deepContains(element, elementFirstChild)).to.be.true;
expect(deepContains(element, elementFirstChildShadow)).to.be.true;

View file

@ -4,65 +4,77 @@ import { isVisible } from '../../src/utils/is-visible.js';
describe('isVisible()', () => {
it('returns true for static block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(
`<div style="width:10px; height:10px;"></div>`,
));
const element = /** @type {HTMLElement} */ (
await fixture(`<div style="width:10px; height:10px;"></div>`)
);
expect(isVisible(element)).to.equal(true);
});
it('returns false for hidden static block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(
`<div style="width:10px; height:10px;" hidden></div>`,
));
const element = /** @type {HTMLElement} */ (
await fixture(`<div style="width:10px; height:10px;" hidden></div>`)
);
expect(isVisible(element)).to.equal(false);
});
it('returns true for relative block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;"></div>`,
));
const element = /** @type {HTMLElement} */ (
await fixture(
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;"></div>`,
)
);
expect(isVisible(element)).to.equal(true);
});
it('returns false for hidden relative block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;" hidden></div>`,
));
const element = /** @type {HTMLElement} */ (
await fixture(
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;" hidden></div>`,
)
);
expect(isVisible(element)).to.equal(false);
});
it('returns true for absolute block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(`
const element = /** @type {HTMLElement} */ (
await fixture(`
<div style="width:10px; height:10px; position:absolute; top:10px; left:10px;"></div>
`));
`)
);
expect(isVisible(element)).to.equal(true);
});
it('returns false for hidden absolute block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(`
const element = /** @type {HTMLElement} */ (
await fixture(`
<div style="width:10px; height:10px; position:absolute; top:10px; left:10px;" hidden></div>
`));
`)
);
expect(isVisible(element)).to.equal(false);
});
it('returns true for relative block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(`
const element = /** @type {HTMLElement} */ (
await fixture(`
<div style="width:10px; height:10px; position:fixed;top:10px; left:10px;"></div>
`));
`)
);
expect(isVisible(element)).to.equal(true);
});
it('returns true for relative block elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(`
const element = /** @type {HTMLElement} */ (
await fixture(`
<div style="width:10px; height:10px; position:fixed;top:10px; left:10px;" hidden></div>
`));
`)
);
expect(isVisible(element)).to.equal(false);
});
@ -80,48 +92,52 @@ describe('isVisible()', () => {
});
it('returns true for static block elements with 0 dimensions', async () => {
const element = /** @type {HTMLElement} */ (await fixture(
`<div style="width:0; height:0;"></div>`,
));
const element = /** @type {HTMLElement} */ (
await fixture(`<div style="width:0; height:0;"></div>`)
);
expect(isVisible(element)).to.equal(true);
});
it('returns false for hidden inline elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(
`<span hidden>Inline content</span>`,
));
const element = /** @type {HTMLElement} */ (
await fixture(`<span hidden>Inline content</span>`)
);
expect(isVisible(element)).to.equal(false);
});
it('returns false invisible elements', async () => {
const element = /** @type {HTMLElement} */ (await fixture(
`<div style="width:10px; height:10px; visibility: hidden;"></div>`,
));
const element = /** @type {HTMLElement} */ (
await fixture(`<div style="width:10px; height:10px; visibility: hidden;"></div>`)
);
expect(isVisible(element)).to.equal(false);
});
it('returns false when hidden by parent', async () => {
const element = /** @type {HTMLElement} */ (await fixture(`
const element = /** @type {HTMLElement} */ (
await fixture(`
<div hidden>
<div id="target" style="width:10px; height:10px;"></div>
<div></div>
</div>
`));
`)
);
const target = /** @type {HTMLElement} */ (element.querySelector('#target'));
expect(isVisible(target)).to.equal(false);
});
it('returns false when invisible by parent', async () => {
const element = /** @type {HTMLElement} */ (await fixture(`
const element = /** @type {HTMLElement} */ (
await fixture(`
<div style="visibility: hidden;">
<div id="target" style="width:10px; height:10px;"></div>
<div></div>
</div>
`));
`)
);
const target = /** @type {HTMLElement} */ (element.querySelector('#target'));
expect(isVisible(target)).to.equal(false);

View file

@ -21,9 +21,9 @@ class LionFieldWithSelect extends LionField {
* @returns {HTMLSelectElement}
*/
get _inputNode() {
return /** @type {HTMLSelectElement} */ (Array.from(this.children).find(
el => el.slot === 'input',
));
return /** @type {HTMLSelectElement} */ (
Array.from(this.children).find(el => el.slot === 'input')
);
}
}

View file

@ -100,9 +100,9 @@ export class LionSteps extends LitElement {
}
get steps() {
const defaultSlot = /** @type {HTMLSlotElement} */ (this.shadowRoot?.querySelector(
'slot:not([name])',
));
const defaultSlot = /** @type {HTMLSlotElement} */ (
this.shadowRoot?.querySelector('slot:not([name])')
);
return /** @type {LionStep[]} */ (defaultSlot.assignedNodes()).filter(
node => node.nodeType === Node.ELEMENT_NODE,
);

View file

@ -33,9 +33,9 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
*/
// @ts-ignore [editor]: prevents vscode from complaining
get _inputNode() {
return /** @type {LionSwitchButton} */ (Array.from(this.children).find(
el => el.slot === 'input',
));
return /** @type {LionSwitchButton} */ (
Array.from(this.children).find(el => el.slot === 'input')
);
}
get slots() {

View file

@ -323,12 +323,16 @@ export class LionTabs extends LitElement {
) {
return;
}
const previousButton = /** @type {HTMLElement} */ (Array.from(this.children).find(
child => child.slot === 'tab' && child.hasAttribute('selected'),
));
const previousPanel = /** @type {HTMLElement} */ (Array.from(this.children).find(
child => child.slot === 'panel' && child.hasAttribute('selected'),
));
const previousButton = /** @type {HTMLElement} */ (
Array.from(this.children).find(
child => child.slot === 'tab' && child.hasAttribute('selected'),
)
);
const previousPanel = /** @type {HTMLElement} */ (
Array.from(this.children).find(
child => child.slot === 'panel' && child.hasAttribute('selected'),
)
);
if (previousButton) {
deselectButton(previousButton);
}