@felleslosninger/minid-elements 0.0.115 → 0.0.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/alert.js.map +1 -1
- package/dist/components/button.component.d.ts +2 -5
- package/dist/components/button.component.d.ts.map +1 -1
- package/dist/components/button.js +10 -15
- package/dist/components/button.js.map +1 -1
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/code-input-old.js +1 -1
- package/dist/components/code-input-old.js.map +1 -1
- package/dist/components/code-input.js.map +1 -1
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/countdown.js.map +1 -1
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/heading.js.map +1 -1
- package/dist/components/helptext.js.map +1 -1
- package/dist/components/icon/icon.js.map +1 -1
- package/dist/components/label.js.map +1 -1
- package/dist/components/link.js.map +1 -1
- package/dist/components/menu-item.js.map +1 -1
- package/dist/components/menu.js.map +1 -1
- package/dist/components/paragraph.js.map +1 -1
- package/dist/components/phone-input.js.map +1 -1
- package/dist/components/popup.js.map +1 -1
- package/dist/components/qr-code.js.map +1 -1
- package/dist/components/radio-button.js.map +1 -1
- package/dist/components/radio-group.js.map +1 -1
- package/dist/components/radio.js.map +1 -1
- package/dist/components/search.js.map +1 -1
- package/dist/components/spinner.js.map +1 -1
- package/dist/components/step-indicator.js.map +1 -1
- package/dist/components/textfield.js.map +1 -1
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/validation-message.js.map +1 -1
- package/dist/internal/animate.js.map +1 -1
- package/dist/internal/debounce.js.map +1 -1
- package/dist/internal/event.js.map +1 -1
- package/dist/internal/offset.js.map +1 -1
- package/dist/internal/scroll.js.map +1 -1
- package/dist/internal/slot.js.map +1 -1
- package/dist/internal/string-converter.js.map +1 -1
- package/dist/internal/tabbable.js.map +1 -1
- package/dist/internal/watch.js.map +1 -1
- package/dist/mixins/form-control.mixin.js.map +1 -1
- package/dist/mixins/form-controller.mixin.js.map +1 -1
- package/dist/mixins/tailwind.mixin.js +2 -2
- package/dist/mixins/tailwind.mixin.js.map +1 -1
- package/dist/mixins/validators.js.map +1 -1
- package/dist/utilities/animation-registry.js.map +1 -1
- package/dist/utilities/web-otp-api.js.map +1 -1
- package/package.json +14 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textfield.js","sources":["../../src/components/textfield.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport { stringConverter } from '../internal/string-converter';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HasSlotController } from '../internal/slot';\nimport { FormControlMixin } from '../mixins/form-control.mixin';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators';\nimport { watch } from '../internal/watch';\nimport './icon/icon.component.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-textfield': MinidTextfield;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n `,\n];\n\nlet nextUniqueId = 0;\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event mid-clear - Emitted when the input value is cleared\n * @event mid-focus - Emitted when input element is focused\n * @event mid-blur - Emitted when focus moves away from input element\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot prefix - Used for decoration to the left of the input\n * @slot suffix - Used for decoration to the right of the input\n * @slot label - The input's label. Alternatively, you can use the `label` attribute.\n *\n * @csspart base - The input's wrapper that has the input field styling.\n * @csspart input - The internal `<input>` element.\n * @csspart field - The element that wraps the label, input, and help text.\n * @csspart clear-button - The clear button\n * @csspart password-toggle-button - The button for toggling password visibility\n */\n@customElement('mid-textfield')\nexport class MinidTextfield extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly inputId!: string;\n private readonly descriptionId!: string;\n private readonly validationId!: string;\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private initialValue = '';\n\n @query('.input')\n input!: HTMLInputElement;\n\n @property()\n label = '';\n\n @property()\n description = '';\n\n @property()\n value = '';\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n @property({ converter: stringConverter })\n placeholder?: string;\n\n /**\n * Autofocus the input field on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * User agent autocomplete hint\n */\n @property()\n autocomplete?: AutoFill;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * The maximum length of input that will be considered valid.\n */\n @property({ type: Number })\n maxlength?: number;\n\n /**\n * The input's minimum value. Only applies to date and number input types.\n */\n @property()\n min?: number | string;\n\n /**\n * The input's maximum value. Only applies to date and number input types.\n */\n @property()\n max?: number | string;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n @property()\n type:\n | 'date'\n | 'datetime-local'\n | 'email'\n | 'file'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week' = 'text';\n\n /**\n * Adds a clear button when the input is not empty.\n * */\n @property({ type: Boolean })\n clearable = false;\n\n /**\n * Adds a button to toggle the password's visibility.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordtoggle = false;\n\n /**\n * Determines wether the password is currently visible.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordvisible = false;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * Visually hides `label` and `description` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n @state()\n hasFocus = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n constructor() {\n super();\n nextUniqueId++;\n this.inputId = `mid-textfield-input-${nextUniqueId}`;\n this.descriptionId = `mid-textfield-description-${nextUniqueId}`;\n this.validationId = `mid-textfield-validation-${nextUniqueId}`;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.initialValue = this.value;\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n if (event.key === 'Enter' && !hasModifier) {\n setTimeout(() => {\n //\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form.requestSubmit();\n }\n });\n }\n }\n\n private handleBlur() {\n this.hasFocus = false;\n this.dispatchEvent(\n new Event('mid-blur', { bubbles: true, composed: true })\n );\n }\n\n private handleChange() {\n this.value = this.input.value;\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n }\n\n private handleInput() {\n this.value = this.input.value;\n this.setValue(this.value);\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n\n private handleFocus() {\n this.hasFocus = true;\n this.dispatchEvent(\n new Event('mid-focus', { composed: true, bubbles: true })\n );\n }\n\n private handlePasswordToggle() {\n this.passwordvisible = !this.passwordvisible;\n }\n\n private handleClearClick(event: MouseEvent) {\n event.preventDefault();\n\n if (this.value !== '') {\n this.value = '';\n this.dispatchEvent(\n new Event('mid-clear', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-change', { composed: true, bubbles: true })\n );\n }\n\n this.input.focus();\n }\n\n focus() {\n this.hasFocus = true;\n this.input.focus();\n }\n\n resetFormControl() {\n this.invalidmessage = '';\n this.value = this.initialValue;\n }\n\n forceError(message?: string): void {\n super.forceError(message);\n }\n\n @watch('value')\n handleValueUpdate() {\n this.setValue(this.value);\n }\n\n override render() {\n const lg = this.size === 'lg';\n const md = this.size === 'md';\n const sm = this.size === 'sm';\n\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const hasClearIcon = this.clearable && !this.disabled && !this.readonly;\n const isClearIconVisible =\n hasClearIcon && (typeof this.value === 'number' || this.value.length > 0);\n\n return html`\n <div\n part=\"field\"\n class=\"${classMap({\n 'opacity-disabled': this.disabled,\n 'text-body-sm': sm,\n 'text-body-md': md,\n 'text-body-lg': lg,\n })} max-w-full\"\n >\n <label\n for=\"${this.inputId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n })} mb-2 inline-flex items-center gap-1 font-medium\"\n >\n ${this.readonly\n ? html`<mid-icon\n class=\"size-5\"\n library=\"system\"\n name=\"padlock-locked-fill\"\n ></mid-icon>`\n : nothing}\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n ${this.description\n ? html`\n <div\n id=\"${this.descriptionId}\"\n part=\"description\"\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n })} text-neutral-subtle mb-2\"\n >\n ${this.description}\n </div>\n `\n : nothing}\n <div\n part=\"base\"\n class=\"${classMap({\n 'border-neutral': !this.invalidmessage && !this.readonly,\n 'border-danger': this.invalidmessage && !this.readonly,\n 'border-neutral-subtle': this.readonly,\n 'bg-neutral-surface-tinted': this.readonly,\n 'bg-neutral-surface': !this.readonly,\n border: !this.invalidmessage,\n 'border-2': this.invalidmessage,\n })} focus-within:focus-ring flex h-12 items-center rounded-md px-3\"\n >\n <span class=\"slotted:!mr-2 slotted:rounded flex items-center\">\n <slot name=\"prefix\"></slot>\n </span>\n <input\n id=\"${this.inputId}\"\n class=\"${classMap({\n 'w-full': !isClearIconVisible,\n 'w-[calc(100%-var(--spacing)*7)]': isClearIconVisible,\n '[&::-webkit-search-cancel-button]:appearance-none':\n this.type === 'search',\n })} input grow overflow-clip focus-visible:outline-0\"\n part=\"input\"\n .value=${live(this.value)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?autofocus=${this.autofocus}\n autocomplete=${ifDefined(this.autocomplete as any)}\n type=${this.type === 'password' && this.passwordvisible\n ? 'text'\n : this.type}\n aria-describedby=\"${this.descriptionId}\"\n aria-errormessage=\"${this.validationId}\"\n placeholder=${ifDefined(this.placeholder)}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n pattern=${ifDefined(this.pattern)}\n @input=${this.handleInput}\n @change=${this.handleChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n @keydown=${this.handleKeydown}\n />\n ${isClearIconVisible\n ? html`\n <button\n part=\"clear-button\"\n type=\"button\"\n class=\"focus-visible:focus-ring ml-2 flex items-center justify-center rounded-sm\"\n aria-label=\"Tøm\"\n @click=${this.handleClearClick}\n >\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"xmark\"\n ></mid-icon>\n </button>\n `\n : ''}\n ${this.passwordtoggle && !this.disabled\n ? html`\n <button\n part=\"password-toggle-button\"\n type=\"button\"\n class=\"ml-2 flex items-center justify-center rounded-sm\"\n aria-label=${this.passwordvisible\n ? 'skjul passord'\n : 'vis passord'}\n @click=${this.handlePasswordToggle}\n tabindex=\"-1\"\n >\n ${this.passwordvisible\n ? html` <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye-slash\"\n ></mid-icon>`\n : html`\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye\"\n ></mid-icon>\n `}\n </button>\n `\n : ''}\n <span part=\"suffix\" class=\"slotted:!ml-2 slotted:rounded\">\n <slot name=\"suffix\"></slot>\n </span>\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,SAAS;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAKF;AAEA,IAAI,eAAe;AAuBZ,IAAM,iBAAN,cAA6B;AAAA,EAClC,OAAO,YAAY,MAAM;AAC3B,EAAE;AAAA,EA2IA,cAAc;AACN,UAAA;AAxIR,SAAiB,mBAAmB,IAAI,kBAAkB,MAAM,OAAO;AACvE,SAAQ,eAAe;AAMf,SAAA,QAAA;AAGM,SAAA,cAAA;AAGN,SAAA,QAAA;AAGmB,SAAA,OAAA;AASf,SAAA,YAAA;AAoCK,SAAA,iBAAA;AAgBJ,SAAA,OAAA;AAMD,SAAA,YAAA;AAOK,SAAA,iBAAA;AAOC,SAAA,kBAAA;AAGP,SAAA,WAAA;AAGA,SAAA,WAAA;AAYA,SAAA,WAAA;AAMC,SAAA,YAAA;AAGD,SAAA,WAAA;AAaT;AACK,SAAA,UAAU,uBAAuB,YAAY;AAC7C,SAAA,gBAAgB,6BAA6B,YAAY;AACzD,SAAA,eAAe,4BAA4B,YAAY;AAAA,EAAA;AAAA,EAd9D,WAAW,wBAAwB;AAC1B,WAAA;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAAA,EAWO,oBAA0B;AACjC,UAAM,kBAAkB;AACxB,SAAK,eAAe,KAAK;AAAA,EAAA;AAAA,EAGnB,cAAc,OAAsB;AAC1C,UAAM,cACJ,MAAM,WAAW,MAAM,WAAW,MAAM,YAAY,MAAM;AAI5D,QAAI,MAAM,QAAQ,WAAW,CAAC,aAAa;AACzC,iBAAW,MAAM;AAIf,YAAI,CAAC,MAAM,oBAAoB,CAAC,MAAM,aAAa;AACjD,eAAK,KAAK,cAAc;AAAA,QAAA;AAAA,MAC1B,CACD;AAAA,IAAA;AAAA,EACH;AAAA,EAGM,aAAa;AACnB,SAAK,WAAW;AACX,SAAA;AAAA,MACH,IAAI,MAAM,YAAY,EAAE,SAAS,MAAM,UAAU,KAAM,CAAA;AAAA,IACzD;AAAA,EAAA;AAAA,EAGM,eAAe;AAChB,SAAA,QAAQ,KAAK,MAAM;AACnB,SAAA;AAAA,MACH,IAAI,MAAM,cAAc,EAAE,SAAS,MAAM,UAAU,KAAM,CAAA;AAAA,IAC3D;AAAA,EAAA;AAAA,EAGM,cAAc;AACf,SAAA,QAAQ,KAAK,MAAM;AACnB,SAAA,SAAS,KAAK,KAAK;AACnB,SAAA;AAAA,MACH,IAAI,MAAM,aAAa,EAAE,SAAS,MAAM,UAAU,KAAM,CAAA;AAAA,IAC1D;AAAA,EAAA;AAAA,EAGM,cAAc;AACpB,SAAK,WAAW;AACX,SAAA;AAAA,MACH,IAAI,MAAM,aAAa,EAAE,UAAU,MAAM,SAAS,KAAM,CAAA;AAAA,IAC1D;AAAA,EAAA;AAAA,EAGM,uBAAuB;AACxB,SAAA,kBAAkB,CAAC,KAAK;AAAA,EAAA;AAAA,EAGvB,iBAAiB,OAAmB;AAC1C,UAAM,eAAe;AAEjB,QAAA,KAAK,UAAU,IAAI;AACrB,WAAK,QAAQ;AACR,WAAA;AAAA,QACH,IAAI,MAAM,aAAa,EAAE,UAAU,MAAM,SAAS,KAAM,CAAA;AAAA,MAC1D;AACK,WAAA;AAAA,QACH,IAAI,MAAM,aAAa,EAAE,UAAU,MAAM,SAAS,KAAM,CAAA;AAAA,MAC1D;AACK,WAAA;AAAA,QACH,IAAI,MAAM,cAAc,EAAE,UAAU,MAAM,SAAS,KAAM,CAAA;AAAA,MAC3D;AAAA,IAAA;AAGF,SAAK,MAAM,MAAM;AAAA,EAAA;AAAA,EAGnB,QAAQ;AACN,SAAK,WAAW;AAChB,SAAK,MAAM,MAAM;AAAA,EAAA;AAAA,EAGnB,mBAAmB;AACjB,SAAK,iBAAiB;AACtB,SAAK,QAAQ,KAAK;AAAA,EAAA;AAAA,EAGpB,WAAW,SAAwB;AACjC,UAAM,WAAW,OAAO;AAAA,EAAA;AAAA,EAI1B,oBAAoB;AACb,SAAA,SAAS,KAAK,KAAK;AAAA,EAAA;AAAA,EAGjB,SAAS;AACV,UAAA,KAAK,KAAK,SAAS;AACnB,UAAA,KAAK,KAAK,SAAS;AACnB,UAAA,KAAK,KAAK,SAAS;AAEzB,UAAM,eAAe,KAAK,iBAAiB,KAAK,OAAO;AACvD,UAAM,WAAW,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;AACnC,UAAM,eAAe,KAAK,aAAa,CAAC,KAAK,YAAY,CAAC,KAAK;AACzD,UAAA,qBACJ,iBAAiB,OAAO,KAAK,UAAU,YAAY,KAAK,MAAM,SAAS;AAElE,WAAA;AAAA;AAAA;AAAA,iBAGM,SAAS;AAAA,MAChB,oBAAoB,KAAK;AAAA,MACzB,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,IAAA,CACjB,CAAC;AAAA;AAAA;AAAA,iBAGO,KAAK,OAAO;AAAA,mBACV,SAAS;AAAA,MAChB,WAAW,KAAK,aAAa,CAAC;AAAA,IAAA,CAC/B,CAAC;AAAA;AAAA,YAEA,KAAK,WACH;AAAA;AAAA;AAAA;AAAA,8BAKA,OAAO;AAAA,gCACW,KAAK,KAAK;AAAA;AAAA,UAEhC,KAAK,cACH;AAAA;AAAA,sBAEU,KAAK,aAAa;AAAA;AAAA,yBAEf,SAAS;AAAA,MAChB,WAAW,KAAK;AAAA,IAAA,CACjB,CAAC;AAAA;AAAA,kBAEA,KAAK,WAAW;AAAA;AAAA,gBAGtB,OAAO;AAAA;AAAA;AAAA,mBAGA,SAAS;AAAA,MAChB,kBAAkB,CAAC,KAAK,kBAAkB,CAAC,KAAK;AAAA,MAChD,iBAAiB,KAAK,kBAAkB,CAAC,KAAK;AAAA,MAC9C,yBAAyB,KAAK;AAAA,MAC9B,6BAA6B,KAAK;AAAA,MAClC,sBAAsB,CAAC,KAAK;AAAA,MAC5B,QAAQ,CAAC,KAAK;AAAA,MACd,YAAY,KAAK;AAAA,IAAA,CAClB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAMM,KAAK,OAAO;AAAA,qBACT,SAAS;AAAA,MAChB,UAAU,CAAC;AAAA,MACX,mCAAmC;AAAA,MACnC,qDACE,KAAK,SAAS;AAAA,IAAA,CACjB,CAAC;AAAA;AAAA,qBAEO,KAAK,KAAK,KAAK,CAAC;AAAA,wBACb,KAAK,QAAQ;AAAA,wBACb,KAAK,QAAQ;AAAA,yBACZ,KAAK,SAAS;AAAA,2BACZ,UAAU,KAAK,YAAmB,CAAC;AAAA,mBAC3C,KAAK,SAAS,cAAc,KAAK,kBACpC,SACA,KAAK,IAAI;AAAA,gCACO,KAAK,aAAa;AAAA,iCACjB,KAAK,YAAY;AAAA,0BACxB,UAAU,KAAK,WAAW,CAAC;AAAA,wBAC7B,UAAU,KAAK,SAAS,CAAC;AAAA,wBACzB,UAAU,KAAK,SAAS,CAAC;AAAA,kBAC/B,UAAU,KAAK,GAAG,CAAC;AAAA,kBACnB,UAAU,KAAK,GAAG,CAAC;AAAA,sBACf,UAAU,KAAK,OAAO,CAAC;AAAA,qBACxB,KAAK,WAAW;AAAA,sBACf,KAAK,YAAY;AAAA,qBAClB,KAAK,WAAW;AAAA,oBACjB,KAAK,UAAU;AAAA,uBACZ,KAAK,aAAa;AAAA;AAAA,YAE7B,qBACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAMa,KAAK,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBASlC,EAAE;AAAA,YACJ,KAAK,kBAAkB,CAAC,KAAK,WAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKiB,KAAK,kBACd,kBACA,aAAa;AAAA,2BACR,KAAK,oBAAoB;AAAA;AAAA;AAAA,oBAGhC,KAAK,kBACH;AAAA;AAAA;AAAA;AAAA,sCAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAMC;AAAA;AAAA,kBAGT,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAOA,KAAK,YAAY;AAAA;AAAA,oBAEb,CAAC,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAM5B,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA,EAAA;AAK/B;AAxYE,gBAAA;AAAA,EADC,MAAM,QAAQ;AAAA,GATJ,eAUX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS;AAAA,GAZC,eAaX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS;AAAA,GAfC,eAgBX,WAAA,eAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS;AAAA,GAlBC,eAmBX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS;AAAA,GArBC,eAsBX,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,WAAW,gBAAiB,CAAA;AAAA,GAxB7B,eAyBX,WAAA,eAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAS,CAAA;AAAA,GA9BhB,eA+BX,WAAA,aAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GApCC,eAqCX,WAAA,gBAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,OAAQ,CAAA;AAAA,GA1Cf,eA2CX,WAAA,aAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,OAAQ,CAAA;AAAA,GAhDf,eAiDX,WAAA,aAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAtDC,eAuDX,WAAA,OAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GA5DC,eA6DX,WAAA,OAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAlEC,eAmEX,WAAA,kBAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS;AAAA,GArEC,eAsEX,WAAA,QAAA,CAAA;AAmBA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAS,CAAA;AAAA,GAxFhB,eAyFX,WAAA,aAAA,CAAA;AAOA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAS,CAAA;AAAA,GA/FhB,eAgGX,WAAA,kBAAA,CAAA;AAOA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAS,CAAA;AAAA,GAtGhB,eAuGX,WAAA,mBAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAM,CAAA;AAAA,GAzG/B,eA0GX,WAAA,YAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAM,CAAA;AAAA,GA5G/B,eA6GX,WAAA,YAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAlHC,eAmHX,WAAA,WAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAS,CAAA;AAAA,GAxHhB,eAyHX,WAAA,YAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAS,CAAA;AAAA,GA9HhB,eA+HX,WAAA,aAAA,CAAA;AAGA,gBAAA;AAAA,EADC,MAAM;AAAA,GAjII,eAkIX,WAAA,YAAA,CAAA;AA6GA,gBAAA;AAAA,EADC,MAAM,OAAO;AAAA,GA9OH,eA+OX,WAAA,qBAAA,CAAA;AA/OW,iBAAN,gBAAA;AAAA,EADN,cAAc,eAAe;AAAA,GACjB,cAAA;"}
|
|
1
|
+
{"version":3,"file":"textfield.js","sources":["../../src/components/textfield.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport { stringConverter } from '../internal/string-converter';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HasSlotController } from '../internal/slot';\nimport { FormControlMixin } from '../mixins/form-control.mixin';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators';\nimport { watch } from '../internal/watch';\nimport './icon/icon.component.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-textfield': MinidTextfield;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n `,\n];\n\nlet nextUniqueId = 0;\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event mid-clear - Emitted when the input value is cleared\n * @event mid-focus - Emitted when input element is focused\n * @event mid-blur - Emitted when focus moves away from input element\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot prefix - Used for decoration to the left of the input\n * @slot suffix - Used for decoration to the right of the input\n * @slot label - The input's label. Alternatively, you can use the `label` attribute.\n *\n * @csspart base - The input's wrapper that has the input field styling.\n * @csspart input - The internal `<input>` element.\n * @csspart field - The element that wraps the label, input, and help text.\n * @csspart clear-button - The clear button\n * @csspart password-toggle-button - The button for toggling password visibility\n */\n@customElement('mid-textfield')\nexport class MinidTextfield extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly inputId!: string;\n private readonly descriptionId!: string;\n private readonly validationId!: string;\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private initialValue = '';\n\n @query('.input')\n input!: HTMLInputElement;\n\n @property()\n label = '';\n\n @property()\n description = '';\n\n @property()\n value = '';\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n @property({ converter: stringConverter })\n placeholder?: string;\n\n /**\n * Autofocus the input field on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * User agent autocomplete hint\n */\n @property()\n autocomplete?: AutoFill;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * The maximum length of input that will be considered valid.\n */\n @property({ type: Number })\n maxlength?: number;\n\n /**\n * The input's minimum value. Only applies to date and number input types.\n */\n @property()\n min?: number | string;\n\n /**\n * The input's maximum value. Only applies to date and number input types.\n */\n @property()\n max?: number | string;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n @property()\n type:\n | 'date'\n | 'datetime-local'\n | 'email'\n | 'file'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week' = 'text';\n\n /**\n * Adds a clear button when the input is not empty.\n * */\n @property({ type: Boolean })\n clearable = false;\n\n /**\n * Adds a button to toggle the password's visibility.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordtoggle = false;\n\n /**\n * Determines wether the password is currently visible.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordvisible = false;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * Visually hides `label` and `description` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n @state()\n hasFocus = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n constructor() {\n super();\n nextUniqueId++;\n this.inputId = `mid-textfield-input-${nextUniqueId}`;\n this.descriptionId = `mid-textfield-description-${nextUniqueId}`;\n this.validationId = `mid-textfield-validation-${nextUniqueId}`;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.initialValue = this.value;\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n if (event.key === 'Enter' && !hasModifier) {\n setTimeout(() => {\n //\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form.requestSubmit();\n }\n });\n }\n }\n\n private handleBlur() {\n this.hasFocus = false;\n this.dispatchEvent(\n new Event('mid-blur', { bubbles: true, composed: true })\n );\n }\n\n private handleChange() {\n this.value = this.input.value;\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n }\n\n private handleInput() {\n this.value = this.input.value;\n this.setValue(this.value);\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n\n private handleFocus() {\n this.hasFocus = true;\n this.dispatchEvent(\n new Event('mid-focus', { composed: true, bubbles: true })\n );\n }\n\n private handlePasswordToggle() {\n this.passwordvisible = !this.passwordvisible;\n }\n\n private handleClearClick(event: MouseEvent) {\n event.preventDefault();\n\n if (this.value !== '') {\n this.value = '';\n this.dispatchEvent(\n new Event('mid-clear', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-change', { composed: true, bubbles: true })\n );\n }\n\n this.input.focus();\n }\n\n focus() {\n this.hasFocus = true;\n this.input.focus();\n }\n\n resetFormControl() {\n this.invalidmessage = '';\n this.value = this.initialValue;\n }\n\n forceError(message?: string): void {\n super.forceError(message);\n }\n\n @watch('value')\n handleValueUpdate() {\n this.setValue(this.value);\n }\n\n override render() {\n const lg = this.size === 'lg';\n const md = this.size === 'md';\n const sm = this.size === 'sm';\n\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const hasClearIcon = this.clearable && !this.disabled && !this.readonly;\n const isClearIconVisible =\n hasClearIcon && (typeof this.value === 'number' || this.value.length > 0);\n\n return html`\n <div\n part=\"field\"\n class=\"${classMap({\n 'opacity-disabled': this.disabled,\n 'text-body-sm': sm,\n 'text-body-md': md,\n 'text-body-lg': lg,\n })} max-w-full\"\n >\n <label\n for=\"${this.inputId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n })} mb-2 inline-flex items-center gap-1 font-medium\"\n >\n ${this.readonly\n ? html`<mid-icon\n class=\"size-5\"\n library=\"system\"\n name=\"padlock-locked-fill\"\n ></mid-icon>`\n : nothing}\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n ${this.description\n ? html`\n <div\n id=\"${this.descriptionId}\"\n part=\"description\"\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n })} text-neutral-subtle mb-2\"\n >\n ${this.description}\n </div>\n `\n : nothing}\n <div\n part=\"base\"\n class=\"${classMap({\n 'border-neutral': !this.invalidmessage && !this.readonly,\n 'border-danger': this.invalidmessage && !this.readonly,\n 'border-neutral-subtle': this.readonly,\n 'bg-neutral-surface-tinted': this.readonly,\n 'bg-neutral-surface': !this.readonly,\n border: !this.invalidmessage,\n 'border-2': this.invalidmessage,\n })} focus-within:focus-ring flex h-12 items-center rounded-md px-3\"\n >\n <span class=\"slotted:!mr-2 slotted:rounded flex items-center\">\n <slot name=\"prefix\"></slot>\n </span>\n <input\n id=\"${this.inputId}\"\n class=\"${classMap({\n 'w-full': !isClearIconVisible,\n 'w-[calc(100%-var(--spacing)*7)]': isClearIconVisible,\n '[&::-webkit-search-cancel-button]:appearance-none':\n this.type === 'search',\n })} input grow overflow-clip focus-visible:outline-0\"\n part=\"input\"\n .value=${live(this.value)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?autofocus=${this.autofocus}\n autocomplete=${ifDefined(this.autocomplete as any)}\n type=${this.type === 'password' && this.passwordvisible\n ? 'text'\n : this.type}\n aria-describedby=\"${this.descriptionId}\"\n aria-errormessage=\"${this.validationId}\"\n placeholder=${ifDefined(this.placeholder)}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n pattern=${ifDefined(this.pattern)}\n @input=${this.handleInput}\n @change=${this.handleChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n @keydown=${this.handleKeydown}\n />\n ${isClearIconVisible\n ? html`\n <button\n part=\"clear-button\"\n type=\"button\"\n class=\"focus-visible:focus-ring ml-2 flex items-center justify-center rounded-sm\"\n aria-label=\"Tøm\"\n @click=${this.handleClearClick}\n >\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"xmark\"\n ></mid-icon>\n </button>\n `\n : ''}\n ${this.passwordtoggle && !this.disabled\n ? html`\n <button\n part=\"password-toggle-button\"\n type=\"button\"\n class=\"ml-2 flex items-center justify-center rounded-sm\"\n aria-label=${this.passwordvisible\n ? 'skjul passord'\n : 'vis passord'}\n @click=${this.handlePasswordToggle}\n tabindex=\"-1\"\n >\n ${this.passwordvisible\n ? html` <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye-slash\"\n ></mid-icon>`\n : html`\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye\"\n ></mid-icon>\n `}\n </button>\n `\n : ''}\n <span part=\"suffix\" class=\"slotted:!ml-2 slotted:rounded\">\n <slot name=\"suffix\"></slot>\n </span>\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooltip.js","sources":["../../src/components/tooltip.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin.js';\nimport './popup.component';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { MinidPopup } from './popup.component';\nimport { watch } from '../internal/watch.js';\nimport {\n animateTo,\n parseDuration,\n stopAnimations,\n} from '../internal/animate.js';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry.js';\nimport { waitForEvent } from '../internal/event.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-tooltip': MinidTooltip;\n }\n}\n\nconst styles = [\n css`\n :host {\n --max-width: 20rem;\n --hide-delay: 0ms;\n --show-delay: 250ms;\n }\n `,\n];\n\n/**\n * @event mid-show - Emitted when open is set to `true`\n * @event mid-hide - Emitted when open is set to `false`\n * @event mid-after-show - Emitted after the tooltip has shown an all animations are complete\n * @event mid-after-hide - Emitted after the tooltip has hidden an all animations are complete\n *\n * @slot -- The default slot is for the trigger element\n * @slot content - The content to render in the tooltip. Alternatively, you can use the `content` attribute.\n *\n * @csspart base - The component base wrapper. `<mid-popup> element\n * @csspart body - The tooltip body, where the content is rendered\n *\n * @method show - Shows the tooltip\n * @method hide - Hides the tooltip\n *\n * @cssproperty [--max-width=20rem] - Max width of the tooltip content\n * @cssproperty [--hide-delay=0ms] - Delay for hiding the tooltip\n * @cssproperty [--show-delay=150ms] - Delay for showing the tooltip\n */\n@customElement('mid-tooltip')\nexport class MinidTooltip extends styled(LitElement, styles) {\n private hoverTimeout?: number;\n private closeWatcher: CloseWatcher | null = null;\n\n @query('#body')\n body!: HTMLElement;\n\n @query('mid-popup')\n popup!: MinidPopup;\n\n /**\n * The text to render in the tooltip. If you need HTML you can use the content slot\n */\n @property()\n content = '';\n\n /**\n * Controls how the tooltip is activated. When manual is used, the tooltip must be activated\n * programmatically.\n */\n @property({ type: String })\n trigger: 'focus hover' | 'hover' | 'focus' | 'manual' | 'click' =\n 'focus hover';\n\n @property() placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'top';\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Disables the tooltip so it won't show when triggered.\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * The distance in pixels from which to offset the tooltip away from its target.\n */\n @property({ type: Number })\n distance = 8;\n\n /**\n * Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * The distance in pixels from which to offset the tooltip along its target.\n */\n @property({ type: Number })\n skidding = 0;\n\n /**\n * Enable this option to prevent the tooltip from being clipped when the component is placed inside a container with\n * `overflow: auto|hidden|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all,\n * scenarios.\n */\n @property({ type: Boolean })\n hoist = false;\n\n /**\n * Inverts the color of the tooltip. Use this on dark backgrounds.\n */\n @property({ type: Boolean })\n inverted = false;\n\n constructor() {\n super();\n this.addEventListener('blur', this.handleBlur, true);\n this.addEventListener('focus', this.handleFocus, true);\n this.addEventListener('click', this.handleClick);\n this.addEventListener('mouseover', this.handleMouseOver);\n this.addEventListener('mouseout', this.handleMouseOut);\n }\n\n disconnectedCallback() {\n // Cleanup this event in case the tooltip is removed while open\n this.closeWatcher?.destroy();\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n }\n\n firstUpdated() {\n this.body.hidden = !this.open;\n\n // If the tooltip is visible on init, update its position\n if (this.open) {\n this.popup.active = true;\n this.popup.reposition();\n }\n }\n\n private handleBlur = () => {\n if (this.hasTrigger('focus')) {\n this.hide();\n }\n };\n\n private handleClick = () => {\n if (this.hasTrigger('click')) {\n if (this.open) {\n this.hide();\n } else {\n this.show();\n }\n }\n };\n\n private handleFocus = () => {\n if (this.hasTrigger('focus')) {\n this.show();\n }\n };\n\n private handleDocumentKeyDown = (event: KeyboardEvent) => {\n // Pressing escape when a tooltip is open should dismiss it\n if (event.key === 'Escape') {\n event.stopPropagation();\n this.hide();\n }\n };\n\n private handleMouseOver = () => {\n if (this.hasTrigger('hover')) {\n const delay = parseDuration(\n getComputedStyle(this).getPropertyValue('--show-delay')\n );\n clearTimeout(this.hoverTimeout);\n this.hoverTimeout = window.setTimeout(() => this.show(), delay);\n }\n };\n\n private handleMouseOut = () => {\n if (this.hasTrigger('hover')) {\n const delay = parseDuration(\n getComputedStyle(this).getPropertyValue('--hide-delay')\n );\n clearTimeout(this.hoverTimeout);\n this.hoverTimeout = window.setTimeout(() => this.hide(), delay);\n }\n };\n\n private hasTrigger(triggerType: string) {\n const triggers = this.trigger.split(' ');\n return triggers.includes(triggerType);\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.open) {\n if (this.disabled) {\n return;\n }\n\n // Show\n this.dispatchEvent(\n new Event('mid-show', { bubbles: true, composed: true })\n );\n if ('CloseWatcher' in window) {\n this.closeWatcher?.destroy();\n this.closeWatcher = new CloseWatcher();\n this.closeWatcher.onclose = () => {\n this.hide();\n };\n } else {\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n }\n\n await stopAnimations(this.body);\n this.body.hidden = false;\n this.popup.active = true;\n const { keyframes, options } = getAnimation(this, 'tooltip.show');\n await animateTo(this.popup.popup, keyframes, options);\n this.popup.reposition();\n\n this.dispatchEvent(\n new Event('mid-after-show', { bubbles: true, composed: true })\n );\n } else {\n // Hide\n this.dispatchEvent(\n new Event('mid-hide', { bubbles: true, composed: true })\n );\n this.closeWatcher?.destroy();\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n\n await stopAnimations(this.body);\n const { keyframes, options } = getAnimation(this, 'tooltip.hide');\n await animateTo(this.popup.popup, keyframes, options);\n this.popup.active = false;\n this.body.hidden = true;\n\n this.dispatchEvent(\n new Event('mid-after-hide', { bubbles: true, composed: true })\n );\n }\n }\n\n @watch(['content', 'distance', 'hoist', 'placement', 'skidding'])\n async handleOptionsChange() {\n if (this.hasUpdated) {\n await this.updateComplete;\n this.popup.reposition();\n }\n }\n\n @watch('disabled')\n handleDisabledChange() {\n if (this.disabled && this.open) {\n this.hide();\n }\n }\n\n /**\n * Shows the tooltip.\n */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'mid-after-show');\n }\n\n /**\n * Hides the tooltip\n */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'mid-after-hide');\n }\n\n override render() {\n return html`\n <mid-popup\n role=\"tooltip\"\n ?active=${this.open}\n part=\"base\"\n class=\"${classMap({\n '[--arrow-color:var(--color-neutral-base)]': !this.inverted,\n '[--arrow-color:var(--color-neutral-surface)]': this.inverted,\n 'text-body-sm': this.size === 'sm',\n 'text-body-md': this.size === 'md',\n 'text-body-lg': this.size === 'lg',\n })}\"\n placement=${this.placement}\n distance=${this.distance}\n skidding=${this.skidding}\n strategy=${this.hoist ? 'fixed' : 'absolute'}\n flip\n shift\n arrow\n hover-bridge\n >\n <slot slot=\"anchor\"></slot>\n <div\n part=\"body\"\n id=\"body\"\n class=\"${classMap({\n 'bg-neutral': this.inverted,\n 'text-neutral': this.inverted,\n 'bg-neutral-base': !this.inverted,\n 'text-neutral-base-contrast': !this.inverted,\n })} leading-sm w-max max-w-(--max-width) rounded px-2 py-1\"\n role=\"tooltip\"\n aria-live=${this.open ? 'polite' : 'off'}\n >\n <slot name=\"content\">${this.content}</slot>\n </div>\n </mid-popup>\n `;\n }\n}\n\nsetDefaultAnimation('tooltip.show', {\n keyframes: [\n { opacity: 0, scale: 0.8 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 150, easing: 'ease' },\n});\n\nsetDefaultAnimation('tooltip.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.8 },\n ],\n options: { duration: 150, easing: 'ease' },\n});\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tooltip.js","sources":["../../src/components/tooltip.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin.js';\nimport './popup.component';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { MinidPopup } from './popup.component';\nimport { watch } from '../internal/watch.js';\nimport {\n animateTo,\n parseDuration,\n stopAnimations,\n} from '../internal/animate.js';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry.js';\nimport { waitForEvent } from '../internal/event.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-tooltip': MinidTooltip;\n }\n}\n\nconst styles = [\n css`\n :host {\n --max-width: 20rem;\n --hide-delay: 0ms;\n --show-delay: 250ms;\n }\n `,\n];\n\n/**\n * @event mid-show - Emitted when open is set to `true`\n * @event mid-hide - Emitted when open is set to `false`\n * @event mid-after-show - Emitted after the tooltip has shown an all animations are complete\n * @event mid-after-hide - Emitted after the tooltip has hidden an all animations are complete\n *\n * @slot -- The default slot is for the trigger element\n * @slot content - The content to render in the tooltip. Alternatively, you can use the `content` attribute.\n *\n * @csspart base - The component base wrapper. `<mid-popup> element\n * @csspart body - The tooltip body, where the content is rendered\n *\n * @method show - Shows the tooltip\n * @method hide - Hides the tooltip\n *\n * @cssproperty [--max-width=20rem] - Max width of the tooltip content\n * @cssproperty [--hide-delay=0ms] - Delay for hiding the tooltip\n * @cssproperty [--show-delay=150ms] - Delay for showing the tooltip\n */\n@customElement('mid-tooltip')\nexport class MinidTooltip extends styled(LitElement, styles) {\n private hoverTimeout?: number;\n private closeWatcher: CloseWatcher | null = null;\n\n @query('#body')\n body!: HTMLElement;\n\n @query('mid-popup')\n popup!: MinidPopup;\n\n /**\n * The text to render in the tooltip. If you need HTML you can use the content slot\n */\n @property()\n content = '';\n\n /**\n * Controls how the tooltip is activated. When manual is used, the tooltip must be activated\n * programmatically.\n */\n @property({ type: String })\n trigger: 'focus hover' | 'hover' | 'focus' | 'manual' | 'click' =\n 'focus hover';\n\n @property() placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'top';\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Disables the tooltip so it won't show when triggered.\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * The distance in pixels from which to offset the tooltip away from its target.\n */\n @property({ type: Number })\n distance = 8;\n\n /**\n * Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * The distance in pixels from which to offset the tooltip along its target.\n */\n @property({ type: Number })\n skidding = 0;\n\n /**\n * Enable this option to prevent the tooltip from being clipped when the component is placed inside a container with\n * `overflow: auto|hidden|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all,\n * scenarios.\n */\n @property({ type: Boolean })\n hoist = false;\n\n /**\n * Inverts the color of the tooltip. Use this on dark backgrounds.\n */\n @property({ type: Boolean })\n inverted = false;\n\n constructor() {\n super();\n this.addEventListener('blur', this.handleBlur, true);\n this.addEventListener('focus', this.handleFocus, true);\n this.addEventListener('click', this.handleClick);\n this.addEventListener('mouseover', this.handleMouseOver);\n this.addEventListener('mouseout', this.handleMouseOut);\n }\n\n disconnectedCallback() {\n // Cleanup this event in case the tooltip is removed while open\n this.closeWatcher?.destroy();\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n }\n\n firstUpdated() {\n this.body.hidden = !this.open;\n\n // If the tooltip is visible on init, update its position\n if (this.open) {\n this.popup.active = true;\n this.popup.reposition();\n }\n }\n\n private handleBlur = () => {\n if (this.hasTrigger('focus')) {\n this.hide();\n }\n };\n\n private handleClick = () => {\n if (this.hasTrigger('click')) {\n if (this.open) {\n this.hide();\n } else {\n this.show();\n }\n }\n };\n\n private handleFocus = () => {\n if (this.hasTrigger('focus')) {\n this.show();\n }\n };\n\n private handleDocumentKeyDown = (event: KeyboardEvent) => {\n // Pressing escape when a tooltip is open should dismiss it\n if (event.key === 'Escape') {\n event.stopPropagation();\n this.hide();\n }\n };\n\n private handleMouseOver = () => {\n if (this.hasTrigger('hover')) {\n const delay = parseDuration(\n getComputedStyle(this).getPropertyValue('--show-delay')\n );\n clearTimeout(this.hoverTimeout);\n this.hoverTimeout = window.setTimeout(() => this.show(), delay);\n }\n };\n\n private handleMouseOut = () => {\n if (this.hasTrigger('hover')) {\n const delay = parseDuration(\n getComputedStyle(this).getPropertyValue('--hide-delay')\n );\n clearTimeout(this.hoverTimeout);\n this.hoverTimeout = window.setTimeout(() => this.hide(), delay);\n }\n };\n\n private hasTrigger(triggerType: string) {\n const triggers = this.trigger.split(' ');\n return triggers.includes(triggerType);\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.open) {\n if (this.disabled) {\n return;\n }\n\n // Show\n this.dispatchEvent(\n new Event('mid-show', { bubbles: true, composed: true })\n );\n if ('CloseWatcher' in window) {\n this.closeWatcher?.destroy();\n this.closeWatcher = new CloseWatcher();\n this.closeWatcher.onclose = () => {\n this.hide();\n };\n } else {\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n }\n\n await stopAnimations(this.body);\n this.body.hidden = false;\n this.popup.active = true;\n const { keyframes, options } = getAnimation(this, 'tooltip.show');\n await animateTo(this.popup.popup, keyframes, options);\n this.popup.reposition();\n\n this.dispatchEvent(\n new Event('mid-after-show', { bubbles: true, composed: true })\n );\n } else {\n // Hide\n this.dispatchEvent(\n new Event('mid-hide', { bubbles: true, composed: true })\n );\n this.closeWatcher?.destroy();\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n\n await stopAnimations(this.body);\n const { keyframes, options } = getAnimation(this, 'tooltip.hide');\n await animateTo(this.popup.popup, keyframes, options);\n this.popup.active = false;\n this.body.hidden = true;\n\n this.dispatchEvent(\n new Event('mid-after-hide', { bubbles: true, composed: true })\n );\n }\n }\n\n @watch(['content', 'distance', 'hoist', 'placement', 'skidding'])\n async handleOptionsChange() {\n if (this.hasUpdated) {\n await this.updateComplete;\n this.popup.reposition();\n }\n }\n\n @watch('disabled')\n handleDisabledChange() {\n if (this.disabled && this.open) {\n this.hide();\n }\n }\n\n /**\n * Shows the tooltip.\n */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'mid-after-show');\n }\n\n /**\n * Hides the tooltip\n */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'mid-after-hide');\n }\n\n override render() {\n return html`\n <mid-popup\n role=\"tooltip\"\n ?active=${this.open}\n part=\"base\"\n class=\"${classMap({\n '[--arrow-color:var(--color-neutral-base)]': !this.inverted,\n '[--arrow-color:var(--color-neutral-surface)]': this.inverted,\n 'text-body-sm': this.size === 'sm',\n 'text-body-md': this.size === 'md',\n 'text-body-lg': this.size === 'lg',\n })}\"\n placement=${this.placement}\n distance=${this.distance}\n skidding=${this.skidding}\n strategy=${this.hoist ? 'fixed' : 'absolute'}\n flip\n shift\n arrow\n hover-bridge\n >\n <slot slot=\"anchor\"></slot>\n <div\n part=\"body\"\n id=\"body\"\n class=\"${classMap({\n 'bg-neutral': this.inverted,\n 'text-neutral': this.inverted,\n 'bg-neutral-base': !this.inverted,\n 'text-neutral-base-contrast': !this.inverted,\n })} leading-sm w-max max-w-(--max-width) rounded px-2 py-1\"\n role=\"tooltip\"\n aria-live=${this.open ? 'polite' : 'off'}\n >\n <slot name=\"content\">${this.content}</slot>\n </div>\n </mid-popup>\n `;\n }\n}\n\nsetDefaultAnimation('tooltip.show', {\n keyframes: [\n { opacity: 0, scale: 0.8 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 150, easing: 'ease' },\n});\n\nsetDefaultAnimation('tooltip.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.8 },\n ],\n options: { duration: 150, easing: 'ease' },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation-message.js","sources":["../../src/components/validation-message.component.ts"],"sourcesContent":["import { html, LitElement } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-validation-message': MinidValidationMessage;\n }\n}\n\n@customElement('mid-validation-message')\nexport class MinidValidationMessage extends styled(LitElement) {\n override render() {\n return html`\n <div class=\"text-danger-subtle mt-2 flex gap-1\" aria-live=\"polite\">\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n <slot> </slot>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAYO,IAAM,yBAAN,cAAqC,OAAO,UAAU,EAAE;AAAA,EACpD,SAAS;
|
|
1
|
+
{"version":3,"file":"validation-message.js","sources":["../../src/components/validation-message.component.ts"],"sourcesContent":["import { html, LitElement } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-validation-message': MinidValidationMessage;\n }\n}\n\n@customElement('mid-validation-message')\nexport class MinidValidationMessage extends styled(LitElement) {\n override render() {\n return html`\n <div class=\"text-danger-subtle mt-2 flex gap-1\" aria-live=\"polite\">\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n <slot> </slot>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAYO,IAAM,yBAAN,cAAqC,OAAO,UAAU,EAAE;AAAA,EACpD,SAAS;AAChB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAUX;AAZa,yBAAN,gBAAA;AAAA,EADN,cAAc,wBAAwB;AAAA,GAC1B,sBAAA;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animate.js","sources":["../../src/internal/animate.ts"],"sourcesContent":["/**\n * Animates an element using keyframes. Returns a promise that resolves after the animation completes or gets canceled.\n */\nexport function animateTo(\n el: HTMLElement,\n keyframes: Keyframe[],\n options?: KeyframeAnimationOptions\n) {\n return new Promise((resolve) => {\n if (options?.duration === Infinity) {\n throw new Error('Promise-based animations must be finite.');\n }\n\n const animation = el.animate(keyframes, {\n ...options,\n duration: prefersReducedMotion() ? 0 : options!.duration,\n });\n\n animation.addEventListener('cancel', resolve, { once: true });\n animation.addEventListener('finish', resolve, { once: true });\n });\n}\n\n/**\n * Parses a CSS duration and returns the number of milliseconds.\n */\nexport function parseDuration(delay: number | string) {\n delay = delay.toString().toLowerCase();\n\n if (delay.indexOf('ms') > -1) {\n return parseFloat(delay);\n }\n\n if (delay.indexOf('s') > -1) {\n return parseFloat(delay) * 1000;\n }\n\n return parseFloat(delay);\n}\n\n/**\n * Tells if the user has enabled the \"reduced motion\" setting in their browser or OS.\n * */\nexport function prefersReducedMotion() {\n const query = window.matchMedia('(prefers-reduced-motion: reduce)');\n return query.matches;\n}\n\n/**\n * Stops all active animations on the target element. Returns a promise that resolves after all animations are canceled.\n */\nexport function stopAnimations(el: HTMLElement) {\n return Promise.all(\n el.getAnimations().map((animation) => {\n return new Promise((resolve) => {\n animation.cancel();\n requestAnimationFrame(resolve);\n });\n })\n );\n}\n\n/**\n * We can't animate `height: auto`, but we can calculate the height and shim keyframes by replacing it with the\n * element's scrollHeight before the animation.\n */\nexport function shimKeyframesHeightAuto(\n keyframes: Keyframe[],\n calculatedHeight: number\n) {\n return keyframes.map((keyframe) => ({\n ...keyframe,\n height:\n keyframe.height === 'auto' ? `${calculatedHeight}px` : keyframe.height,\n }));\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"animate.js","sources":["../../src/internal/animate.ts"],"sourcesContent":["/**\n * Animates an element using keyframes. Returns a promise that resolves after the animation completes or gets canceled.\n */\nexport function animateTo(\n el: HTMLElement,\n keyframes: Keyframe[],\n options?: KeyframeAnimationOptions\n) {\n return new Promise((resolve) => {\n if (options?.duration === Infinity) {\n throw new Error('Promise-based animations must be finite.');\n }\n\n const animation = el.animate(keyframes, {\n ...options,\n duration: prefersReducedMotion() ? 0 : options!.duration,\n });\n\n animation.addEventListener('cancel', resolve, { once: true });\n animation.addEventListener('finish', resolve, { once: true });\n });\n}\n\n/**\n * Parses a CSS duration and returns the number of milliseconds.\n */\nexport function parseDuration(delay: number | string) {\n delay = delay.toString().toLowerCase();\n\n if (delay.indexOf('ms') > -1) {\n return parseFloat(delay);\n }\n\n if (delay.indexOf('s') > -1) {\n return parseFloat(delay) * 1000;\n }\n\n return parseFloat(delay);\n}\n\n/**\n * Tells if the user has enabled the \"reduced motion\" setting in their browser or OS.\n * */\nexport function prefersReducedMotion() {\n const query = window.matchMedia('(prefers-reduced-motion: reduce)');\n return query.matches;\n}\n\n/**\n * Stops all active animations on the target element. Returns a promise that resolves after all animations are canceled.\n */\nexport function stopAnimations(el: HTMLElement) {\n return Promise.all(\n el.getAnimations().map((animation) => {\n return new Promise((resolve) => {\n animation.cancel();\n requestAnimationFrame(resolve);\n });\n })\n );\n}\n\n/**\n * We can't animate `height: auto`, but we can calculate the height and shim keyframes by replacing it with the\n * element's scrollHeight before the animation.\n */\nexport function shimKeyframesHeightAuto(\n keyframes: Keyframe[],\n calculatedHeight: number\n) {\n return keyframes.map((keyframe) => ({\n ...keyframe,\n height:\n keyframe.height === 'auto' ? `${calculatedHeight}px` : keyframe.height,\n }));\n}\n"],"names":[],"mappings":"AAGO,SAAS,UACd,IACA,WACA,SACA;AACA,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,SAAS,aAAa,UAAU;AAClC,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAAA;AAG5D,UAAM,YAAY,GAAG,QAAQ,WAAW;AAAA,MACtC,GAAG;AAAA,MACH,UAAU,qBAAA,IAAyB,IAAI,QAAS;AAAA,IAAA,CACjD;AAED,cAAU,iBAAiB,UAAU,SAAS,EAAE,MAAM,MAAM;AAC5D,cAAU,iBAAiB,UAAU,SAAS,EAAE,MAAM,MAAM;AAAA,EAAA,CAC7D;AACH;AAKO,SAAS,cAAc,OAAwB;AACpD,UAAQ,MAAM,SAAA,EAAW,YAAA;AAEzB,MAAI,MAAM,QAAQ,IAAI,IAAI,IAAI;AAC5B,WAAO,WAAW,KAAK;AAAA,EAAA;AAGzB,MAAI,MAAM,QAAQ,GAAG,IAAI,IAAI;AAC3B,WAAO,WAAW,KAAK,IAAI;AAAA,EAAA;AAG7B,SAAO,WAAW,KAAK;AACzB;AAKO,SAAS,uBAAuB;AACrC,QAAM,QAAQ,OAAO,WAAW,kCAAkC;AAClE,SAAO,MAAM;AACf;AAKO,SAAS,eAAe,IAAiB;AAC9C,SAAO,QAAQ;AAAA,IACb,GAAG,cAAA,EAAgB,IAAI,CAAC,cAAc;AACpC,aAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,kBAAU,OAAA;AACV,8BAAsB,OAAO;AAAA,MAAA,CAC9B;AAAA,IAAA,CACF;AAAA,EAAA;AAEL;AAMO,SAAS,wBACd,WACA,kBACA;AACA,SAAO,UAAU,IAAI,CAAC,cAAc;AAAA,IAClC,GAAG;AAAA,IACH,QACE,SAAS,WAAW,SAAS,GAAG,gBAAgB,OAAO,SAAS;AAAA,EAAA,EAClE;AACJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debounce.js","sources":["../../src/internal/debounce.ts"],"sourcesContent":["export const debounce = (\n callback: Function,\n wait: number,\n options?: Partial<{\n stopPropagation: boolean;\n }>\n) => {\n let timeoutId: number | undefined = undefined;\n return (...args: [any, any]) => {\n if (options?.stopPropagation) {\n (args[0] as Event).stopPropagation();\n }\n\n window.clearTimeout(timeoutId);\n if (wait < 1) {\n callback(...args);\n return;\n }\n\n timeoutId = window.setTimeout(() => {\n callback(...args);\n }, wait);\n };\n};\n"],"names":[],"mappings":"AAAO,MAAM,WAAW,CACtB,UACA,MACA,YAGG;AACH,MAAI,YAAgC;AACpC,SAAO,IAAI,SAAqB;AAC9B,QAAI,SAAS,iBAAiB;AAC3B,WAAK,CAAC,EAAY,
|
|
1
|
+
{"version":3,"file":"debounce.js","sources":["../../src/internal/debounce.ts"],"sourcesContent":["export const debounce = (\n callback: Function,\n wait: number,\n options?: Partial<{\n stopPropagation: boolean;\n }>\n) => {\n let timeoutId: number | undefined = undefined;\n return (...args: [any, any]) => {\n if (options?.stopPropagation) {\n (args[0] as Event).stopPropagation();\n }\n\n window.clearTimeout(timeoutId);\n if (wait < 1) {\n callback(...args);\n return;\n }\n\n timeoutId = window.setTimeout(() => {\n callback(...args);\n }, wait);\n };\n};\n"],"names":[],"mappings":"AAAO,MAAM,WAAW,CACtB,UACA,MACA,YAGG;AACH,MAAI,YAAgC;AACpC,SAAO,IAAI,SAAqB;AAC9B,QAAI,SAAS,iBAAiB;AAC3B,WAAK,CAAC,EAAY,gBAAA;AAAA,IAAgB;AAGrC,WAAO,aAAa,SAAS;AAC7B,QAAI,OAAO,GAAG;AACZ,eAAS,GAAG,IAAI;AAChB;AAAA,IAAA;AAGF,gBAAY,OAAO,WAAW,MAAM;AAClC,eAAS,GAAG,IAAI;AAAA,IAAA,GACf,IAAI;AAAA,EAAA;AAEX;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event.js","sources":["../../src/internal/event.ts"],"sourcesContent":["/**\n * Waits for a specific event to be emitted from an element. Ignores events that bubble up from child elements.\n */\n\nexport function waitForEvent(el: HTMLElement, eventName: string) {\n return new Promise<void>((resolve) => {\n function done(event: Event) {\n if (event.target === el) {\n el.removeEventListener(eventName, done);\n resolve();\n }\n }\n\n el.addEventListener(eventName, done);\n });\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event.js","sources":["../../src/internal/event.ts"],"sourcesContent":["/**\n * Waits for a specific event to be emitted from an element. Ignores events that bubble up from child elements.\n */\n\nexport function waitForEvent(el: HTMLElement, eventName: string) {\n return new Promise<void>((resolve) => {\n function done(event: Event) {\n if (event.target === el) {\n el.removeEventListener(eventName, done);\n resolve();\n }\n }\n\n el.addEventListener(eventName, done);\n });\n}\n"],"names":[],"mappings":"AAIO,SAAS,aAAa,IAAiB,WAAmB;AAC/D,SAAO,IAAI,QAAc,CAAC,YAAY;AACpC,aAAS,KAAK,OAAc;AAC1B,UAAI,MAAM,WAAW,IAAI;AACvB,WAAG,oBAAoB,WAAW,IAAI;AACtC,gBAAA;AAAA,MAAQ;AAAA,IACV;AAGF,OAAG,iBAAiB,WAAW,IAAI;AAAA,EAAA,CACpC;AACH;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"offset.js","sources":["../../src/internal/offset.ts"],"sourcesContent":["/**\n * Returns an element's offset relative to its parent. Similar to element.offsetTop and element.offsetLeft, except the\n * parent doesn't have to be positioned relative or absolute.\n *\n * NOTE: This was created to work around what appears to be a bug in Chrome where a slotted element's offsetParent seems\n * to ignore elements inside the surrounding shadow DOM: https://bugs.chromium.org/p/chromium/issues/detail?id=920069\n */\nexport function getOffset(element: HTMLElement, parent: HTMLElement) {\n return {\n top: Math.round(\n element.getBoundingClientRect().top - parent.getBoundingClientRect().top\n ),\n left: Math.round(\n element.getBoundingClientRect().left - parent.getBoundingClientRect().left\n ),\n };\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"offset.js","sources":["../../src/internal/offset.ts"],"sourcesContent":["/**\n * Returns an element's offset relative to its parent. Similar to element.offsetTop and element.offsetLeft, except the\n * parent doesn't have to be positioned relative or absolute.\n *\n * NOTE: This was created to work around what appears to be a bug in Chrome where a slotted element's offsetParent seems\n * to ignore elements inside the surrounding shadow DOM: https://bugs.chromium.org/p/chromium/issues/detail?id=920069\n */\nexport function getOffset(element: HTMLElement, parent: HTMLElement) {\n return {\n top: Math.round(\n element.getBoundingClientRect().top - parent.getBoundingClientRect().top\n ),\n left: Math.round(\n element.getBoundingClientRect().left - parent.getBoundingClientRect().left\n ),\n };\n}\n"],"names":[],"mappings":"AAOO,SAAS,UAAU,SAAsB,QAAqB;AACnE,SAAO;AAAA,IACL,KAAK,KAAK;AAAA,MACR,QAAQ,sBAAA,EAAwB,MAAM,OAAO,wBAAwB;AAAA,IAAA;AAAA,IAEvE,MAAM,KAAK;AAAA,MACT,QAAQ,sBAAA,EAAwB,OAAO,OAAO,wBAAwB;AAAA,IAAA;AAAA,EACxE;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll.js","sources":["../../src/internal/scroll.ts"],"sourcesContent":["import { getOffset } from './offset.ts';\n\nconst locks = new Set();\n\n/** Returns the width of the document's scrollbar */\nfunction getScrollbarWidth() {\n const documentWidth = document.documentElement.clientWidth;\n return Math.abs(window.innerWidth - documentWidth);\n}\n\n/**\n * Used in conjunction with `scrollbarWidth` to set proper body padding in case the user has padding already on the `<body>` element.\n */\nfunction getExistingBodyPadding() {\n const padding = Number(\n getComputedStyle(document.body).paddingRight.replace(/px/, '')\n );\n\n if (isNaN(padding) || !padding) {\n return 0;\n }\n\n return padding;\n}\n\n/**\n * Prevents body scrolling. Keeps track of which elements requested a lock so multiple levels of locking are possible\n * without premature unlocking.\n */\nexport function lockBodyScrolling(lockingEl: HTMLElement) {\n locks.add(lockingEl);\n\n // When the first lock is created, set the scroll lock size to match the scrollbar's width to prevent content from\n // shifting. We only do this on the first lock because the scrollbar width will measure zero after overflow is hidden.\n if (!document.documentElement.classList.contains('mid-scroll-lock')) {\n /** Scrollbar width + body padding calculation can go away once Safari has scrollbar-gutter support. */\n const scrollbarWidth = getScrollbarWidth() + getExistingBodyPadding(); // must be measured before the `mid-scroll-lock` class is applied\n\n let scrollbarGutterProperty = getComputedStyle(\n document.documentElement\n ).scrollbarGutter;\n\n // default is auto, unsupported browsers is \"undefined\"\n if (!scrollbarGutterProperty || scrollbarGutterProperty === 'auto') {\n scrollbarGutterProperty = 'stable';\n }\n\n /** Sometimes the scrollbar width is 1px, even then, we assume nothing is overflowing. */\n if (scrollbarWidth < 2) {\n // if there's no scrollbar, just set it to an empty string so whatever the user has set gets used. This is useful if the page is not overflowing and showing a scrollbar, or if the user has overflow: hidden, or any other reason a scrollbar may not be showing.\n scrollbarGutterProperty = '';\n }\n document.documentElement.style.setProperty(\n '--mid-scroll-lock-gutter',\n scrollbarGutterProperty\n );\n document.documentElement.classList.add('mid-scroll-lock');\n document.documentElement.style.setProperty(\n '--mid-scroll-lock-size',\n `${scrollbarWidth}px`\n );\n }\n}\n\n/**\n * Unlocks body scrolling. Scrolling will only be unlocked once all elements that requested a lock call this method.\n */\nexport function unlockBodyScrolling(lockingEl: HTMLElement) {\n locks.delete(lockingEl);\n\n if (locks.size === 0) {\n document.documentElement.classList.remove('mid-scroll-lock');\n document.documentElement.style.removeProperty('--mid-scroll-lock-size');\n }\n}\n\n/**\n * Scrolls an element into view of its container. If the element is already in view, nothing will happen.\n */\nexport function scrollIntoView(\n element: HTMLElement,\n container: HTMLElement,\n direction: 'horizontal' | 'vertical' | 'both' = 'vertical',\n behavior: 'smooth' | 'auto' = 'smooth'\n) {\n const offset = getOffset(element, container);\n const offsetTop = offset.top + container.scrollTop;\n const offsetLeft = offset.left + container.scrollLeft;\n const minX = container.scrollLeft;\n const maxX = container.scrollLeft + container.offsetWidth;\n const minY = container.scrollTop;\n const maxY = container.scrollTop + container.offsetHeight;\n\n if (direction === 'horizontal' || direction === 'both') {\n if (offsetLeft < minX) {\n container.scrollTo({ left: offsetLeft, behavior });\n } else if (offsetLeft + element.clientWidth > maxX) {\n container.scrollTo({\n left: offsetLeft - container.offsetWidth + element.clientWidth,\n behavior,\n });\n }\n }\n\n if (direction === 'vertical' || direction === 'both') {\n if (offsetTop < minY) {\n container.scrollTo({ top: offsetTop, behavior });\n } else if (offsetTop + element.offsetHeight > maxY) {\n container.scrollTo({\n top: offsetTop - container.offsetHeight + element.offsetHeight,\n behavior,\n });\n }\n }\n}\n"],"names":[],"mappings":";AAEA,MAAM,4BAAY,
|
|
1
|
+
{"version":3,"file":"scroll.js","sources":["../../src/internal/scroll.ts"],"sourcesContent":["import { getOffset } from './offset.ts';\n\nconst locks = new Set();\n\n/** Returns the width of the document's scrollbar */\nfunction getScrollbarWidth() {\n const documentWidth = document.documentElement.clientWidth;\n return Math.abs(window.innerWidth - documentWidth);\n}\n\n/**\n * Used in conjunction with `scrollbarWidth` to set proper body padding in case the user has padding already on the `<body>` element.\n */\nfunction getExistingBodyPadding() {\n const padding = Number(\n getComputedStyle(document.body).paddingRight.replace(/px/, '')\n );\n\n if (isNaN(padding) || !padding) {\n return 0;\n }\n\n return padding;\n}\n\n/**\n * Prevents body scrolling. Keeps track of which elements requested a lock so multiple levels of locking are possible\n * without premature unlocking.\n */\nexport function lockBodyScrolling(lockingEl: HTMLElement) {\n locks.add(lockingEl);\n\n // When the first lock is created, set the scroll lock size to match the scrollbar's width to prevent content from\n // shifting. We only do this on the first lock because the scrollbar width will measure zero after overflow is hidden.\n if (!document.documentElement.classList.contains('mid-scroll-lock')) {\n /** Scrollbar width + body padding calculation can go away once Safari has scrollbar-gutter support. */\n const scrollbarWidth = getScrollbarWidth() + getExistingBodyPadding(); // must be measured before the `mid-scroll-lock` class is applied\n\n let scrollbarGutterProperty = getComputedStyle(\n document.documentElement\n ).scrollbarGutter;\n\n // default is auto, unsupported browsers is \"undefined\"\n if (!scrollbarGutterProperty || scrollbarGutterProperty === 'auto') {\n scrollbarGutterProperty = 'stable';\n }\n\n /** Sometimes the scrollbar width is 1px, even then, we assume nothing is overflowing. */\n if (scrollbarWidth < 2) {\n // if there's no scrollbar, just set it to an empty string so whatever the user has set gets used. This is useful if the page is not overflowing and showing a scrollbar, or if the user has overflow: hidden, or any other reason a scrollbar may not be showing.\n scrollbarGutterProperty = '';\n }\n document.documentElement.style.setProperty(\n '--mid-scroll-lock-gutter',\n scrollbarGutterProperty\n );\n document.documentElement.classList.add('mid-scroll-lock');\n document.documentElement.style.setProperty(\n '--mid-scroll-lock-size',\n `${scrollbarWidth}px`\n );\n }\n}\n\n/**\n * Unlocks body scrolling. Scrolling will only be unlocked once all elements that requested a lock call this method.\n */\nexport function unlockBodyScrolling(lockingEl: HTMLElement) {\n locks.delete(lockingEl);\n\n if (locks.size === 0) {\n document.documentElement.classList.remove('mid-scroll-lock');\n document.documentElement.style.removeProperty('--mid-scroll-lock-size');\n }\n}\n\n/**\n * Scrolls an element into view of its container. If the element is already in view, nothing will happen.\n */\nexport function scrollIntoView(\n element: HTMLElement,\n container: HTMLElement,\n direction: 'horizontal' | 'vertical' | 'both' = 'vertical',\n behavior: 'smooth' | 'auto' = 'smooth'\n) {\n const offset = getOffset(element, container);\n const offsetTop = offset.top + container.scrollTop;\n const offsetLeft = offset.left + container.scrollLeft;\n const minX = container.scrollLeft;\n const maxX = container.scrollLeft + container.offsetWidth;\n const minY = container.scrollTop;\n const maxY = container.scrollTop + container.offsetHeight;\n\n if (direction === 'horizontal' || direction === 'both') {\n if (offsetLeft < minX) {\n container.scrollTo({ left: offsetLeft, behavior });\n } else if (offsetLeft + element.clientWidth > maxX) {\n container.scrollTo({\n left: offsetLeft - container.offsetWidth + element.clientWidth,\n behavior,\n });\n }\n }\n\n if (direction === 'vertical' || direction === 'both') {\n if (offsetTop < minY) {\n container.scrollTo({ top: offsetTop, behavior });\n } else if (offsetTop + element.offsetHeight > maxY) {\n container.scrollTo({\n top: offsetTop - container.offsetHeight + element.offsetHeight,\n behavior,\n });\n }\n }\n}\n"],"names":[],"mappings":";AAEA,MAAM,4BAAY,IAAA;AAGlB,SAAS,oBAAoB;AAC3B,QAAM,gBAAgB,SAAS,gBAAgB;AAC/C,SAAO,KAAK,IAAI,OAAO,aAAa,aAAa;AACnD;AAKA,SAAS,yBAAyB;AAChC,QAAM,UAAU;AAAA,IACd,iBAAiB,SAAS,IAAI,EAAE,aAAa,QAAQ,MAAM,EAAE;AAAA,EAAA;AAG/D,MAAI,MAAM,OAAO,KAAK,CAAC,SAAS;AAC9B,WAAO;AAAA,EAAA;AAGT,SAAO;AACT;AAMO,SAAS,kBAAkB,WAAwB;AACxD,QAAM,IAAI,SAAS;AAInB,MAAI,CAAC,SAAS,gBAAgB,UAAU,SAAS,iBAAiB,GAAG;AAEnE,UAAM,iBAAiB,kBAAA,IAAsB,uBAAA;AAE7C,QAAI,0BAA0B;AAAA,MAC5B,SAAS;AAAA,IAAA,EACT;AAGF,QAAI,CAAC,2BAA2B,4BAA4B,QAAQ;AAClE,gCAA0B;AAAA,IAAA;AAI5B,QAAI,iBAAiB,GAAG;AAEtB,gCAA0B;AAAA,IAAA;AAE5B,aAAS,gBAAgB,MAAM;AAAA,MAC7B;AAAA,MACA;AAAA,IAAA;AAEF,aAAS,gBAAgB,UAAU,IAAI,iBAAiB;AACxD,aAAS,gBAAgB,MAAM;AAAA,MAC7B;AAAA,MACA,GAAG,cAAc;AAAA,IAAA;AAAA,EACnB;AAEJ;AAKO,SAAS,oBAAoB,WAAwB;AAC1D,QAAM,OAAO,SAAS;AAEtB,MAAI,MAAM,SAAS,GAAG;AACpB,aAAS,gBAAgB,UAAU,OAAO,iBAAiB;AAC3D,aAAS,gBAAgB,MAAM,eAAe,wBAAwB;AAAA,EAAA;AAE1E;AAKO,SAAS,eACd,SACA,WACA,YAAgD,YAChD,WAA8B,UAC9B;AACA,QAAM,SAAS,UAAU,SAAS,SAAS;AAC3C,QAAM,YAAY,OAAO,MAAM,UAAU;AACzC,QAAM,aAAa,OAAO,OAAO,UAAU;AAC3C,QAAM,OAAO,UAAU;AACvB,QAAM,OAAO,UAAU,aAAa,UAAU;AAC9C,QAAM,OAAO,UAAU;AACvB,QAAM,OAAO,UAAU,YAAY,UAAU;AAE7C,MAAI,cAAc,gBAAgB,cAAc,QAAQ;AACtD,QAAI,aAAa,MAAM;AACrB,gBAAU,SAAS,EAAE,MAAM,YAAY,UAAU;AAAA,IAAA,WACxC,aAAa,QAAQ,cAAc,MAAM;AAClD,gBAAU,SAAS;AAAA,QACjB,MAAM,aAAa,UAAU,cAAc,QAAQ;AAAA,QACnD;AAAA,MAAA,CACD;AAAA,IAAA;AAAA,EACH;AAGF,MAAI,cAAc,cAAc,cAAc,QAAQ;AACpD,QAAI,YAAY,MAAM;AACpB,gBAAU,SAAS,EAAE,KAAK,WAAW,UAAU;AAAA,IAAA,WACtC,YAAY,QAAQ,eAAe,MAAM;AAClD,gBAAU,SAAS;AAAA,QACjB,KAAK,YAAY,UAAU,eAAe,QAAQ;AAAA,QAClD;AAAA,MAAA,CACD;AAAA,IAAA;AAAA,EACH;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot.js","sources":["../../src/internal/slot.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/** A reactive controller that determines when slots exist. */\nexport class HasSlotController implements ReactiveController {\n host: ReactiveControllerHost & Element;\n slotNames: string[] = [];\n\n constructor(host: ReactiveControllerHost & Element, ...slotNames: string[]) {\n (this.host = host).addController(this);\n this.slotNames = slotNames;\n }\n\n private hasDefaultSlot() {\n return Array.from(this.host.childNodes).some((node) => {\n if (node.nodeType === node.TEXT_NODE && node.textContent!.trim() !== '') {\n return true;\n }\n\n if (node.nodeType === node.ELEMENT_NODE) {\n const el = node as HTMLElement;\n const tagName = el.tagName.toLowerCase();\n\n // Ignore visually hidden elements since they aren't rendered\n if (tagName === 'sr-only') {\n return false;\n }\n\n // If it doesn't have a slot attribute, it's part of the default slot\n if (!el.hasAttribute('slot')) {\n return true;\n }\n }\n\n return false;\n });\n }\n\n private hasNamedSlot(name: string) {\n return this.host.querySelector(`:scope > [slot=\"${name}\"]`) !== null;\n }\n\n test(slotName: string) {\n return slotName === '[default]'\n ? this.hasDefaultSlot()\n : this.hasNamedSlot(slotName);\n }\n\n hostConnected() {\n this.host.shadowRoot!.addEventListener('slotchange', this.handleSlotChange);\n }\n\n hostDisconnected() {\n this.host.shadowRoot!.removeEventListener(\n 'slotchange',\n this.handleSlotChange\n );\n }\n\n private handleSlotChange = (event: Event) => {\n const slot = event.target as HTMLSlotElement;\n\n if (\n (this.slotNames.includes('[default]') && !slot.name) ||\n (slot.name && this.slotNames.includes(slot.name))\n ) {\n this.host.requestUpdate();\n }\n };\n}\n\n/**\n * Given a slot, this function iterates over all of its assigned element and text nodes and returns the concatenated\n * HTML as a string. This is useful because we can't use slot.innerHTML as an alternative.\n */\nexport function getInnerHTML(slot: HTMLSlotElement): string {\n const nodes = slot.assignedNodes({ flatten: true });\n let html = '';\n\n [...nodes].forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n html += (node as HTMLElement).outerHTML;\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n html += node.textContent;\n }\n });\n\n return html;\n}\n\n/**\n * Given a slot, this function iterates over all of its assigned text nodes and returns the concatenated text as a\n * string. This is useful because we can't use slot.textContent as an alternative.\n */\nexport function getTextContent(\n slot: HTMLSlotElement | undefined | null\n): string {\n if (!slot) {\n return '';\n }\n const nodes = slot.assignedNodes({ flatten: true });\n let text = '';\n\n [...nodes].forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent;\n }\n });\n\n return text;\n}\n"],"names":[],"mappings":"AAGO,MAAM,kBAAgD;AAAA,EAI3D,YAAY,SAA2C,WAAqB;AAF5E,SAAA,YAAsB,
|
|
1
|
+
{"version":3,"file":"slot.js","sources":["../../src/internal/slot.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/** A reactive controller that determines when slots exist. */\nexport class HasSlotController implements ReactiveController {\n host: ReactiveControllerHost & Element;\n slotNames: string[] = [];\n\n constructor(host: ReactiveControllerHost & Element, ...slotNames: string[]) {\n (this.host = host).addController(this);\n this.slotNames = slotNames;\n }\n\n private hasDefaultSlot() {\n return Array.from(this.host.childNodes).some((node) => {\n if (node.nodeType === node.TEXT_NODE && node.textContent!.trim() !== '') {\n return true;\n }\n\n if (node.nodeType === node.ELEMENT_NODE) {\n const el = node as HTMLElement;\n const tagName = el.tagName.toLowerCase();\n\n // Ignore visually hidden elements since they aren't rendered\n if (tagName === 'sr-only') {\n return false;\n }\n\n // If it doesn't have a slot attribute, it's part of the default slot\n if (!el.hasAttribute('slot')) {\n return true;\n }\n }\n\n return false;\n });\n }\n\n private hasNamedSlot(name: string) {\n return this.host.querySelector(`:scope > [slot=\"${name}\"]`) !== null;\n }\n\n test(slotName: string) {\n return slotName === '[default]'\n ? this.hasDefaultSlot()\n : this.hasNamedSlot(slotName);\n }\n\n hostConnected() {\n this.host.shadowRoot!.addEventListener('slotchange', this.handleSlotChange);\n }\n\n hostDisconnected() {\n this.host.shadowRoot!.removeEventListener(\n 'slotchange',\n this.handleSlotChange\n );\n }\n\n private handleSlotChange = (event: Event) => {\n const slot = event.target as HTMLSlotElement;\n\n if (\n (this.slotNames.includes('[default]') && !slot.name) ||\n (slot.name && this.slotNames.includes(slot.name))\n ) {\n this.host.requestUpdate();\n }\n };\n}\n\n/**\n * Given a slot, this function iterates over all of its assigned element and text nodes and returns the concatenated\n * HTML as a string. This is useful because we can't use slot.innerHTML as an alternative.\n */\nexport function getInnerHTML(slot: HTMLSlotElement): string {\n const nodes = slot.assignedNodes({ flatten: true });\n let html = '';\n\n [...nodes].forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n html += (node as HTMLElement).outerHTML;\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n html += node.textContent;\n }\n });\n\n return html;\n}\n\n/**\n * Given a slot, this function iterates over all of its assigned text nodes and returns the concatenated text as a\n * string. This is useful because we can't use slot.textContent as an alternative.\n */\nexport function getTextContent(\n slot: HTMLSlotElement | undefined | null\n): string {\n if (!slot) {\n return '';\n }\n const nodes = slot.assignedNodes({ flatten: true });\n let text = '';\n\n [...nodes].forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent;\n }\n });\n\n return text;\n}\n"],"names":[],"mappings":"AAGO,MAAM,kBAAgD;AAAA,EAI3D,YAAY,SAA2C,WAAqB;AAF5E,SAAA,YAAsB,CAAA;AAqDtB,SAAQ,mBAAmB,CAAC,UAAiB;AAC3C,YAAM,OAAO,MAAM;AAEnB,UACG,KAAK,UAAU,SAAS,WAAW,KAAK,CAAC,KAAK,QAC9C,KAAK,QAAQ,KAAK,UAAU,SAAS,KAAK,IAAI,GAC/C;AACA,aAAK,KAAK,cAAA;AAAA,MAAc;AAAA,IAC1B;AA1DA,KAAC,KAAK,OAAO,MAAM,cAAc,IAAI;AACrC,SAAK,YAAY;AAAA,EAAA;AAAA,EAGX,iBAAiB;AACvB,WAAO,MAAM,KAAK,KAAK,KAAK,UAAU,EAAE,KAAK,CAAC,SAAS;AACrD,UAAI,KAAK,aAAa,KAAK,aAAa,KAAK,YAAa,KAAA,MAAW,IAAI;AACvE,eAAO;AAAA,MAAA;AAGT,UAAI,KAAK,aAAa,KAAK,cAAc;AACvC,cAAM,KAAK;AACX,cAAM,UAAU,GAAG,QAAQ,YAAA;AAG3B,YAAI,YAAY,WAAW;AACzB,iBAAO;AAAA,QAAA;AAIT,YAAI,CAAC,GAAG,aAAa,MAAM,GAAG;AAC5B,iBAAO;AAAA,QAAA;AAAA,MACT;AAGF,aAAO;AAAA,IAAA,CACR;AAAA,EAAA;AAAA,EAGK,aAAa,MAAc;AACjC,WAAO,KAAK,KAAK,cAAc,mBAAmB,IAAI,IAAI,MAAM;AAAA,EAAA;AAAA,EAGlE,KAAK,UAAkB;AACrB,WAAO,aAAa,cAChB,KAAK,mBACL,KAAK,aAAa,QAAQ;AAAA,EAAA;AAAA,EAGhC,gBAAgB;AACd,SAAK,KAAK,WAAY,iBAAiB,cAAc,KAAK,gBAAgB;AAAA,EAAA;AAAA,EAG5E,mBAAmB;AACjB,SAAK,KAAK,WAAY;AAAA,MACpB;AAAA,MACA,KAAK;AAAA,IAAA;AAAA,EACP;AAaJ;AAMO,SAAS,aAAa,MAA+B;AAC1D,QAAM,QAAQ,KAAK,cAAc,EAAE,SAAS,MAAM;AAClD,MAAI,OAAO;AAEX,GAAC,GAAG,KAAK,EAAE,QAAQ,CAAC,SAAS;AAC3B,QAAI,KAAK,aAAa,KAAK,cAAc;AACvC,cAAS,KAAqB;AAAA,IAAA;AAGhC,QAAI,KAAK,aAAa,KAAK,WAAW;AACpC,cAAQ,KAAK;AAAA,IAAA;AAAA,EACf,CACD;AAED,SAAO;AACT;AAMO,SAAS,eACd,MACQ;AACR,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EAAA;AAET,QAAM,QAAQ,KAAK,cAAc,EAAE,SAAS,MAAM;AAClD,MAAI,OAAO;AAEX,GAAC,GAAG,KAAK,EAAE,QAAQ,CAAC,SAAS;AAC3B,QAAI,KAAK,aAAa,KAAK,WAAW;AACpC,cAAQ,KAAK;AAAA,IAAA;AAAA,EACf,CACD;AAED,SAAO;AACT;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string-converter.js","sources":["../../src/internal/string-converter.ts"],"sourcesContent":["import type { ComplexAttributeConverter } from 'lit';\n\nexport const stringConverter: ComplexAttributeConverter = {\n fromAttribute(value: string | null): string {\n return value ?? '';\n },\n toAttribute(value: string): string | null {\n return value || null;\n },\n};\n"],"names":[],"mappings":"AAEO,MAAM,kBAA6C;AAAA,EACxD,cAAc,OAA8B;AAC1C,WAAO,SAAS;AAAA,
|
|
1
|
+
{"version":3,"file":"string-converter.js","sources":["../../src/internal/string-converter.ts"],"sourcesContent":["import type { ComplexAttributeConverter } from 'lit';\n\nexport const stringConverter: ComplexAttributeConverter = {\n fromAttribute(value: string | null): string {\n return value ?? '';\n },\n toAttribute(value: string): string | null {\n return value || null;\n },\n};\n"],"names":[],"mappings":"AAEO,MAAM,kBAA6C;AAAA,EACxD,cAAc,OAA8B;AAC1C,WAAO,SAAS;AAAA,EAAA;AAAA,EAElB,YAAY,OAA8B;AACxC,WAAO,SAAS;AAAA,EAAA;AAEpB;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabbable.js","sources":["../../src/internal/tabbable.ts"],"sourcesContent":["// Cached compute style calls. This is specifically for browsers that dont support `checkVisibility()`.\n// computedStyle calls are \"live\" so they only need to be retrieved once for an element.\nconst computedStyleMap = new WeakMap<Element, CSSStyleDeclaration>();\n\nfunction getCachedComputedStyle(el: HTMLElement): CSSStyleDeclaration {\n let computedStyle: undefined | CSSStyleDeclaration = computedStyleMap.get(el);\n\n if (!computedStyle) {\n computedStyle = window.getComputedStyle(el, null);\n computedStyleMap.set(el, computedStyle);\n }\n\n return computedStyle;\n}\n\nfunction isVisible(el: HTMLElement): boolean {\n // This is the fastest check, but isn't supported in Safari.\n if (typeof el.checkVisibility === 'function') {\n // Opacity is focusable, visibility is not.\n return el.checkVisibility({\n checkOpacity: false,\n checkVisibilityCSS: true,\n });\n }\n\n // Fallback \"polyfill\" for \"checkVisibility\"\n const computedStyle = getCachedComputedStyle(el);\n\n return (\n computedStyle.visibility !== 'hidden' && computedStyle.display !== 'none'\n );\n}\n\n// While this behavior isn't standard in Safari / Chrome yet, I think it's the most reasonable\n// way of handling tabbable overflow areas. Browser sniffing seems gross, and it's the most\n// accessible way of handling overflow areas. [Konnor]\nfunction isOverflowingAndTabbable(el: HTMLElement): boolean {\n const computedStyle = getCachedComputedStyle(el);\n\n const { overflowY, overflowX } = computedStyle;\n\n if (overflowY === 'scroll' || overflowX === 'scroll') {\n return true;\n }\n\n if (overflowY !== 'auto' || overflowX !== 'auto') {\n return false;\n }\n\n // Always overflow === \"auto\" by this point\n const isOverflowingY = el.scrollHeight > el.clientHeight;\n\n if (isOverflowingY && overflowY === 'auto') {\n return true;\n }\n\n const isOverflowingX = el.scrollWidth > el.clientWidth;\n\n if (isOverflowingX && overflowX === 'auto') {\n return true;\n }\n\n return false;\n}\n\n/** Determines if the specified element is tabbable using heuristics inspired by https://github.com/focus-trap/tabbable */\nfunction isTabbable(el: HTMLElement) {\n const tag = el.tagName.toLowerCase();\n\n const tabindex = Number(el.getAttribute('tabindex'));\n const hasTabindex = el.hasAttribute('tabindex');\n\n // elements with a tabindex attribute that is either NaN or <= -1 are not tabbable\n if (hasTabindex && (isNaN(tabindex) || tabindex <= -1)) {\n return false;\n }\n\n // Elements with a disabled attribute are not tabbable\n if (el.hasAttribute('disabled')) {\n return false;\n }\n\n // If any parents have \"inert\", we aren't \"tabbable\"\n if (el.closest('[inert]')) {\n return false;\n }\n\n // Radios without a checked attribute are not tabbable\n if (\n tag === 'input' &&\n el.getAttribute('type') === 'radio' &&\n !el.hasAttribute('checked')\n ) {\n return false;\n }\n\n if (!isVisible(el)) {\n return false;\n }\n\n // Audio and video elements with the controls attribute are tabbable\n if ((tag === 'audio' || tag === 'video') && el.hasAttribute('controls')) {\n return true;\n }\n\n // Elements with a tabindex other than -1 are tabbable\n if (el.hasAttribute('tabindex')) {\n return true;\n }\n\n // Elements with a contenteditable attribute are tabbable\n if (\n el.hasAttribute('contenteditable') &&\n el.getAttribute('contenteditable') !== 'false'\n ) {\n return true;\n }\n\n // At this point, the following elements are considered tabbable\n const isNativelyTabbable = [\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'a',\n 'audio',\n 'video',\n 'summary',\n 'iframe',\n ].includes(tag);\n\n if (isNativelyTabbable) {\n return true;\n }\n\n // We save the overflow checks for last, because they're the most expensive\n return isOverflowingAndTabbable(el);\n}\n\n/**\n * Returns the first and last bounding elements that are tabbable. This is more performant than checking every single\n * element because it short-circuits after finding the first and last ones.\n */\nexport function getTabbableBoundary(root: HTMLElement | ShadowRoot) {\n const tabbableElements = getTabbableElements(root);\n\n // Find the first and last tabbable elements\n const start = tabbableElements[0] ?? null;\n const end = tabbableElements[tabbableElements.length - 1] ?? null;\n\n return { start, end };\n}\n\n/**\n * This looks funky. Basically a slot's children will always be picked up *if* they're within the `root` element.\n * However, there is an edge case when, if the `root` is wrapped by another shadow DOM, it won't grab the children.\n * This fixes that fun edge case.\n */\nfunction getSlottedChildrenOutsideRootElement(\n slotElement: HTMLSlotElement,\n root: HTMLElement | ShadowRoot\n) {\n return (\n (slotElement.getRootNode({ composed: true }) as ShadowRoot | null)?.host !==\n root\n );\n}\n\nexport function getTabbableElements(root: HTMLElement | ShadowRoot) {\n const walkedEls = new WeakMap();\n const tabbableElements: HTMLElement[] = [];\n\n function walk(el: HTMLElement | ShadowRoot) {\n if (el instanceof Element) {\n // if the element has \"inert\" we can just no-op it.\n if (el.hasAttribute('inert') || el.closest('[inert]')) {\n return;\n }\n\n if (walkedEls.has(el)) {\n return;\n }\n walkedEls.set(el, true);\n\n if (!tabbableElements.includes(el) && isTabbable(el)) {\n tabbableElements.push(el);\n }\n\n if (\n el instanceof HTMLSlotElement &&\n getSlottedChildrenOutsideRootElement(el, root)\n ) {\n el.assignedElements({ flatten: true }).forEach((assignedEl) => {\n walk(assignedEl as HTMLElement);\n });\n }\n\n if (el.shadowRoot !== null && el.shadowRoot.mode === 'open') {\n walk(el.shadowRoot);\n }\n }\n\n for (const e of Array.from(el.children)) {\n walk(e as HTMLElement);\n }\n }\n\n // Collect all elements including the root\n walk(root);\n\n // Is this worth having? Most sorts will always add increased overhead. And positive tabindexes shouldn't really be used.\n // So is it worth being right? Or fast?\n return tabbableElements.sort((a, b) => {\n // Make sure we sort by tabindex.\n const aTabindex = Number(a.getAttribute('tabindex')) || 0;\n const bTabindex = Number(b.getAttribute('tabindex')) || 0;\n return bTabindex - aTabindex;\n });\n}\n"],"names":[],"mappings":"AAEA,MAAM,uCAAuB,
|
|
1
|
+
{"version":3,"file":"tabbable.js","sources":["../../src/internal/tabbable.ts"],"sourcesContent":["// Cached compute style calls. This is specifically for browsers that dont support `checkVisibility()`.\n// computedStyle calls are \"live\" so they only need to be retrieved once for an element.\nconst computedStyleMap = new WeakMap<Element, CSSStyleDeclaration>();\n\nfunction getCachedComputedStyle(el: HTMLElement): CSSStyleDeclaration {\n let computedStyle: undefined | CSSStyleDeclaration = computedStyleMap.get(el);\n\n if (!computedStyle) {\n computedStyle = window.getComputedStyle(el, null);\n computedStyleMap.set(el, computedStyle);\n }\n\n return computedStyle;\n}\n\nfunction isVisible(el: HTMLElement): boolean {\n // This is the fastest check, but isn't supported in Safari.\n if (typeof el.checkVisibility === 'function') {\n // Opacity is focusable, visibility is not.\n return el.checkVisibility({\n checkOpacity: false,\n checkVisibilityCSS: true,\n });\n }\n\n // Fallback \"polyfill\" for \"checkVisibility\"\n const computedStyle = getCachedComputedStyle(el);\n\n return (\n computedStyle.visibility !== 'hidden' && computedStyle.display !== 'none'\n );\n}\n\n// While this behavior isn't standard in Safari / Chrome yet, I think it's the most reasonable\n// way of handling tabbable overflow areas. Browser sniffing seems gross, and it's the most\n// accessible way of handling overflow areas. [Konnor]\nfunction isOverflowingAndTabbable(el: HTMLElement): boolean {\n const computedStyle = getCachedComputedStyle(el);\n\n const { overflowY, overflowX } = computedStyle;\n\n if (overflowY === 'scroll' || overflowX === 'scroll') {\n return true;\n }\n\n if (overflowY !== 'auto' || overflowX !== 'auto') {\n return false;\n }\n\n // Always overflow === \"auto\" by this point\n const isOverflowingY = el.scrollHeight > el.clientHeight;\n\n if (isOverflowingY && overflowY === 'auto') {\n return true;\n }\n\n const isOverflowingX = el.scrollWidth > el.clientWidth;\n\n if (isOverflowingX && overflowX === 'auto') {\n return true;\n }\n\n return false;\n}\n\n/** Determines if the specified element is tabbable using heuristics inspired by https://github.com/focus-trap/tabbable */\nfunction isTabbable(el: HTMLElement) {\n const tag = el.tagName.toLowerCase();\n\n const tabindex = Number(el.getAttribute('tabindex'));\n const hasTabindex = el.hasAttribute('tabindex');\n\n // elements with a tabindex attribute that is either NaN or <= -1 are not tabbable\n if (hasTabindex && (isNaN(tabindex) || tabindex <= -1)) {\n return false;\n }\n\n // Elements with a disabled attribute are not tabbable\n if (el.hasAttribute('disabled')) {\n return false;\n }\n\n // If any parents have \"inert\", we aren't \"tabbable\"\n if (el.closest('[inert]')) {\n return false;\n }\n\n // Radios without a checked attribute are not tabbable\n if (\n tag === 'input' &&\n el.getAttribute('type') === 'radio' &&\n !el.hasAttribute('checked')\n ) {\n return false;\n }\n\n if (!isVisible(el)) {\n return false;\n }\n\n // Audio and video elements with the controls attribute are tabbable\n if ((tag === 'audio' || tag === 'video') && el.hasAttribute('controls')) {\n return true;\n }\n\n // Elements with a tabindex other than -1 are tabbable\n if (el.hasAttribute('tabindex')) {\n return true;\n }\n\n // Elements with a contenteditable attribute are tabbable\n if (\n el.hasAttribute('contenteditable') &&\n el.getAttribute('contenteditable') !== 'false'\n ) {\n return true;\n }\n\n // At this point, the following elements are considered tabbable\n const isNativelyTabbable = [\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'a',\n 'audio',\n 'video',\n 'summary',\n 'iframe',\n ].includes(tag);\n\n if (isNativelyTabbable) {\n return true;\n }\n\n // We save the overflow checks for last, because they're the most expensive\n return isOverflowingAndTabbable(el);\n}\n\n/**\n * Returns the first and last bounding elements that are tabbable. This is more performant than checking every single\n * element because it short-circuits after finding the first and last ones.\n */\nexport function getTabbableBoundary(root: HTMLElement | ShadowRoot) {\n const tabbableElements = getTabbableElements(root);\n\n // Find the first and last tabbable elements\n const start = tabbableElements[0] ?? null;\n const end = tabbableElements[tabbableElements.length - 1] ?? null;\n\n return { start, end };\n}\n\n/**\n * This looks funky. Basically a slot's children will always be picked up *if* they're within the `root` element.\n * However, there is an edge case when, if the `root` is wrapped by another shadow DOM, it won't grab the children.\n * This fixes that fun edge case.\n */\nfunction getSlottedChildrenOutsideRootElement(\n slotElement: HTMLSlotElement,\n root: HTMLElement | ShadowRoot\n) {\n return (\n (slotElement.getRootNode({ composed: true }) as ShadowRoot | null)?.host !==\n root\n );\n}\n\nexport function getTabbableElements(root: HTMLElement | ShadowRoot) {\n const walkedEls = new WeakMap();\n const tabbableElements: HTMLElement[] = [];\n\n function walk(el: HTMLElement | ShadowRoot) {\n if (el instanceof Element) {\n // if the element has \"inert\" we can just no-op it.\n if (el.hasAttribute('inert') || el.closest('[inert]')) {\n return;\n }\n\n if (walkedEls.has(el)) {\n return;\n }\n walkedEls.set(el, true);\n\n if (!tabbableElements.includes(el) && isTabbable(el)) {\n tabbableElements.push(el);\n }\n\n if (\n el instanceof HTMLSlotElement &&\n getSlottedChildrenOutsideRootElement(el, root)\n ) {\n el.assignedElements({ flatten: true }).forEach((assignedEl) => {\n walk(assignedEl as HTMLElement);\n });\n }\n\n if (el.shadowRoot !== null && el.shadowRoot.mode === 'open') {\n walk(el.shadowRoot);\n }\n }\n\n for (const e of Array.from(el.children)) {\n walk(e as HTMLElement);\n }\n }\n\n // Collect all elements including the root\n walk(root);\n\n // Is this worth having? Most sorts will always add increased overhead. And positive tabindexes shouldn't really be used.\n // So is it worth being right? Or fast?\n return tabbableElements.sort((a, b) => {\n // Make sure we sort by tabindex.\n const aTabindex = Number(a.getAttribute('tabindex')) || 0;\n const bTabindex = Number(b.getAttribute('tabindex')) || 0;\n return bTabindex - aTabindex;\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sources":["../../src/internal/watch.ts"],"sourcesContent":["import type { LitElement } from 'lit';\n\ntype UpdateHandler = (prev?: unknown, next?: unknown) => void;\n\ntype NonUndefined<A> = A extends undefined ? never : A;\n\ntype UpdateHandlerFunctionKeys<T extends object> = {\n [K in keyof T]-?: NonUndefined<T[K]> extends UpdateHandler ? K : never;\n}[keyof T];\n\ninterface WatchOptions {\n /**\n * If true, will only start watching after the initial update/render\n */\n waitUntilFirstUpdate?: boolean;\n}\n\n/**\n * Runs when observed properties change, e.g. @property or @state, but before the component updates. To wait for an\n * update to complete after a change occurs, use `await this.updateComplete` in the handler. To start watching after the\n * initial update/render, use `{ waitUntilFirstUpdate: true }` or `this.hasUpdated` in the handler.\n *\n * Usage:\n *\n * @watch('propName')\n * handlePropChange(oldValue, newValue) {\n * ...\n * }\n */\nexport function watch(propertyName: string | string[], options?: WatchOptions) {\n const resolvedOptions: Required<WatchOptions> = {\n waitUntilFirstUpdate: false,\n ...options,\n };\n return <ElemClass extends LitElement>(\n proto: ElemClass,\n decoratedFnName: UpdateHandlerFunctionKeys<ElemClass>\n ) => {\n // @ts-expect-error - update is a protected property\n const { update } = proto;\n const watchedProperties = Array.isArray(propertyName)\n ? propertyName\n : [propertyName];\n\n // @ts-expect-error - update is a protected property\n proto.update = function (\n this: ElemClass,\n changedProps: Map<keyof ElemClass, ElemClass[keyof ElemClass]>\n ) {\n watchedProperties.forEach((property) => {\n const key = property as keyof ElemClass;\n if (changedProps.has(key)) {\n const oldValue = changedProps.get(key);\n const newValue = this[key];\n\n if (oldValue !== newValue) {\n if (!resolvedOptions.waitUntilFirstUpdate || this.hasUpdated) {\n (this[decoratedFnName] as unknown as UpdateHandler)(\n oldValue,\n newValue\n );\n }\n }\n }\n });\n\n update.call(this, changedProps);\n };\n };\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"watch.js","sources":["../../src/internal/watch.ts"],"sourcesContent":["import type { LitElement } from 'lit';\n\ntype UpdateHandler = (prev?: unknown, next?: unknown) => void;\n\ntype NonUndefined<A> = A extends undefined ? never : A;\n\ntype UpdateHandlerFunctionKeys<T extends object> = {\n [K in keyof T]-?: NonUndefined<T[K]> extends UpdateHandler ? K : never;\n}[keyof T];\n\ninterface WatchOptions {\n /**\n * If true, will only start watching after the initial update/render\n */\n waitUntilFirstUpdate?: boolean;\n}\n\n/**\n * Runs when observed properties change, e.g. @property or @state, but before the component updates. To wait for an\n * update to complete after a change occurs, use `await this.updateComplete` in the handler. To start watching after the\n * initial update/render, use `{ waitUntilFirstUpdate: true }` or `this.hasUpdated` in the handler.\n *\n * Usage:\n *\n * @watch('propName')\n * handlePropChange(oldValue, newValue) {\n * ...\n * }\n */\nexport function watch(propertyName: string | string[], options?: WatchOptions) {\n const resolvedOptions: Required<WatchOptions> = {\n waitUntilFirstUpdate: false,\n ...options,\n };\n return <ElemClass extends LitElement>(\n proto: ElemClass,\n decoratedFnName: UpdateHandlerFunctionKeys<ElemClass>\n ) => {\n // @ts-expect-error - update is a protected property\n const { update } = proto;\n const watchedProperties = Array.isArray(propertyName)\n ? propertyName\n : [propertyName];\n\n // @ts-expect-error - update is a protected property\n proto.update = function (\n this: ElemClass,\n changedProps: Map<keyof ElemClass, ElemClass[keyof ElemClass]>\n ) {\n watchedProperties.forEach((property) => {\n const key = property as keyof ElemClass;\n if (changedProps.has(key)) {\n const oldValue = changedProps.get(key);\n const newValue = this[key];\n\n if (oldValue !== newValue) {\n if (!resolvedOptions.waitUntilFirstUpdate || this.hasUpdated) {\n (this[decoratedFnName] as unknown as UpdateHandler)(\n oldValue,\n newValue\n );\n }\n }\n }\n });\n\n update.call(this, changedProps);\n };\n };\n}\n"],"names":[],"mappings":"AA6BO,SAAS,MAAM,cAAiC,SAAwB;AAC7E,QAAM,kBAA0C;AAAA,IAC9C,sBAAsB;AAAA,IACtB,GAAG;AAAA,EAAA;AAEL,SAAO,CACL,OACA,oBACG;AAEH,UAAM,EAAE,WAAW;AACnB,UAAM,oBAAoB,MAAM,QAAQ,YAAY,IAChD,eACA,CAAC,YAAY;AAGjB,UAAM,SAAS,SAEb,cACA;AACA,wBAAkB,QAAQ,CAAC,aAAa;AACtC,cAAM,MAAM;AACZ,YAAI,aAAa,IAAI,GAAG,GAAG;AACzB,gBAAM,WAAW,aAAa,IAAI,GAAG;AACrC,gBAAM,WAAW,KAAK,GAAG;AAEzB,cAAI,aAAa,UAAU;AACzB,gBAAI,CAAC,gBAAgB,wBAAwB,KAAK,YAAY;AAC3D,mBAAK,eAAe;AAAA,gBACnB;AAAA,gBACA;AAAA,cAAA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CACD;AAED,aAAO,KAAK,MAAM,YAAY;AAAA,IAAA;AAAA,EAChC;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-control.mixin.js","sources":["../../src/mixins/form-control.mixin.ts"],"sourcesContent":["import { LitElement } from 'lit';\nimport type { IControlHost } from '../types/control-host';\nimport type { FormControlInterface } from '../types/form-control';\nimport type { FormValue } from '../types/form-value';\nimport type { Constructor } from '../types/mixin-constructor';\nimport type {\n CustomValidityState,\n validationMessageCallback,\n Validator,\n} from '../types/validator.type';\n\n/**\n *\n * https://github.com/open-wc/form-participation/tree/main/packages/form-control\n */\nexport function FormControlMixin<\n TBase extends Constructor<LitElement & IControlHost> & {\n observedAttributes?: string[];\n },\n>(SuperClass: TBase) {\n class FormControl extends SuperClass {\n /**\n * Wires up control instances to be form associated\n * @ignore\n */\n static get formAssociated(): boolean {\n return true;\n }\n\n /**\n * A list of Validator objects that will be evaluated when a control's form\n * value is modified or optionally when a given attribute changes.\n *\n * When a Validator's callback returns false, the entire form control will\n * be set to an invalid state.\n * @ignore\n */\n declare static formControlValidators: Validator[];\n\n /**\n * If set to true the control described should be evaluated and validated\n * as part of a group. Like a radio, if any member of the group's validity\n * changes the the other members should update as well.\n * @ignore\n */\n declare static formControlValidationGroup: boolean;\n\n /**\n * @ignore\n */\n private static get validators(): Validator[] {\n return this.formControlValidators || [];\n }\n\n /**\n * Allows the FormControl instance to respond to Validator attributes.\n * For instance, if a given Validator has a `required` attribute, that\n * validator will be evaluated whenever the host's required attribute\n * is updated.\n * @ignore\n */\n static get observedAttributes(): string[] {\n const validatorAttributes = this.validators\n .map((validator) => validator.attribute)\n .flat();\n\n const observedAttributes = super.observedAttributes || [];\n\n /** Make sure there are no duplicates inside the attributes list */\n const attributeSet = new Set([\n ...observedAttributes,\n ...validatorAttributes,\n ]);\n return [...attributeSet] as string[];\n }\n\n /**\n * Return the validator associated with a given attribute. If no\n * Validator is associated with the attribute, it will return null.\n * @ignore\n */\n static getValidator(attribute: string): Validator | null {\n return (\n this.validators.find(\n (validator) => validator.attribute === attribute\n ) || null\n );\n }\n\n /**\n * Get all validators that are set to react to a given attribute\n * @param {string} attribute - The attribute that has changed\n * @returns {Validator[]}\n * @ignore\n */\n static getValidators(attribute: string): Validator[] | null {\n return this.validators.filter((validator) => {\n if (\n validator.attribute === attribute ||\n validator.attribute?.includes(attribute)\n ) {\n return true;\n }\n });\n }\n\n /**\n * The ElementInternals instance for the control.\n * @ignore\n */\n internals = this.attachInternals();\n\n /**\n * Keep track of if the control has focus\n * @private\n * @ignore\n */\n #focused = false;\n\n /**\n * Exists to control when an error should be displayed\n * @private\n * @ignore\n */\n #forceError = false;\n\n /**\n * Toggles to true whenever the element has been focused. This property\n * will reset whenever the control's formResetCallback is called.\n * @private\n * @ignore\n */\n #touched = false;\n\n /**\n * An internal abort controller for cancelling pending async validation\n * @ignore\n */\n #abortController?: AbortController;\n\n /**\n * Used for tracking if a validation target has been set to manage focus\n * when the control's validity is reported\n * @ignore\n */\n #awaitingValidationTarget = true;\n\n /**\n * Acts as a cache for the current value so the value can be re-evaluated\n * whenever an attribute changes or on some other event.\n * @ignore\n */\n #value: FormValue = '';\n\n /**\n * Set this[touched] and this[focused]\n * to true when the element is focused\n * @private\n * @ignore\n */\n #onFocus = (): void => {\n this.#touched = true;\n this.#focused = true;\n this.#shouldShowError();\n };\n\n /**\n * Reset this[focused] on blur\n * @private\n * @ignore\n */\n #onBlur = (): void => {\n this.#focused = false;\n\n this.#runValidators(this.shouldFormValueUpdate() ? this.#value : '');\n\n /**\n * Set forceError to ensure error messages persist until\n * the value is changed.\n */\n if (!this.validity.valid && this.#touched) {\n this.#forceError = true;\n }\n const showError = this.#shouldShowError();\n\n if (this.validationMessageCallback) {\n this.validationMessageCallback(showError ? this.validationMessage : '');\n }\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * For the show error state on invalid\n * @private\n * @ignore\n */\n #onInvalid = (event?: Event): void => {\n event?.preventDefault();\n event?.stopImmediatePropagation();\n\n if (this.#awaitingValidationTarget && this.validationTarget) {\n this.internals.setValidity(\n this.validity,\n this.validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n }\n this.#touched = true;\n this.#forceError = true;\n const showError = this.#shouldShowError();\n this?.validationMessageCallback?.(\n showError ? this.validationMessage : ''\n );\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * Return a reference to the control's form\n * @ignore\n */\n get form(): HTMLFormElement {\n return this.internals.form as HTMLFormElement;\n }\n\n /**\n * Will return true if it is recommended that the control shows an internal\n * error. If using this property, it is wise to listen for 'invalid' events\n * on the element host and call preventDefault on the event. Doing this will\n * prevent browsers from showing a validation popup.\n * @ignore\n */\n get showError(): boolean {\n return this.#shouldShowError();\n }\n\n /**\n * Forward the internals checkValidity method\n * will return the valid state of the control.\n * @ignore\n */\n checkValidity(): boolean {\n return this.internals.checkValidity();\n }\n\n /**\n * The element's validity state\n * @ignore\n */\n get validity(): ValidityState {\n return this.internals.validity;\n }\n\n /**\n * The validation message shown by a given Validator object. If the control\n * is in a valid state this should be falsy.\n * @ignore\n */\n get validationMessage(): string {\n return this.internals.validationMessage;\n }\n\n constructor(...args: any[]) {\n super(...args);\n this.addEventListener?.('focus', this.#onFocus);\n this.addEventListener?.('blur', this.#onBlur);\n this.addEventListener?.('invalid', this.#onInvalid);\n this.setValue(null);\n }\n\n attributeChangedCallback(\n name: string,\n oldValue: string,\n newValue: string\n ): void {\n super.attributeChangedCallback?.(name, oldValue, newValue);\n\n /**\n * Check to see if a Validator is associated with the changed attribute.\n * If one exists, call control's validate function which will perform\n * control validation.\n * @ignore\n */\n const proto = this.constructor as typeof FormControl;\n const validators = proto.getValidators(name);\n\n if (validators?.length && this.validationTarget) {\n this.setValue(this.#value);\n }\n }\n\n /** PUBLIC LIFECYCLE METHODS */\n\n /**\n * Sets the control's form value if the call to `shouldFormValueUpdate`\n * returns `true`.\n * @param value {FormValue} - The value to pass to the form\n * @ignore\n */\n setValue(value: FormValue): void {\n this.#forceError = false;\n this.validationMessageCallback?.('');\n this.#value = value;\n const valueShouldUpdate = this.shouldFormValueUpdate();\n const valueToUpdate = valueShouldUpdate ? value : null;\n this.internals.setFormValue(valueToUpdate as string);\n this.#runValidators(valueToUpdate);\n if (this.valueChangedCallback) {\n this.valueChangedCallback(valueToUpdate);\n }\n const showError = this.#shouldShowError();\n this.#dispatchInvalidEvent(showError);\n }\n\n /**\n * Forces the control to show an error state. If a message is passed in,\n * it will be set as the control's internal validity state message.\n * @param message { string | undefined } - The message for internals validity state\n */\n forceError(message?: string) {\n if (message) {\n this.#setValidityWithOptionalTarget({ customError: true }, message);\n }\n this.#forceError = true;\n this.#shouldShowError();\n }\n\n /**\n * This method can be overridden to determine if the control's form value\n * should be set on a call to `setValue`. An example of when a user might want\n * to skip this step is when implementing checkbox-like behavior, first checking\n * to see if `this.checked` is set to a truthy value. By default this returns\n * `true`.\n * @ignore\n */\n shouldFormValueUpdate(): boolean {\n return true;\n }\n\n /**\n * Save a reference to the validation complete resolver\n * @ignore\n */\n #validationCompleteResolver?: (value: void | PromiseLike<void>) => void;\n\n /**\n * When true validation will be pending\n * @ignore\n */\n #isValidationPending = false;\n\n /**\n * @ignore\n */\n #validationComplete = Promise.resolve();\n\n /**\n * A promise that will resolve when all pending validations are complete\n * @ignore\n */\n get validationComplete(): Promise<void> {\n return new Promise((resolve) => resolve(this.#validationComplete));\n }\n\n /** DECLARED INSTANCE METHODS AND PROPERTIES*/\n\n /**\n * Resets a form control to its initial state\n * @ignore\n */\n declare resetFormControl: () => void;\n\n /**\n * This method is used to override the controls' validity message\n * for a given Validator key. This has the highest level of priority when\n * setting a validationMessage, so use this method wisely.\n *\n * The returned value will be used as the validationMessage for the given key.\n * @param validationKey {string} - The key that has returned invalid\n * @ignore\n */\n declare validityCallback: (validationKey: string) => string | void;\n\n /**\n * Called when the control's validationMessage should be changed\n * @param message { string } - The new validation message\n * @ignore\n */\n declare validationMessageCallback: (message: string) => void;\n\n /**\n * A callback for when the controls' form value changes. The value\n * passed to this function should not be confused with the control's\n * value property, this is the value that will appear on the form.\n *\n * In cases where `checked` did not exist on the control's prototype\n * upon initialization, this value and the value property will be identical;\n * in cases where `checked` is present upon initialization, this will be\n * effectively `this.checked && this.value`.\n * @ignore\n */\n declare valueChangedCallback: (value: FormValue) => void;\n\n /**\n * The element that will receive focus when the control's validity\n * state is reported either by a form submission or via API\n *\n * We use declare since this is optional and we don't particularly\n * care how the consuming component implements this (as a field, member\n * or getter/setter)\n * @ignore\n */\n declare validationTarget: HTMLElement | null;\n\n /** PRIVATE LIFECYCLE METHODS */\n\n /**\n * Check to see if an error should be shown. This method will also\n * update the internals state object with the --show-error state\n * if necessary.\n * @private\n * @ignore\n */\n #shouldShowError(): boolean {\n if (this.hasAttribute('disabled')) {\n return false;\n }\n\n const showError =\n this.#forceError ||\n (this.#touched && !this.validity.valid && !this.#focused);\n\n if (showError && this.internals.states) {\n this.internals.states.add('--show-error');\n this.internals.states.add('--invalid');\n } else if (this.internals.states) {\n this.internals.states.delete('--show-error');\n this.internals.states.delete('--invalid');\n }\n\n return showError;\n }\n\n #runValidators(value: FormValue): void {\n const proto = this.constructor as typeof FormControl;\n const validity: CustomValidityState = {};\n const validators = proto.validators;\n const asyncValidators: Promise<boolean | void>[] = [];\n const hasAsyncValidators = validators.some(\n (validator) => validator.isValid instanceof Promise\n );\n\n if (!this.#isValidationPending) {\n this.#validationComplete = new Promise((resolve) => {\n this.#validationCompleteResolver = resolve;\n });\n this.#isValidationPending = true;\n }\n\n /**\n * If an abort controller exists from a previous validation step\n * notify still-running async validators that we are requesting they\n * discontinue any work.\n */\n if (this.#abortController) {\n this.#abortController.abort();\n }\n\n /**\n * Create a new abort controller and replace the instance reference\n * so we can clean it up for next time\n */\n const abortController = new AbortController();\n this.#abortController = abortController;\n let validationMessage: string | undefined = undefined;\n\n /** Track to see if any validity key has changed */\n let hasChange = false;\n\n if (!validators.length) {\n return;\n }\n\n validators.forEach((validator) => {\n const key = validator.key || 'customError';\n const isValid = validator.isValid(this, value, abortController.signal);\n const isAsyncValidator = isValid instanceof Promise;\n\n if (isAsyncValidator) {\n asyncValidators.push(isValid);\n\n isValid.then((isValidatorValid) => {\n if (isValidatorValid === undefined || isValidatorValid === null) {\n return;\n }\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValidatorValid;\n\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n });\n } else {\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValid;\n\n if (this.validity[key] !== !isValid) {\n hasChange = true;\n }\n\n // only update the validationMessage for the first invalid scenario\n // so that earlier invalid validators dont get their messages overwritten by later ones\n // in the validators array\n if (!isValid && !validationMessage) {\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n }\n }\n });\n\n /** Once all the async validators have settled, resolve validationComplete */\n Promise.allSettled(asyncValidators).then(() => {\n /** Don't resolve validations if the signal is aborted */\n if (!abortController?.signal.aborted) {\n this.#isValidationPending = false;\n this.#validationCompleteResolver?.();\n }\n });\n\n /**\n * If async validators are present:\n * Only run updates when a sync validator has a change. This is to prevent\n * situations where running sync validators can override async validators\n * that are still in progress\n *\n * If async validators are not present, always update validity\n */\n if (hasChange || !hasAsyncValidators) {\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n }\n }\n\n /**\n * If the validationTarget is not set, the user can decide how they would\n * prefer to handle focus when the field is validated.\n * @ignore\n */\n #setValidityWithOptionalTarget(\n validity: Partial<ValidityState>,\n validationMessage: string | undefined\n ): void {\n if (this.validationTarget) {\n this.internals.setValidity(\n validity,\n validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n } else {\n this.internals.setValidity(validity, validationMessage);\n\n if (this.internals.validity.valid) {\n return;\n }\n\n /**\n * Sets mark the component as awaiting a validation target\n * if the element dispatches an invalid event, the #onInvalid listener\n * will check to see if the validation target has been set since this call\n * has run. This useful in cases like Lit's use of the query\n * decorator for setting the validationTarget or any scenario\n * where the validationTarget isn't available upon construction\n */\n this.#awaitingValidationTarget = true;\n }\n }\n\n /**\n * Process the validator message attribute\n * @ignore\n */\n #getValidatorMessageForValue(\n validator: Validator,\n value: FormValue\n ): string {\n /** If the validity callback exists and returns, use that as the result */\n\n if (this.validityCallback) {\n const message = this.validityCallback(validator.key || 'customError');\n\n if (message) {\n return message;\n }\n }\n\n if (validator.message instanceof Function) {\n return (validator.message as validationMessageCallback)(this, value);\n } else {\n return validator.message as string;\n }\n }\n\n /**\n * Reset control state when the form is reset\n */\n formResetCallback() {\n this.#touched = false;\n this.#forceError = false;\n this.#shouldShowError();\n this.resetFormControl?.();\n const showError = this.#shouldShowError();\n this.validationMessageCallback?.(showError ? this.validationMessage : '');\n this.#dispatchInvalidEvent(showError);\n }\n\n #dispatchInvalidEvent(showError: boolean) {\n const event = showError ? 'mid-invalid-show' : 'mid-invalid-hide';\n this.dispatchEvent(\n new CustomEvent(event, {\n bubbles: true,\n composed: true,\n detail: {\n validity: this.validity,\n },\n })\n );\n }\n }\n\n return FormControl as unknown as Constructor<FormControlInterface> & TBase;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"form-control.mixin.js","sources":["../../src/mixins/form-control.mixin.ts"],"sourcesContent":["import { LitElement } from 'lit';\nimport type { IControlHost } from '../types/control-host';\nimport type { FormControlInterface } from '../types/form-control';\nimport type { FormValue } from '../types/form-value';\nimport type { Constructor } from '../types/mixin-constructor';\nimport type {\n CustomValidityState,\n validationMessageCallback,\n Validator,\n} from '../types/validator.type';\n\n/**\n *\n * https://github.com/open-wc/form-participation/tree/main/packages/form-control\n */\nexport function FormControlMixin<\n TBase extends Constructor<LitElement & IControlHost> & {\n observedAttributes?: string[];\n },\n>(SuperClass: TBase) {\n class FormControl extends SuperClass {\n /**\n * Wires up control instances to be form associated\n * @ignore\n */\n static get formAssociated(): boolean {\n return true;\n }\n\n /**\n * A list of Validator objects that will be evaluated when a control's form\n * value is modified or optionally when a given attribute changes.\n *\n * When a Validator's callback returns false, the entire form control will\n * be set to an invalid state.\n * @ignore\n */\n declare static formControlValidators: Validator[];\n\n /**\n * If set to true the control described should be evaluated and validated\n * as part of a group. Like a radio, if any member of the group's validity\n * changes the the other members should update as well.\n * @ignore\n */\n declare static formControlValidationGroup: boolean;\n\n /**\n * @ignore\n */\n private static get validators(): Validator[] {\n return this.formControlValidators || [];\n }\n\n /**\n * Allows the FormControl instance to respond to Validator attributes.\n * For instance, if a given Validator has a `required` attribute, that\n * validator will be evaluated whenever the host's required attribute\n * is updated.\n * @ignore\n */\n static get observedAttributes(): string[] {\n const validatorAttributes = this.validators\n .map((validator) => validator.attribute)\n .flat();\n\n const observedAttributes = super.observedAttributes || [];\n\n /** Make sure there are no duplicates inside the attributes list */\n const attributeSet = new Set([\n ...observedAttributes,\n ...validatorAttributes,\n ]);\n return [...attributeSet] as string[];\n }\n\n /**\n * Return the validator associated with a given attribute. If no\n * Validator is associated with the attribute, it will return null.\n * @ignore\n */\n static getValidator(attribute: string): Validator | null {\n return (\n this.validators.find(\n (validator) => validator.attribute === attribute\n ) || null\n );\n }\n\n /**\n * Get all validators that are set to react to a given attribute\n * @param {string} attribute - The attribute that has changed\n * @returns {Validator[]}\n * @ignore\n */\n static getValidators(attribute: string): Validator[] | null {\n return this.validators.filter((validator) => {\n if (\n validator.attribute === attribute ||\n validator.attribute?.includes(attribute)\n ) {\n return true;\n }\n });\n }\n\n /**\n * The ElementInternals instance for the control.\n * @ignore\n */\n internals = this.attachInternals();\n\n /**\n * Keep track of if the control has focus\n * @private\n * @ignore\n */\n #focused = false;\n\n /**\n * Exists to control when an error should be displayed\n * @private\n * @ignore\n */\n #forceError = false;\n\n /**\n * Toggles to true whenever the element has been focused. This property\n * will reset whenever the control's formResetCallback is called.\n * @private\n * @ignore\n */\n #touched = false;\n\n /**\n * An internal abort controller for cancelling pending async validation\n * @ignore\n */\n #abortController?: AbortController;\n\n /**\n * Used for tracking if a validation target has been set to manage focus\n * when the control's validity is reported\n * @ignore\n */\n #awaitingValidationTarget = true;\n\n /**\n * Acts as a cache for the current value so the value can be re-evaluated\n * whenever an attribute changes or on some other event.\n * @ignore\n */\n #value: FormValue = '';\n\n /**\n * Set this[touched] and this[focused]\n * to true when the element is focused\n * @private\n * @ignore\n */\n #onFocus = (): void => {\n this.#touched = true;\n this.#focused = true;\n this.#shouldShowError();\n };\n\n /**\n * Reset this[focused] on blur\n * @private\n * @ignore\n */\n #onBlur = (): void => {\n this.#focused = false;\n\n this.#runValidators(this.shouldFormValueUpdate() ? this.#value : '');\n\n /**\n * Set forceError to ensure error messages persist until\n * the value is changed.\n */\n if (!this.validity.valid && this.#touched) {\n this.#forceError = true;\n }\n const showError = this.#shouldShowError();\n\n if (this.validationMessageCallback) {\n this.validationMessageCallback(showError ? this.validationMessage : '');\n }\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * For the show error state on invalid\n * @private\n * @ignore\n */\n #onInvalid = (event?: Event): void => {\n event?.preventDefault();\n event?.stopImmediatePropagation();\n\n if (this.#awaitingValidationTarget && this.validationTarget) {\n this.internals.setValidity(\n this.validity,\n this.validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n }\n this.#touched = true;\n this.#forceError = true;\n const showError = this.#shouldShowError();\n this?.validationMessageCallback?.(\n showError ? this.validationMessage : ''\n );\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * Return a reference to the control's form\n * @ignore\n */\n get form(): HTMLFormElement {\n return this.internals.form as HTMLFormElement;\n }\n\n /**\n * Will return true if it is recommended that the control shows an internal\n * error. If using this property, it is wise to listen for 'invalid' events\n * on the element host and call preventDefault on the event. Doing this will\n * prevent browsers from showing a validation popup.\n * @ignore\n */\n get showError(): boolean {\n return this.#shouldShowError();\n }\n\n /**\n * Forward the internals checkValidity method\n * will return the valid state of the control.\n * @ignore\n */\n checkValidity(): boolean {\n return this.internals.checkValidity();\n }\n\n /**\n * The element's validity state\n * @ignore\n */\n get validity(): ValidityState {\n return this.internals.validity;\n }\n\n /**\n * The validation message shown by a given Validator object. If the control\n * is in a valid state this should be falsy.\n * @ignore\n */\n get validationMessage(): string {\n return this.internals.validationMessage;\n }\n\n constructor(...args: any[]) {\n super(...args);\n this.addEventListener?.('focus', this.#onFocus);\n this.addEventListener?.('blur', this.#onBlur);\n this.addEventListener?.('invalid', this.#onInvalid);\n this.setValue(null);\n }\n\n attributeChangedCallback(\n name: string,\n oldValue: string,\n newValue: string\n ): void {\n super.attributeChangedCallback?.(name, oldValue, newValue);\n\n /**\n * Check to see if a Validator is associated with the changed attribute.\n * If one exists, call control's validate function which will perform\n * control validation.\n * @ignore\n */\n const proto = this.constructor as typeof FormControl;\n const validators = proto.getValidators(name);\n\n if (validators?.length && this.validationTarget) {\n this.setValue(this.#value);\n }\n }\n\n /** PUBLIC LIFECYCLE METHODS */\n\n /**\n * Sets the control's form value if the call to `shouldFormValueUpdate`\n * returns `true`.\n * @param value {FormValue} - The value to pass to the form\n * @ignore\n */\n setValue(value: FormValue): void {\n this.#forceError = false;\n this.validationMessageCallback?.('');\n this.#value = value;\n const valueShouldUpdate = this.shouldFormValueUpdate();\n const valueToUpdate = valueShouldUpdate ? value : null;\n this.internals.setFormValue(valueToUpdate as string);\n this.#runValidators(valueToUpdate);\n if (this.valueChangedCallback) {\n this.valueChangedCallback(valueToUpdate);\n }\n const showError = this.#shouldShowError();\n this.#dispatchInvalidEvent(showError);\n }\n\n /**\n * Forces the control to show an error state. If a message is passed in,\n * it will be set as the control's internal validity state message.\n * @param message { string | undefined } - The message for internals validity state\n */\n forceError(message?: string) {\n if (message) {\n this.#setValidityWithOptionalTarget({ customError: true }, message);\n }\n this.#forceError = true;\n this.#shouldShowError();\n }\n\n /**\n * This method can be overridden to determine if the control's form value\n * should be set on a call to `setValue`. An example of when a user might want\n * to skip this step is when implementing checkbox-like behavior, first checking\n * to see if `this.checked` is set to a truthy value. By default this returns\n * `true`.\n * @ignore\n */\n shouldFormValueUpdate(): boolean {\n return true;\n }\n\n /**\n * Save a reference to the validation complete resolver\n * @ignore\n */\n #validationCompleteResolver?: (value: void | PromiseLike<void>) => void;\n\n /**\n * When true validation will be pending\n * @ignore\n */\n #isValidationPending = false;\n\n /**\n * @ignore\n */\n #validationComplete = Promise.resolve();\n\n /**\n * A promise that will resolve when all pending validations are complete\n * @ignore\n */\n get validationComplete(): Promise<void> {\n return new Promise((resolve) => resolve(this.#validationComplete));\n }\n\n /** DECLARED INSTANCE METHODS AND PROPERTIES*/\n\n /**\n * Resets a form control to its initial state\n * @ignore\n */\n declare resetFormControl: () => void;\n\n /**\n * This method is used to override the controls' validity message\n * for a given Validator key. This has the highest level of priority when\n * setting a validationMessage, so use this method wisely.\n *\n * The returned value will be used as the validationMessage for the given key.\n * @param validationKey {string} - The key that has returned invalid\n * @ignore\n */\n declare validityCallback: (validationKey: string) => string | void;\n\n /**\n * Called when the control's validationMessage should be changed\n * @param message { string } - The new validation message\n * @ignore\n */\n declare validationMessageCallback: (message: string) => void;\n\n /**\n * A callback for when the controls' form value changes. The value\n * passed to this function should not be confused with the control's\n * value property, this is the value that will appear on the form.\n *\n * In cases where `checked` did not exist on the control's prototype\n * upon initialization, this value and the value property will be identical;\n * in cases where `checked` is present upon initialization, this will be\n * effectively `this.checked && this.value`.\n * @ignore\n */\n declare valueChangedCallback: (value: FormValue) => void;\n\n /**\n * The element that will receive focus when the control's validity\n * state is reported either by a form submission or via API\n *\n * We use declare since this is optional and we don't particularly\n * care how the consuming component implements this (as a field, member\n * or getter/setter)\n * @ignore\n */\n declare validationTarget: HTMLElement | null;\n\n /** PRIVATE LIFECYCLE METHODS */\n\n /**\n * Check to see if an error should be shown. This method will also\n * update the internals state object with the --show-error state\n * if necessary.\n * @private\n * @ignore\n */\n #shouldShowError(): boolean {\n if (this.hasAttribute('disabled')) {\n return false;\n }\n\n const showError =\n this.#forceError ||\n (this.#touched && !this.validity.valid && !this.#focused);\n\n if (showError && this.internals.states) {\n this.internals.states.add('--show-error');\n this.internals.states.add('--invalid');\n } else if (this.internals.states) {\n this.internals.states.delete('--show-error');\n this.internals.states.delete('--invalid');\n }\n\n return showError;\n }\n\n #runValidators(value: FormValue): void {\n const proto = this.constructor as typeof FormControl;\n const validity: CustomValidityState = {};\n const validators = proto.validators;\n const asyncValidators: Promise<boolean | void>[] = [];\n const hasAsyncValidators = validators.some(\n (validator) => validator.isValid instanceof Promise\n );\n\n if (!this.#isValidationPending) {\n this.#validationComplete = new Promise((resolve) => {\n this.#validationCompleteResolver = resolve;\n });\n this.#isValidationPending = true;\n }\n\n /**\n * If an abort controller exists from a previous validation step\n * notify still-running async validators that we are requesting they\n * discontinue any work.\n */\n if (this.#abortController) {\n this.#abortController.abort();\n }\n\n /**\n * Create a new abort controller and replace the instance reference\n * so we can clean it up for next time\n */\n const abortController = new AbortController();\n this.#abortController = abortController;\n let validationMessage: string | undefined = undefined;\n\n /** Track to see if any validity key has changed */\n let hasChange = false;\n\n if (!validators.length) {\n return;\n }\n\n validators.forEach((validator) => {\n const key = validator.key || 'customError';\n const isValid = validator.isValid(this, value, abortController.signal);\n const isAsyncValidator = isValid instanceof Promise;\n\n if (isAsyncValidator) {\n asyncValidators.push(isValid);\n\n isValid.then((isValidatorValid) => {\n if (isValidatorValid === undefined || isValidatorValid === null) {\n return;\n }\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValidatorValid;\n\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n });\n } else {\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValid;\n\n if (this.validity[key] !== !isValid) {\n hasChange = true;\n }\n\n // only update the validationMessage for the first invalid scenario\n // so that earlier invalid validators dont get their messages overwritten by later ones\n // in the validators array\n if (!isValid && !validationMessage) {\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n }\n }\n });\n\n /** Once all the async validators have settled, resolve validationComplete */\n Promise.allSettled(asyncValidators).then(() => {\n /** Don't resolve validations if the signal is aborted */\n if (!abortController?.signal.aborted) {\n this.#isValidationPending = false;\n this.#validationCompleteResolver?.();\n }\n });\n\n /**\n * If async validators are present:\n * Only run updates when a sync validator has a change. This is to prevent\n * situations where running sync validators can override async validators\n * that are still in progress\n *\n * If async validators are not present, always update validity\n */\n if (hasChange || !hasAsyncValidators) {\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n }\n }\n\n /**\n * If the validationTarget is not set, the user can decide how they would\n * prefer to handle focus when the field is validated.\n * @ignore\n */\n #setValidityWithOptionalTarget(\n validity: Partial<ValidityState>,\n validationMessage: string | undefined\n ): void {\n if (this.validationTarget) {\n this.internals.setValidity(\n validity,\n validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n } else {\n this.internals.setValidity(validity, validationMessage);\n\n if (this.internals.validity.valid) {\n return;\n }\n\n /**\n * Sets mark the component as awaiting a validation target\n * if the element dispatches an invalid event, the #onInvalid listener\n * will check to see if the validation target has been set since this call\n * has run. This useful in cases like Lit's use of the query\n * decorator for setting the validationTarget or any scenario\n * where the validationTarget isn't available upon construction\n */\n this.#awaitingValidationTarget = true;\n }\n }\n\n /**\n * Process the validator message attribute\n * @ignore\n */\n #getValidatorMessageForValue(\n validator: Validator,\n value: FormValue\n ): string {\n /** If the validity callback exists and returns, use that as the result */\n\n if (this.validityCallback) {\n const message = this.validityCallback(validator.key || 'customError');\n\n if (message) {\n return message;\n }\n }\n\n if (validator.message instanceof Function) {\n return (validator.message as validationMessageCallback)(this, value);\n } else {\n return validator.message as string;\n }\n }\n\n /**\n * Reset control state when the form is reset\n */\n formResetCallback() {\n this.#touched = false;\n this.#forceError = false;\n this.#shouldShowError();\n this.resetFormControl?.();\n const showError = this.#shouldShowError();\n this.validationMessageCallback?.(showError ? this.validationMessage : '');\n this.#dispatchInvalidEvent(showError);\n }\n\n #dispatchInvalidEvent(showError: boolean) {\n const event = showError ? 'mid-invalid-show' : 'mid-invalid-hide';\n this.dispatchEvent(\n new CustomEvent(event, {\n bubbles: true,\n composed: true,\n detail: {\n validity: this.validity,\n },\n })\n );\n }\n }\n\n return FormControl as unknown as Constructor<FormControlInterface> & TBase;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-controller.mixin.js","sources":["../../src/mixins/form-controller.mixin.ts"],"sourcesContent":["import { LitElement } from 'lit';\nimport type { Constructor } from '../types/mixin-constructor';\n\nexport interface FormAssociatedMixinInterface {\n internals: ElementInternals;\n shadowRoot: ShadowRoot | null;\n setFormValue(\n value: File | string | FormData | null,\n state?: File | string | FormData | null\n ): void;\n}\n\nexport const FormControllerMixin = <TBase extends Constructor<LitElement>>(\n Base: TBase\n): TBase & Constructor<FormAssociatedMixinInterface> => {\n class FormAssociated extends Base implements FormAssociatedMixinInterface {\n static formAssociated = true;\n\n internals: ElementInternals;\n\n constructor(...args: any[]) {\n super(...(args as ConstructorParameters<typeof Base>));\n // @ts-expect-error missing some u\n this.internals = this.attachInternals();\n }\n\n setFormValue(\n value: File | string | FormData | null,\n state?: File | string | FormData | null\n ) {\n this.internals.setFormValue(value, state);\n }\n\n get shadowRoot() {\n return this.internals.shadowRoot;\n }\n }\n\n return FormAssociated as TBase & Constructor<FormAssociatedMixinInterface>;\n};\n\nexport interface ConstraintsValidationMixinInterface\n extends FormAssociatedMixinInterface {\n validity: ValidityState;\n validationMessage: string | undefined;\n setValidity(\n validity: ValidityState,\n message?: string,\n anchor?: HTMLElement\n ): void;\n checkValidity(): boolean;\n reportValidity(): boolean;\n}\n\nexport const ConstraintsValidationMixin = <\n TBase extends Constructor<LitElement>,\n>(\n Base: TBase\n): TBase & Constructor<ConstraintsValidationMixinInterface> => {\n class ConstraintsValidation\n extends FormControllerMixin(Base)\n implements ConstraintsValidationMixinInterface\n {\n validity: ValidityState;\n validationMessage: string | undefined;\n\n constructor(...args: any[]) {\n super(...(args as ConstructorParameters<typeof Base>));\n this.validity = this.internals.validity;\n this.validationMessage = this.internals.validationMessage;\n }\n\n setValidity(\n validity: ValidityStateFlags,\n message?: string,\n anchor?: HTMLElement\n ) {\n this.validationMessage = message;\n this.internals.setValidity(validity, this.validationMessage, anchor);\n }\n\n checkValidity(): boolean {\n return this.internals.checkValidity();\n }\n\n reportValidity(): boolean {\n return this.internals.reportValidity();\n }\n }\n\n return ConstraintsValidation as TBase &\n Constructor<ConstraintsValidationMixinInterface>;\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"form-controller.mixin.js","sources":["../../src/mixins/form-controller.mixin.ts"],"sourcesContent":["import { LitElement } from 'lit';\nimport type { Constructor } from '../types/mixin-constructor';\n\nexport interface FormAssociatedMixinInterface {\n internals: ElementInternals;\n shadowRoot: ShadowRoot | null;\n setFormValue(\n value: File | string | FormData | null,\n state?: File | string | FormData | null\n ): void;\n}\n\nexport const FormControllerMixin = <TBase extends Constructor<LitElement>>(\n Base: TBase\n): TBase & Constructor<FormAssociatedMixinInterface> => {\n class FormAssociated extends Base implements FormAssociatedMixinInterface {\n static formAssociated = true;\n\n internals: ElementInternals;\n\n constructor(...args: any[]) {\n super(...(args as ConstructorParameters<typeof Base>));\n // @ts-expect-error missing some u\n this.internals = this.attachInternals();\n }\n\n setFormValue(\n value: File | string | FormData | null,\n state?: File | string | FormData | null\n ) {\n this.internals.setFormValue(value, state);\n }\n\n get shadowRoot() {\n return this.internals.shadowRoot;\n }\n }\n\n return FormAssociated as TBase & Constructor<FormAssociatedMixinInterface>;\n};\n\nexport interface ConstraintsValidationMixinInterface\n extends FormAssociatedMixinInterface {\n validity: ValidityState;\n validationMessage: string | undefined;\n setValidity(\n validity: ValidityState,\n message?: string,\n anchor?: HTMLElement\n ): void;\n checkValidity(): boolean;\n reportValidity(): boolean;\n}\n\nexport const ConstraintsValidationMixin = <\n TBase extends Constructor<LitElement>,\n>(\n Base: TBase\n): TBase & Constructor<ConstraintsValidationMixinInterface> => {\n class ConstraintsValidation\n extends FormControllerMixin(Base)\n implements ConstraintsValidationMixinInterface\n {\n validity: ValidityState;\n validationMessage: string | undefined;\n\n constructor(...args: any[]) {\n super(...(args as ConstructorParameters<typeof Base>));\n this.validity = this.internals.validity;\n this.validationMessage = this.internals.validationMessage;\n }\n\n setValidity(\n validity: ValidityStateFlags,\n message?: string,\n anchor?: HTMLElement\n ) {\n this.validationMessage = message;\n this.internals.setValidity(validity, this.validationMessage, anchor);\n }\n\n checkValidity(): boolean {\n return this.internals.checkValidity();\n }\n\n reportValidity(): boolean {\n return this.internals.reportValidity();\n }\n }\n\n return ConstraintsValidation as TBase &\n Constructor<ConstraintsValidationMixinInterface>;\n};\n"],"names":[],"mappings":"AAYO,MAAM,sBAAsB,CACjC,SACsD;AACtD,QAAM,kBAAN,MAAM,wBAAuB,KAA6C;AAAA,IAKxE,eAAe,MAAa;AAC1B,YAAM,GAAI,IAA2C;AAErD,WAAK,YAAY,KAAK,gBAAA;AAAA,IAAgB;AAAA,IAGxC,aACE,OACA,OACA;AACA,WAAK,UAAU,aAAa,OAAO,KAAK;AAAA,IAAA;AAAA,IAG1C,IAAI,aAAa;AACf,aAAO,KAAK,UAAU;AAAA,IAAA;AAAA,EACxB;AAnBA,kBAAO,iBAAiB;AAD1B,MAAM,iBAAN;AAuBA,SAAO;AACT;AAeO,MAAM,6BAA6B,CAGxC,SAC6D;AAAA,EAC7D,MAAM,8BACI,oBAAoB,IAAI,EAElC;AAAA,IAIE,eAAe,MAAa;AAC1B,YAAM,GAAI,IAA2C;AACrD,WAAK,WAAW,KAAK,UAAU;AAC/B,WAAK,oBAAoB,KAAK,UAAU;AAAA,IAAA;AAAA,IAG1C,YACE,UACA,SACA,QACA;AACA,WAAK,oBAAoB;AACzB,WAAK,UAAU,YAAY,UAAU,KAAK,mBAAmB,MAAM;AAAA,IAAA;AAAA,IAGrE,gBAAyB;AACvB,aAAO,KAAK,UAAU,cAAA;AAAA,IAAc;AAAA,IAGtC,iBAA0B;AACxB,aAAO,KAAK,UAAU,eAAA;AAAA,IAAe;AAAA,EACvC;AAGF,SAAO;AAET;"}
|
|
@@ -4,8 +4,8 @@ const styled = (superClass, elementCss = []) => {
|
|
|
4
4
|
return _a = class extends superClass {
|
|
5
5
|
constructor(..._) {
|
|
6
6
|
super();
|
|
7
|
-
this.tailwindLinkElement = document.
|
|
8
|
-
"tailwind
|
|
7
|
+
this.tailwindLinkElement = document.querySelector(
|
|
8
|
+
"[data-mid-tailwind]"
|
|
9
9
|
);
|
|
10
10
|
}
|
|
11
11
|
connectedCallback() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tailwind.mixin.js","sources":["../../src/mixins/tailwind.mixin.ts"],"sourcesContent":["import { type CSSResultArray, LitElement } from 'lit';\nimport type { Constructor } from '../types/mixin-constructor';\n\nconst tailwindSheet = new CSSStyleSheet();\n\nexport const styled = <T extends Constructor<LitElement>>(\n superClass: T,\n elementCss: CSSResultArray = []\n): T =>\n class extends superClass {\n static styles = [tailwindSheet, elementCss];\n tailwindLinkElement: HTMLStyleElement;\n\n constructor(..._: any[]) {\n super();\n this.tailwindLinkElement = document.
|
|
1
|
+
{"version":3,"file":"tailwind.mixin.js","sources":["../../src/mixins/tailwind.mixin.ts"],"sourcesContent":["import { type CSSResultArray, LitElement } from 'lit';\nimport type { Constructor } from '../types/mixin-constructor';\n\nconst tailwindSheet = new CSSStyleSheet();\n\nexport const styled = <T extends Constructor<LitElement>>(\n superClass: T,\n elementCss: CSSResultArray = []\n): T =>\n class extends superClass {\n static styles = [tailwindSheet, elementCss];\n tailwindLinkElement: HTMLStyleElement;\n\n constructor(..._: any[]) {\n super();\n this.tailwindLinkElement = document.querySelector(\n '[data-mid-tailwind]'\n ) as HTMLStyleElement;\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n\n if (tailwindSheet.cssRules.length) {\n return;\n }\n\n if (!this.tailwindLinkElement) {\n return;\n }\n\n this.tailwindLinkElement.addEventListener('load', () => {\n if (tailwindSheet.cssRules.length) {\n return;\n }\n\n this.insertCssRules();\n });\n\n // Handle cases where the stylesheet might already be in the cache\n this.insertCssRules();\n }\n\n private insertCssRules() {\n if (this.tailwindLinkElement.sheet) {\n Array.from(this.tailwindLinkElement.sheet.cssRules).forEach((rule) => {\n try {\n tailwindSheet.insertRule(\n rule.cssText,\n tailwindSheet.cssRules.length\n );\n } catch (error) {\n console.warn('Error inserting rule:', rule.cssText, error);\n }\n });\n } else {\n console.warn(\n 'Error getting css stylesheet from element with id \"tailwind-styles\"'\n );\n }\n }\n };\n"],"names":[],"mappings":"AAGA,MAAM,gBAAgB,IAAI,cAAA;AAEnB,MAAM,SAAS,CACpB,YACA,aAA6B,CAAA,MAAC;AAJhC;AAME,4BAAc,WAAW;AAAA,IAIvB,eAAe,GAAU;AACvB,YAAA;AACA,WAAK,sBAAsB,SAAS;AAAA,QAClC;AAAA,MAAA;AAAA,IACF;AAAA,IAGF,oBAA0B;AACxB,YAAM,kBAAA;AAEN,UAAI,cAAc,SAAS,QAAQ;AACjC;AAAA,MAAA;AAGF,UAAI,CAAC,KAAK,qBAAqB;AAC7B;AAAA,MAAA;AAGF,WAAK,oBAAoB,iBAAiB,QAAQ,MAAM;AACtD,YAAI,cAAc,SAAS,QAAQ;AACjC;AAAA,QAAA;AAGF,aAAK,eAAA;AAAA,MAAe,CACrB;AAGD,WAAK,eAAA;AAAA,IAAe;AAAA,IAGd,iBAAiB;AACvB,UAAI,KAAK,oBAAoB,OAAO;AAClC,cAAM,KAAK,KAAK,oBAAoB,MAAM,QAAQ,EAAE,QAAQ,CAAC,SAAS;AACpE,cAAI;AACF,0BAAc;AAAA,cACZ,KAAK;AAAA,cACL,cAAc,SAAS;AAAA,YAAA;AAAA,UACzB,SACO,OAAO;AACd,oBAAQ,KAAK,yBAAyB,KAAK,SAAS,KAAK;AAAA,UAAA;AAAA,QAC3D,CACD;AAAA,MAAA,OACI;AACL,gBAAQ;AAAA,UACN;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EAEJ,GAnDE,GAAO,SAAS,CAAC,eAAe,UAAU,GAD5C;AAAA;"}
|