@felleslosninger/minid-elements 0.1.0 → 0.1.1
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/dialog.component.d.ts +6 -0
- package/dist/components/dialog.component.d.ts.map +1 -1
- package/dist/components/dialog.js +19 -2
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/textfield.component.d.ts +3 -1
- package/dist/components/textfield.component.d.ts.map +1 -1
- package/dist/components/textfield.js +10 -2
- package/dist/components/textfield.js.map +1 -1
- package/dist/mixins/validators.d.ts +1 -0
- package/dist/mixins/validators.d.ts.map +1 -1
- package/dist/mixins/validators.js +18 -1
- package/dist/mixins/validators.js.map +1 -1
- package/dist/utilities/translations.d.ts +1 -0
- package/dist/utilities/translations.d.ts.map +1 -1
- package/dist/utilities/translations.js +8 -4
- package/dist/utilities/translations.js.map +1 -1
- package/package.json +1 -1
|
@@ -42,6 +42,11 @@ export declare class MinidDialog extends MinidDialog_base {
|
|
|
42
42
|
* `no-header`, as it is required for proper accessibility. If you need to display HTML, use the `label` slot instead.
|
|
43
43
|
*/
|
|
44
44
|
heading: string;
|
|
45
|
+
/**
|
|
46
|
+
* When set, the dialog uses `role="alertdialog"` instead of `role="dialog"`, signalling urgency to screen readers.
|
|
47
|
+
* Use this for blocking dialogs that require immediate user attention.
|
|
48
|
+
*/
|
|
49
|
+
alertdialog: boolean;
|
|
45
50
|
private requestClose;
|
|
46
51
|
handleDialogCancel: (event: Event) => void;
|
|
47
52
|
private handleBackdropClick;
|
|
@@ -54,6 +59,7 @@ export declare class MinidDialog extends MinidDialog_base {
|
|
|
54
59
|
* Hides the dialog
|
|
55
60
|
*/
|
|
56
61
|
hide(): Promise<void>;
|
|
62
|
+
constructor();
|
|
57
63
|
render(): import('lit').TemplateResult<1>;
|
|
58
64
|
}
|
|
59
65
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.component.d.ts","sourceRoot":"","sources":["../../src/components/dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,
|
|
1
|
+
{"version":3,"file":"dialog.component.d.ts","sourceRoot":"","sources":["../../src/components/dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAQrD,OAAO,uBAAuB,CAAC;AAQ/B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,WAAW,CAAC;KAC3B;CACF;;AAWD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBACa,WAAY,SAAQ,gBAA0B;IAEzD,MAAM,EAAG,iBAAiB,CAAC;IAE3B;;;OAGG;IAEH,IAAI,UAAS;IAEb;;;OAGG;IAEH,OAAO,SAAM;IAEb;;;OAGG;IAEH,WAAW,UAAS;IAEpB,OAAO,CAAC,YAAY;IAkBpB,kBAAkB,GAAI,OAAO,KAAK,UAQhC;IAEF,OAAO,CAAC,mBAAmB;IAQrB,gBAAgB;IAmDtB;;OAEG;IACG,IAAI;IASV;;OAEG;IACG,IAAI;;IAcD,MAAM;CAqChB"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { css, LitElement, html } from "lit";
|
|
1
|
+
import { css, LitElement, nothing, html } from "lit";
|
|
2
2
|
import { query, property, customElement } from "lit/decorators.js";
|
|
3
|
+
import { getLang } from "../utilities/lang.js";
|
|
4
|
+
import { getTranslations } from "../utilities/translations.js";
|
|
5
|
+
import { L as LangController } from "../lang.controller-P4W-9ipy.js";
|
|
3
6
|
import { waitForEvent } from "../internal/event.js";
|
|
4
7
|
import { watch } from "../internal/watch.js";
|
|
5
8
|
import { styled } from "../mixins/tailwind.mixin.js";
|
|
@@ -27,9 +30,10 @@ const styles = [
|
|
|
27
30
|
];
|
|
28
31
|
let MinidDialog = class extends styled(LitElement, styles) {
|
|
29
32
|
constructor() {
|
|
30
|
-
super(
|
|
33
|
+
super();
|
|
31
34
|
this.open = false;
|
|
32
35
|
this.heading = "";
|
|
36
|
+
this.alertdialog = false;
|
|
33
37
|
this.handleDialogCancel = (event) => {
|
|
34
38
|
event.preventDefault();
|
|
35
39
|
if (event.defaultPrevented) {
|
|
@@ -38,6 +42,7 @@ let MinidDialog = class extends styled(LitElement, styles) {
|
|
|
38
42
|
this.hide();
|
|
39
43
|
}
|
|
40
44
|
};
|
|
45
|
+
new LangController(this);
|
|
41
46
|
}
|
|
42
47
|
requestClose(source) {
|
|
43
48
|
const requestCloseEvent = new CustomEvent("mid-request-close", {
|
|
@@ -65,6 +70,9 @@ let MinidDialog = class extends styled(LitElement, styles) {
|
|
|
65
70
|
new Event("mid-show", { composed: true, bubbles: true })
|
|
66
71
|
);
|
|
67
72
|
this.dialog.showModal();
|
|
73
|
+
if (this.alertdialog) {
|
|
74
|
+
this.dialog.focus();
|
|
75
|
+
}
|
|
68
76
|
lockBodyScrolling(this);
|
|
69
77
|
const panelAnimation = getAnimation(this, "dialog.show");
|
|
70
78
|
await animateTo(
|
|
@@ -116,10 +124,15 @@ let MinidDialog = class extends styled(LitElement, styles) {
|
|
|
116
124
|
return waitForEvent(this, "mid-after-hide");
|
|
117
125
|
}
|
|
118
126
|
render() {
|
|
127
|
+
const t = getTranslations(getLang(this));
|
|
119
128
|
return html`
|
|
120
129
|
<dialog
|
|
121
130
|
part="base"
|
|
122
131
|
id="dialog"
|
|
132
|
+
tabindex="-1"
|
|
133
|
+
role=${this.alertdialog ? "alertdialog" : "dialog"}
|
|
134
|
+
aria-label=${this.heading || nothing}
|
|
135
|
+
aria-modal="true"
|
|
123
136
|
class="text-neutral m-auto max-h-[calc(100%---spacing(8))] w-(--width) max-w-[calc(100%---spacing(8))] flex-col rounded-lg p-6 shadow-xl backdrop:bg-black/50 open:flex open:animate-none"
|
|
124
137
|
@cancel=${this.handleDialogCancel}
|
|
125
138
|
@click=${this.handleBackdropClick}
|
|
@@ -129,6 +142,7 @@ let MinidDialog = class extends styled(LitElement, styles) {
|
|
|
129
142
|
<div class="h-0">
|
|
130
143
|
<button
|
|
131
144
|
autofocus
|
|
145
|
+
aria-label=${t.close}
|
|
132
146
|
@click="${() => this.requestClose("close-button")}"
|
|
133
147
|
class="text-body-md focus-visible:focus-ring text-neutral hover:bg-neutral-surface-hover float-right flex size-12 translate-x-3 -translate-y-3 items-center justify-center rounded"
|
|
134
148
|
>
|
|
@@ -155,6 +169,9 @@ __decorateClass([
|
|
|
155
169
|
__decorateClass([
|
|
156
170
|
property({ reflect: true })
|
|
157
171
|
], MinidDialog.prototype, "heading", 2);
|
|
172
|
+
__decorateClass([
|
|
173
|
+
property({ type: Boolean, reflect: true })
|
|
174
|
+
], MinidDialog.prototype, "alertdialog", 2);
|
|
158
175
|
__decorateClass([
|
|
159
176
|
watch("open", { waitUntilFirstUpdate: true })
|
|
160
177
|
], MinidDialog.prototype, "handleOpenChange", 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.js","sources":["../../src/components/dialog.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { waitForEvent } from '../internal/event';\nimport { watch } from '../internal/watch';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry';\nimport { animateTo, stopAnimations } from '../internal/animate';\nimport { lockBodyScrolling, unlockBodyScrolling } from '../internal/scroll';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-dialog': MinidDialog;\n }\n}\n\nconst styles = [\n css`\n :host {\n --width: 40rem;\n display: block;\n }\n `,\n];\n\n/**\n *\n * @event mid-show - Emitted when the dialog opens.\n * @event mid-after-show - Emitted after the dialog opens and all animations are complete.\n * @event mid-hide - Emitted when the dialog closes.\n * @event mid-after-hide - Emitted after the dialog closes and all animations are complete.\n * @event {{ source: 'close-button' | 'keyboard' | 'overlay' }} mid-request-close - Emitted when the user attempts to\n * close the dialog by clicking the close button, clicking the overlay, or pressing escape. Calling\n * `event.preventDefault()` will keep the dialog open. Avoid using this unless closing the dialog will result in\n * destructive behavior such as data loss.\n *\n * @csspart base - Select the base `dialog` element\n * @csspart header - Select the `header` element\n * @csspart body - Select the `article` element\n * @csspart footer - Select the `footer` element\n *\n * @slot -- The default slot for the body content of the dialog\n * @slot heading - The content inside the `h2` element\n * @slot footer - The content inside the `footer` element\n *\n * @animation dialog.show - The animation to use when showing the dialog.\n * @animation dialog.hide - The animation to use when hiding the dialog.\n * @animation dialog.denyClose - The animation to use when closing the dialog is prevented.\n *\n */\n@customElement('mid-dialog')\nexport class MinidDialog extends styled(LitElement, styles) {\n @query('#dialog')\n dialog!: HTMLDialogElement;\n\n /**\n * Indicates whether or not the dialog is open. You can toggle this attribute to show and hide the dialog, or you can\n * use the `show()` and `hide()` methods and this attribute will reflect the dialog's open state.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * The dialog's label as displayed in the header. You should always include a relevant label even when using\n * `no-header`, as it is required for proper accessibility. If you need to display HTML, use the `label` slot instead.\n */\n @property({ reflect: true })\n heading = '';\n\n private requestClose(source: 'close-button' | 'keyboard' | 'overlay') {\n const requestCloseEvent = new CustomEvent('mid-request-close', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { source },\n });\n this.dispatchEvent(requestCloseEvent);\n\n if (requestCloseEvent.defaultPrevented) {\n const { keyframes, options } = getAnimation(this, 'dialog.denyClose');\n animateTo(this.dialog, keyframes, options);\n return;\n }\n\n this.hide();\n }\n\n handleDialogCancel = (event: Event) => {\n event.preventDefault();\n\n if (event.defaultPrevented) {\n this.requestClose('keyboard');\n } else {\n this.hide();\n }\n };\n\n private handleBackdropClick({ target }: Event) {\n // if the target is the dialog, the backdrop was clicked\n if (target === this.dialog) {\n this.requestClose('overlay');\n }\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.open) {\n // Show\n this.dispatchEvent(\n new Event('mid-show', { composed: true, bubbles: true })\n );\n // this.addOpenListeners();\n this.dialog.showModal();\n\n lockBodyScrolling(this);\n\n const panelAnimation = getAnimation(this, 'dialog.show');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\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\n await Promise.all([stopAnimations(this.dialog)]);\n const panelAnimation = getAnimation(this, 'dialog.hide');\n\n // The backdrop can only be animated with css because it's a pseudo element\n // so we add a animation class to trigger it at the same time as the dialog animation\n this.dialog.classList.add('backdrop:animate-fade-out');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\n );\n this.dialog.classList.remove('backdrop:animate-fade-out');\n this.dialog.close();\n this.dialog.hidden = false;\n unlockBodyScrolling(this);\n this.dispatchEvent(\n new Event('mid-after-hide', { composed: true, bubbles: true })\n );\n }\n }\n\n /**\n * Shows the dialog.\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 dialog\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 <dialog\n part=\"base\"\n id=\"dialog\"\n class=\"text-neutral m-auto max-h-[calc(100%---spacing(8))] w-(--width) max-w-[calc(100%---spacing(8))] flex-col rounded-lg p-6 shadow-xl backdrop:bg-black/50 open:flex open:animate-none\"\n @cancel=${this.handleDialogCancel}\n @click=${this.handleBackdropClick}\n >\n <header part=\"header\" class=\"text-heading-sm flex justify-between\">\n <slot name=\"heading\"></slot>\n <div class=\"h-0\">\n <button\n autofocus\n @click=\"${() => this.requestClose('close-button')}\"\n class=\"text-body-md focus-visible:focus-ring text-neutral hover:bg-neutral-surface-hover float-right flex size-12 translate-x-3 -translate-y-3 items-center justify-center rounded\"\n >\n <mid-icon class=\"size-6\" name=\"xmark\"></mid-icon>\n </button>\n </div>\n </header>\n <div part=\"body\" class=\"overflow-auto\">\n <slot> </slot>\n </div>\n <footer part=\"footer\">\n <slot name=\"footer\"> </slot>\n </footer>\n </dialog>\n `;\n }\n}\n\nsetDefaultAnimation('dialog.show', {\n keyframes: [\n { opacity: 0, scale: 0.8 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.8 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.denyClose', {\n keyframes: [{ scale: 1 }, { scale: 1.03 }, { scale: 1 }],\n options: { duration: 100 },\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,MAAM,SAAS;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF;AA4BO,IAAM,cAAN,cAA0B,OAAO,YAAY,MAAM,EAAE;AAAA,EAArD,cAAA;AAAA,UAAA,GAAA,SAAA;AASL,SAAA,OAAO;AAOP,SAAA,UAAU;AAoBV,SAAA,qBAAqB,CAAC,UAAiB;AACrC,YAAM,eAAA;AAEN,UAAI,MAAM,kBAAkB;AAC1B,aAAK,aAAa,UAAU;AAAA,MAC9B,OAAO;AACL,aAAK,KAAA;AAAA,MACP;AAAA,IACF;AAAA,EAAA;AAAA,EA1BQ,aAAa,QAAiD;AACpE,UAAM,oBAAoB,IAAI,YAAY,qBAAqB;AAAA,MAC7D,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,QAAQ,EAAE,OAAA;AAAA,IAAO,CAClB;AACD,SAAK,cAAc,iBAAiB;AAEpC,QAAI,kBAAkB,kBAAkB;AACtC,YAAM,EAAE,WAAW,QAAA,IAAY,aAAa,MAAM,kBAAkB;AACpE,gBAAU,KAAK,QAAQ,WAAW,OAAO;AACzC;AAAA,IACF;AAEA,SAAK,KAAA;AAAA,EACP;AAAA,EAYQ,oBAAoB,EAAE,UAAiB;AAE7C,QAAI,WAAW,KAAK,QAAQ;AAC1B,WAAK,aAAa,SAAS;AAAA,IAC7B;AAAA,EACF;AAAA,EAGA,MAAM,mBAAmB;AACvB,QAAI,KAAK,MAAM;AAEb,WAAK;AAAA,QACH,IAAI,MAAM,YAAY,EAAE,UAAU,MAAM,SAAS,MAAM;AAAA,MAAA;AAGzD,WAAK,OAAO,UAAA;AAEZ,wBAAkB,IAAI;AAEtB,YAAM,iBAAiB,aAAa,MAAM,aAAa;AACvD,YAAM;AAAA,QACJ,KAAK;AAAA,QACL,eAAe;AAAA,QACf,eAAe;AAAA,MAAA,GAEf,KAAK;AAAA,QACH,IAAI,MAAM,kBAAkB,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,MAAA;AAAA,IAEnE,OAAO;AAEL,WAAK;AAAA,QACH,IAAI,MAAM,YAAY,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,MAAA;AAGzD,YAAM,QAAQ,IAAI,CAAC,eAAe,KAAK,MAAM,CAAC,CAAC;AAC/C,YAAM,iBAAiB,aAAa,MAAM,aAAa;AAIvD,WAAK,OAAO,UAAU,IAAI,2BAA2B;AACrD,YAAM;AAAA,QACJ,KAAK;AAAA,QACL,eAAe;AAAA,QACf,eAAe;AAAA,MAAA;AAEjB,WAAK,OAAO,UAAU,OAAO,2BAA2B;AACxD,WAAK,OAAO,MAAA;AACZ,WAAK,OAAO,SAAS;AACrB,0BAAoB,IAAI;AACxB,WAAK;AAAA,QACH,IAAI,MAAM,kBAAkB,EAAE,UAAU,MAAM,SAAS,MAAM;AAAA,MAAA;AAAA,IAEjE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO;AACX,QAAI,KAAK,MAAM;AACb,aAAO;AAAA,IACT;AAEA,SAAK,OAAO;AACZ,WAAO,aAAa,MAAM,gBAAgB;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO;AACX,QAAI,CAAC,KAAK,MAAM;AACd,aAAO;AAAA,IACT;AAEA,SAAK,OAAO;AACZ,WAAO,aAAa,MAAM,gBAAgB;AAAA,EAC5C;AAAA,EAES,SAAS;AAChB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA,kBAKO,KAAK,kBAAkB;AAAA,iBACxB,KAAK,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAOjB,MAAM,KAAK,aAAa,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe7D;AACF;AAzJE,gBAAA;AAAA,EADC,MAAM,SAAS;AAAA,GADL,YAEX,WAAA,UAAA,CAAA;AAOA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA,GAR/B,YASX,WAAA,QAAA,CAAA;AAOA,gBAAA;AAAA,EADC,SAAS,EAAE,SAAS,KAAA,CAAM;AAAA,GAfhB,YAgBX,WAAA,WAAA,CAAA;AAsCM,gBAAA;AAAA,EADL,MAAM,QAAQ,EAAE,sBAAsB,MAAM;AAAA,GArDlC,YAsDL,WAAA,oBAAA,CAAA;AAtDK,cAAN,gBAAA;AAAA,EADN,cAAc,YAAY;AAAA,GACd,WAAA;AA6Jb,oBAAoB,eAAe;AAAA,EACjC,WAAW;AAAA,IACT,EAAE,SAAS,GAAG,OAAO,IAAA;AAAA,IACrB,EAAE,SAAS,GAAG,OAAO,EAAA;AAAA,EAAE;AAAA,EAEzB,SAAS,EAAE,UAAU,KAAK,QAAQ,OAAA;AACpC,CAAC;AAED,oBAAoB,eAAe;AAAA,EACjC,WAAW;AAAA,IACT,EAAE,SAAS,GAAG,OAAO,EAAA;AAAA,IACrB,EAAE,SAAS,GAAG,OAAO,IAAA;AAAA,EAAI;AAAA,EAE3B,SAAS,EAAE,UAAU,KAAK,QAAQ,OAAA;AACpC,CAAC;AAED,oBAAoB,oBAAoB;AAAA,EACtC,WAAW,CAAC,EAAE,OAAO,KAAK,EAAE,OAAO,QAAQ,EAAE,OAAO,GAAG;AAAA,EACvD,SAAS,EAAE,UAAU,IAAA;AACvB,CAAC;"}
|
|
1
|
+
{"version":3,"file":"dialog.js","sources":["../../src/components/dialog.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { getLang } from '../utilities/lang';\nimport { getTranslations } from '../utilities/translations';\nimport { LangController } from '../controllers/lang.controller.js';\nimport { waitForEvent } from '../internal/event';\nimport { watch } from '../internal/watch';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry';\nimport { animateTo, stopAnimations } from '../internal/animate';\nimport { lockBodyScrolling, unlockBodyScrolling } from '../internal/scroll';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-dialog': MinidDialog;\n }\n}\n\nconst styles = [\n css`\n :host {\n --width: 40rem;\n display: block;\n }\n `,\n];\n\n/**\n *\n * @event mid-show - Emitted when the dialog opens.\n * @event mid-after-show - Emitted after the dialog opens and all animations are complete.\n * @event mid-hide - Emitted when the dialog closes.\n * @event mid-after-hide - Emitted after the dialog closes and all animations are complete.\n * @event {{ source: 'close-button' | 'keyboard' | 'overlay' }} mid-request-close - Emitted when the user attempts to\n * close the dialog by clicking the close button, clicking the overlay, or pressing escape. Calling\n * `event.preventDefault()` will keep the dialog open. Avoid using this unless closing the dialog will result in\n * destructive behavior such as data loss.\n *\n * @csspart base - Select the base `dialog` element\n * @csspart header - Select the `header` element\n * @csspart body - Select the `article` element\n * @csspart footer - Select the `footer` element\n *\n * @slot -- The default slot for the body content of the dialog\n * @slot heading - The content inside the `h2` element\n * @slot footer - The content inside the `footer` element\n *\n * @animation dialog.show - The animation to use when showing the dialog.\n * @animation dialog.hide - The animation to use when hiding the dialog.\n * @animation dialog.denyClose - The animation to use when closing the dialog is prevented.\n *\n */\n@customElement('mid-dialog')\nexport class MinidDialog extends styled(LitElement, styles) {\n @query('#dialog')\n dialog!: HTMLDialogElement;\n\n /**\n * Indicates whether or not the dialog is open. You can toggle this attribute to show and hide the dialog, or you can\n * use the `show()` and `hide()` methods and this attribute will reflect the dialog's open state.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * The dialog's label as displayed in the header. You should always include a relevant label even when using\n * `no-header`, as it is required for proper accessibility. If you need to display HTML, use the `label` slot instead.\n */\n @property({ reflect: true })\n heading = '';\n\n /**\n * When set, the dialog uses `role=\"alertdialog\"` instead of `role=\"dialog\"`, signalling urgency to screen readers.\n * Use this for blocking dialogs that require immediate user attention.\n */\n @property({ type: Boolean, reflect: true })\n alertdialog = false;\n\n private requestClose(source: 'close-button' | 'keyboard' | 'overlay') {\n const requestCloseEvent = new CustomEvent('mid-request-close', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { source },\n });\n this.dispatchEvent(requestCloseEvent);\n\n if (requestCloseEvent.defaultPrevented) {\n const { keyframes, options } = getAnimation(this, 'dialog.denyClose');\n animateTo(this.dialog, keyframes, options);\n return;\n }\n\n this.hide();\n }\n\n handleDialogCancel = (event: Event) => {\n event.preventDefault();\n\n if (event.defaultPrevented) {\n this.requestClose('keyboard');\n } else {\n this.hide();\n }\n };\n\n private handleBackdropClick({ target }: Event) {\n // if the target is the dialog, the backdrop was clicked\n if (target === this.dialog) {\n this.requestClose('overlay');\n }\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.open) {\n // Show\n this.dispatchEvent(\n new Event('mid-show', { composed: true, bubbles: true })\n );\n // this.addOpenListeners();\n this.dialog.showModal();\n\n if (this.alertdialog) {\n this.dialog.focus();\n }\n\n lockBodyScrolling(this);\n\n const panelAnimation = getAnimation(this, 'dialog.show');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\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\n await Promise.all([stopAnimations(this.dialog)]);\n const panelAnimation = getAnimation(this, 'dialog.hide');\n\n // The backdrop can only be animated with css because it's a pseudo element\n // so we add a animation class to trigger it at the same time as the dialog animation\n this.dialog.classList.add('backdrop:animate-fade-out');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\n );\n this.dialog.classList.remove('backdrop:animate-fade-out');\n this.dialog.close();\n this.dialog.hidden = false;\n unlockBodyScrolling(this);\n this.dispatchEvent(\n new Event('mid-after-hide', { composed: true, bubbles: true })\n );\n }\n }\n\n /**\n * Shows the dialog.\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 dialog\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 constructor() {\n super();\n new LangController(this);\n }\n\n override render() {\n const t = getTranslations(getLang(this));\n\n return html`\n <dialog\n part=\"base\"\n id=\"dialog\"\n tabindex=\"-1\"\n role=${this.alertdialog ? 'alertdialog' : 'dialog'}\n aria-label=${this.heading || nothing}\n aria-modal=\"true\"\n class=\"text-neutral m-auto max-h-[calc(100%---spacing(8))] w-(--width) max-w-[calc(100%---spacing(8))] flex-col rounded-lg p-6 shadow-xl backdrop:bg-black/50 open:flex open:animate-none\"\n @cancel=${this.handleDialogCancel}\n @click=${this.handleBackdropClick}\n >\n <header part=\"header\" class=\"text-heading-sm flex justify-between\">\n <slot name=\"heading\"></slot>\n <div class=\"h-0\">\n <button\n autofocus\n aria-label=${t.close}\n @click=\"${() => this.requestClose('close-button')}\"\n class=\"text-body-md focus-visible:focus-ring text-neutral hover:bg-neutral-surface-hover float-right flex size-12 translate-x-3 -translate-y-3 items-center justify-center rounded\"\n >\n <mid-icon class=\"size-6\" name=\"xmark\"></mid-icon>\n </button>\n </div>\n </header>\n <div part=\"body\" class=\"overflow-auto\">\n <slot> </slot>\n </div>\n <footer part=\"footer\">\n <slot name=\"footer\"> </slot>\n </footer>\n </dialog>\n `;\n }\n}\n\nsetDefaultAnimation('dialog.show', {\n keyframes: [\n { opacity: 0, scale: 0.8 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.8 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.denyClose', {\n keyframes: [{ scale: 1 }, { scale: 1.03 }, { scale: 1 }],\n options: { duration: 100 },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
1
|
+
import { LitElement, PropertyValues } from 'lit';
|
|
2
2
|
import { MaskType } from 'maska';
|
|
3
3
|
declare global {
|
|
4
4
|
interface HTMLElementTagNameMap {
|
|
@@ -112,6 +112,8 @@ export declare class MinidTextfield extends MinidTextfield_base {
|
|
|
112
112
|
static get formControlValidators(): import('../types/validator.type.ts').Validator[];
|
|
113
113
|
constructor();
|
|
114
114
|
connectedCallback(): void;
|
|
115
|
+
get validationTarget(): HTMLInputElement;
|
|
116
|
+
protected firstUpdated(_changedProperties: PropertyValues): void;
|
|
115
117
|
disconnectedCallback(): void;
|
|
116
118
|
private handleKeydown;
|
|
117
119
|
private handleBlur;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textfield.component.d.ts","sourceRoot":"","sources":["../../src/components/textfield.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"textfield.component.d.ts","sourceRoot":"","sources":["../../src/components/textfield.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAiB1E,OAAO,0BAA0B,CAAC;AAClC,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAKjD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,cAAc,CAAC;KACjC;CACF;;AAyBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,cAAe,SAAQ,mBAA4C;IAC9E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA4D;IAC7F,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,YAAY,CAAM;IAG1B,KAAK,EAAG,gBAAgB,CAAC;IAGzB,KAAK,SAAM;IAGX,WAAW,SAAM;IAGjB,KAAK,SAAM;IAGX,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAGhC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,YAAY,CAAC,EAAE,QAAQ,CAAC;IAExB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB;;OAEG;IAEH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB;;OAEG;IAEH,cAAc,SAAM;IAGpB,IAAI,EACA,MAAM,GACN,gBAAgB,GAChB,OAAO,GACP,MAAM,GACN,OAAO,GACP,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,KAAK,GACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,MAAM,CAAU;IAEpB;;OAEG;IAEH,SAAS,EACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,KAAK,GACL,OAAO,GACP,SAAS,GACT,SAAS,CAAU;IAEvB;;OAEG;IAEH,SAAS,UAAS;IAElB;;;OAGG;IAEH,cAAc,UAAS;IAEvB;;;OAGG;IAEH,eAAe,UAAS;IAGxB,QAAQ,UAAS;IAGjB,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;;;;;OAMG;IAEH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAGhB,QAAQ,UAAS;IAEjB,MAAM,KAAK,qBAAqB,qDAQ/B;;IAYQ,iBAAiB,IAAI,IAAI;IAKlC,IAAI,gBAAgB,qBAEnB;IAED,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI;IAKhE,oBAAoB,IAAI,IAAI;IAI5B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,gBAAgB;IAmBxB,KAAK;IAKL,gBAAgB;IAKhB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAKlC,iBAAiB;IAKX,gBAAgB;IAUb,MAAM;CA8IhB"}
|
|
@@ -7,7 +7,7 @@ import { styled } from "../mixins/tailwind.mixin.js";
|
|
|
7
7
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
8
8
|
import { HasSlotController } from "../internal/slot.js";
|
|
9
9
|
import { FormControlMixin } from "../mixins/form-control.mixin.js";
|
|
10
|
-
import { requiredValidator, maxLengthValidator, minLengthValidator, patternValidator } from "../mixins/validators.js";
|
|
10
|
+
import { requiredValidator, maxLengthValidator, minLengthValidator, patternValidator, typeMismatchValidator } from "../mixins/validators.js";
|
|
11
11
|
import { watch } from "../internal/watch.js";
|
|
12
12
|
import "./icon/icon.js";
|
|
13
13
|
import { MaskInput } from "maska";
|
|
@@ -78,13 +78,21 @@ let MinidTextfield = class extends FormControlMixin(styled(LitElement, styles))
|
|
|
78
78
|
requiredValidator,
|
|
79
79
|
maxLengthValidator,
|
|
80
80
|
minLengthValidator,
|
|
81
|
-
patternValidator
|
|
81
|
+
patternValidator,
|
|
82
|
+
typeMismatchValidator
|
|
82
83
|
];
|
|
83
84
|
}
|
|
84
85
|
connectedCallback() {
|
|
85
86
|
super.connectedCallback();
|
|
86
87
|
this.initialValue = this.value;
|
|
87
88
|
}
|
|
89
|
+
get validationTarget() {
|
|
90
|
+
return this.input;
|
|
91
|
+
}
|
|
92
|
+
firstUpdated(_changedProperties) {
|
|
93
|
+
super.firstUpdated(_changedProperties);
|
|
94
|
+
this.setValue(this.value);
|
|
95
|
+
}
|
|
88
96
|
disconnectedCallback() {
|
|
89
97
|
this.inputMask?.destroy();
|
|
90
98
|
}
|
|
@@ -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';\nimport { MaskInput, type MaskType } from 'maska';\nimport { getLang } from '../utilities/lang';\nimport { getTranslations } from '../utilities/translations';\nimport { LangController } from '../controllers/lang.controller.js';\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 /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n\n .ds-field-affixes {\n background: var(--ds-color-neutral-background-tinted);\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(styled(LitElement, styles)) {\n private readonly inputId!: string;\n private readonly descriptionId!: string;\n private readonly validationId!: string;\n private readonly hasSlotControler = new HasSlotController(this, 'label', 'prefix', 'suffix');\n private inputMask?: MaskInput;\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 * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode:\n | 'none'\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'numeric'\n | 'decimal' = '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 /**\n * Modify input value based on mask e.g: `\"##:##\"` = 12:34.\n * `#`: /[0-9]/\n * `@`: /[a-zA-Z]/\n * `*`: /[a-zA-Z0-9]/\n * For more information go to https://beholdr.github.io/maska\n */\n @property()\n mask?: MaskType;\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 new LangController(this);\n nextUniqueId++;\n this.inputId = `mid-textfield-input-${nextUniqueId}`;\n this.descriptionId = `mid-textfield-description-${nextUniqueId}`;\n this.validationId = `mid-textfield-validation-${nextUniqueId}`;\n this.setValue(this.value);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.initialValue = this.value;\n }\n\n disconnectedCallback(): void {\n this.inputMask?.destroy();\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n if (event.key === 'Enter' && !hasModifier) {\n setTimeout(() => {\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 let tmp_value = this.input.value;\n\n if (this.type === 'number') {\n tmp_value = tmp_value.replace(/[^0-9]/g, '');\n }\n\n this.value = tmp_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 @watch('mask')\n async handleMaskUpdate() {\n if (!this.mask) return;\n await this.updateComplete;\n this.inputMask?.destroy();\n this.inputMask = new MaskInput(this.input, {\n mask: this.mask,\n eager: true,\n });\n }\n\n override render() {\n const lang = getLang(this);\n const t = getTranslations(lang);\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const hasPrefix = this.hasSlotControler.test('prefix');\n const hasSuffix = this.hasSlotControler.test('suffix');\n const hasClearIcon = this.clearable && !this.disabled && !this.readonly;\n const hasAffixes = hasPrefix || hasSuffix || hasClearIcon || (this.passwordtoggle && !this.disabled);\n const isClearIconVisible =\n hasClearIcon && (typeof this.value === 'number' || this.value.length > 0);\n const describedBy = [\n this.description ? this.descriptionId : undefined,\n this.invalidmessage ? this.validationId : undefined,\n ]\n .filter(Boolean)\n .join(' ');\n\n return html`\n <ds-field\n part=\"field\"\n class=\"ds-field\"\n data-size=${this.size}\n >\n <label\n for=\"${this.inputId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n })} ds-label\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n ${this.description\n ? html`\n <div\n id=\"${this.descriptionId}\"\n part=\"description\"\n data-field=\"description\"\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n })}\"\n >\n ${this.description}\n </div>\n `\n : nothing}\n <div\n part=\"base\"\n class=\"${hasAffixes ? 'ds-field-affixes' : ''}\"\n >\n ${hasPrefix ? html`<span class=\"ds-field-affix\"><slot name=\"prefix\"></slot></span>` : html`<slot name=\"prefix\"></slot>`}\n <input\n id=\"${this.inputId}\"\n class=\"ds-input\"\n part=\"input\"\n lang=${lang}\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=${ifDefined(describedBy || undefined)}\n aria-invalid=${this.invalidmessage ? 'true' : 'false'}\n aria-errormessage=${ifDefined(\n this.invalidmessage ? this.validationId : undefined\n )}\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 inputmode=${this.inputmode}\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 <span class=\"ds-field-affix\" part=\"clear-button\">\n <button\n type=\"button\"\n class=\"focus-visible:focus-ring flex items-center justify-center rounded-sm\"\n aria-label=${t.clear}\n @click=${this.handleClearClick}\n >\n <mid-icon\n class=\"size-7\"\n library=\"nav-aksel\"\n name=\"trash\"\n ></mid-icon>\n </button>\n </span>\n `\n : ''}\n ${this.passwordtoggle && !this.disabled\n ? html`\n <span class=\"ds-field-affix\" part=\"password-toggle-button\">\n <button\n type=\"button\"\n class=\"focus-visible:focus-ring flex items-center justify-center rounded-sm\"\n aria-label=${this.passwordvisible\n ? t.hidePassword\n : t.showPassword}\n @click=${this.handlePasswordToggle}\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 </span>\n `\n : ''}\n ${hasSuffix ? html`<span part=\"suffix\" class=\"ds-field-affix\"><slot name=\"suffix\"></slot></span>` : html`<slot name=\"suffix\"></slot>`}\n </div>\n <p\n class=\"ds-validation-message\"\n data-field=\"validation\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n ${this.invalidmessage}\n </p>\n </ds-field>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textfield.js","sources":["../../src/components/textfield.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing, type PropertyValues } 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 typeMismatchValidator,\n} from '../mixins/validators';\nimport { watch } from '../internal/watch';\nimport './icon/icon.component.ts';\nimport { MaskInput, type MaskType } from 'maska';\nimport { getLang } from '../utilities/lang';\nimport { getTranslations } from '../utilities/translations';\nimport { LangController } from '../controllers/lang.controller.js';\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 /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n\n .ds-field-affixes {\n background: var(--ds-color-neutral-background-tinted);\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(styled(LitElement, styles)) {\n private readonly inputId!: string;\n private readonly descriptionId!: string;\n private readonly validationId!: string;\n private readonly hasSlotControler = new HasSlotController(this, 'label', 'prefix', 'suffix');\n private inputMask?: MaskInput;\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 * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode:\n | 'none'\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'numeric'\n | 'decimal' = '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 /**\n * Modify input value based on mask e.g: `\"##:##\"` = 12:34.\n * `#`: /[0-9]/\n * `@`: /[a-zA-Z]/\n * `*`: /[a-zA-Z0-9]/\n * For more information go to https://beholdr.github.io/maska\n */\n @property()\n mask?: MaskType;\n\n @state()\n hasFocus = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n typeMismatchValidator,\n ];\n }\n\n constructor() {\n super();\n new LangController(this);\n nextUniqueId++;\n this.inputId = `mid-textfield-input-${nextUniqueId}`;\n this.descriptionId = `mid-textfield-description-${nextUniqueId}`;\n this.validationId = `mid-textfield-validation-${nextUniqueId}`;\n this.setValue(this.value);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.initialValue = this.value;\n }\n\n get validationTarget() {\n return this.input;\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n super.firstUpdated(_changedProperties);\n this.setValue(this.value);\n }\n\n disconnectedCallback(): void {\n this.inputMask?.destroy();\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n if (event.key === 'Enter' && !hasModifier) {\n setTimeout(() => {\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 let tmp_value = this.input.value;\n\n if (this.type === 'number') {\n tmp_value = tmp_value.replace(/[^0-9]/g, '');\n }\n\n this.value = tmp_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 @watch('mask')\n async handleMaskUpdate() {\n if (!this.mask) return;\n await this.updateComplete;\n this.inputMask?.destroy();\n this.inputMask = new MaskInput(this.input, {\n mask: this.mask,\n eager: true,\n });\n }\n\n override render() {\n const lang = getLang(this);\n const t = getTranslations(lang);\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const hasPrefix = this.hasSlotControler.test('prefix');\n const hasSuffix = this.hasSlotControler.test('suffix');\n const hasClearIcon = this.clearable && !this.disabled && !this.readonly;\n const hasAffixes = hasPrefix || hasSuffix || hasClearIcon || (this.passwordtoggle && !this.disabled);\n const isClearIconVisible =\n hasClearIcon && (typeof this.value === 'number' || this.value.length > 0);\n const describedBy = [\n this.description ? this.descriptionId : undefined,\n this.invalidmessage ? this.validationId : undefined,\n ]\n .filter(Boolean)\n .join(' ');\n\n return html`\n <ds-field\n part=\"field\"\n class=\"ds-field\"\n data-size=${this.size}\n >\n <label\n for=\"${this.inputId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n })} ds-label\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n ${this.description\n ? html`\n <div\n id=\"${this.descriptionId}\"\n part=\"description\"\n data-field=\"description\"\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n })}\"\n >\n ${this.description}\n </div>\n `\n : nothing}\n <div\n part=\"base\"\n class=\"${hasAffixes ? 'ds-field-affixes' : ''}\"\n >\n ${hasPrefix ? html`<span class=\"ds-field-affix\"><slot name=\"prefix\"></slot></span>` : html`<slot name=\"prefix\"></slot>`}\n <input\n id=\"${this.inputId}\"\n class=\"ds-input\"\n part=\"input\"\n lang=${lang}\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=${ifDefined(describedBy || undefined)}\n aria-invalid=${this.invalidmessage ? 'true' : 'false'}\n aria-errormessage=${ifDefined(\n this.invalidmessage ? this.validationId : undefined\n )}\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 inputmode=${this.inputmode}\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 <span class=\"ds-field-affix\" part=\"clear-button\">\n <button\n type=\"button\"\n class=\"focus-visible:focus-ring flex items-center justify-center rounded-sm\"\n aria-label=${t.clear}\n @click=${this.handleClearClick}\n >\n <mid-icon\n class=\"size-7\"\n library=\"nav-aksel\"\n name=\"trash\"\n ></mid-icon>\n </button>\n </span>\n `\n : ''}\n ${this.passwordtoggle && !this.disabled\n ? html`\n <span class=\"ds-field-affix\" part=\"password-toggle-button\">\n <button\n type=\"button\"\n class=\"focus-visible:focus-ring flex items-center justify-center rounded-sm\"\n aria-label=${this.passwordvisible\n ? t.hidePassword\n : t.showPassword}\n @click=${this.handlePasswordToggle}\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 </span>\n `\n : ''}\n ${hasSuffix ? html`<span part=\"suffix\" class=\"ds-field-affix\"><slot name=\"suffix\"></slot></span>` : html`<slot name=\"suffix\"></slot>`}\n </div>\n <p\n class=\"ds-validation-message\"\n data-field=\"validation\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n ${this.invalidmessage}\n </p>\n </ds-field>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -3,4 +3,5 @@ export declare const requiredValidator: Validator;
|
|
|
3
3
|
export declare const minLengthValidator: Validator;
|
|
4
4
|
export declare const maxLengthValidator: Validator;
|
|
5
5
|
export declare const patternValidator: Validator;
|
|
6
|
+
export declare const typeMismatchValidator: Validator;
|
|
6
7
|
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/mixins/validators.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,eAAO,MAAM,iBAAiB,EAAE,SAgB/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,SAyBhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,SAyBhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,SAa9B,CAAC"}
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/mixins/validators.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,eAAO,MAAM,iBAAiB,EAAE,SAgB/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,SAyBhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,SAyBhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,SAa9B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,SAyBnC,CAAC"}
|
|
@@ -56,10 +56,27 @@ const patternValidator = {
|
|
|
56
56
|
return !!regExp.exec(value);
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
|
+
const typeMismatchValidator = {
|
|
60
|
+
attribute: "type",
|
|
61
|
+
key: "typeMismatch",
|
|
62
|
+
message(instance) {
|
|
63
|
+
return instance.input?.validationMessage || "Please enter a valid value";
|
|
64
|
+
},
|
|
65
|
+
isValid(instance, value) {
|
|
66
|
+
if (!value || typeof value !== "string" || instance.type !== "email" && instance.type !== "url" || typeof document === "undefined") {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
const input = document.createElement("input");
|
|
70
|
+
input.type = instance.type;
|
|
71
|
+
input.value = value;
|
|
72
|
+
return !input.validity.typeMismatch;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
59
75
|
export {
|
|
60
76
|
maxLengthValidator,
|
|
61
77
|
minLengthValidator,
|
|
62
78
|
patternValidator,
|
|
63
|
-
requiredValidator
|
|
79
|
+
requiredValidator,
|
|
80
|
+
typeMismatchValidator
|
|
64
81
|
};
|
|
65
82
|
//# sourceMappingURL=validators.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.js","sources":["../../src/mixins/validators.ts"],"sourcesContent":["import type { FormControlInterface } from '../types/form-control';\nimport type { FormValue } from '../types/form-value';\nimport type { Validator } from '../types/validator.type';\n\nexport const requiredValidator: Validator = {\n attribute: 'required',\n key: 'valueMissing',\n message: 'Please fill out this field',\n isValid(\n instance: HTMLElement & { required: boolean },\n value: FormValue\n ): boolean {\n let valid = true;\n\n if ((instance.hasAttribute('required') || instance.required) && !value) {\n valid = false;\n }\n\n return valid;\n },\n};\n\nexport const minLengthValidator: Validator = {\n attribute: 'minlength',\n key: 'tooShort',\n message(\n instance: FormControlInterface & { minlength: number },\n value: FormValue\n ): string {\n const _value = (value as string) || '';\n return `Please use at least ${instance.minlength} characters (you are currently using ${_value.length} characters).`;\n },\n isValid(\n instance: HTMLElement & { minlength: number },\n value: string\n ): boolean {\n /** If no value is provided, this validator should return true */\n if (!value) {\n return true;\n }\n\n if (!!value && instance.minlength > value.length) {\n return false;\n }\n\n return true;\n },\n};\n\nexport const maxLengthValidator: Validator = {\n attribute: 'maxlength',\n key: 'tooLong',\n message(\n instance: FormControlInterface & { maxLength: number },\n value: FormValue\n ): string {\n const _value = (value as string) || '';\n return `Please use no more than ${instance.maxLength} characters (you are currently using ${_value.length} characters).`;\n },\n isValid(\n instance: HTMLElement & { maxLength: number },\n value: string\n ): boolean {\n /** If maxLength isn't set, this is valid */\n if (!instance.maxLength) {\n return true;\n }\n\n if (!!value && instance.maxLength < value.length) {\n return false;\n }\n\n return true;\n },\n};\n\nexport const patternValidator: Validator = {\n attribute: 'pattern',\n key: 'patternMismatch',\n message: 'Please match the requested format',\n isValid(instance: HTMLElement & { pattern: string }, value: string): boolean {\n /** If no value is provided, this validator should return true */\n if (!value || !instance.pattern) {\n return true;\n }\n\n const regExp = new RegExp(instance.pattern);\n return !!regExp.exec(value);\n },\n};\n"],"names":[],"mappings":"AAIO,MAAM,oBAA+B;AAAA,EAC1C,WAAW;AAAA,EACX,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QACE,UACA,OACS;AACT,QAAI,QAAQ;AAEZ,SAAK,SAAS,aAAa,UAAU,KAAK,SAAS,aAAa,CAAC,OAAO;AACtE,cAAQ;AAAA,IACV;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,qBAAgC;AAAA,EAC3C,WAAW;AAAA,EACX,KAAK;AAAA,EACL,QACE,UACA,OACQ;AACR,UAAM,SAAU,SAAoB;AACpC,WAAO,uBAAuB,SAAS,SAAS,wCAAwC,OAAO,MAAM;AAAA,EACvG;AAAA,EACA,QACE,UACA,OACS;AAET,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,CAAC,SAAS,SAAS,YAAY,MAAM,QAAQ;AAChD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,qBAAgC;AAAA,EAC3C,WAAW;AAAA,EACX,KAAK;AAAA,EACL,QACE,UACA,OACQ;AACR,UAAM,SAAU,SAAoB;AACpC,WAAO,2BAA2B,SAAS,SAAS,wCAAwC,OAAO,MAAM;AAAA,EAC3G;AAAA,EACA,QACE,UACA,OACS;AAET,QAAI,CAAC,SAAS,WAAW;AACvB,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,CAAC,SAAS,SAAS,YAAY,MAAM,QAAQ;AAChD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,mBAA8B;AAAA,EACzC,WAAW;AAAA,EACX,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ,UAA6C,OAAwB;AAE3E,QAAI,CAAC,SAAS,CAAC,SAAS,SAAS;AAC/B,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,IAAI,OAAO,SAAS,OAAO;AAC1C,WAAO,CAAC,CAAC,OAAO,KAAK,KAAK;AAAA,EAC5B;AACF;"}
|
|
1
|
+
{"version":3,"file":"validators.js","sources":["../../src/mixins/validators.ts"],"sourcesContent":["import type { FormControlInterface } from '../types/form-control';\nimport type { FormValue } from '../types/form-value';\nimport type { Validator } from '../types/validator.type';\n\nexport const requiredValidator: Validator = {\n attribute: 'required',\n key: 'valueMissing',\n message: 'Please fill out this field',\n isValid(\n instance: HTMLElement & { required: boolean },\n value: FormValue\n ): boolean {\n let valid = true;\n\n if ((instance.hasAttribute('required') || instance.required) && !value) {\n valid = false;\n }\n\n return valid;\n },\n};\n\nexport const minLengthValidator: Validator = {\n attribute: 'minlength',\n key: 'tooShort',\n message(\n instance: FormControlInterface & { minlength: number },\n value: FormValue\n ): string {\n const _value = (value as string) || '';\n return `Please use at least ${instance.minlength} characters (you are currently using ${_value.length} characters).`;\n },\n isValid(\n instance: HTMLElement & { minlength: number },\n value: string\n ): boolean {\n /** If no value is provided, this validator should return true */\n if (!value) {\n return true;\n }\n\n if (!!value && instance.minlength > value.length) {\n return false;\n }\n\n return true;\n },\n};\n\nexport const maxLengthValidator: Validator = {\n attribute: 'maxlength',\n key: 'tooLong',\n message(\n instance: FormControlInterface & { maxLength: number },\n value: FormValue\n ): string {\n const _value = (value as string) || '';\n return `Please use no more than ${instance.maxLength} characters (you are currently using ${_value.length} characters).`;\n },\n isValid(\n instance: HTMLElement & { maxLength: number },\n value: string\n ): boolean {\n /** If maxLength isn't set, this is valid */\n if (!instance.maxLength) {\n return true;\n }\n\n if (!!value && instance.maxLength < value.length) {\n return false;\n }\n\n return true;\n },\n};\n\nexport const patternValidator: Validator = {\n attribute: 'pattern',\n key: 'patternMismatch',\n message: 'Please match the requested format',\n isValid(instance: HTMLElement & { pattern: string }, value: string): boolean {\n /** If no value is provided, this validator should return true */\n if (!value || !instance.pattern) {\n return true;\n }\n\n const regExp = new RegExp(instance.pattern);\n return !!regExp.exec(value);\n },\n};\n\nexport const typeMismatchValidator: Validator = {\n attribute: 'type',\n key: 'typeMismatch',\n message(instance: HTMLElement & { input?: HTMLInputElement }): string {\n return instance.input?.validationMessage || 'Please enter a valid value';\n },\n isValid(\n instance: HTMLElement & { type?: HTMLInputElement['type'] },\n value: FormValue\n ): boolean {\n if (\n !value ||\n typeof value !== 'string' ||\n (instance.type !== 'email' && instance.type !== 'url') ||\n typeof document === 'undefined'\n ) {\n return true;\n }\n\n const input = document.createElement('input');\n input.type = instance.type;\n input.value = value;\n\n return !input.validity.typeMismatch;\n },\n};\n"],"names":[],"mappings":"AAIO,MAAM,oBAA+B;AAAA,EAC1C,WAAW;AAAA,EACX,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QACE,UACA,OACS;AACT,QAAI,QAAQ;AAEZ,SAAK,SAAS,aAAa,UAAU,KAAK,SAAS,aAAa,CAAC,OAAO;AACtE,cAAQ;AAAA,IACV;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,qBAAgC;AAAA,EAC3C,WAAW;AAAA,EACX,KAAK;AAAA,EACL,QACE,UACA,OACQ;AACR,UAAM,SAAU,SAAoB;AACpC,WAAO,uBAAuB,SAAS,SAAS,wCAAwC,OAAO,MAAM;AAAA,EACvG;AAAA,EACA,QACE,UACA,OACS;AAET,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,CAAC,SAAS,SAAS,YAAY,MAAM,QAAQ;AAChD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,qBAAgC;AAAA,EAC3C,WAAW;AAAA,EACX,KAAK;AAAA,EACL,QACE,UACA,OACQ;AACR,UAAM,SAAU,SAAoB;AACpC,WAAO,2BAA2B,SAAS,SAAS,wCAAwC,OAAO,MAAM;AAAA,EAC3G;AAAA,EACA,QACE,UACA,OACS;AAET,QAAI,CAAC,SAAS,WAAW;AACvB,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,CAAC,SAAS,SAAS,YAAY,MAAM,QAAQ;AAChD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,mBAA8B;AAAA,EACzC,WAAW;AAAA,EACX,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ,UAA6C,OAAwB;AAE3E,QAAI,CAAC,SAAS,CAAC,SAAS,SAAS;AAC/B,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,IAAI,OAAO,SAAS,OAAO;AAC1C,WAAO,CAAC,CAAC,OAAO,KAAK,KAAK;AAAA,EAC5B;AACF;AAEO,MAAM,wBAAmC;AAAA,EAC9C,WAAW;AAAA,EACX,KAAK;AAAA,EACL,QAAQ,UAA8D;AACpE,WAAO,SAAS,OAAO,qBAAqB;AAAA,EAC9C;AAAA,EACA,QACE,UACA,OACS;AACT,QACE,CAAC,SACD,OAAO,UAAU,YAChB,SAAS,SAAS,WAAW,SAAS,SAAS,SAChD,OAAO,aAAa,aACpB;AACA,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,OAAO,SAAS;AACtB,UAAM,QAAQ;AAEd,WAAO,CAAC,MAAM,SAAS;AAAA,EACzB;AACF;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../src/utilities/translations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../src/utilities/translations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAsCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAC3C,IAAI,CAIN;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,CAMnE"}
|
|
@@ -3,25 +3,29 @@ const builtins = {
|
|
|
3
3
|
clear: "Tøm",
|
|
4
4
|
showPassword: "Vis passord",
|
|
5
5
|
hidePassword: "Skjul passord",
|
|
6
|
-
openCountrySelector: "Åpne landsvelger"
|
|
6
|
+
openCountrySelector: "Åpne landsvelger",
|
|
7
|
+
close: "Lukk"
|
|
7
8
|
},
|
|
8
9
|
nn: {
|
|
9
10
|
clear: "Tøm",
|
|
10
11
|
showPassword: "Vis passord",
|
|
11
12
|
hidePassword: "Gøym passord",
|
|
12
|
-
openCountrySelector: "Opna landsveljar"
|
|
13
|
+
openCountrySelector: "Opna landsveljar",
|
|
14
|
+
close: "Lukk"
|
|
13
15
|
},
|
|
14
16
|
se: {
|
|
15
17
|
clear: "Sihko",
|
|
16
18
|
showPassword: "Čájet sátnesuodji",
|
|
17
19
|
hidePassword: "Čiehka sátnesuodji",
|
|
18
|
-
openCountrySelector: "Rahpat riikkaválljenjoavkku"
|
|
20
|
+
openCountrySelector: "Rahpat riikkaválljenjoavkku",
|
|
21
|
+
close: "Gidde"
|
|
19
22
|
},
|
|
20
23
|
en: {
|
|
21
24
|
clear: "Clear",
|
|
22
25
|
showPassword: "Show password",
|
|
23
26
|
hidePassword: "Hide password",
|
|
24
|
-
openCountrySelector: "Open country selector"
|
|
27
|
+
openCountrySelector: "Open country selector",
|
|
28
|
+
close: "Close"
|
|
25
29
|
}
|
|
26
30
|
};
|
|
27
31
|
const registry = new Map(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translations.js","sources":["../../src/utilities/translations.ts"],"sourcesContent":["/**\n * All UI strings that components render themselves (e.g. aria-labels on\n * icon-only buttons). Every supported language must provide all keys.\n */\nexport interface ComponentTranslations {\n clear: string;\n showPassword: string;\n hidePassword: string;\n openCountrySelector: string;\n}\n\n\nconst builtins: Record<string, ComponentTranslations> = {\n nb: {\n clear: 'Tøm',\n showPassword: 'Vis passord',\n hidePassword: 'Skjul passord',\n openCountrySelector: 'Åpne landsvelger',\n },\n nn: {\n clear: 'Tøm',\n showPassword: 'Vis passord',\n hidePassword: 'Gøym passord',\n openCountrySelector: 'Opna landsveljar',\n },\n se: {\n clear: 'Sihko',\n showPassword: 'Čájet sátnesuodji',\n hidePassword: 'Čiehka sátnesuodji',\n openCountrySelector: 'Rahpat riikkaválljenjoavkku',\n },\n en: {\n clear: 'Clear',\n showPassword: 'Show password',\n hidePassword: 'Hide password',\n openCountrySelector: 'Open country selector',\n },\n};\n\nconst registry = new Map<string, ComponentTranslations>(\n Object.entries(builtins)\n);\n\n/**\n * Override or extend translations for a given BCP-47 language tag.\n * Merges the provided strings with the existing entry for that tag, so you\n * only need to supply the keys you want to change.\n *\n * Call this once at app startup, before any components render.\n *\n * @example Override a single string for Norwegian Bokmål\n * ```ts\n * setTranslations('nb', { clear: 'Slett' });\n * ```\n *\n * @example Register a completely new language\n * ```ts\n * setTranslations('fr', {\n * clear: 'Effacer',\n * showPassword: 'Afficher le mot de passe',\n * hidePassword: 'Masquer le mot de passe',\n * });\n * ```\n */\nexport function setTranslations(\n lang: string,\n translations: Partial<ComponentTranslations>\n): void {\n const base = resolveBaseLang(lang);\n const existing = registry.get(lang) ?? registry.get(base) ?? builtins.nb;\n registry.set(lang, { ...existing, ...translations });\n}\n\n/**\n * Returns the translations for the given BCP-47 language tag.\n *\n * Resolution order:\n * 1. Exact tag match (e.g. `'nb-NO'`)\n * 2. Base language match (e.g. `'nb'` from `'nb-NO'`)\n * 3. Norwegian Bokmål as final fallback\n */\nexport function getTranslations(lang: string): ComponentTranslations {\n return (\n registry.get(lang) ??\n registry.get(resolveBaseLang(lang)) ??\n builtins.nb\n );\n}\n\nfunction resolveBaseLang(lang: string): string {\n return lang.toLowerCase().split('-')[0];\n}"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"translations.js","sources":["../../src/utilities/translations.ts"],"sourcesContent":["/**\n * All UI strings that components render themselves (e.g. aria-labels on\n * icon-only buttons). Every supported language must provide all keys.\n */\nexport interface ComponentTranslations {\n clear: string;\n showPassword: string;\n hidePassword: string;\n openCountrySelector: string;\n close: string;\n}\n\n\nconst builtins: Record<string, ComponentTranslations> = {\n nb: {\n clear: 'Tøm',\n showPassword: 'Vis passord',\n hidePassword: 'Skjul passord',\n openCountrySelector: 'Åpne landsvelger',\n close: 'Lukk',\n },\n nn: {\n clear: 'Tøm',\n showPassword: 'Vis passord',\n hidePassword: 'Gøym passord',\n openCountrySelector: 'Opna landsveljar',\n close: 'Lukk',\n },\n se: {\n clear: 'Sihko',\n showPassword: 'Čájet sátnesuodji',\n hidePassword: 'Čiehka sátnesuodji',\n openCountrySelector: 'Rahpat riikkaválljenjoavkku',\n close: 'Gidde',\n },\n en: {\n clear: 'Clear',\n showPassword: 'Show password',\n hidePassword: 'Hide password',\n openCountrySelector: 'Open country selector',\n close: 'Close',\n },\n};\n\nconst registry = new Map<string, ComponentTranslations>(\n Object.entries(builtins)\n);\n\n/**\n * Override or extend translations for a given BCP-47 language tag.\n * Merges the provided strings with the existing entry for that tag, so you\n * only need to supply the keys you want to change.\n *\n * Call this once at app startup, before any components render.\n *\n * @example Override a single string for Norwegian Bokmål\n * ```ts\n * setTranslations('nb', { clear: 'Slett' });\n * ```\n *\n * @example Register a completely new language\n * ```ts\n * setTranslations('fr', {\n * clear: 'Effacer',\n * showPassword: 'Afficher le mot de passe',\n * hidePassword: 'Masquer le mot de passe',\n * });\n * ```\n */\nexport function setTranslations(\n lang: string,\n translations: Partial<ComponentTranslations>\n): void {\n const base = resolveBaseLang(lang);\n const existing = registry.get(lang) ?? registry.get(base) ?? builtins.nb;\n registry.set(lang, { ...existing, ...translations });\n}\n\n/**\n * Returns the translations for the given BCP-47 language tag.\n *\n * Resolution order:\n * 1. Exact tag match (e.g. `'nb-NO'`)\n * 2. Base language match (e.g. `'nb'` from `'nb-NO'`)\n * 3. Norwegian Bokmål as final fallback\n */\nexport function getTranslations(lang: string): ComponentTranslations {\n return (\n registry.get(lang) ??\n registry.get(resolveBaseLang(lang)) ??\n builtins.nb\n );\n}\n\nfunction resolveBaseLang(lang: string): string {\n return lang.toLowerCase().split('-')[0];\n}"],"names":[],"mappings":"AAaA,MAAM,WAAkD;AAAA,EACtD,IAAI;AAAA,IACF,OAAO;AAAA,IACP,cAAc;AAAA,IACd,cAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,OAAO;AAAA,EAAA;AAAA,EAET,IAAI;AAAA,IACF,OAAO;AAAA,IACP,cAAc;AAAA,IACd,cAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,OAAO;AAAA,EAAA;AAAA,EAET,IAAI;AAAA,IACF,OAAO;AAAA,IACP,cAAc;AAAA,IACd,cAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,OAAO;AAAA,EAAA;AAAA,EAET,IAAI;AAAA,IACF,OAAO;AAAA,IACP,cAAc;AAAA,IACd,cAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,OAAO;AAAA,EAAA;AAEX;AAEA,MAAM,WAAW,IAAI;AAAA,EACnB,OAAO,QAAQ,QAAQ;AACzB;AAuBO,SAAS,gBACd,MACA,cACM;AACN,QAAM,OAAO,gBAAgB,IAAI;AACjC,QAAM,WAAW,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS;AACtE,WAAS,IAAI,MAAM,EAAE,GAAG,UAAU,GAAG,cAAc;AACrD;AAUO,SAAS,gBAAgB,MAAqC;AACnE,SACE,SAAS,IAAI,IAAI,KACjB,SAAS,IAAI,gBAAgB,IAAI,CAAC,KAClC,SAAS;AAEb;AAEA,SAAS,gBAAgB,MAAsB;AAC7C,SAAO,KAAK,YAAA,EAAc,MAAM,GAAG,EAAE,CAAC;AACxC;"}
|