chore: format & changeset
This commit is contained in:
parent
e17f7bdfa6
commit
72067c0d19
35 changed files with 520 additions and 351 deletions
40
.changeset/fuzzy-snails-attack.md
Normal file
40
.changeset/fuzzy-snails-attack.md
Normal 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
|
||||||
|
|
@ -36,9 +36,8 @@ There are the following methods available to control the pagination.
|
||||||
```js preview-story
|
```js preview-story
|
||||||
export const methods = ({ shadowRoot }) => {
|
export const methods = ({ shadowRoot }) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
shadowRoot.getElementById('pagination-method-demo').innerText = shadowRoot.getElementById(
|
shadowRoot.getElementById('pagination-method-demo').innerText =
|
||||||
'pagination-method',
|
shadowRoot.getElementById('pagination-method').current;
|
||||||
).current;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
|
@ -80,9 +79,8 @@ export const methods = ({ shadowRoot }) => {
|
||||||
```js preview-story
|
```js preview-story
|
||||||
export const event = ({ shadowRoot }) => {
|
export const event = ({ shadowRoot }) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
shadowRoot.getElementById('pagination-event-demo-text').innerText = shadowRoot.getElementById(
|
shadowRoot.getElementById('pagination-event-demo-text').innerText =
|
||||||
'pagination-event-demo',
|
shadowRoot.getElementById('pagination-event-demo').current;
|
||||||
).current;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ import '@lion/button/define';
|
||||||
|
|
||||||
export class UmbrellaForm extends LitElement {
|
export class UmbrellaForm extends LitElement {
|
||||||
get _lionFormNode() {
|
get _lionFormNode() {
|
||||||
return /** @type {import('@lion/form').LionForm} */ (this.shadowRoot?.querySelector(
|
return /** @type {import('@lion/form').LionForm} */ (
|
||||||
'lion-form',
|
this.shadowRoot?.querySelector('lion-form')
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,10 @@ class PBoard extends DecorateMixin(LitElement) {
|
||||||
checked
|
checked
|
||||||
@change="${({ target }) => {
|
@change="${({ target }) => {
|
||||||
// TODO: of course, logic depending on dom is never a good idea
|
// TODO: of course, logic depending on dom is never a good idea
|
||||||
const groupBoxes = target.parentElement.nextElementSibling.querySelectorAll(
|
const groupBoxes =
|
||||||
'input[type=checkbox]',
|
target.parentElement.nextElementSibling.querySelectorAll(
|
||||||
);
|
'input[type=checkbox]',
|
||||||
|
);
|
||||||
const { checked } = target;
|
const { checked } = target;
|
||||||
Array.from(groupBoxes).forEach(box => {
|
Array.from(groupBoxes).forEach(box => {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,8 @@ const promptAnalyzerModule = require('../../src/cli/prompt-analyzer-menu.js');
|
||||||
const { toPosixPath } = require('../../src/program/utils/to-posix-path.js');
|
const { toPosixPath } = require('../../src/program/utils/to-posix-path.js');
|
||||||
const { getExtendDocsResults } = require('../../src/cli/launch-providence-with-extend-docs.js');
|
const { getExtendDocsResults } = require('../../src/cli/launch-providence-with-extend-docs.js');
|
||||||
|
|
||||||
const {
|
const { pathsArrayFromCs, pathsArrayFromCollectionName, appendProjectDependencyPaths } =
|
||||||
pathsArrayFromCs,
|
cliHelpersModule;
|
||||||
pathsArrayFromCollectionName,
|
|
||||||
appendProjectDependencyPaths,
|
|
||||||
} = cliHelpersModule;
|
|
||||||
|
|
||||||
const queryResults = [];
|
const queryResults = [];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,8 @@ const {
|
||||||
restoreSuppressNonCriticalLogs,
|
restoreSuppressNonCriticalLogs,
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
||||||
|
|
||||||
const findCustomelementsQueryConfig = QueryService.getQueryConfigFromAnalyzer(
|
const findCustomelementsQueryConfig =
|
||||||
'find-customelements',
|
QueryService.getQueryConfigFromAnalyzer('find-customelements');
|
||||||
);
|
|
||||||
const _providenceCfg = {
|
const _providenceCfg = {
|
||||||
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,8 @@ describe('remarkExtend', () => {
|
||||||
|
|
||||||
it('throws if an import file does not exist', async () => {
|
it('throws if an import file does not exist', async () => {
|
||||||
await expectThrowsAsync(() => execute("```js ::import('./fixtures/not-available.md')\n```"), {
|
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 =
|
const input =
|
||||||
"```js ::import('./fixtures/three-sections-red.md', 'heading:has([value=Does not exit])')\n```";
|
"```js ::import('./fixtures/three-sections-red.md', 'heading:has([value=Does not exit])')\n```";
|
||||||
await expectThrowsAsync(() => execute(input), {
|
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 =
|
const input =
|
||||||
"```js ::import('./fixtures/three-sections-red.md', 'heading:has([value=More Red])', 'heading:has([value=Does not exit])')\n```";
|
"```js ::import('./fixtures/three-sections-red.md', 'heading:has([value=More Red])', 'heading:has([value=Does not exit])')\n```";
|
||||||
await expectThrowsAsync(() => execute(input), {
|
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 ".*"\./,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,12 +226,12 @@ export class LionAccordion extends LitElement {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
__setupStore() {
|
__setupStore() {
|
||||||
const invokers = /** @type {HTMLElement[]} */ (Array.from(
|
const invokers = /** @type {HTMLElement[]} */ (
|
||||||
this.querySelectorAll('[slot="invoker"]'),
|
Array.from(this.querySelectorAll('[slot="invoker"]'))
|
||||||
));
|
);
|
||||||
const contents = /** @type {HTMLElement[]} */ (Array.from(
|
const contents = /** @type {HTMLElement[]} */ (
|
||||||
this.querySelectorAll('[slot="content"]'),
|
Array.from(this.querySelectorAll('[slot="content"]'))
|
||||||
));
|
);
|
||||||
if (invokers.length !== contents.length) {
|
if (invokers.length !== contents.length) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn(
|
console.warn(
|
||||||
|
|
@ -356,9 +356,11 @@ export class LionAccordion extends LitElement {
|
||||||
if (!(this.__store && this.__store[this.focusedIndex])) {
|
if (!(this.__store && this.__store[this.focusedIndex])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const previousInvoker = /** @type {HTMLElement | undefined} */ (Array.from(this.children).find(
|
const previousInvoker = /** @type {HTMLElement | undefined} */ (
|
||||||
child => child.slot === 'invoker' && child.firstElementChild?.hasAttribute('focused'),
|
Array.from(this.children).find(
|
||||||
));
|
child => child.slot === 'invoker' && child.firstElementChild?.hasAttribute('focused'),
|
||||||
|
)
|
||||||
|
);
|
||||||
if (previousInvoker) {
|
if (previousInvoker) {
|
||||||
unfocusInvoker(previousInvoker);
|
unfocusInvoker(previousInvoker);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,9 +162,9 @@ export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement))
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
get _nativeButtonNode() {
|
get _nativeButtonNode() {
|
||||||
return /** @type {HTMLButtonElement} */ (Array.from(this.children).find(
|
return /** @type {HTMLButtonElement} */ (
|
||||||
child => child.slot === '_button',
|
Array.from(this.children).find(child => child.slot === '_button')
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get slots() {
|
get slots() {
|
||||||
|
|
|
||||||
|
|
@ -813,12 +813,10 @@ describe('<lion-calendar>', () => {
|
||||||
`);
|
`);
|
||||||
const elObj = new CalendarObject(el);
|
const elObj = new CalendarObject(el);
|
||||||
expect(
|
expect(
|
||||||
elObj.checkForAllDayObjs(/** @param {DayObject} d */ d => d.el.hasAttribute('disabled'), [
|
elObj.checkForAllDayObjs(
|
||||||
1,
|
/** @param {DayObject} d */ d => d.el.hasAttribute('disabled'),
|
||||||
2,
|
[1, 2, 30, 31],
|
||||||
30,
|
),
|
||||||
31,
|
|
||||||
]),
|
|
||||||
).to.equal(true);
|
).to.equal(true);
|
||||||
|
|
||||||
clock.restore();
|
clock.restore();
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,8 @@ function compareMultipleMonth(obj) {
|
||||||
week.days.forEach((day, dayi) => {
|
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
|
// @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
|
// eslint-disable-next-line no-param-reassign
|
||||||
obj.months[monthi].weeks[weeki].days[dayi].date = obj.months[monthi].weeks[weeki].days[
|
obj.months[monthi].weeks[weeki].days[dayi].date =
|
||||||
dayi
|
obj.months[monthi].weeks[weeki].days[dayi].date.toISOString();
|
||||||
].date.toISOString();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -108,9 +108,9 @@ describe('SlotMixin', () => {
|
||||||
const tag = defineCE(SlotPrivateText);
|
const tag = defineCE(SlotPrivateText);
|
||||||
const el = /** @type {SlotPrivateText} */ (await fixture(`<${tag}><${tag}>`));
|
const el = /** @type {SlotPrivateText} */ (await fixture(`<${tag}><${tag}>`));
|
||||||
expect(el.didCreateConditionalSlot()).to.be.true;
|
expect(el.didCreateConditionalSlot()).to.be.true;
|
||||||
const elUserSlot = /** @type {SlotPrivateText} */ (await fixture(
|
const elUserSlot = /** @type {SlotPrivateText} */ (
|
||||||
`<${tag}><p slot="conditional">foo</p><${tag}>`,
|
await fixture(`<${tag}><p slot="conditional">foo</p><${tag}>`)
|
||||||
));
|
);
|
||||||
expect(elUserSlot.didCreateConditionalSlot()).to.be.false;
|
expect(elUserSlot.didCreateConditionalSlot()).to.be.false;
|
||||||
renderSlot = false;
|
renderSlot = false;
|
||||||
const elNoSlot = /** @type {SlotPrivateText} */ (await fixture(`<${tag}><${tag}>`));
|
const elNoSlot = /** @type {SlotPrivateText} */ (await fixture(`<${tag}><${tag}>`));
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { dedupeMixin } from '@lion/core';
|
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();
|
const polyfilledNodes = new WeakMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,13 @@ const FormRegistrarPortalMixinImplementation = superclass =>
|
||||||
* @type {(FormRegistrarPortalHost & HTMLElement) | undefined}
|
* @type {(FormRegistrarPortalHost & HTMLElement) | undefined}
|
||||||
*/
|
*/
|
||||||
this.registrationTarget = undefined;
|
this.registrationTarget = undefined;
|
||||||
this.__redispatchEventForFormRegistrarPortalMixin = this.__redispatchEventForFormRegistrarPortalMixin.bind(
|
this.__redispatchEventForFormRegistrarPortalMixin =
|
||||||
this,
|
this.__redispatchEventForFormRegistrarPortalMixin.bind(this);
|
||||||
);
|
|
||||||
this.addEventListener(
|
this.addEventListener(
|
||||||
'form-element-register',
|
'form-element-register',
|
||||||
/** @type {EventListenerOrEventListenerObject} */ (this
|
/** @type {EventListenerOrEventListenerObject} */ (
|
||||||
.__redispatchEventForFormRegistrarPortalMixin),
|
this.__redispatchEventForFormRegistrarPortalMixin
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,10 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass)))),
|
SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass)))),
|
||||||
) {
|
) {
|
||||||
static get scopedElements() {
|
static get scopedElements() {
|
||||||
const scopedElementsCtor = /** @type {typeof import('@open-wc/scoped-elements/src/types').ScopedElementsHost} */ (super
|
const scopedElementsCtor =
|
||||||
.constructor);
|
/** @type {typeof import('@open-wc/scoped-elements/src/types').ScopedElementsHost} */ (
|
||||||
|
super.constructor
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
...scopedElementsCtor.scopedElements,
|
...scopedElementsCtor.scopedElements,
|
||||||
'lion-validation-feedback': LionValidationFeedback,
|
'lion-validation-feedback': LionValidationFeedback,
|
||||||
|
|
@ -482,10 +484,12 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
__executeResultValidators(regularValidationResult) {
|
__executeResultValidators(regularValidationResult) {
|
||||||
const resultValidators = /** @type {ResultValidator[]} */ (this._allValidators.filter(v => {
|
const resultValidators = /** @type {ResultValidator[]} */ (
|
||||||
const vCtor = /** @type {typeof Validator} */ (v.constructor);
|
this._allValidators.filter(v => {
|
||||||
return !vCtor.async && v instanceof ResultValidator;
|
const vCtor = /** @type {typeof Validator} */ (v.constructor);
|
||||||
}));
|
return !vCtor.async && v instanceof ResultValidator;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return resultValidators.filter(v =>
|
return resultValidators.filter(v =>
|
||||||
v.executeOnResults({
|
v.executeOnResults({
|
||||||
|
|
@ -511,8 +515,10 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
this.__validationResult = [...resultOutCome, ...syncAndAsyncOutcome];
|
this.__validationResult = [...resultOutCome, ...syncAndAsyncOutcome];
|
||||||
// this._storeResultsOnInstance(this.__validationResult);
|
// this._storeResultsOnInstance(this.__validationResult);
|
||||||
|
|
||||||
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
|
const ctor =
|
||||||
.constructor);
|
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
|
||||||
|
this.constructor
|
||||||
|
);
|
||||||
|
|
||||||
/** @type {Object.<string, Object.<string, boolean>>} */
|
/** @type {Object.<string, Object.<string, boolean>>} */
|
||||||
const validationStates = ctor.validationTypes.reduce(
|
const validationStates = ctor.validationTypes.reduce(
|
||||||
|
|
@ -582,8 +588,10 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
console.error(errorMessage, this);
|
console.error(errorMessage, this);
|
||||||
throw new Error(errorMessage);
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
|
const ctor =
|
||||||
.constructor);
|
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
|
||||||
|
this.constructor
|
||||||
|
);
|
||||||
if (ctor.validationTypes.indexOf(v.type) === -1) {
|
if (ctor.validationTypes.indexOf(v.type) === -1) {
|
||||||
const vCtor = /** @type {typeof Validator} */ (v.constructor);
|
const vCtor = /** @type {typeof Validator} */ (v.constructor);
|
||||||
// throws in constructor are not visible to end user so we do both
|
// 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('shouldShowFeedbackFor') ||
|
||||||
changedProperties.has('hasFeedbackFor')
|
changedProperties.has('hasFeedbackFor')
|
||||||
) {
|
) {
|
||||||
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
|
const ctor =
|
||||||
.constructor);
|
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
|
||||||
|
this.constructor
|
||||||
|
);
|
||||||
// Necessary typecast because types aren't smart enough to understand that we filter out undefined
|
// Necessary typecast because types aren't smart enough to understand that we filter out undefined
|
||||||
this.showsFeedbackFor = /** @type {string[]} */ (ctor.validationTypes
|
this.showsFeedbackFor = /** @type {string[]} */ (
|
||||||
.map(type => (this._hasFeedbackVisibleFor(type) ? type : undefined))
|
ctor.validationTypes
|
||||||
.filter(Boolean));
|
.map(type => (this._hasFeedbackVisibleFor(type) ? type : undefined))
|
||||||
|
.filter(Boolean)
|
||||||
|
);
|
||||||
this._updateFeedbackComponent();
|
this._updateFeedbackComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -791,9 +803,9 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changedProperties.has('validationStates')) {
|
if (changedProperties.has('validationStates')) {
|
||||||
const prevStates = /** @type {{[key: string]: object;}} */ (changedProperties.get(
|
const prevStates = /** @type {{[key: string]: object;}} */ (
|
||||||
'validationStates',
|
changedProperties.get('validationStates')
|
||||||
));
|
);
|
||||||
if (prevStates) {
|
if (prevStates) {
|
||||||
Object.entries(this.validationStates).forEach(([type, feedbackObj]) => {
|
Object.entries(this.validationStates).forEach(([type, feedbackObj]) => {
|
||||||
if (
|
if (
|
||||||
|
|
@ -811,21 +823,25 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
_updateShouldShowFeedbackFor() {
|
_updateShouldShowFeedbackFor() {
|
||||||
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
|
const ctor =
|
||||||
.constructor);
|
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
|
||||||
|
this.constructor
|
||||||
|
);
|
||||||
|
|
||||||
// Necessary typecast because types aren't smart enough to understand that we filter out undefined
|
// Necessary typecast because types aren't smart enough to understand that we filter out undefined
|
||||||
const newShouldShowFeedbackFor = /** @type {string[]} */ (ctor.validationTypes
|
const newShouldShowFeedbackFor = /** @type {string[]} */ (
|
||||||
.map(type =>
|
ctor.validationTypes
|
||||||
this.feedbackCondition(
|
.map(type =>
|
||||||
type,
|
this.feedbackCondition(
|
||||||
this._feedbackConditionMeta,
|
type,
|
||||||
this._showFeedbackConditionFor.bind(this),
|
this._feedbackConditionMeta,
|
||||||
|
this._showFeedbackConditionFor.bind(this),
|
||||||
|
)
|
||||||
|
? type
|
||||||
|
: undefined,
|
||||||
)
|
)
|
||||||
? type
|
.filter(Boolean)
|
||||||
: undefined,
|
);
|
||||||
)
|
|
||||||
.filter(Boolean));
|
|
||||||
|
|
||||||
if (JSON.stringify(this.shouldShowFeedbackFor) !== JSON.stringify(newShouldShowFeedbackFor)) {
|
if (JSON.stringify(this.shouldShowFeedbackFor) !== JSON.stringify(newShouldShowFeedbackFor)) {
|
||||||
this.shouldShowFeedbackFor = newShouldShowFeedbackFor;
|
this.shouldShowFeedbackFor = newShouldShowFeedbackFor;
|
||||||
|
|
@ -841,8 +857,10 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
_prioritizeAndFilterFeedback({ validationResult }) {
|
_prioritizeAndFilterFeedback({ validationResult }) {
|
||||||
const ctor = /** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (this
|
const ctor =
|
||||||
.constructor);
|
/** @type {typeof import('../../types/validate/ValidateMixinTypes').ValidateHost} */ (
|
||||||
|
this.constructor
|
||||||
|
);
|
||||||
const types = ctor.validationTypes;
|
const types = ctor.validationTypes;
|
||||||
// Sort all validators based on the type provided.
|
// Sort all validators based on the type provided.
|
||||||
const res = validationResult
|
const res = validationResult
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
export class IsEmail extends Validator {
|
||||||
static get validatorName() {
|
static get validatorName() {
|
||||||
return 'IsEmail';
|
return 'IsEmail';
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,13 @@ export const runRegistrationSuite = customConfig => {
|
||||||
const { parentTagString, childTagString } = cfg;
|
const { parentTagString, childTagString } = cfg;
|
||||||
|
|
||||||
it('can register a formElement', async () => {
|
it('can register a formElement', async () => {
|
||||||
const el = /** @type {RegistrarClass} */ (await fixture(html`
|
const el = /** @type {RegistrarClass} */ (
|
||||||
|
await fixture(html`
|
||||||
<${parentTag}>
|
<${parentTag}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
</${parentTag}>
|
</${parentTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
expect(el.formElements.length).to.equal(1);
|
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 () => {
|
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}>
|
<${parentTag}>
|
||||||
<div>
|
<div>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
</div>
|
</div>
|
||||||
</${parentTag}>
|
</${parentTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
expect(el.formElements.length).to.equal(1);
|
expect(el.formElements.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports nested registration parents', async () => {
|
it('supports nested registration parents', async () => {
|
||||||
const el = /** @type {RegistrarClass} */ (await fixture(html`
|
const el = /** @type {RegistrarClass} */ (
|
||||||
|
await fixture(html`
|
||||||
<${parentTag}>
|
<${parentTag}>
|
||||||
<${parentTag} class="sub-group">
|
<${parentTag} class="sub-group">
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
</${parentTag}>
|
</${parentTag}>
|
||||||
</${parentTag}>
|
</${parentTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
expect(el.formElements.length).to.equal(1);
|
expect(el.formElements.length).to.equal(1);
|
||||||
|
|
||||||
const subGroup = /** @type {RegistrarClass} */ (el.querySelector('.sub-group'));
|
const subGroup = /** @type {RegistrarClass} */ (el.querySelector('.sub-group'));
|
||||||
|
|
@ -95,20 +101,24 @@ export const runRegistrationSuite = customConfig => {
|
||||||
}
|
}
|
||||||
const tagWrapperString = defineCE(PerformUpdate);
|
const tagWrapperString = defineCE(PerformUpdate);
|
||||||
const tagWrapper = unsafeStatic(tagWrapperString);
|
const tagWrapper = unsafeStatic(tagWrapperString);
|
||||||
const el = /** @type {PerformUpdate} */ (await fixture(html`
|
const el = /** @type {PerformUpdate} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tagWrapper}>
|
<${tagWrapper}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
</${tagWrapper}>
|
</${tagWrapper}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
expect(el.formElements.length).to.equal(1);
|
expect(el.formElements.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can dynamically add/remove elements', async () => {
|
it('can dynamically add/remove elements', async () => {
|
||||||
const el = /** @type {RegistrarClass} */ (await fixture(html`
|
const el = /** @type {RegistrarClass} */ (
|
||||||
|
await fixture(html`
|
||||||
<${parentTag}>
|
<${parentTag}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
</${parentTag}>
|
</${parentTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const newField = await fixture(html`
|
const newField = await fixture(html`
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
`);
|
`);
|
||||||
|
|
@ -122,20 +132,24 @@ export const runRegistrationSuite = customConfig => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds elements to formElements in the right order (DOM)', async () => {
|
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}>
|
<${parentTag}>
|
||||||
<${childTag} pos="0"></${childTag}>
|
<${childTag} pos="0"></${childTag}>
|
||||||
<${childTag} pos="1"></${childTag}>
|
<${childTag} pos="1"></${childTag}>
|
||||||
<${childTag} pos="2"></${childTag}>
|
<${childTag} pos="2"></${childTag}>
|
||||||
</${parentTag}>
|
</${parentTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
/** INSERT field before the pos=1 */
|
/** INSERT field before the pos=1 */
|
||||||
/**
|
/**
|
||||||
* @typedef {Object.<string, string>} prop
|
* @typedef {Object.<string, string>} prop
|
||||||
*/
|
*/
|
||||||
const newField = /** @type {RegisteringClass & prop} */ (await fixture(html`
|
const newField = /** @type {RegisteringClass & prop} */ (
|
||||||
|
await fixture(html`
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
newField.setAttribute('pos', 'inserted-before-1');
|
newField.setAttribute('pos', 'inserted-before-1');
|
||||||
el.insertBefore(newField, el.children[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');
|
expect(el.formElements[1].getAttribute('pos')).to.equal('inserted-before-1');
|
||||||
|
|
||||||
/** INSERT field before the pos=0 (e.g. at the top) */
|
/** 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}>
|
<${childTag}></${childTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
topField.setAttribute('pos', 'inserted-before-0');
|
topField.setAttribute('pos', 'inserted-before-0');
|
||||||
el.insertBefore(topField, el.children[0]);
|
el.insertBefore(topField, el.children[0]);
|
||||||
|
|
||||||
|
|
@ -159,9 +175,9 @@ export const runRegistrationSuite = customConfig => {
|
||||||
|
|
||||||
describe('FormRegistrarPortalMixin', () => {
|
describe('FormRegistrarPortalMixin', () => {
|
||||||
it('forwards registrations to the .registrationTarget', async () => {
|
it('forwards registrations to the .registrationTarget', async () => {
|
||||||
const el = /** @type {RegistrarClass} */ (await fixture(
|
const el = /** @type {RegistrarClass} */ (
|
||||||
html`<${parentTag}></${parentTag}>`,
|
await fixture(html`<${parentTag}></${parentTag}>`)
|
||||||
));
|
);
|
||||||
await fixture(html`
|
await fixture(html`
|
||||||
<${portalTag} .registrationTarget=${el}>
|
<${portalTag} .registrationTarget=${el}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
|
|
@ -172,9 +188,9 @@ export const runRegistrationSuite = customConfig => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can dynamically add/remove elements', async () => {
|
it('can dynamically add/remove elements', async () => {
|
||||||
const el = /** @type {RegistrarClass} */ (await fixture(
|
const el = /** @type {RegistrarClass} */ (
|
||||||
html`<${parentTag}></${parentTag}>`,
|
await fixture(html`<${parentTag}></${parentTag}>`)
|
||||||
));
|
);
|
||||||
const portal = await fixture(html`
|
const portal = await fixture(html`
|
||||||
<${portalTag} .registrationTarget=${el}>
|
<${portalTag} .registrationTarget=${el}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
|
|
@ -194,13 +210,15 @@ export const runRegistrationSuite = customConfig => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds elements to formElements in the right order', async () => {
|
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}>
|
<${parentTag}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
</${parentTag}>
|
</${parentTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
expect(el.formElements.length).to.equal(3);
|
expect(el.formElements.length).to.equal(3);
|
||||||
|
|
||||||
|
|
@ -232,9 +250,9 @@ export const runRegistrationSuite = customConfig => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps working if moving the portal itself', async () => {
|
it('keeps working if moving the portal itself', async () => {
|
||||||
const el = /** @type {RegistrarClass} */ (await fixture(
|
const el = /** @type {RegistrarClass} */ (
|
||||||
html`<${parentTag}></${parentTag}>`,
|
await fixture(html`<${parentTag}></${parentTag}>`)
|
||||||
));
|
);
|
||||||
const portal = await fixture(html`
|
const portal = await fixture(html`
|
||||||
<${portalTag} .registrationTarget=${el}>
|
<${portalTag} .registrationTarget=${el}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
|
|
@ -270,9 +288,9 @@ export const runRegistrationSuite = customConfig => {
|
||||||
);
|
);
|
||||||
const delayedPortalTag = unsafeStatic(delayedPortalString);
|
const delayedPortalTag = unsafeStatic(delayedPortalString);
|
||||||
|
|
||||||
const el = /** @type {RegistrarClass} */ (await fixture(
|
const el = /** @type {RegistrarClass} */ (
|
||||||
html`<${parentTag}></${parentTag}>`,
|
await fixture(html`<${parentTag}></${parentTag}>`)
|
||||||
));
|
);
|
||||||
await fixture(html`
|
await fixture(html`
|
||||||
<${delayedPortalTag} .registrationTarget=${el}>
|
<${delayedPortalTag} .registrationTarget=${el}>
|
||||||
<${childTag}></${childTag}>
|
<${childTag}></${childTag}>
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,9 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets an attribute "filled" if the input has a non-empty modelValue', async () => {
|
it('sets an attribute "filled" if the input has a non-empty modelValue', async () => {
|
||||||
const el = /** @type {IState} */ (await fixture(
|
const el = /** @type {IState} */ (
|
||||||
html`<${tag} .modelValue=${'hello'}></${tag}>`,
|
await fixture(html`<${tag} .modelValue=${'hello'}></${tag}>`)
|
||||||
));
|
);
|
||||||
expect(el.hasAttribute('filled')).to.equal(true);
|
expect(el.hasAttribute('filled')).to.equal(true);
|
||||||
el.modelValue = '';
|
el.modelValue = '';
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
|
@ -97,9 +97,11 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
it('fires "(touched|dirty)-state-changed" event when state changes', async () => {
|
it('fires "(touched|dirty)-state-changed" event when state changes', async () => {
|
||||||
const touchedSpy = sinon.spy();
|
const touchedSpy = sinon.spy();
|
||||||
const dirtySpy = sinon.spy();
|
const dirtySpy = sinon.spy();
|
||||||
const el = /** @type {IState} */ (await fixture(
|
const el = /** @type {IState} */ (
|
||||||
html`<${tag} @touched-changed=${touchedSpy} @dirty-changed=${dirtySpy}></${tag}>`,
|
await fixture(
|
||||||
));
|
html`<${tag} @touched-changed=${touchedSpy} @dirty-changed=${dirtySpy}></${tag}>`,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
el.touched = true;
|
el.touched = true;
|
||||||
expect(touchedSpy.callCount).to.equal(1);
|
expect(touchedSpy.callCount).to.equal(1);
|
||||||
|
|
@ -109,14 +111,18 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets prefilled once instantiated', async () => {
|
it('sets prefilled once instantiated', async () => {
|
||||||
const el = /** @type {IState} */ (await fixture(html`
|
const el = /** @type {IState} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag} .modelValue=${'prefilled'}></${tag}>
|
<${tag} .modelValue=${'prefilled'}></${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
expect(el.prefilled).to.be.true;
|
expect(el.prefilled).to.be.true;
|
||||||
|
|
||||||
const nonPrefilled = /** @type {IState} */ (await fixture(html`
|
const nonPrefilled = /** @type {IState} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag} .modelValue=${''}></${tag}>
|
<${tag} .modelValue=${''}></${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
expect(nonPrefilled.prefilled).to.be.false;
|
expect(nonPrefilled.prefilled).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -125,9 +131,9 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
(${cfg.allowedModelValueTypes.map(t => t.name).join(', ')})`, async () => {
|
(${cfg.allowedModelValueTypes.map(t => t.name).join(', ')})`, async () => {
|
||||||
/** @typedef {{_inputNode: HTMLElement}} inputNodeInterface */
|
/** @typedef {{_inputNode: HTMLElement}} inputNodeInterface */
|
||||||
|
|
||||||
const el = /** @type {IState & inputNodeInterface} */ (await fixture(
|
const el = /** @type {IState & inputNodeInterface} */ (
|
||||||
html`<${tag}></${tag}>`,
|
await fixture(html`<${tag}></${tag}>`)
|
||||||
));
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {*} modelValue
|
* @param {*} modelValue
|
||||||
|
|
@ -213,9 +219,11 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
|
|
||||||
describe('Validation integration with states', () => {
|
describe('Validation integration with states', () => {
|
||||||
it('has .shouldShowFeedbackFor indicating for which type to show messages', async () => {
|
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}>
|
<${tag}></${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
// @ts-ignore [allow-private] in test
|
// @ts-ignore [allow-private] in test
|
||||||
expect(el.shouldShowFeedbackFor).to.deep.equal([]);
|
expect(el.shouldShowFeedbackFor).to.deep.equal([]);
|
||||||
el.submitted = true;
|
el.submitted = true;
|
||||||
|
|
@ -225,9 +233,11 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps the feedback component in sync', async () => {
|
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}>
|
<${tag} .validators=${[new MinLength(3)]}></${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
|
@ -257,9 +267,9 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
}
|
}
|
||||||
const tagLeaveString = defineCE(IStateCustomBlur);
|
const tagLeaveString = defineCE(IStateCustomBlur);
|
||||||
const tagLeave = unsafeStatic(tagLeaveString);
|
const tagLeave = unsafeStatic(tagLeaveString);
|
||||||
const el = /** @type {IStateCustomBlur} */ (await fixture(
|
const el = /** @type {IStateCustomBlur} */ (
|
||||||
html`<${tagLeave}></${tagLeave}>`,
|
await fixture(html`<${tagLeave}></${tagLeave}>`)
|
||||||
));
|
);
|
||||||
el.dispatchEvent(new Event('custom-blur'));
|
el.dispatchEvent(new Event('custom-blur'));
|
||||||
expect(el.touched).to.be.true;
|
expect(el.touched).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,11 @@ export function runValidateMixinFeedbackPart() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has .showsFeedbackFor indicating for which type it actually shows messages', async () => {
|
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}>
|
<${tag} submitted .validators=${[new MinLength(3)]}>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
el.modelValue = 'a';
|
el.modelValue = 'a';
|
||||||
await el.feedbackComplete;
|
await el.feedbackComplete;
|
||||||
|
|
@ -87,14 +89,16 @@ export function runValidateMixinFeedbackPart() {
|
||||||
}
|
}
|
||||||
const elTagString = defineCE(ValidateElementCustomTypes);
|
const elTagString = defineCE(ValidateElementCustomTypes);
|
||||||
const elTag = unsafeStatic(elTagString);
|
const elTag = unsafeStatic(elTagString);
|
||||||
const el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
|
const el = /** @type {ValidateElementCustomTypes} */ (
|
||||||
|
await fixture(html`
|
||||||
<${elTag}
|
<${elTag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[
|
.validators=${[
|
||||||
new MinLength(2, { type: 'x' }),
|
new MinLength(2, { type: 'x' }),
|
||||||
new MinLength(3, { type: 'error' }),
|
new MinLength(3, { type: 'error' }),
|
||||||
]}>${lightDom}</${elTag}>
|
]}>${lightDom}</${elTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
el.modelValue = '1';
|
el.modelValue = '1';
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
|
@ -116,12 +120,14 @@ export function runValidateMixinFeedbackPart() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes a message to the "._feedbackNode"', async () => {
|
it('passes a message to the "._feedbackNode"', async () => {
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
expect(_feedbackNode.feedbackData).to.deep.equal([]);
|
expect(_feedbackNode.feedbackData).to.deep.equal([]);
|
||||||
|
|
@ -132,13 +138,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has configurable feedback visibility hook', async () => {
|
it('has configurable feedback visibility hook', async () => {
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
.validators=${[new AlwaysInvalid()]}
|
.validators=${[new AlwaysInvalid()]}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
|
@ -153,13 +161,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('writes prioritized result to "._feedbackNode" based on Validator order', async () => {
|
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}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
.validators=${[new AlwaysInvalid(), new MinLength(4)]}
|
.validators=${[new AlwaysInvalid(), new MinLength(4)]}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
|
@ -179,13 +189,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
return 'this ends up in "._feedbackNode"';
|
return 'this ends up in "._feedbackNode"';
|
||||||
};
|
};
|
||||||
|
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
.validators=${[new AlwaysInvalid()]}
|
.validators=${[new AlwaysInvalid()]}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
expect(_feedbackNode.feedbackData).to.be.undefined;
|
expect(_feedbackNode.feedbackData).to.be.undefined;
|
||||||
|
|
@ -208,13 +220,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
return 'this ends up in "._feedbackNode"';
|
return 'this ends up in "._feedbackNode"';
|
||||||
};
|
};
|
||||||
|
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
.validators=${[new AlwaysInvalid()]}
|
.validators=${[new AlwaysInvalid()]}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
expect(_feedbackNode.feedbackData).to.be.undefined;
|
expect(_feedbackNode.feedbackData).to.be.undefined;
|
||||||
|
|
@ -248,8 +262,9 @@ export function runValidateMixinFeedbackPart() {
|
||||||
render() {
|
render() {
|
||||||
let name = '';
|
let name = '';
|
||||||
if (this.feedbackData && this.feedbackData.length > 0) {
|
if (this.feedbackData && this.feedbackData.length > 0) {
|
||||||
const ctor = /** @type {typeof Validator} */ (this.feedbackData[0]?.validator
|
const ctor = /** @type {typeof Validator} */ (
|
||||||
?.constructor);
|
this.feedbackData[0]?.validator?.constructor
|
||||||
|
);
|
||||||
name = ctor.validatorName;
|
name = ctor.validatorName;
|
||||||
}
|
}
|
||||||
return html`Custom for ${name}`;
|
return html`Custom for ${name}`;
|
||||||
|
|
@ -257,13 +272,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
}
|
}
|
||||||
const customFeedbackTagString = defineCE(ValidateElementCustomRender);
|
const customFeedbackTagString = defineCE(ValidateElementCustomRender);
|
||||||
const customFeedbackTag = unsafeStatic(customFeedbackTagString);
|
const customFeedbackTag = unsafeStatic(customFeedbackTagString);
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[new ContainsLowercaseA(), new AlwaysInvalid()]}>
|
.validators=${[new ContainsLowercaseA(), new AlwaysInvalid()]}>
|
||||||
<${customFeedbackTag} slot="feedback"><${customFeedbackTag}>
|
<${customFeedbackTag} slot="feedback"><${customFeedbackTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
expect(_feedbackNode.localName).to.equal(customFeedbackTagString);
|
expect(_feedbackNode.localName).to.equal(customFeedbackTagString);
|
||||||
|
|
@ -282,12 +299,14 @@ export function runValidateMixinFeedbackPart() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports custom messages in Validator instance configuration object', async () => {
|
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}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[new MinLength(3, { getMessage: () => 'custom via config' })]}
|
.validators=${[new MinLength(3, { getMessage: () => 'custom via config' })]}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
el.modelValue = 'a';
|
el.modelValue = 'a';
|
||||||
|
|
@ -297,13 +316,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updates the feedback component when locale changes', async () => {
|
it('updates the feedback component when locale changes', async () => {
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[new MinLength(3)]}
|
.validators=${[new MinLength(3)]}
|
||||||
.modelValue=${'1'}
|
.modelValue=${'1'}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
await el.feedbackComplete;
|
await el.feedbackComplete;
|
||||||
|
|
@ -323,7 +344,8 @@ export function runValidateMixinFeedbackPart() {
|
||||||
}
|
}
|
||||||
const elTagString = defineCE(ValidateElementCustomTypes);
|
const elTagString = defineCE(ValidateElementCustomTypes);
|
||||||
const elTag = unsafeStatic(elTagString);
|
const elTag = unsafeStatic(elTagString);
|
||||||
const el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
|
const el = /** @type {ValidateElementCustomTypes} */ (
|
||||||
|
await fixture(html`
|
||||||
<${elTag}
|
<${elTag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[
|
.validators=${[
|
||||||
|
|
@ -331,7 +353,8 @@ export function runValidateMixinFeedbackPart() {
|
||||||
new DefaultSuccess(null, { getMessage: () => 'This is a success message' }),
|
new DefaultSuccess(null, { getMessage: () => 'This is a success message' }),
|
||||||
]}
|
]}
|
||||||
>${lightDom}</${elTag}>
|
>${lightDom}</${elTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
el.modelValue = 'a';
|
el.modelValue = 'a';
|
||||||
|
|
@ -347,13 +370,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
|
|
||||||
describe('Accessibility', () => {
|
describe('Accessibility', () => {
|
||||||
it('sets [aria-invalid="true"] to "._inputNode" when there is an error', async () => {
|
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}
|
<${tag}
|
||||||
submitted
|
submitted
|
||||||
.validators=${[new Required()]}
|
.validators=${[new Required()]}
|
||||||
.modelValue=${'a'}
|
.modelValue=${'a'}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _inputNode } = getFormControlMembers(el);
|
const { _inputNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
const inputNode = _inputNode;
|
const inputNode = _inputNode;
|
||||||
|
|
@ -386,13 +411,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
|
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
|
||||||
const constructorMessageSpy = sinon.spy(ctorValidator, 'getMessage');
|
const constructorMessageSpy = sinon.spy(ctorValidator, 'getMessage');
|
||||||
|
|
||||||
el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
|
el = /** @type {ValidateElementCustomTypes} */ (
|
||||||
|
await fixture(html`
|
||||||
<${elTag}
|
<${elTag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[constructorValidator]}
|
.validators=${[constructorValidator]}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
>${lightDom}</${elTag}>
|
>${lightDom}</${elTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
await el.feedbackComplete;
|
await el.feedbackComplete;
|
||||||
expect(constructorMessageSpy.args[0][0]).to.eql({
|
expect(constructorMessageSpy.args[0][0]).to.eql({
|
||||||
|
|
@ -408,13 +435,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
const instanceMessageSpy = sinon.spy();
|
const instanceMessageSpy = sinon.spy();
|
||||||
const instanceValidator = new MinLength(4, { getMessage: instanceMessageSpy });
|
const instanceValidator = new MinLength(4, { getMessage: instanceMessageSpy });
|
||||||
|
|
||||||
el = /** @type {ValidateElementCustomTypes} */ (await fixture(html`
|
el = /** @type {ValidateElementCustomTypes} */ (
|
||||||
|
await fixture(html`
|
||||||
<${elTag}
|
<${elTag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[instanceValidator]}
|
.validators=${[instanceValidator]}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
>${lightDom}</${elTag}>
|
>${lightDom}</${elTag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
await el.feedbackComplete;
|
await el.feedbackComplete;
|
||||||
expect(instanceMessageSpy.args[0][0]).to.eql({
|
expect(instanceMessageSpy.args[0][0]).to.eql({
|
||||||
|
|
@ -435,14 +464,16 @@ export function runValidateMixinFeedbackPart() {
|
||||||
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
|
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
|
||||||
const spy = sinon.spy(ctorValidator, 'getMessage');
|
const spy = sinon.spy(ctorValidator, 'getMessage');
|
||||||
|
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[constructorValidator]}
|
.validators=${[constructorValidator]}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
.fieldName=${new Promise(resolve => resolve('myField'))}
|
.fieldName=${new Promise(resolve => resolve('myField'))}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
await el.feedbackComplete;
|
await el.feedbackComplete;
|
||||||
expect(spy.args[0][0]).to.eql({
|
expect(spy.args[0][0]).to.eql({
|
||||||
|
|
@ -464,14 +495,16 @@ export function runValidateMixinFeedbackPart() {
|
||||||
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
|
const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
|
||||||
const spy = sinon.spy(ctorValidator, 'getMessage');
|
const spy = sinon.spy(ctorValidator, 'getMessage');
|
||||||
|
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[constructorValidator]}
|
.validators=${[constructorValidator]}
|
||||||
.modelValue=${'cat'}
|
.modelValue=${'cat'}
|
||||||
.fieldName=${new Promise(resolve => resolve('myField'))}
|
.fieldName=${new Promise(resolve => resolve('myField'))}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
await el.feedbackComplete;
|
await el.feedbackComplete;
|
||||||
|
|
||||||
|
|
@ -500,13 +533,15 @@ export function runValidateMixinFeedbackPart() {
|
||||||
* The Queue system solves this by queueing the updateFeedbackComponent tasks and
|
* The Queue system solves this by queueing the updateFeedbackComponent tasks and
|
||||||
* await them one by one.
|
* await them one by one.
|
||||||
*/
|
*/
|
||||||
const el = /** @type {ValidateElement} */ (await fixture(html`
|
const el = /** @type {ValidateElement} */ (
|
||||||
|
await fixture(html`
|
||||||
<${tag}
|
<${tag}
|
||||||
.submitted=${true}
|
.submitted=${true}
|
||||||
.validators=${[new MinLength(3)]}
|
.validators=${[new MinLength(3)]}
|
||||||
.modelValue=${'1'}
|
.modelValue=${'1'}
|
||||||
>${lightDom}</${tag}>
|
>${lightDom}</${tag}>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
const { _feedbackNode } = getFormControlMembers(el);
|
const { _feedbackNode } = getFormControlMembers(el);
|
||||||
|
|
||||||
el.modelValue = '12345';
|
el.modelValue = '12345';
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ import '@lion/input-stepper/define';
|
||||||
|
|
||||||
export class UmbrellaForm extends LitElement {
|
export class UmbrellaForm extends LitElement {
|
||||||
get _lionFormNode() {
|
get _lionFormNode() {
|
||||||
return /** @type {import('@lion/form').LionForm} */ (this.shadowRoot?.querySelector(
|
return /** @type {import('@lion/form').LionForm} */ (
|
||||||
'lion-form',
|
this.shadowRoot?.querySelector('lion-form')
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -18,30 +18,34 @@ describe('<lion-input-amount>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses formatAmount for formatting', async () => {
|
it('uses formatAmount for formatting', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount></lion-input-amount>`,
|
await fixture(`<lion-input-amount></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
expect(el.formatter).to.equal(formatAmount);
|
expect(el.formatter).to.equal(formatAmount);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formatAmount uses currency provided on webcomponent', async () => {
|
it('formatAmount uses currency provided on webcomponent', async () => {
|
||||||
// JOD displays 3 fraction digits by default
|
// JOD displays 3 fraction digits by default
|
||||||
localize.locale = 'fr-FR';
|
localize.locale = 'fr-FR';
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
html`<lion-input-amount currency="JOD" .modelValue="${123}"></lion-input-amount>`,
|
await fixture(
|
||||||
));
|
html`<lion-input-amount currency="JOD" .modelValue="${123}"></lion-input-amount>`,
|
||||||
|
)
|
||||||
|
);
|
||||||
expect(el.formattedValue).to.equal('123,000');
|
expect(el.formattedValue).to.equal('123,000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formatAmount uses locale provided in formatOptions', async () => {
|
it('formatAmount uses locale provided in formatOptions', async () => {
|
||||||
let el = /** @type {LionInputAmount} */ (await fixture(
|
let el = /** @type {LionInputAmount} */ (
|
||||||
html`
|
await fixture(
|
||||||
<lion-input-amount
|
html`
|
||||||
.formatOptions="${{ locale: 'en-GB' }}"
|
<lion-input-amount
|
||||||
.modelValue="${123}"
|
.formatOptions="${{ locale: 'en-GB' }}"
|
||||||
></lion-input-amount>
|
.modelValue="${123}"
|
||||||
`,
|
></lion-input-amount>
|
||||||
));
|
`,
|
||||||
|
)
|
||||||
|
);
|
||||||
expect(el.formattedValue).to.equal('123.00');
|
expect(el.formattedValue).to.equal('123.00');
|
||||||
el = await fixture(
|
el = await fixture(
|
||||||
html`
|
html`
|
||||||
|
|
@ -55,9 +59,11 @@ describe('<lion-input-amount>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ignores global locale change if property is provided', async () => {
|
it('ignores global locale change if property is provided', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(html`
|
const el = /** @type {LionInputAmount} */ (
|
||||||
<lion-input-amount .modelValue=${123456.78} .locale="${'en-GB'}"></lion-input-amount>
|
await fixture(html`
|
||||||
`));
|
<lion-input-amount .modelValue=${123456.78} .locale="${'en-GB'}"></lion-input-amount>
|
||||||
|
`)
|
||||||
|
);
|
||||||
expect(el.formattedValue).to.equal('123,456.78'); // British
|
expect(el.formattedValue).to.equal('123,456.78'); // British
|
||||||
localize.locale = 'nl-NL';
|
localize.locale = 'nl-NL';
|
||||||
await aTimeout(0);
|
await aTimeout(0);
|
||||||
|
|
@ -65,24 +71,24 @@ describe('<lion-input-amount>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses parseAmount for parsing', async () => {
|
it('uses parseAmount for parsing', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount></lion-input-amount>`,
|
await fixture(`<lion-input-amount></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
expect(el.parser).to.equal(parseAmount);
|
expect(el.parser).to.equal(parseAmount);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets inputmode attribute to decimal', async () => {
|
it('sets inputmode attribute to decimal', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount></lion-input-amount>`,
|
await fixture(`<lion-input-amount></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
|
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
|
||||||
expect(_inputNode.getAttribute('inputmode')).to.equal('decimal');
|
expect(_inputNode.getAttribute('inputmode')).to.equal('decimal');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has type="text" to activate default keyboard on mobile with all necessary symbols', async () => {
|
it('has type="text" to activate default keyboard on mobile with all necessary symbols', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount></lion-input-amount>`,
|
await fixture(`<lion-input-amount></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
|
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
|
||||||
expect(_inputNode.type).to.equal('text');
|
expect(_inputNode.type).to.equal('text');
|
||||||
});
|
});
|
||||||
|
|
@ -93,9 +99,9 @@ describe('<lion-input-amount>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays currency if provided', async () => {
|
it('displays currency if provided', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount currency="EUR"></lion-input-amount>`,
|
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
expect(
|
expect(
|
||||||
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'after')
|
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'after')
|
||||||
?.innerText,
|
?.innerText,
|
||||||
|
|
@ -104,9 +110,9 @@ describe('<lion-input-amount>', () => {
|
||||||
|
|
||||||
it('displays correct currency for TRY if locale is tr-TR', async () => {
|
it('displays correct currency for TRY if locale is tr-TR', async () => {
|
||||||
localize.locale = 'tr-TR';
|
localize.locale = 'tr-TR';
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount currency="TRY"></lion-input-amount>`,
|
await fixture(`<lion-input-amount currency="TRY"></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
expect(
|
expect(
|
||||||
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'after')
|
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'after')
|
||||||
?.innerText,
|
?.innerText,
|
||||||
|
|
@ -114,9 +120,9 @@ describe('<lion-input-amount>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can update currency', async () => {
|
it('can update currency', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount currency="EUR"></lion-input-amount>`,
|
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
el.currency = 'USD';
|
el.currency = 'USD';
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(
|
expect(
|
||||||
|
|
@ -126,9 +132,11 @@ describe('<lion-input-amount>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ignores currency if a suffix is already present', async () => {
|
it('ignores currency if a suffix is already present', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount currency="EUR"><span slot="suffix">my-currency</span></lion-input-amount>`,
|
await fixture(
|
||||||
));
|
`<lion-input-amount currency="EUR"><span slot="suffix">my-currency</span></lion-input-amount>`,
|
||||||
|
)
|
||||||
|
);
|
||||||
expect(
|
expect(
|
||||||
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'suffix')
|
/** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'suffix')
|
||||||
?.innerText,
|
?.innerText,
|
||||||
|
|
@ -143,18 +151,18 @@ describe('<lion-input-amount>', () => {
|
||||||
|
|
||||||
describe('Accessibility', () => {
|
describe('Accessibility', () => {
|
||||||
it('adds currency id to aria-labelledby of input', async () => {
|
it('adds currency id to aria-labelledby of input', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount currency="EUR"></lion-input-amount>`,
|
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
expect(el._currencyDisplayNode?.getAttribute('data-label')).to.be.not.null;
|
expect(el._currencyDisplayNode?.getAttribute('data-label')).to.be.not.null;
|
||||||
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
|
const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
|
||||||
expect(_inputNode.getAttribute('aria-labelledby')).to.contain(el._currencyDisplayNode?.id);
|
expect(_inputNode.getAttribute('aria-labelledby')).to.contain(el._currencyDisplayNode?.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds an aria-label to currency slot', async () => {
|
it('adds an aria-label to currency slot', async () => {
|
||||||
const el = /** @type {LionInputAmount} */ (await fixture(
|
const el = /** @type {LionInputAmount} */ (
|
||||||
`<lion-input-amount currency="EUR"></lion-input-amount>`,
|
await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
|
||||||
));
|
);
|
||||||
expect(el._currencyDisplayNode?.getAttribute('aria-label')).to.equal('euros');
|
expect(el._currencyDisplayNode?.getAttribute('aria-label')).to.equal('euros');
|
||||||
el.currency = 'USD';
|
el.currency = 'USD';
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
|
|
||||||
|
|
@ -57,13 +57,15 @@ export class DatepickerInputObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
get overlayHeadingEl() {
|
get overlayHeadingEl() {
|
||||||
return /** @type {HTMLElement} */ (this.overlayEl &&
|
return /** @type {HTMLElement} */ (
|
||||||
this.overlayEl.shadowRoot?.querySelector('.calendar-overlay__heading'));
|
this.overlayEl && this.overlayEl.shadowRoot?.querySelector('.calendar-overlay__heading')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get overlayCloseButtonEl() {
|
get overlayCloseButtonEl() {
|
||||||
return /** @type {HTMLElement} */ (this.calendarEl &&
|
return /** @type {HTMLElement} */ (
|
||||||
this.overlayEl.shadowRoot?.querySelector('#close-button'));
|
this.calendarEl && this.overlayEl.shadowRoot?.querySelector('#close-button')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get calendarEl() {
|
get calendarEl() {
|
||||||
|
|
|
||||||
|
|
@ -235,9 +235,9 @@ export class LocalizeManager {
|
||||||
loadNamespace(namespaceObj, { locale = this.locale } = { locale: this.locale }) {
|
loadNamespace(namespaceObj, { locale = this.locale } = { locale: this.locale }) {
|
||||||
const isDynamicImport = typeof namespaceObj === 'object';
|
const isDynamicImport = typeof namespaceObj === 'object';
|
||||||
|
|
||||||
const namespace = /** @type {string} */ (isDynamicImport
|
const namespace = /** @type {string} */ (
|
||||||
? Object.keys(namespaceObj)[0]
|
isDynamicImport ? Object.keys(namespaceObj)[0] : namespaceObj
|
||||||
: namespaceObj);
|
);
|
||||||
|
|
||||||
if (this._isNamespaceInCache(locale, namespace)) {
|
if (this._isNamespaceInCache(locale, namespace)) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,14 @@ import { forceCurrencyNameForPHPEnGB } from './utils/normalize-get-currency-name
|
||||||
* @returns {string} currency name like 'US dollar'
|
* @returns {string} currency name like 'US dollar'
|
||||||
*/
|
*/
|
||||||
export function getCurrencyName(currencyIso, options) {
|
export function getCurrencyName(currencyIso, options) {
|
||||||
const parts = /** @type {FormatNumberPart[]} */ (formatNumberToParts(1, {
|
const parts = /** @type {FormatNumberPart[]} */ (
|
||||||
...options,
|
formatNumberToParts(1, {
|
||||||
style: 'currency',
|
...options,
|
||||||
currency: currencyIso,
|
style: 'currency',
|
||||||
currencyDisplay: 'name',
|
currency: currencyIso,
|
||||||
}));
|
currencyDisplay: 'name',
|
||||||
|
})
|
||||||
|
);
|
||||||
let currencyName = parts
|
let currencyName = parts
|
||||||
.filter(p => p.type === 'currency')
|
.filter(p => p.type === 'currency')
|
||||||
.map(o => o.value)
|
.map(o => o.value)
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ import { formatNumberToParts } from './formatNumberToParts.js';
|
||||||
* @returns {number} fraction for the given currency
|
* @returns {number} fraction for the given currency
|
||||||
*/
|
*/
|
||||||
export function getFractionDigits(currency = 'EUR') {
|
export function getFractionDigits(currency = 'EUR') {
|
||||||
const parts = /** @type {FormatNumberPart[]} */ (formatNumberToParts(123, {
|
const parts = /** @type {FormatNumberPart[]} */ (
|
||||||
style: 'currency',
|
formatNumberToParts(123, {
|
||||||
currency,
|
style: 'currency',
|
||||||
}));
|
currency,
|
||||||
|
})
|
||||||
|
);
|
||||||
const [fractionPart] = parts.filter(part => part.type === 'fraction');
|
const [fractionPart] = parts.filter(part => part.type === 'fraction');
|
||||||
return fractionPart ? fractionPart.value.length : 0;
|
return fractionPart ? fractionPart.value.length : 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,8 @@ import { LocalizeManager } from '../src/LocalizeManager.js';
|
||||||
*/
|
*/
|
||||||
function getProtectedMembers(localizeManagerEl) {
|
function getProtectedMembers(localizeManagerEl) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const {
|
const { __storage: storage, _supportExternalTranslationTools: supportExternalTranslationTools } =
|
||||||
__storage: storage,
|
localizeManagerEl;
|
||||||
_supportExternalTranslationTools: supportExternalTranslationTools,
|
|
||||||
} = localizeManagerEl;
|
|
||||||
return {
|
return {
|
||||||
storage,
|
storage,
|
||||||
supportExternalTranslationTools,
|
supportExternalTranslationTools,
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,8 @@ import { localize, setLocalize } from '../src/localize.js';
|
||||||
*/
|
*/
|
||||||
function getProtectedMembers(localizeManagerEl) {
|
function getProtectedMembers(localizeManagerEl) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const {
|
const { _autoLoadOnLocaleChange: autoLoadOnLocaleChange, _fallbackLocale: fallbackLocale } =
|
||||||
_autoLoadOnLocaleChange: autoLoadOnLocaleChange,
|
localizeManagerEl;
|
||||||
_fallbackLocale: fallbackLocale,
|
|
||||||
} = localizeManagerEl;
|
|
||||||
return {
|
return {
|
||||||
autoLoadOnLocaleChange,
|
autoLoadOnLocaleChange,
|
||||||
fallbackLocale,
|
fallbackLocale,
|
||||||
|
|
|
||||||
|
|
@ -244,8 +244,9 @@ export class OverlayController extends EventTargetShim {
|
||||||
* @type {HTMLElement}
|
* @type {HTMLElement}
|
||||||
*/
|
*/
|
||||||
get contentWrapperNode() {
|
get contentWrapperNode() {
|
||||||
return /** @type {HTMLElement} */ (this.__contentWrapperNode ||
|
return /** @type {HTMLElement} */ (
|
||||||
this.config?.contentWrapperNode);
|
this.__contentWrapperNode || this.config?.contentWrapperNode
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -262,8 +263,9 @@ export class OverlayController extends EventTargetShim {
|
||||||
* @type {HTMLElement}
|
* @type {HTMLElement}
|
||||||
*/
|
*/
|
||||||
get elementToFocusAfterHide() {
|
get elementToFocusAfterHide() {
|
||||||
return /** @type {HTMLElement} */ (this.__elementToFocusAfterHide ||
|
return /** @type {HTMLElement} */ (
|
||||||
this.config?.elementToFocusAfterHide);
|
this.__elementToFocusAfterHide || this.config?.elementToFocusAfterHide
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -588,8 +590,9 @@ export class OverlayController extends EventTargetShim {
|
||||||
if (this.__isContentNodeProjected && this.contentWrapperNode.isConnected) {
|
if (this.__isContentNodeProjected && this.contentWrapperNode.isConnected) {
|
||||||
// We need to keep track of the original local context.
|
// We need to keep track of the original local context.
|
||||||
/** config [l2], [l4] */
|
/** config [l2], [l4] */
|
||||||
this.__originalContentParent = /** @type {HTMLElement} */ (this.contentWrapperNode
|
this.__originalContentParent = /** @type {HTMLElement} */ (
|
||||||
.parentNode);
|
this.contentWrapperNode.parentNode
|
||||||
|
);
|
||||||
} else if (cfgToAdd.contentNode && cfgToAdd.contentNode.isConnected) {
|
} else if (cfgToAdd.contentNode && cfgToAdd.contentNode.isConnected) {
|
||||||
// We need to keep track of the original local context.
|
// We need to keep track of the original local context.
|
||||||
/** config [l1], [l3], [g1] */
|
/** config [l1], [l3], [g1] */
|
||||||
|
|
@ -905,8 +908,9 @@ export class OverlayController extends EventTargetShim {
|
||||||
|
|
||||||
/** @protected */
|
/** @protected */
|
||||||
_restoreFocus() {
|
_restoreFocus() {
|
||||||
const { activeElement } = /** @type {* & ShadowRoot} */ (this
|
const { activeElement } = /** @type {* & ShadowRoot} */ (
|
||||||
.__contentWrapperNode).getRootNode();
|
this.__contentWrapperNode
|
||||||
|
).getRootNode();
|
||||||
// We only are allowed to move focus if we (still) 'own' it.
|
// We only are allowed to move focus if we (still) 'own' it.
|
||||||
// Otherwise we assume the 'outside world' has, purposefully, taken over
|
// Otherwise we assume the 'outside world' has, purposefully, taken over
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,14 @@ describe('ArrowMixin', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows by default', async () => {
|
it('shows by default', async () => {
|
||||||
const el = /** @type {ArrowTest} */ (await fixture(html`
|
const el = /** @type {ArrowTest} */ (
|
||||||
<arrow-test>
|
await fixture(html`
|
||||||
<div slot="content">This is a tooltip</div>
|
<arrow-test>
|
||||||
<button slot="invoker">Tooltip button</button>
|
<div slot="content">This is a tooltip</div>
|
||||||
</arrow-test>
|
<button slot="invoker">Tooltip button</button>
|
||||||
`));
|
</arrow-test>
|
||||||
|
`)
|
||||||
|
);
|
||||||
expect(el.hasAttribute('has-arrow')).to.be.true;
|
expect(el.hasAttribute('has-arrow')).to.be.true;
|
||||||
|
|
||||||
const arrowNode = /** @type {Element} */ (el._arrowNode);
|
const arrowNode = /** @type {Element} */ (el._arrowNode);
|
||||||
|
|
@ -62,12 +64,14 @@ describe('ArrowMixin', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides the arrow when has-arrow is false', async () => {
|
it('hides the arrow when has-arrow is false', async () => {
|
||||||
const el = /** @type {ArrowTest} */ (await fixture(html`
|
const el = /** @type {ArrowTest} */ (
|
||||||
<arrow-test>
|
await fixture(html`
|
||||||
<div slot="content">This is a tooltip</div>
|
<arrow-test>
|
||||||
<button slot="invoker">Tooltip button</button>
|
<div slot="content">This is a tooltip</div>
|
||||||
</arrow-test>
|
<button slot="invoker">Tooltip button</button>
|
||||||
`));
|
</arrow-test>
|
||||||
|
`)
|
||||||
|
);
|
||||||
el.hasArrow = false;
|
el.hasArrow = false;
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(el.hasAttribute('has-arrow')).to.be.false;
|
expect(el.hasAttribute('has-arrow')).to.be.false;
|
||||||
|
|
@ -76,21 +80,23 @@ describe('ArrowMixin', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('makes sure positioning of the arrow is correct', async () => {
|
it('makes sure positioning of the arrow is correct', async () => {
|
||||||
const el = /** @type {ArrowTest} */ (await fixture(html`
|
const el = /** @type {ArrowTest} */ (
|
||||||
<arrow-test
|
await fixture(html`
|
||||||
.config="${
|
<arrow-test
|
||||||
/** @type {import('../types/OverlayConfig').OverlayConfig} */ ({
|
.config="${
|
||||||
popperConfig: {
|
/** @type {import('../types/OverlayConfig').OverlayConfig} */ ({
|
||||||
placement: 'right',
|
popperConfig: {
|
||||||
},
|
placement: 'right',
|
||||||
})
|
},
|
||||||
}"
|
})
|
||||||
style="position: relative; top: 10px;"
|
}"
|
||||||
>
|
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>
|
<div slot="content" style="height: 30px; background-color: red;">Hey there</div>
|
||||||
</arrow-test>
|
<button slot="invoker" style="height: 30px;">Tooltip button</button>
|
||||||
`));
|
</arrow-test>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
el.opened = true;
|
el.opened = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,14 @@ describe('deepContains()', () => {
|
||||||
<input id="el-3">
|
<input id="el-3">
|
||||||
`;
|
`;
|
||||||
const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-1'));
|
const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-1'));
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(html`
|
const element = /** @type {HTMLElement} */ (
|
||||||
<div id="light">
|
await fixture(html`
|
||||||
${shadowElement}
|
<div id="light">
|
||||||
<button id="light-el-1"></button>
|
${shadowElement}
|
||||||
</div>
|
<button id="light-el-1"></button>
|
||||||
`));
|
</div>
|
||||||
|
`)
|
||||||
|
);
|
||||||
const lightChildEl = /** @type {HTMLElement} */ (element.querySelector('#light-el-1'));
|
const lightChildEl = /** @type {HTMLElement} */ (element.querySelector('#light-el-1'));
|
||||||
|
|
||||||
expect(deepContains(element, element)).to.be.true;
|
expect(deepContains(element, element)).to.be.true;
|
||||||
|
|
@ -59,12 +61,14 @@ describe('deepContains()', () => {
|
||||||
|
|
||||||
const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-2'));
|
const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-2'));
|
||||||
const shadowElementChild2 = /** @type {HTMLElement} */ (shadowRoot2.querySelector('#el-2'));
|
const shadowElementChild2 = /** @type {HTMLElement} */ (shadowRoot2.querySelector('#el-2'));
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(html`
|
const element = /** @type {HTMLElement} */ (
|
||||||
<div id="light">
|
await fixture(html`
|
||||||
${shadowElement} ${shadowElement2}
|
<div id="light">
|
||||||
<button id="light-el-1"></button>
|
${shadowElement} ${shadowElement2}
|
||||||
</div>
|
<button id="light-el-1"></button>
|
||||||
`));
|
</div>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
expect(deepContains(element, shadowElementChild)).to.be.true;
|
expect(deepContains(element, shadowElementChild)).to.be.true;
|
||||||
expect(deepContains(shadowElement, shadowElementChild)).to.be.true;
|
expect(deepContains(shadowElement, shadowElementChild)).to.be.true;
|
||||||
|
|
@ -93,21 +97,26 @@ describe('deepContains()', () => {
|
||||||
`;
|
`;
|
||||||
shadowRoot.insertBefore(shadowNestedElement, shadowRoot.lastElementChild);
|
shadowRoot.insertBefore(shadowNestedElement, shadowRoot.lastElementChild);
|
||||||
|
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(html`
|
const element = /** @type {HTMLElement} */ (
|
||||||
<div id="light">
|
await fixture(html`
|
||||||
${shadowElement}
|
<div id="light">
|
||||||
<button id="light-el-1"></button>
|
${shadowElement}
|
||||||
</div>
|
<button id="light-el-1"></button>
|
||||||
`));
|
</div>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
const elementFirstChild = /** @type {HTMLElement} */ (element.firstElementChild);
|
const elementFirstChild = /** @type {HTMLElement} */ (element.firstElementChild);
|
||||||
const elementFirstChildShadow = /** @type {ShadowRoot} */ (elementFirstChild.shadowRoot);
|
const elementFirstChildShadow = /** @type {ShadowRoot} */ (elementFirstChild.shadowRoot);
|
||||||
const elementFirstChildShadowChildren = /** @type {HTMLElement[]} */ (Array.from(
|
const elementFirstChildShadowChildren = /** @type {HTMLElement[]} */ (
|
||||||
elementFirstChildShadow.children,
|
Array.from(elementFirstChildShadow.children)
|
||||||
));
|
);
|
||||||
const elementFirstChildShadowChildShadow = /** @type {ShadowRoot} */ (elementFirstChildShadowChildren[1]
|
const elementFirstChildShadowChildShadow = /** @type {ShadowRoot} */ (
|
||||||
.shadowRoot);
|
elementFirstChildShadowChildren[1].shadowRoot
|
||||||
const elementFirstChildShadowChildShadowLastChild = /** @type {HTMLElement} */ (elementFirstChildShadowChildShadow.lastElementChild);
|
);
|
||||||
|
const elementFirstChildShadowChildShadowLastChild = /** @type {HTMLElement} */ (
|
||||||
|
elementFirstChildShadowChildShadow.lastElementChild
|
||||||
|
);
|
||||||
|
|
||||||
expect(deepContains(element, elementFirstChild)).to.be.true;
|
expect(deepContains(element, elementFirstChild)).to.be.true;
|
||||||
expect(deepContains(element, elementFirstChildShadow)).to.be.true;
|
expect(deepContains(element, elementFirstChildShadow)).to.be.true;
|
||||||
|
|
|
||||||
|
|
@ -4,65 +4,77 @@ import { isVisible } from '../../src/utils/is-visible.js';
|
||||||
|
|
||||||
describe('isVisible()', () => {
|
describe('isVisible()', () => {
|
||||||
it('returns true for static block elements', async () => {
|
it('returns true for static block elements', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(
|
const element = /** @type {HTMLElement} */ (
|
||||||
`<div style="width:10px; height:10px;"></div>`,
|
await fixture(`<div style="width:10px; height:10px;"></div>`)
|
||||||
));
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(true);
|
expect(isVisible(element)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for hidden static block elements', async () => {
|
it('returns false for hidden static block elements', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(
|
const element = /** @type {HTMLElement} */ (
|
||||||
`<div style="width:10px; height:10px;" hidden></div>`,
|
await fixture(`<div style="width:10px; height:10px;" hidden></div>`)
|
||||||
));
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(false);
|
expect(isVisible(element)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for relative block elements', async () => {
|
it('returns true for relative block elements', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(
|
const element = /** @type {HTMLElement} */ (
|
||||||
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;"></div>`,
|
await fixture(
|
||||||
));
|
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;"></div>`,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(true);
|
expect(isVisible(element)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for hidden relative block elements', async () => {
|
it('returns false for hidden relative block elements', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(
|
const element = /** @type {HTMLElement} */ (
|
||||||
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;" hidden></div>`,
|
await fixture(
|
||||||
));
|
`<div style="width:10px; height:10px; position:relative; top:10px; left:10px;" hidden></div>`,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(false);
|
expect(isVisible(element)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for absolute block elements', async () => {
|
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>
|
<div style="width:10px; height:10px; position:absolute; top:10px; left:10px;"></div>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(true);
|
expect(isVisible(element)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for hidden absolute block elements', async () => {
|
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>
|
<div style="width:10px; height:10px; position:absolute; top:10px; left:10px;" hidden></div>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(false);
|
expect(isVisible(element)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for relative block elements', async () => {
|
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>
|
<div style="width:10px; height:10px; position:fixed;top:10px; left:10px;"></div>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(true);
|
expect(isVisible(element)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for relative block elements', async () => {
|
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>
|
<div style="width:10px; height:10px; position:fixed;top:10px; left:10px;" hidden></div>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(false);
|
expect(isVisible(element)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
@ -80,48 +92,52 @@ describe('isVisible()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for static block elements with 0 dimensions', async () => {
|
it('returns true for static block elements with 0 dimensions', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(
|
const element = /** @type {HTMLElement} */ (
|
||||||
`<div style="width:0; height:0;"></div>`,
|
await fixture(`<div style="width:0; height:0;"></div>`)
|
||||||
));
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(true);
|
expect(isVisible(element)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for hidden inline elements', async () => {
|
it('returns false for hidden inline elements', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(
|
const element = /** @type {HTMLElement} */ (
|
||||||
`<span hidden>Inline content</span>`,
|
await fixture(`<span hidden>Inline content</span>`)
|
||||||
));
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(false);
|
expect(isVisible(element)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false invisible elements', async () => {
|
it('returns false invisible elements', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(
|
const element = /** @type {HTMLElement} */ (
|
||||||
`<div style="width:10px; height:10px; visibility: hidden;"></div>`,
|
await fixture(`<div style="width:10px; height:10px; visibility: hidden;"></div>`)
|
||||||
));
|
);
|
||||||
|
|
||||||
expect(isVisible(element)).to.equal(false);
|
expect(isVisible(element)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false when hidden by parent', async () => {
|
it('returns false when hidden by parent', async () => {
|
||||||
const element = /** @type {HTMLElement} */ (await fixture(`
|
const element = /** @type {HTMLElement} */ (
|
||||||
|
await fixture(`
|
||||||
<div hidden>
|
<div hidden>
|
||||||
<div id="target" style="width:10px; height:10px;"></div>
|
<div id="target" style="width:10px; height:10px;"></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
const target = /** @type {HTMLElement} */ (element.querySelector('#target'));
|
const target = /** @type {HTMLElement} */ (element.querySelector('#target'));
|
||||||
expect(isVisible(target)).to.equal(false);
|
expect(isVisible(target)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false when invisible by parent', async () => {
|
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 style="visibility: hidden;">
|
||||||
<div id="target" style="width:10px; height:10px;"></div>
|
<div id="target" style="width:10px; height:10px;"></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
`));
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
const target = /** @type {HTMLElement} */ (element.querySelector('#target'));
|
const target = /** @type {HTMLElement} */ (element.querySelector('#target'));
|
||||||
expect(isVisible(target)).to.equal(false);
|
expect(isVisible(target)).to.equal(false);
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ class LionFieldWithSelect extends LionField {
|
||||||
* @returns {HTMLSelectElement}
|
* @returns {HTMLSelectElement}
|
||||||
*/
|
*/
|
||||||
get _inputNode() {
|
get _inputNode() {
|
||||||
return /** @type {HTMLSelectElement} */ (Array.from(this.children).find(
|
return /** @type {HTMLSelectElement} */ (
|
||||||
el => el.slot === 'input',
|
Array.from(this.children).find(el => el.slot === 'input')
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,9 +100,9 @@ export class LionSteps extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
get steps() {
|
get steps() {
|
||||||
const defaultSlot = /** @type {HTMLSlotElement} */ (this.shadowRoot?.querySelector(
|
const defaultSlot = /** @type {HTMLSlotElement} */ (
|
||||||
'slot:not([name])',
|
this.shadowRoot?.querySelector('slot:not([name])')
|
||||||
));
|
);
|
||||||
return /** @type {LionStep[]} */ (defaultSlot.assignedNodes()).filter(
|
return /** @type {LionStep[]} */ (defaultSlot.assignedNodes()).filter(
|
||||||
node => node.nodeType === Node.ELEMENT_NODE,
|
node => node.nodeType === Node.ELEMENT_NODE,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
|
||||||
*/
|
*/
|
||||||
// @ts-ignore [editor]: prevents vscode from complaining
|
// @ts-ignore [editor]: prevents vscode from complaining
|
||||||
get _inputNode() {
|
get _inputNode() {
|
||||||
return /** @type {LionSwitchButton} */ (Array.from(this.children).find(
|
return /** @type {LionSwitchButton} */ (
|
||||||
el => el.slot === 'input',
|
Array.from(this.children).find(el => el.slot === 'input')
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get slots() {
|
get slots() {
|
||||||
|
|
|
||||||
|
|
@ -323,12 +323,16 @@ export class LionTabs extends LitElement {
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const previousButton = /** @type {HTMLElement} */ (Array.from(this.children).find(
|
const previousButton = /** @type {HTMLElement} */ (
|
||||||
child => child.slot === 'tab' && child.hasAttribute('selected'),
|
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 previousPanel = /** @type {HTMLElement} */ (
|
||||||
|
Array.from(this.children).find(
|
||||||
|
child => child.slot === 'panel' && child.hasAttribute('selected'),
|
||||||
|
)
|
||||||
|
);
|
||||||
if (previousButton) {
|
if (previousButton) {
|
||||||
deselectButton(previousButton);
|
deselectButton(previousButton);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue