@felleslosninger/minid-elements 0.1.5 → 0.1.6
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/checkbox.component.d.ts +8 -0
- package/dist/components/checkbox.component.d.ts.map +1 -1
- package/dist/components/checkbox.js +49 -3
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/code-input.component.d.ts +23 -0
- package/dist/components/code-input.component.d.ts.map +1 -1
- package/dist/components/code-input.js +167 -25
- package/dist/components/code-input.js.map +1 -1
- package/dist/components/textfield.component.d.ts +1 -0
- package/dist/components/textfield.component.d.ts.map +1 -1
- package/dist/components/textfield.js +17 -2
- package/dist/components/textfield.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,10 +9,17 @@ declare const MinidCheckbox_base: import('../types/mixin-constructor.ts').Constr
|
|
|
9
9
|
* @slot -- The default slot for the label text of the checkbox
|
|
10
10
|
* @slot description - The slot for the description text of the checkbox
|
|
11
11
|
*
|
|
12
|
+
* @csspart label - The checkbox's label.
|
|
13
|
+
* @csspart description - The checkbox's description.
|
|
14
|
+
* @csspart validation-message - The error message shown by `invalidmessage`.
|
|
15
|
+
*
|
|
12
16
|
* @event mid-change - Emitted when the checked state changes
|
|
13
17
|
*/
|
|
14
18
|
export declare class MinidCheckbox extends MinidCheckbox_base {
|
|
15
19
|
private input;
|
|
20
|
+
private readonly hasSlotController;
|
|
21
|
+
private readonly descriptionId;
|
|
22
|
+
private readonly validationId;
|
|
16
23
|
/**
|
|
17
24
|
* The name of the checkbox, submitted as a name/value pair with form data.
|
|
18
25
|
*/
|
|
@@ -26,6 +33,7 @@ export declare class MinidCheckbox extends MinidCheckbox_base {
|
|
|
26
33
|
disabled: boolean;
|
|
27
34
|
readonly: boolean;
|
|
28
35
|
invalid: boolean;
|
|
36
|
+
invalidmessage: string;
|
|
29
37
|
required: boolean;
|
|
30
38
|
static get formControlValidators(): import('../types/validator.type.ts').Validator[];
|
|
31
39
|
shouldFormValueUpdate(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.component.d.ts","sourceRoot":"","sources":["../../src/components/checkbox.component.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"checkbox.component.d.ts","sourceRoot":"","sources":["../../src/components/checkbox.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AAK5C,OAAO,0BAA0B,CAAC;AAOlC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,aAAa,CAAC;KAC/B;CACF;;AAUD;;;;;;;;;GASG;AAEH,qBACa,aAAc,SAAQ,kBAElC;IAEC,OAAO,CAAC,KAAK,CAAoB;IAEjC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAGhC;IAEF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAE7C;;OAEG;IAEH,IAAI,SAAM;IAEV;;OAEG;IAEH,KAAK,SAAQ;IAGb,OAAO,UAAS;IAGhB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,QAAQ,UAAS;IAGjB,QAAQ,UAAS;IAGjB,OAAO,UAAS;IAGhB,cAAc,SAAM;IAGpB,QAAQ,UAAS;IAEjB,MAAM,KAAK,qBAAqB,qDAE/B;IAED,qBAAqB,IAAI,OAAO;IAIhC,IAAI,gBAAgB,qBAEnB;IAED,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACH,KAAK;IAIL;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY;IAI5B;;OAEG;IACH,IAAI;IAKJ,iBAAiB;IAKR,MAAM;CAoEhB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { LitElement, html } from "lit";
|
|
1
|
+
import { css, LitElement, html } from "lit";
|
|
2
2
|
import { query, property, customElement } from "lit/decorators.js";
|
|
3
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
3
4
|
import { live } from "lit/directives/live.js";
|
|
4
5
|
import { styled } from "../mixins/tailwind.mixin.js";
|
|
5
6
|
import "./icon/icon.js";
|
|
@@ -7,6 +8,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
|
|
7
8
|
import { FormControlMixin } from "../mixins/form-control.mixin.js";
|
|
8
9
|
import { watch } from "../internal/watch.js";
|
|
9
10
|
import { requiredValidator } from "../mixins/validators.js";
|
|
11
|
+
import { HasSlotController } from "../internal/slot.js";
|
|
10
12
|
var __defProp = Object.defineProperty;
|
|
11
13
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
14
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -17,15 +19,31 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
17
19
|
if (kind && result) __defProp(target, key, result);
|
|
18
20
|
return result;
|
|
19
21
|
};
|
|
20
|
-
|
|
22
|
+
const styles = [
|
|
23
|
+
css`
|
|
24
|
+
.description {
|
|
25
|
+
color: var(--ds-color-neutral-text-subtle);
|
|
26
|
+
}
|
|
27
|
+
`
|
|
28
|
+
];
|
|
29
|
+
let MinidCheckbox = class extends FormControlMixin(
|
|
30
|
+
styled(LitElement, styles)
|
|
31
|
+
) {
|
|
21
32
|
constructor() {
|
|
22
33
|
super(...arguments);
|
|
34
|
+
this.hasSlotController = new HasSlotController(
|
|
35
|
+
this,
|
|
36
|
+
"description"
|
|
37
|
+
);
|
|
38
|
+
this.descriptionId = "description";
|
|
39
|
+
this.validationId = "validation";
|
|
23
40
|
this.name = "";
|
|
24
41
|
this.value = "on";
|
|
25
42
|
this.checked = false;
|
|
26
43
|
this.disabled = false;
|
|
27
44
|
this.readonly = false;
|
|
28
45
|
this.invalid = false;
|
|
46
|
+
this.invalidmessage = "";
|
|
29
47
|
this.required = false;
|
|
30
48
|
}
|
|
31
49
|
static get formControlValidators() {
|
|
@@ -73,6 +91,12 @@ let MinidCheckbox = class extends FormControlMixin(styled(LitElement)) {
|
|
|
73
91
|
this.setValue(this.value);
|
|
74
92
|
}
|
|
75
93
|
render() {
|
|
94
|
+
const hasDescription = !!this.description || this.hasSlotController.test("description");
|
|
95
|
+
const isInvalid = this.invalid || !!this.invalidmessage;
|
|
96
|
+
const describedBy = [
|
|
97
|
+
hasDescription ? this.descriptionId : void 0,
|
|
98
|
+
this.invalidmessage ? this.validationId : void 0
|
|
99
|
+
].filter(Boolean).join(" ") || void 0;
|
|
76
100
|
return html`
|
|
77
101
|
<ds-field class="ds-field">
|
|
78
102
|
<input
|
|
@@ -85,6 +109,11 @@ let MinidCheckbox = class extends FormControlMixin(styled(LitElement)) {
|
|
|
85
109
|
?checked=${this.checked}
|
|
86
110
|
?readonly=${this.readonly}
|
|
87
111
|
?required=${this.required}
|
|
112
|
+
aria-invalid=${isInvalid ? "true" : "false"}
|
|
113
|
+
aria-describedby=${ifDefined(describedBy)}
|
|
114
|
+
aria-errormessage=${ifDefined(
|
|
115
|
+
this.invalidmessage ? this.validationId : void 0
|
|
116
|
+
)}
|
|
88
117
|
@click=${this.handleClick}
|
|
89
118
|
@keydown=${this.handleKeydown}
|
|
90
119
|
/>
|
|
@@ -95,7 +124,11 @@ let MinidCheckbox = class extends FormControlMixin(styled(LitElement)) {
|
|
|
95
124
|
>
|
|
96
125
|
<slot></slot>
|
|
97
126
|
</label>
|
|
98
|
-
<div
|
|
127
|
+
<div
|
|
128
|
+
class="description"
|
|
129
|
+
id="${this.descriptionId}"
|
|
130
|
+
aria-hidden="true"
|
|
131
|
+
>
|
|
99
132
|
<slot
|
|
100
133
|
name="description"
|
|
101
134
|
part="description"
|
|
@@ -103,6 +136,16 @@ let MinidCheckbox = class extends FormControlMixin(styled(LitElement)) {
|
|
|
103
136
|
${this.description}
|
|
104
137
|
</slot>
|
|
105
138
|
</div>
|
|
139
|
+
<p
|
|
140
|
+
class="${classMap({
|
|
141
|
+
"ds-validation-message": !!this.invalidmessage
|
|
142
|
+
})}"
|
|
143
|
+
part="validation-message"
|
|
144
|
+
id="${this.validationId}"
|
|
145
|
+
aria-live="polite"
|
|
146
|
+
>
|
|
147
|
+
${this.invalidmessage}
|
|
148
|
+
</p>
|
|
106
149
|
</ds-field>
|
|
107
150
|
`;
|
|
108
151
|
}
|
|
@@ -131,6 +174,9 @@ __decorateClass([
|
|
|
131
174
|
__decorateClass([
|
|
132
175
|
property({ type: Boolean })
|
|
133
176
|
], MinidCheckbox.prototype, "invalid", 2);
|
|
177
|
+
__decorateClass([
|
|
178
|
+
property()
|
|
179
|
+
], MinidCheckbox.prototype, "invalidmessage", 2);
|
|
134
180
|
__decorateClass([
|
|
135
181
|
property({ type: Boolean, reflect: true })
|
|
136
182
|
], MinidCheckbox.prototype, "required", 2);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.js","sources":["../../src/components/checkbox.component.ts"],"sourcesContent":["import { html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { watch } from '../internal/watch.ts';\nimport { requiredValidator } from '../mixins/validators.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-checkbox': MinidCheckbox;\n }\n}\n\n/**\n * @slot -- The default slot for the label text of the checkbox\n * @slot description - The slot for the description text of the checkbox\n *\n * @event mid-change - Emitted when the checked state changes\n */\n\n@customElement('mid-checkbox')\nexport class MinidCheckbox extends FormControlMixin(styled(LitElement)) {\n @query('input[type=\"checkbox\"]')\n private input!: HTMLInputElement;\n\n /**\n * The name of the checkbox, submitted as a name/value pair with form data.\n */\n @property()\n name = '';\n\n /**\n * The current value of the checkbox, submitted as a name/value pair with form data.\n */\n @property()\n value = 'on';\n\n @property({ type: Boolean })\n checked = false;\n\n @property()\n description?: string;\n\n @property({ type: Boolean })\n disabled = false;\n\n @property({ type: Boolean })\n readonly = false;\n\n @property({ type: Boolean })\n invalid = false;\n\n @property({ type: Boolean, reflect: true })\n required = false;\n\n static get formControlValidators() {\n return [requiredValidator];\n }\n\n shouldFormValueUpdate(): boolean {\n return this.checked;\n }\n\n get validationTarget() {\n return this.input;\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 handleClick() {\n this.checked = !this.checked;\n // this.indeterminate = false;\n this.dispatchEvent(new Event('mid-change'));\n }\n\n /**\n * Simulates a click on the checkbox.\n */\n click() {\n this.input.click();\n }\n\n /**\n * Sets focus on the checkbox.\n */\n focus(options?: FocusOptions) {\n this.input.focus(options);\n }\n\n /**\n * Removes focus from the checkbox.\n */\n blur() {\n this.input.blur();\n }\n\n @watch(['checked', 'value'])\n handleStateChange() {\n // this.input.indeterminate = this.indeterminate; // force a sync update\n this.setValue(this.value);\n }\n\n override render() {\n\n return html`\n <ds-field class=\"ds-field\">\n <input\n id=\"input\"\n class=\"ds-input\"\n type=\"checkbox\"\n value=${ifDefined(this.value)}\n .checked=${live(this.checked)}\n ?disabled=${this.disabled}\n ?checked=${this.checked}\n ?readonly=${this.readonly}\n ?required=${this.required}\n @click=${this.handleClick}\n @keydown=${this.handleKeydown}\n />\n <label\n class=\"ds-label\"\n part=\"label\"\n for=\"input\"\n >\n <slot></slot>\n </label>\n <div
|
|
1
|
+
{"version":3,"file":"checkbox.js","sources":["../../src/components/checkbox.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { watch } from '../internal/watch.ts';\nimport { requiredValidator } from '../mixins/validators.ts';\nimport { HasSlotController } from '../internal/slot.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-checkbox': MinidCheckbox;\n }\n}\n\nconst styles = [\n css`\n .description {\n color: var(--ds-color-neutral-text-subtle);\n }\n `,\n];\n\n/**\n * @slot -- The default slot for the label text of the checkbox\n * @slot description - The slot for the description text of the checkbox\n *\n * @csspart label - The checkbox's label.\n * @csspart description - The checkbox's description.\n * @csspart validation-message - The error message shown by `invalidmessage`.\n *\n * @event mid-change - Emitted when the checked state changes\n */\n\n@customElement('mid-checkbox')\nexport class MinidCheckbox extends FormControlMixin(\n styled(LitElement, styles)\n) {\n @query('input[type=\"checkbox\"]')\n private input!: HTMLInputElement;\n\n private readonly hasSlotController = new HasSlotController(\n this,\n 'description'\n );\n\n private readonly descriptionId = 'description';\n private readonly validationId = 'validation';\n\n /**\n * The name of the checkbox, submitted as a name/value pair with form data.\n */\n @property()\n name = '';\n\n /**\n * The current value of the checkbox, submitted as a name/value pair with form data.\n */\n @property()\n value = 'on';\n\n @property({ type: Boolean })\n checked = false;\n\n @property()\n description?: string;\n\n @property({ type: Boolean })\n disabled = false;\n\n @property({ type: Boolean })\n readonly = false;\n\n @property({ type: Boolean })\n invalid = false;\n\n @property()\n invalidmessage = '';\n\n @property({ type: Boolean, reflect: true })\n required = false;\n\n static get formControlValidators() {\n return [requiredValidator];\n }\n\n shouldFormValueUpdate(): boolean {\n return this.checked;\n }\n\n get validationTarget() {\n return this.input;\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 handleClick() {\n this.checked = !this.checked;\n // this.indeterminate = false;\n this.dispatchEvent(new Event('mid-change'));\n }\n\n /**\n * Simulates a click on the checkbox.\n */\n click() {\n this.input.click();\n }\n\n /**\n * Sets focus on the checkbox.\n */\n focus(options?: FocusOptions) {\n this.input.focus(options);\n }\n\n /**\n * Removes focus from the checkbox.\n */\n blur() {\n this.input.blur();\n }\n\n @watch(['checked', 'value'])\n handleStateChange() {\n // this.input.indeterminate = this.indeterminate; // force a sync update\n this.setValue(this.value);\n }\n\n override render() {\n const hasDescription =\n !!this.description || this.hasSlotController.test('description');\n const isInvalid = this.invalid || !!this.invalidmessage;\n const describedBy =\n [\n hasDescription ? this.descriptionId : undefined,\n this.invalidmessage ? this.validationId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n // The description wrapper is aria-hidden. It is already announced through\n // the aria-describedby above, and without this the text is also reachable as\n // its own node when navigating the page, so it is read out twice.\n\n return html`\n <ds-field class=\"ds-field\">\n <input\n id=\"input\"\n class=\"ds-input\"\n type=\"checkbox\"\n value=${ifDefined(this.value)}\n .checked=${live(this.checked)}\n ?disabled=${this.disabled}\n ?checked=${this.checked}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-invalid=${isInvalid ? 'true' : 'false'}\n aria-describedby=${ifDefined(describedBy)}\n aria-errormessage=${ifDefined(\n this.invalidmessage ? this.validationId : undefined\n )}\n @click=${this.handleClick}\n @keydown=${this.handleKeydown}\n />\n <label\n class=\"ds-label\"\n part=\"label\"\n for=\"input\"\n >\n <slot></slot>\n </label>\n <div\n class=\"description\"\n id=\"${this.descriptionId}\"\n aria-hidden=\"true\"\n >\n <slot\n name=\"description\"\n part=\"description\"\n >\n ${this.description}\n </slot>\n </div>\n <p\n class=\"${classMap({\n 'ds-validation-message': !!this.invalidmessage,\n })}\"\n part=\"validation-message\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n >\n ${this.invalidmessage}\n </p>\n </ds-field>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkBA,MAAM,SAAS;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAKF;AAcO,IAAM,gBAAN,cAA4B;AAAA,EACjC,OAAO,YAAY,MAAM;AAC3B,EAAE;AAAA,EAFK,cAAA;AAAA,UAAA,GAAA,SAAA;AAML,SAAiB,oBAAoB,IAAI;AAAA,MACvC;AAAA,MACA;AAAA,IAAA;AAGF,SAAiB,gBAAgB;AACjC,SAAiB,eAAe;AAMhC,SAAA,OAAO;AAMP,SAAA,QAAQ;AAGR,SAAA,UAAU;AAMV,SAAA,WAAW;AAGX,SAAA,WAAW;AAGX,SAAA,UAAU;AAGV,SAAA,iBAAiB;AAGjB,SAAA,WAAW;AAAA,EAAA;AAAA,EAEX,WAAW,wBAAwB;AACjC,WAAO,CAAC,iBAAiB;AAAA,EAC3B;AAAA,EAEA,wBAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,mBAAmB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,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,cAAA;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,cAAc;AACpB,SAAK,UAAU,CAAC,KAAK;AAErB,SAAK,cAAc,IAAI,MAAM,YAAY,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AACN,SAAK,MAAM,MAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAwB;AAC5B,SAAK,MAAM,MAAM,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO;AACL,SAAK,MAAM,KAAA;AAAA,EACb;AAAA,EAGA,oBAAoB;AAElB,SAAK,SAAS,KAAK,KAAK;AAAA,EAC1B;AAAA,EAES,SAAS;AAChB,UAAM,iBACJ,CAAC,CAAC,KAAK,eAAe,KAAK,kBAAkB,KAAK,aAAa;AACjE,UAAM,YAAY,KAAK,WAAW,CAAC,CAAC,KAAK;AACzC,UAAM,cACJ;AAAA,MACE,iBAAiB,KAAK,gBAAgB;AAAA,MACtC,KAAK,iBAAiB,KAAK,eAAe;AAAA,IAAA,EAEzC,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAMlB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAMG,UAAU,KAAK,KAAK,CAAC;AAAA,iBAClB,KAAK,KAAK,OAAO,CAAC;AAAA,sBACb,KAAK,QAAQ;AAAA,qBACd,KAAK,OAAO;AAAA,sBACX,KAAK,QAAQ;AAAA,sBACb,KAAK,QAAQ;AAAA,yBACV,YAAY,SAAS,OAAO;AAAA,6BACxB,UAAU,WAAW,CAAC;AAAA,8BACrB;AAAA,MAClB,KAAK,iBAAiB,KAAK,eAAe;AAAA,IAAA,CAC3C;AAAA,mBACQ,KAAK,WAAW;AAAA,qBACd,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAWvB,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAOpB,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA,mBAIX,SAAS;AAAA,MAChB,yBAAyB,CAAC,CAAC,KAAK;AAAA,IAAA,CACjC,CAAC;AAAA;AAAA,gBAEI,KAAK,YAAY;AAAA;AAAA;AAAA,YAGrB,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA,EAI7B;AACF;AA9KU,gBAAA;AAAA,EADP,MAAM,wBAAwB;AAAA,GAHpB,cAIH,WAAA,SAAA,CAAA;AAcR,gBAAA;AAAA,EADC,SAAA;AAAS,GAjBC,cAkBX,WAAA,QAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAA;AAAS,GAvBC,cAwBX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GA1BhB,cA2BX,WAAA,WAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GA7BC,cA8BX,WAAA,eAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAhChB,cAiCX,WAAA,YAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAnChB,cAoCX,WAAA,YAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAtChB,cAuCX,WAAA,WAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAzCC,cA0CX,WAAA,kBAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA,GA5C/B,cA6CX,WAAA,YAAA,CAAA;AA4DA,gBAAA;AAAA,EADC,MAAM,CAAC,WAAW,OAAO,CAAC;AAAA,GAxGhB,cAyGX,WAAA,qBAAA,CAAA;AAzGW,gBAAN,gBAAA;AAAA,EADN,cAAc,cAAc;AAAA,GAChB,aAAA;"}
|
|
@@ -14,10 +14,13 @@ declare const MinidCodeInput_base: import('../types/mixin-constructor.ts').Const
|
|
|
14
14
|
* @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown
|
|
15
15
|
*
|
|
16
16
|
* @slot label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.
|
|
17
|
+
* @slot description - The input's description if you need to use HTML. Alternatively, you can use the `description` attribute.
|
|
17
18
|
*
|
|
18
19
|
* @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.
|
|
20
|
+
* @csspart description - The description shown between the label and the character boxes.
|
|
19
21
|
* @csspart character-boxes - The container for the visual character boxes.
|
|
20
22
|
* @csspart character-box - An individual character box.
|
|
23
|
+
* @csspart validation-message - The error message shown by `invalidmessage`.
|
|
21
24
|
*
|
|
22
25
|
* @method focus - Focuses the input element
|
|
23
26
|
* @method clear - Clears the input
|
|
@@ -25,10 +28,12 @@ declare const MinidCodeInput_base: import('../types/mixin-constructor.ts').Const
|
|
|
25
28
|
export declare class MinidCodeInput extends MinidCodeInput_base {
|
|
26
29
|
private readonly hasSlotControler;
|
|
27
30
|
private readonly labelId;
|
|
31
|
+
private readonly descriptionId;
|
|
28
32
|
private readonly validationId;
|
|
29
33
|
private inputElement;
|
|
30
34
|
value: string;
|
|
31
35
|
label: string;
|
|
36
|
+
description: string;
|
|
32
37
|
type: 'number' | 'text';
|
|
33
38
|
/**
|
|
34
39
|
* For displaying appropriate virtual keyboard
|
|
@@ -38,6 +43,7 @@ export declare class MinidCodeInput extends MinidCodeInput_base {
|
|
|
38
43
|
* Adjusts the font-size of the code inputs
|
|
39
44
|
*/
|
|
40
45
|
size: 'sm' | 'md' | 'lg';
|
|
46
|
+
labelsize?: 'sm' | 'md' | 'lg';
|
|
41
47
|
/**
|
|
42
48
|
* Number of input characters or digits
|
|
43
49
|
*/
|
|
@@ -59,6 +65,7 @@ export declare class MinidCodeInput extends MinidCodeInput_base {
|
|
|
59
65
|
* Visually hides `label` (still available for screen readers)
|
|
60
66
|
*/
|
|
61
67
|
hidelabel: boolean;
|
|
68
|
+
hidedescription: boolean;
|
|
62
69
|
/**
|
|
63
70
|
* Makes the input required
|
|
64
71
|
*/
|
|
@@ -68,13 +75,28 @@ export declare class MinidCodeInput extends MinidCodeInput_base {
|
|
|
68
75
|
*/
|
|
69
76
|
pattern?: string;
|
|
70
77
|
private isFocused;
|
|
78
|
+
private caretPosition;
|
|
71
79
|
static get formControlValidators(): import('../types/validator.type.ts').Validator[];
|
|
72
80
|
get validationTarget(): HTMLInputElement;
|
|
73
81
|
protected firstUpdated(_changedProperties: PropertyValues): void;
|
|
82
|
+
connectedCallback(): void;
|
|
83
|
+
disconnectedCallback(): void;
|
|
74
84
|
private handleBoxClick;
|
|
85
|
+
/**
|
|
86
|
+
* Catches caret moves we did not make - arrow keys, Home/End, word jumps,
|
|
87
|
+
* shift-selection - without enumerating keys, and keeps up while a key is held.
|
|
88
|
+
*
|
|
89
|
+
* Must be listened for on the document: for a caret move the user made,
|
|
90
|
+
* Chromium fires it only there, not at the input and not into the shadow root,
|
|
91
|
+
* so an `@selectionchange` binding on either never runs.
|
|
92
|
+
*/
|
|
93
|
+
private handleSelectionChange;
|
|
94
|
+
private syncCaretPosition;
|
|
75
95
|
private handleFocus;
|
|
76
96
|
private handleBlur;
|
|
97
|
+
private filterValue;
|
|
77
98
|
private handleBeforeInput;
|
|
99
|
+
private handlePaste;
|
|
78
100
|
private handleInput;
|
|
79
101
|
private handleChange;
|
|
80
102
|
private handleKeydown;
|
|
@@ -82,6 +104,7 @@ export declare class MinidCodeInput extends MinidCodeInput_base {
|
|
|
82
104
|
resetFormControl(): void;
|
|
83
105
|
focus(options?: FocusOptions): void;
|
|
84
106
|
handleLengthChange(): void;
|
|
107
|
+
handleValueChange(): void;
|
|
85
108
|
render(): import('lit').TemplateResult<1>;
|
|
86
109
|
}
|
|
87
110
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-input.component.d.ts","sourceRoot":"","sources":["../../src/components/code-input.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,
|
|
1
|
+
{"version":3,"file":"code-input.component.d.ts","sourceRoot":"","sources":["../../src/components/code-input.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,cAAc,EAAE,MAAM,KAAK,CAAC;AASrE,OAAO,0BAA0B,CAAC;AASlC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,cAAc,CAAC;KAClC;CACF;;AA2PD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,cAAe,SAAQ,mBAEnC;IACC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAI/B;IACF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IACpE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkD;IAChF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiD;IAG9E,OAAO,CAAC,YAAY,CAAoB;IAGxC,KAAK,SAAM;IAGX,KAAK,SAAM;IAGX,WAAW,SAAM;IAGjB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAU;IAEjC;;OAEG;IAEH,SAAS,EAAE,SAAS,GAAG,MAAM,CAAa;IAE1C;;OAEG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAGhC,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAE/B;;OAEG;IAEH,MAAM,SAAK;IAGX,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,cAAc,SAAM;IAEpB;;OAEG;IAEH,SAAS,UAAS;IAGlB,eAAe,UAAS;IAExB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,aAAa,CAAK;IAE1B,MAAM,KAAK,qBAAqB,qDAO/B;IAED,IAAI,gBAAgB,qBAEnB;IAED,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI;IAIvD,iBAAiB;IAQjB,oBAAoB;IAQ7B,OAAO,CAAC,cAAc;IAYtB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB,CAK3B;IAEF,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,WAAW;IAqCnB,OAAO,CAAC,WAAW;IA6BnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;IAiBrB,KAAK;IAOL,gBAAgB;IAIhB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI;IAWnC,kBAAkB;IAOlB,iBAAiB;IAWR,MAAM;CAsIhB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { css, LitElement, html } from "lit";
|
|
1
|
+
import { css, LitElement, nothing, html } from "lit";
|
|
2
2
|
import { query, property, state, customElement } from "lit/decorators.js";
|
|
3
3
|
import { classMap } from "lit/directives/class-map.js";
|
|
4
4
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
@@ -35,7 +35,32 @@ const styles = [
|
|
|
35
35
|
font-weight: 500;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
.code-input-label--
|
|
38
|
+
.code-input-label--with-description {
|
|
39
|
+
margin-block-end: 0.25rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.code-input-label--sm {
|
|
43
|
+
font-size: var(--ds-body-sm-font-size, 1rem);
|
|
44
|
+
line-height: var(--ds-body-md-line-height, 1.5);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.code-input-label--md {
|
|
48
|
+
font-size: var(--ds-body-md-font-size, 1.125rem);
|
|
49
|
+
line-height: var(--ds-body-md-line-height, 1.5);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.code-input-label--lg {
|
|
53
|
+
font-size: var(--ds-body-lg-font-size, 1.3125rem);
|
|
54
|
+
line-height: var(--ds-body-md-line-height, 1.5);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.code-input-description {
|
|
58
|
+
margin-block-end: 0.5rem;
|
|
59
|
+
color: var(--ds-color-neutral-text-subtle, #545e6b);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.code-input-label--hidden,
|
|
63
|
+
.code-input-description--hidden {
|
|
39
64
|
position: absolute;
|
|
40
65
|
width: 1px;
|
|
41
66
|
height: 1px;
|
|
@@ -48,6 +73,7 @@ const styles = [
|
|
|
48
73
|
}
|
|
49
74
|
|
|
50
75
|
.code-input-label--disabled,
|
|
76
|
+
.code-input-description--disabled,
|
|
51
77
|
.input-wrapper--disabled {
|
|
52
78
|
opacity: var(--ds-opacity-disabled, 0.38);
|
|
53
79
|
}
|
|
@@ -215,27 +241,25 @@ const styles = [
|
|
|
215
241
|
animation: blink 1s step-end infinite;
|
|
216
242
|
}
|
|
217
243
|
|
|
244
|
+
.character-box--caret-leading::after {
|
|
245
|
+
inset-inline-start: 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
218
248
|
/* Hide placeholder circle when the caret is at this position */
|
|
219
249
|
.character-box--caret.character-box--empty {
|
|
220
250
|
color: transparent;
|
|
221
251
|
}
|
|
222
252
|
|
|
223
|
-
/* Hide increment/decrement buttons on number inputs */
|
|
224
|
-
input[type='number']::-webkit-outer-spin-button,
|
|
225
|
-
input[type='number']::-webkit-inner-spin-button,
|
|
226
|
-
input[type='number'] {
|
|
227
|
-
-webkit-appearance: none;
|
|
228
|
-
margin: 0;
|
|
229
|
-
-moz-appearance: textfield !important;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
253
|
.validation-message {
|
|
233
254
|
display: flex;
|
|
234
255
|
gap: 0.25rem;
|
|
235
|
-
margin-block-start: 0.5rem;
|
|
236
256
|
color: var(--ds-color-danger-text-subtle, #a22e2e);
|
|
237
257
|
}
|
|
238
258
|
|
|
259
|
+
.validation-message--visible {
|
|
260
|
+
margin-block-start: 0.5rem;
|
|
261
|
+
}
|
|
262
|
+
|
|
239
263
|
.validation-icon {
|
|
240
264
|
margin-block-start: 0.25rem;
|
|
241
265
|
min-width: 1.25rem;
|
|
@@ -248,11 +272,17 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
248
272
|
) {
|
|
249
273
|
constructor() {
|
|
250
274
|
super(...arguments);
|
|
251
|
-
this.hasSlotControler = new HasSlotController(
|
|
275
|
+
this.hasSlotControler = new HasSlotController(
|
|
276
|
+
this,
|
|
277
|
+
"label",
|
|
278
|
+
"description"
|
|
279
|
+
);
|
|
252
280
|
this.labelId = `mid-code-input-label-${nextUniqueId++}`;
|
|
281
|
+
this.descriptionId = `mid-code-input-description-${nextUniqueId++}`;
|
|
253
282
|
this.validationId = `mid-code-input-validation-${nextUniqueId++}`;
|
|
254
283
|
this.value = "";
|
|
255
284
|
this.label = "";
|
|
285
|
+
this.description = "";
|
|
256
286
|
this.type = "text";
|
|
257
287
|
this.inputmode = "numeric";
|
|
258
288
|
this.size = "sm";
|
|
@@ -261,8 +291,15 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
261
291
|
this.autofocus = false;
|
|
262
292
|
this.invalidmessage = "";
|
|
263
293
|
this.hidelabel = false;
|
|
294
|
+
this.hidedescription = false;
|
|
264
295
|
this.required = false;
|
|
265
296
|
this.isFocused = false;
|
|
297
|
+
this.caretPosition = 0;
|
|
298
|
+
this.handleSelectionChange = () => {
|
|
299
|
+
if (this.isFocused) {
|
|
300
|
+
this.syncCaretPosition();
|
|
301
|
+
}
|
|
302
|
+
};
|
|
266
303
|
}
|
|
267
304
|
static get formControlValidators() {
|
|
268
305
|
return [
|
|
@@ -278,6 +315,20 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
278
315
|
firstUpdated(_changedProperties) {
|
|
279
316
|
webOtpApiInit(this.renderRoot);
|
|
280
317
|
}
|
|
318
|
+
connectedCallback() {
|
|
319
|
+
super.connectedCallback();
|
|
320
|
+
this.ownerDocument.addEventListener(
|
|
321
|
+
"selectionchange",
|
|
322
|
+
this.handleSelectionChange
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
disconnectedCallback() {
|
|
326
|
+
super.disconnectedCallback();
|
|
327
|
+
this.ownerDocument.removeEventListener(
|
|
328
|
+
"selectionchange",
|
|
329
|
+
this.handleSelectionChange
|
|
330
|
+
);
|
|
331
|
+
}
|
|
281
332
|
handleBoxClick(index) {
|
|
282
333
|
if (this.disabled) {
|
|
283
334
|
return;
|
|
@@ -285,30 +336,67 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
285
336
|
this.value = this.value.substring(0, index);
|
|
286
337
|
this.focus();
|
|
287
338
|
}
|
|
339
|
+
syncCaretPosition() {
|
|
340
|
+
const input = this.inputElement;
|
|
341
|
+
if (!input) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
this.caretPosition = (input.selectionDirection === "backward" ? input.selectionStart : input.selectionEnd) ?? this.value.length;
|
|
345
|
+
}
|
|
288
346
|
handleFocus() {
|
|
289
347
|
this.isFocused = true;
|
|
290
348
|
if (this.value.length > 0) {
|
|
291
349
|
const length = this.value.length;
|
|
292
350
|
this.inputElement.setSelectionRange(length, length);
|
|
293
351
|
}
|
|
352
|
+
this.syncCaretPosition();
|
|
294
353
|
}
|
|
295
354
|
handleBlur() {
|
|
296
355
|
this.isFocused = false;
|
|
297
356
|
}
|
|
357
|
+
filterValue(value) {
|
|
358
|
+
return this.type === "number" ? value.replace(/\D/g, "") : value;
|
|
359
|
+
}
|
|
298
360
|
handleBeforeInput(e) {
|
|
299
|
-
if (e.inputType === "insertText" && e.data) {
|
|
300
|
-
if (
|
|
361
|
+
if (this.type === "number" && e.inputType === "insertText" && e.data) {
|
|
362
|
+
if (!/\d/.test(e.data)) {
|
|
301
363
|
e.preventDefault();
|
|
302
364
|
}
|
|
303
365
|
}
|
|
304
366
|
}
|
|
367
|
+
handlePaste(event) {
|
|
368
|
+
if (this.type !== "number") {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const pasted = event.clipboardData?.getData("text") ?? "";
|
|
372
|
+
const digits = this.filterValue(pasted);
|
|
373
|
+
if (digits === pasted) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
event.preventDefault();
|
|
377
|
+
const input = this.inputElement;
|
|
378
|
+
const start = input.selectionStart ?? input.value.length;
|
|
379
|
+
const end = input.selectionEnd ?? start;
|
|
380
|
+
const next = (input.value.slice(0, start) + digits + input.value.slice(end)).substring(0, this.length);
|
|
381
|
+
if (next === input.value) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
input.value = next;
|
|
385
|
+
input.dispatchEvent(
|
|
386
|
+
new InputEvent("input", { bubbles: true, composed: true })
|
|
387
|
+
);
|
|
388
|
+
const caret = Math.min(start + digits.length, input.value.length);
|
|
389
|
+
input.setSelectionRange(caret, caret);
|
|
390
|
+
this.syncCaretPosition();
|
|
391
|
+
}
|
|
305
392
|
handleInput(event) {
|
|
306
393
|
const input = event.target;
|
|
307
|
-
let value = input.value;
|
|
394
|
+
let value = this.filterValue(input.value);
|
|
308
395
|
value = value.substring(0, this.length);
|
|
309
396
|
if (input.value !== value) {
|
|
310
397
|
input.value = value;
|
|
311
398
|
}
|
|
399
|
+
this.syncCaretPosition();
|
|
312
400
|
if (this.value !== value) {
|
|
313
401
|
this.value = value;
|
|
314
402
|
this.setValue(value);
|
|
@@ -344,6 +432,7 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
344
432
|
this.value = "";
|
|
345
433
|
this.setValue("");
|
|
346
434
|
this.invalidmessage = "";
|
|
435
|
+
this.caretPosition = 0;
|
|
347
436
|
}
|
|
348
437
|
resetFormControl() {
|
|
349
438
|
this.clear();
|
|
@@ -354,34 +443,65 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
354
443
|
const length = this.value.length;
|
|
355
444
|
this.inputElement.setSelectionRange(length, length);
|
|
356
445
|
}
|
|
446
|
+
this.syncCaretPosition();
|
|
357
447
|
}
|
|
358
448
|
handleLengthChange() {
|
|
359
449
|
if (this.value.length > this.length) {
|
|
360
450
|
this.value = this.value.substring(0, this.length);
|
|
361
451
|
}
|
|
362
452
|
}
|
|
453
|
+
handleValueChange() {
|
|
454
|
+
const filtered = this.filterValue(this.value);
|
|
455
|
+
if (filtered !== this.value) {
|
|
456
|
+
this.value = filtered;
|
|
457
|
+
}
|
|
458
|
+
this.caretPosition = Math.min(this.caretPosition, this.value.length);
|
|
459
|
+
this.setValue(filtered);
|
|
460
|
+
}
|
|
363
461
|
render() {
|
|
364
462
|
const hasLabelSlot = this.hasSlotControler.test("label");
|
|
365
463
|
const hasLabel = !!this.label || !!hasLabelSlot;
|
|
366
|
-
const
|
|
464
|
+
const hasDescriptionSlot = this.hasSlotControler.test("description");
|
|
465
|
+
const hasDescription = !!this.description || !!hasDescriptionSlot;
|
|
466
|
+
const describedBy = [
|
|
467
|
+
hasDescription ? this.descriptionId : void 0,
|
|
468
|
+
this.invalidmessage ? this.validationId : void 0
|
|
469
|
+
].filter(Boolean).join(" ") || void 0;
|
|
367
470
|
const chars = this.value.split("");
|
|
368
471
|
const displayValues = Array.from(
|
|
369
472
|
{ length: this.length },
|
|
370
473
|
(_, i) => chars[i] || ""
|
|
371
474
|
);
|
|
372
|
-
const
|
|
373
|
-
const
|
|
475
|
+
const caretIndex = this.disabled || this.length === 0 ? -1 : Math.min(this.caretPosition, this.length - 1);
|
|
476
|
+
const caretIsInABox = this.caretPosition < this.length;
|
|
374
477
|
return html`
|
|
375
478
|
<label
|
|
376
479
|
id="${this.labelId}"
|
|
377
480
|
for="mid-code-input-hidden"
|
|
378
481
|
class="code-input-label ${classMap({
|
|
482
|
+
"code-input-label--sm": this.labelsize === "sm",
|
|
483
|
+
"code-input-label--md": this.labelsize === "md",
|
|
484
|
+
"code-input-label--lg": this.labelsize === "lg",
|
|
379
485
|
"code-input-label--hidden": this.hidelabel || !hasLabel,
|
|
486
|
+
"code-input-label--with-description": hasDescription,
|
|
380
487
|
"code-input-label--disabled": this.disabled
|
|
381
488
|
})}"
|
|
382
489
|
>
|
|
383
490
|
<slot name="label"> ${this.label} </slot>
|
|
384
491
|
</label>
|
|
492
|
+
${hasDescription ? html`
|
|
493
|
+
<div
|
|
494
|
+
id="${this.descriptionId}"
|
|
495
|
+
part="description"
|
|
496
|
+
aria-hidden="true"
|
|
497
|
+
class="code-input-description ${classMap({
|
|
498
|
+
"code-input-description--hidden": this.hidedescription,
|
|
499
|
+
"code-input-description--disabled": this.disabled
|
|
500
|
+
})}"
|
|
501
|
+
>
|
|
502
|
+
<slot name="description"> ${this.description} </slot>
|
|
503
|
+
</div>
|
|
504
|
+
` : nothing}
|
|
385
505
|
<div
|
|
386
506
|
part="input-container"
|
|
387
507
|
class="input-wrapper ${classMap({
|
|
@@ -395,7 +515,7 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
395
515
|
<div part="character-boxes" class="character-boxes" aria-hidden="true">
|
|
396
516
|
${displayValues.map((char, index) => {
|
|
397
517
|
const isFocusTarget = this.isFocused && index === caretIndex;
|
|
398
|
-
const hasCaret = isFocusTarget &&
|
|
518
|
+
const hasCaret = isFocusTarget && caretIsInABox;
|
|
399
519
|
return html`
|
|
400
520
|
<div
|
|
401
521
|
part="character-box"
|
|
@@ -403,6 +523,7 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
403
523
|
class="character-box ${classMap({
|
|
404
524
|
"character-box--invalid": !!this.invalidmessage,
|
|
405
525
|
"character-box--caret": hasCaret,
|
|
526
|
+
"character-box--caret-leading": hasCaret && !!char,
|
|
406
527
|
"character-box--empty": !char,
|
|
407
528
|
"focus-ring-sm": isFocusTarget
|
|
408
529
|
})}"
|
|
@@ -420,7 +541,7 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
420
541
|
class="hidden-input"
|
|
421
542
|
.value="${live(this.value)}"
|
|
422
543
|
id="mid-code-input-hidden"
|
|
423
|
-
type="
|
|
544
|
+
type="text"
|
|
424
545
|
aria-labelledby="${this.labelId}"
|
|
425
546
|
aria-describedby=${ifDefined(describedBy)}
|
|
426
547
|
aria-invalid=${this.invalidmessage ? "true" : "false"}
|
|
@@ -435,6 +556,7 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
435
556
|
inputmode="${this.inputmode}"
|
|
436
557
|
autocomplete="one-time-code"
|
|
437
558
|
@beforeinput="${this.handleBeforeInput}"
|
|
559
|
+
@paste="${this.handlePaste}"
|
|
438
560
|
@input="${this.handleInput}"
|
|
439
561
|
@change="${this.handleChange}"
|
|
440
562
|
@keydown="${this.handleKeydown}"
|
|
@@ -443,13 +565,18 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
443
565
|
/>
|
|
444
566
|
</div>
|
|
445
567
|
<div
|
|
446
|
-
class="validation-message
|
|
568
|
+
class="validation-message ${classMap({
|
|
569
|
+
"validation-message--visible": !!this.invalidmessage
|
|
570
|
+
})}"
|
|
571
|
+
part="validation-message"
|
|
447
572
|
id="${this.validationId}"
|
|
448
573
|
aria-live="polite"
|
|
449
|
-
?hidden=${!this.invalidmessage}
|
|
450
574
|
>
|
|
451
|
-
|
|
452
|
-
|
|
575
|
+
${this.invalidmessage ? html`<mid-icon
|
|
576
|
+
name="xmark-octagon-fill"
|
|
577
|
+
class="validation-icon"
|
|
578
|
+
></mid-icon>
|
|
579
|
+
${this.invalidmessage}` : nothing}
|
|
453
580
|
</div>
|
|
454
581
|
`;
|
|
455
582
|
}
|
|
@@ -463,6 +590,9 @@ __decorateClass([
|
|
|
463
590
|
__decorateClass([
|
|
464
591
|
property()
|
|
465
592
|
], MinidCodeInput.prototype, "label", 2);
|
|
593
|
+
__decorateClass([
|
|
594
|
+
property()
|
|
595
|
+
], MinidCodeInput.prototype, "description", 2);
|
|
466
596
|
__decorateClass([
|
|
467
597
|
property()
|
|
468
598
|
], MinidCodeInput.prototype, "type", 2);
|
|
@@ -472,6 +602,9 @@ __decorateClass([
|
|
|
472
602
|
__decorateClass([
|
|
473
603
|
property()
|
|
474
604
|
], MinidCodeInput.prototype, "size", 2);
|
|
605
|
+
__decorateClass([
|
|
606
|
+
property()
|
|
607
|
+
], MinidCodeInput.prototype, "labelsize", 2);
|
|
475
608
|
__decorateClass([
|
|
476
609
|
property({ type: Number })
|
|
477
610
|
], MinidCodeInput.prototype, "length", 2);
|
|
@@ -490,6 +623,9 @@ __decorateClass([
|
|
|
490
623
|
__decorateClass([
|
|
491
624
|
property({ type: Boolean })
|
|
492
625
|
], MinidCodeInput.prototype, "hidelabel", 2);
|
|
626
|
+
__decorateClass([
|
|
627
|
+
property({ type: Boolean })
|
|
628
|
+
], MinidCodeInput.prototype, "hidedescription", 2);
|
|
493
629
|
__decorateClass([
|
|
494
630
|
property({ type: Boolean })
|
|
495
631
|
], MinidCodeInput.prototype, "required", 2);
|
|
@@ -499,9 +635,15 @@ __decorateClass([
|
|
|
499
635
|
__decorateClass([
|
|
500
636
|
state()
|
|
501
637
|
], MinidCodeInput.prototype, "isFocused", 2);
|
|
638
|
+
__decorateClass([
|
|
639
|
+
state()
|
|
640
|
+
], MinidCodeInput.prototype, "caretPosition", 2);
|
|
502
641
|
__decorateClass([
|
|
503
642
|
watch("length")
|
|
504
643
|
], MinidCodeInput.prototype, "handleLengthChange", 1);
|
|
644
|
+
__decorateClass([
|
|
645
|
+
watch(["value", "type"])
|
|
646
|
+
], MinidCodeInput.prototype, "handleValueChange", 1);
|
|
505
647
|
MinidCodeInput = __decorateClass([
|
|
506
648
|
customElement("mid-code-input")
|
|
507
649
|
], MinidCodeInput);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-input.js","sources":["../../src/components/code-input.component.ts"],"sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { live } from 'lit/directives/live.js';\nimport { watch } from '../internal/watch.ts';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { HasSlotController } from '../internal/slot.ts';\nimport './icon/icon.component.ts';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators.ts';\nimport { webOtpApiInit } from '../utilities/web-otp-api.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n\n .code-input-label {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n margin-block-end: 0.5rem;\n font-weight: 500;\n }\n\n .code-input-label--hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n .code-input-label--disabled,\n .input-wrapper--disabled {\n opacity: var(--ds-opacity-disabled, 0.38);\n }\n\n .input-wrapper {\n position: relative;\n cursor: text;\n width: fit-content;\n font-size: 1rem;\n line-height: 1.3;\n font-weight: 500;\n }\n\n .input-wrapper--sm {\n font-size: var(--ds-heading-sm-font-size, 1.125rem);\n line-height: var(--ds-heading-sm-line-height, 1.3);\n font-weight: var(--ds-heading-sm-font-weight, 500);\n }\n\n .input-wrapper--md {\n font-size: var(--ds-heading-md-font-size, 1.25rem);\n line-height: var(--ds-heading-md-line-height, 1.3);\n font-weight: var(--ds-heading-md-font-weight, 500);\n }\n\n .input-wrapper--lg {\n font-size: var(--ds-heading-lg-font-size, 1.5rem);\n line-height: var(--ds-heading-lg-line-height, 1.3);\n font-weight: var(--ds-heading-lg-font-weight, 500);\n }\n\n .input-wrapper--disabled {\n cursor: not-allowed;\n }\n\n .character-boxes {\n display: inline-flex;\n gap: var(--mid-code-input-gap, 0.5rem);\n }\n\n .character-box {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n box-sizing: border-box;\n width: var(--mid-code-input-box-size, var(--ds-size-13, 3.25rem));\n height: var(--mid-code-input-box-size, var(--ds-size-13, 3.25rem));\n padding-inline: 0.25rem;\n user-select: none;\n text-align: center;\n font-family:\n ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,\n 'Liberation Mono', 'Courier New', monospace;\n line-height: 1;\n border: var(--ds-border-width-default, 1px) solid\n var(\n --mid-code-input-border-color,\n var(--ds-color-neutral-border-default, #717a84)\n );\n border-radius: var(\n --mid-code-input-border-radius,\n var(--ds-border-radius-md, 0.25rem)\n );\n background-color: var(\n --mid-code-input-background,\n var(--ds-color-neutral-background-default, #ffffff)\n );\n color: var(--mid-code-input-text-color, inherit);\n }\n\n .character-box--empty {\n color: var(\n --mid-code-input-placeholder-color,\n var(--ds-color-neutral-surface-active, #c7cacf)\n );\n }\n\n .character-box--empty::before {\n content: '';\n box-sizing: border-box;\n width: 0.55em;\n height: 0.55em;\n border: 2px solid currentColor;\n border-radius: 50%;\n }\n\n .character-box--invalid {\n border-width: 2px;\n border-color: var(\n --mid-code-input-danger-border-color,\n var(--ds-color-danger-border-default, #ce4d4d)\n );\n background-color: var(\n --mid-code-input-danger-background,\n var(--ds-color-danger-surface-tinted, #f8e4e4)\n );\n }\n\n .character-box--invalid.character-box--empty {\n color: var(\n --mid-code-input-danger-placeholder-color,\n var(--ds-color-danger-surface-active, #edbfbf)\n );\n }\n\n .focus-ring-sm {\n outline: 2px solid var(--ds-color-focus-outer, #1f2c3d);\n outline-offset: 2px;\n box-shadow: 0 0 0 2px var(--ds-color-focus-inner, #ffffff);\n }\n\n /* Ensure hidden attribute always hides elements even when Tailwind's\n @layer base [hidden] rule is not available in the shadow DOM */\n [hidden] {\n display: none !important;\n }\n\n .hidden-input {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n margin: 0;\n background: transparent;\n border: none;\n outline: none;\n color: transparent;\n caret-color: transparent;\n font-size: 16px; /* Minimum 16px prevents iOS zoom on focus */\n pointer-events: none;\n -webkit-appearance: none;\n appearance: none;\n }\n\n .hidden-input:focus {\n outline: none;\n }\n\n .hidden-input:disabled {\n cursor: not-allowed;\n }\n\n @keyframes blink {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n }\n }\n\n .character-box--caret::after {\n content: '';\n position: absolute;\n width: 2px;\n height: 60%;\n background-color: var(\n --color-accent-base,\n var(--ds-color-accent-base-default, blue)\n );\n animation: blink 1s step-end infinite;\n }\n\n /* Hide placeholder circle when the caret is at this position */\n .character-box--caret.character-box--empty {\n color: transparent;\n }\n\n /* Hide increment/decrement buttons on number 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 .validation-message {\n display: flex;\n gap: 0.25rem;\n margin-block-start: 0.5rem;\n color: var(--ds-color-danger-text-subtle, #a22e2e);\n }\n\n .validation-icon {\n margin-block-start: 0.25rem;\n min-width: 1.25rem;\n min-height: 1.25rem;\n }\n `,\n];\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-complete - Emitted when all characters have been entered.\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 label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.\n *\n * @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.\n * @csspart character-boxes - The container for the visual character boxes.\n * @csspart character-box - An individual character box.\n *\n * @method focus - Focuses the input element\n * @method clear - Clears the input\n */\n@customElement('mid-code-input')\nexport class MinidCodeInput extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private readonly labelId = `mid-code-input-label-${nextUniqueId++}`;\n private readonly validationId = `mid-code-input-validation-${nextUniqueId++}`;\n\n @query('.hidden-input')\n private inputElement!: HTMLInputElement;\n\n @property({ reflect: true })\n value = '';\n\n @property()\n label = '';\n\n @property()\n type: 'number' | 'text' = 'text';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode: 'numeric' | 'text' = 'numeric';\n\n /**\n * Adjusts the font-size of the code inputs\n */\n @property()\n size: 'sm' | 'md' | 'lg' = 'sm';\n\n /**\n * Number of input characters or digits\n */\n @property({ type: Number })\n length = 5;\n\n @property({ type: Boolean })\n disabled = false;\n\n /**\n * Focuses the first input element on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n /**\n * Visually hides `label` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n @state()\n private isFocused = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n get validationTarget() {\n return this.inputElement;\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n webOtpApiInit(this.renderRoot);\n }\n\n private handleBoxClick(index: number) {\n if (this.disabled) {\n return;\n }\n\n // Truncate the value to the clicked position\n this.value = this.value.substring(0, index);\n\n // Focus the input to move the caret\n this.focus();\n }\n\n private handleFocus() {\n this.isFocused = true;\n /* don't select text, move caret to the end */\n if (this.value.length > 0) {\n const length = this.value.length;\n this.inputElement.setSelectionRange(length, length);\n }\n }\n\n private handleBlur() {\n this.isFocused = false;\n }\n\n private handleBeforeInput(e: InputEvent) {\n if (e.inputType === 'insertText' && e.data) {\n if (this.type == 'number' && e.data.replace(/\\D/g, '') == '') {\n e.preventDefault();\n }\n }\n }\n\n private handleInput(event: InputEvent) {\n const input = event.target as HTMLInputElement;\n let value = input.value;\n\n value = value.substring(0, this.length);\n\n if (input.value !== value) {\n input.value = value;\n }\n\n // Update the component's public `value` property if it has changed.\n if (this.value !== value) {\n this.value = value;\n this.setValue(value);\n }\n\n this.inputElement.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n\n if (this.value.length === this.length && this.value.length > 0) {\n this.inputElement.dispatchEvent(\n new Event('mid-complete', { bubbles: true, composed: true })\n );\n }\n }\n\n private handleChange() {\n this.inputElement.dispatchEvent(\n new Event('mid-change', {\n bubbles: true,\n composed: true,\n })\n );\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 // 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 setTimeout(() => {\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 clear() {\n this.value = '';\n this.setValue('');\n this.invalidmessage = '';\n }\n\n resetFormControl() {\n this.clear();\n }\n\n focus(options?: FocusOptions): void {\n this.inputElement?.focus(options);\n /* don't select text, move caret to the end */\n if (this.value.length > 0) {\n const length = this.value.length;\n this.inputElement.setSelectionRange(length, length);\n }\n }\n\n @watch('length')\n handleLengthChange() {\n if (this.value.length > this.length) {\n this.value = this.value.substring(0, this.length);\n }\n }\n\n override render() {\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const describedBy = this.invalidmessage ? this.validationId : undefined;\n\n const chars = this.value.split('');\n const displayValues = Array.from(\n { length: this.length },\n (_, i) => chars[i] || ''\n );\n const isComplete = this.value.length >= this.length;\n const caretIndex =\n this.disabled || this.length === 0\n ? -1\n : Math.min(this.value.length, this.length - 1);\n\n return html`\n <label\n id=\"${this.labelId}\"\n for=\"mid-code-input-hidden\"\n class=\"code-input-label ${classMap({\n 'code-input-label--hidden': this.hidelabel || !hasLabel,\n 'code-input-label--disabled': this.disabled,\n })}\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n <div\n part=\"input-container\"\n class=\"input-wrapper ${classMap({\n 'input-wrapper--sm': this.size === 'sm',\n 'input-wrapper--md': this.size === 'md',\n 'input-wrapper--lg': this.size === 'lg',\n 'input-wrapper--disabled': this.disabled,\n })}\"\n @click=${() => this.focus()}\n >\n <div part=\"character-boxes\" class=\"character-boxes\" aria-hidden=\"true\">\n ${displayValues.map((char, index) => {\n const isFocusTarget = this.isFocused && index === caretIndex;\n const hasCaret = isFocusTarget && !isComplete;\n return html`\n <div\n part=\"character-box\"\n aria-hidden=\"true\"\n class=\"character-box ${classMap({\n 'character-box--invalid': !!this.invalidmessage,\n 'character-box--caret': hasCaret,\n 'character-box--empty': !char,\n 'focus-ring-sm': isFocusTarget,\n })}\"\n @click=${(e: MouseEvent) => {\n e.stopPropagation();\n this.handleBoxClick(index);\n }}\n >\n ${char}\n </div>\n `;\n })}\n </div>\n <input\n class=\"hidden-input\"\n .value=\"${live(this.value)}\"\n id=\"mid-code-input-hidden\"\n type=\"${this.type}\"\n aria-labelledby=\"${this.labelId}\"\n aria-describedby=${ifDefined(describedBy)}\n aria-invalid=${this.invalidmessage ? 'true' : 'false'}\n aria-errormessage=${ifDefined(\n this.invalidmessage ? this.validationId : undefined\n )}\n maxlength=\"${this.length}\"\n ?autofocus=\"${this.autofocus}\"\n ?disabled=\"${this.disabled}\"\n ?required=\"${this.required}\"\n pattern=${ifDefined(this.pattern)}\n inputmode=\"${this.inputmode}\"\n autocomplete=\"one-time-code\"\n @beforeinput=\"${this.handleBeforeInput}\"\n @input=\"${this.handleInput}\"\n @change=\"${this.handleChange}\"\n @keydown=\"${this.handleKeydown}\"\n @focus=\"${this.handleFocus}\"\n @blur=\"${this.handleBlur}\"\n />\n </div>\n <div\n class=\"validation-message\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon name=\"xmark-octagon-fill\" class=\"validation-icon\"></mid-icon>\n ${this.invalidmessage}\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"code-input.js","sources":["../../src/components/code-input.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing, PropertyValues } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { live } from 'lit/directives/live.js';\nimport { watch } from '../internal/watch.ts';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { HasSlotController } from '../internal/slot.ts';\nimport './icon/icon.component.ts';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators.ts';\nimport { webOtpApiInit } from '../utilities/web-otp-api.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n\n .code-input-label {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n margin-block-end: 0.5rem;\n font-weight: 500;\n }\n\n .code-input-label--with-description {\n margin-block-end: 0.25rem;\n }\n\n .code-input-label--sm {\n font-size: var(--ds-body-sm-font-size, 1rem);\n line-height: var(--ds-body-md-line-height, 1.5);\n }\n\n .code-input-label--md {\n font-size: var(--ds-body-md-font-size, 1.125rem);\n line-height: var(--ds-body-md-line-height, 1.5);\n }\n\n .code-input-label--lg {\n font-size: var(--ds-body-lg-font-size, 1.3125rem);\n line-height: var(--ds-body-md-line-height, 1.5);\n }\n\n .code-input-description {\n margin-block-end: 0.5rem;\n color: var(--ds-color-neutral-text-subtle, #545e6b);\n }\n\n .code-input-label--hidden,\n .code-input-description--hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n .code-input-label--disabled,\n .code-input-description--disabled,\n .input-wrapper--disabled {\n opacity: var(--ds-opacity-disabled, 0.38);\n }\n\n .input-wrapper {\n position: relative;\n cursor: text;\n width: fit-content;\n font-size: 1rem;\n line-height: 1.3;\n font-weight: 500;\n }\n\n .input-wrapper--sm {\n font-size: var(--ds-heading-sm-font-size, 1.125rem);\n line-height: var(--ds-heading-sm-line-height, 1.3);\n font-weight: var(--ds-heading-sm-font-weight, 500);\n }\n\n .input-wrapper--md {\n font-size: var(--ds-heading-md-font-size, 1.25rem);\n line-height: var(--ds-heading-md-line-height, 1.3);\n font-weight: var(--ds-heading-md-font-weight, 500);\n }\n\n .input-wrapper--lg {\n font-size: var(--ds-heading-lg-font-size, 1.5rem);\n line-height: var(--ds-heading-lg-line-height, 1.3);\n font-weight: var(--ds-heading-lg-font-weight, 500);\n }\n\n .input-wrapper--disabled {\n cursor: not-allowed;\n }\n\n .character-boxes {\n display: inline-flex;\n gap: var(--mid-code-input-gap, 0.5rem);\n }\n\n .character-box {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n box-sizing: border-box;\n width: var(--mid-code-input-box-size, var(--ds-size-13, 3.25rem));\n height: var(--mid-code-input-box-size, var(--ds-size-13, 3.25rem));\n padding-inline: 0.25rem;\n user-select: none;\n text-align: center;\n font-family:\n ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,\n 'Liberation Mono', 'Courier New', monospace;\n line-height: 1;\n border: var(--ds-border-width-default, 1px) solid\n var(\n --mid-code-input-border-color,\n var(--ds-color-neutral-border-default, #717a84)\n );\n border-radius: var(\n --mid-code-input-border-radius,\n var(--ds-border-radius-md, 0.25rem)\n );\n background-color: var(\n --mid-code-input-background,\n var(--ds-color-neutral-background-default, #ffffff)\n );\n color: var(--mid-code-input-text-color, inherit);\n }\n\n .character-box--empty {\n color: var(\n --mid-code-input-placeholder-color,\n var(--ds-color-neutral-surface-active, #c7cacf)\n );\n }\n\n .character-box--empty::before {\n content: '';\n box-sizing: border-box;\n width: 0.55em;\n height: 0.55em;\n border: 2px solid currentColor;\n border-radius: 50%;\n }\n\n .character-box--invalid {\n border-width: 2px;\n border-color: var(\n --mid-code-input-danger-border-color,\n var(--ds-color-danger-border-default, #ce4d4d)\n );\n background-color: var(\n --mid-code-input-danger-background,\n var(--ds-color-danger-surface-tinted, #f8e4e4)\n );\n }\n\n .character-box--invalid.character-box--empty {\n color: var(\n --mid-code-input-danger-placeholder-color,\n var(--ds-color-danger-surface-active, #edbfbf)\n );\n }\n\n .focus-ring-sm {\n outline: 2px solid var(--ds-color-focus-outer, #1f2c3d);\n outline-offset: 2px;\n box-shadow: 0 0 0 2px var(--ds-color-focus-inner, #ffffff);\n }\n\n /* Ensure hidden attribute always hides elements even when Tailwind's\n @layer base [hidden] rule is not available in the shadow DOM */\n [hidden] {\n display: none !important;\n }\n\n .hidden-input {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n margin: 0;\n background: transparent;\n border: none;\n outline: none;\n color: transparent;\n caret-color: transparent;\n font-size: 16px; /* Minimum 16px prevents iOS zoom on focus */\n pointer-events: none;\n -webkit-appearance: none;\n appearance: none;\n }\n\n .hidden-input:focus {\n outline: none;\n }\n\n .hidden-input:disabled {\n cursor: not-allowed;\n }\n\n @keyframes blink {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n }\n }\n\n .character-box--caret::after {\n content: '';\n position: absolute;\n width: 2px;\n height: 60%;\n background-color: var(\n --color-accent-base,\n var(--ds-color-accent-base-default, blue)\n );\n animation: blink 1s step-end infinite;\n }\n\n .character-box--caret-leading::after {\n inset-inline-start: 0;\n }\n\n /* Hide placeholder circle when the caret is at this position */\n .character-box--caret.character-box--empty {\n color: transparent;\n }\n\n .validation-message {\n display: flex;\n gap: 0.25rem;\n color: var(--ds-color-danger-text-subtle, #a22e2e);\n }\n\n .validation-message--visible {\n margin-block-start: 0.5rem;\n }\n\n .validation-icon {\n margin-block-start: 0.25rem;\n min-width: 1.25rem;\n min-height: 1.25rem;\n }\n `,\n];\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-complete - Emitted when all characters have been entered.\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 label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.\n * @slot description - The input's description if you need to use HTML. Alternatively, you can use the `description` attribute.\n *\n * @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.\n * @csspart description - The description shown between the label and the character boxes.\n * @csspart character-boxes - The container for the visual character boxes.\n * @csspart character-box - An individual character box.\n * @csspart validation-message - The error message shown by `invalidmessage`.\n *\n * @method focus - Focuses the input element\n * @method clear - Clears the input\n */\n@customElement('mid-code-input')\nexport class MinidCodeInput extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly hasSlotControler = new HasSlotController(\n this,\n 'label',\n 'description'\n );\n private readonly labelId = `mid-code-input-label-${nextUniqueId++}`;\n private readonly descriptionId = `mid-code-input-description-${nextUniqueId++}`;\n private readonly validationId = `mid-code-input-validation-${nextUniqueId++}`;\n\n @query('.hidden-input')\n private inputElement!: HTMLInputElement;\n\n @property({ reflect: true })\n value = '';\n\n @property()\n label = '';\n\n @property()\n description = '';\n\n @property()\n type: 'number' | 'text' = 'text';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode: 'numeric' | 'text' = 'numeric';\n\n /**\n * Adjusts the font-size of the code inputs\n */\n @property()\n size: 'sm' | 'md' | 'lg' = 'sm';\n\n @property()\n labelsize?: 'sm' | 'md' | 'lg';\n\n /**\n * Number of input characters or digits\n */\n @property({ type: Number })\n length = 5;\n\n @property({ type: Boolean })\n disabled = false;\n\n /**\n * Focuses the first input element on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n /**\n * Visually hides `label` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n @property({ type: Boolean })\n hidedescription = false;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n @state()\n private isFocused = false;\n\n @state()\n private caretPosition = 0;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n get validationTarget() {\n return this.inputElement;\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n webOtpApiInit(this.renderRoot);\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.ownerDocument.addEventListener(\n 'selectionchange',\n this.handleSelectionChange\n );\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.ownerDocument.removeEventListener(\n 'selectionchange',\n this.handleSelectionChange\n );\n }\n\n private handleBoxClick(index: number) {\n if (this.disabled) {\n return;\n }\n\n // Truncate the value to the clicked position\n this.value = this.value.substring(0, index);\n\n // Focus the input to move the caret\n this.focus();\n }\n\n /**\n * Catches caret moves we did not make - arrow keys, Home/End, word jumps,\n * shift-selection - without enumerating keys, and keeps up while a key is held.\n *\n * Must be listened for on the document: for a caret move the user made,\n * Chromium fires it only there, not at the input and not into the shadow root,\n * so an `@selectionchange` binding on either never runs.\n */\n private handleSelectionChange = () => {\n // Fires for selection changes anywhere on the page\n if (this.isFocused) {\n this.syncCaretPosition();\n }\n };\n\n private syncCaretPosition() {\n const input = this.inputElement;\n\n if (!input) {\n return;\n }\n\n this.caretPosition =\n (input.selectionDirection === 'backward'\n ? input.selectionStart\n : input.selectionEnd) ?? this.value.length;\n }\n\n private handleFocus() {\n this.isFocused = true;\n /* don't select text, move caret to the end */\n if (this.value.length > 0) {\n const length = this.value.length;\n this.inputElement.setSelectionRange(length, length);\n }\n this.syncCaretPosition();\n }\n\n private handleBlur() {\n this.isFocused = false;\n }\n\n private filterValue(value: string) {\n return this.type === 'number' ? value.replace(/\\D/g, '') : value;\n }\n\n private handleBeforeInput(e: InputEvent) {\n if (this.type === 'number' && e.inputType === 'insertText' && e.data) {\n if (!/\\d/.test(e.data)) {\n e.preventDefault();\n }\n }\n }\n\n private handlePaste(event: ClipboardEvent) {\n if (this.type !== 'number') {\n return;\n }\n\n const pasted = event.clipboardData?.getData('text') ?? '';\n const digits = this.filterValue(pasted);\n\n if (digits === pasted) {\n return;\n }\n\n event.preventDefault();\n\n const input = this.inputElement;\n const start = input.selectionStart ?? input.value.length;\n const end = input.selectionEnd ?? start;\n const next = (\n input.value.slice(0, start) +\n digits +\n input.value.slice(end)\n ).substring(0, this.length);\n\n if (next === input.value) {\n return;\n }\n\n input.value = next;\n input.dispatchEvent(\n new InputEvent('input', { bubbles: true, composed: true })\n );\n\n const caret = Math.min(start + digits.length, input.value.length);\n input.setSelectionRange(caret, caret);\n this.syncCaretPosition();\n }\n\n private handleInput(event: InputEvent) {\n const input = event.target as HTMLInputElement;\n let value = this.filterValue(input.value);\n\n value = value.substring(0, this.length);\n\n if (input.value !== value) {\n input.value = value;\n }\n\n this.syncCaretPosition();\n\n // Update the component's public `value` property if it has changed.\n if (this.value !== value) {\n this.value = value;\n this.setValue(value);\n }\n\n this.inputElement.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n\n if (this.value.length === this.length && this.value.length > 0) {\n this.inputElement.dispatchEvent(\n new Event('mid-complete', { bubbles: true, composed: true })\n );\n }\n }\n\n private handleChange() {\n this.inputElement.dispatchEvent(\n new Event('mid-change', {\n bubbles: true,\n composed: true,\n })\n );\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 // 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 setTimeout(() => {\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 clear() {\n this.value = '';\n this.setValue('');\n this.invalidmessage = '';\n this.caretPosition = 0;\n }\n\n resetFormControl() {\n this.clear();\n }\n\n focus(options?: FocusOptions): void {\n this.inputElement?.focus(options);\n /* don't select text, move caret to the end */\n if (this.value.length > 0) {\n const length = this.value.length;\n this.inputElement.setSelectionRange(length, length);\n }\n this.syncCaretPosition();\n }\n\n @watch('length')\n handleLengthChange() {\n if (this.value.length > this.length) {\n this.value = this.value.substring(0, this.length);\n }\n }\n\n @watch(['value', 'type'])\n handleValueChange() {\n const filtered = this.filterValue(this.value);\n\n if (filtered !== this.value) {\n this.value = filtered;\n }\n\n this.caretPosition = Math.min(this.caretPosition, this.value.length);\n this.setValue(filtered);\n }\n\n override render() {\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const hasDescriptionSlot = this.hasSlotControler.test('description');\n const hasDescription = !!this.description || !!hasDescriptionSlot;\n const describedBy =\n [\n hasDescription ? this.descriptionId : undefined,\n this.invalidmessage ? this.validationId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n const chars = this.value.split('');\n const displayValues = Array.from(\n { length: this.length },\n (_, i) => chars[i] || ''\n );\n const caretIndex =\n this.disabled || this.length === 0\n ? -1\n : Math.min(this.caretPosition, this.length - 1);\n const caretIsInABox = this.caretPosition < this.length;\n\n return html`\n <label\n id=\"${this.labelId}\"\n for=\"mid-code-input-hidden\"\n class=\"code-input-label ${classMap({\n 'code-input-label--sm': this.labelsize === 'sm',\n 'code-input-label--md': this.labelsize === 'md',\n 'code-input-label--lg': this.labelsize === 'lg',\n 'code-input-label--hidden': this.hidelabel || !hasLabel,\n 'code-input-label--with-description': hasDescription,\n 'code-input-label--disabled': this.disabled,\n })}\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n ${hasDescription\n ? html`\n <div\n id=\"${this.descriptionId}\"\n part=\"description\"\n aria-hidden=\"true\"\n class=\"code-input-description ${classMap({\n 'code-input-description--hidden': this.hidedescription,\n 'code-input-description--disabled': this.disabled,\n })}\"\n >\n <slot name=\"description\"> ${this.description} </slot>\n </div>\n `\n : nothing}\n <div\n part=\"input-container\"\n class=\"input-wrapper ${classMap({\n 'input-wrapper--sm': this.size === 'sm',\n 'input-wrapper--md': this.size === 'md',\n 'input-wrapper--lg': this.size === 'lg',\n 'input-wrapper--disabled': this.disabled,\n })}\"\n @click=${() => this.focus()}\n >\n <div part=\"character-boxes\" class=\"character-boxes\" aria-hidden=\"true\">\n ${displayValues.map((char, index) => {\n const isFocusTarget = this.isFocused && index === caretIndex;\n const hasCaret = isFocusTarget && caretIsInABox;\n return html`\n <div\n part=\"character-box\"\n aria-hidden=\"true\"\n class=\"character-box ${classMap({\n 'character-box--invalid': !!this.invalidmessage,\n 'character-box--caret': hasCaret,\n 'character-box--caret-leading': hasCaret && !!char,\n 'character-box--empty': !char,\n 'focus-ring-sm': isFocusTarget,\n })}\"\n @click=${(e: MouseEvent) => {\n e.stopPropagation();\n this.handleBoxClick(index);\n }}\n >\n ${char}\n </div>\n `;\n })}\n </div>\n <input\n class=\"hidden-input\"\n .value=\"${live(this.value)}\"\n id=\"mid-code-input-hidden\"\n type=\"text\"\n aria-labelledby=\"${this.labelId}\"\n aria-describedby=${ifDefined(describedBy)}\n aria-invalid=${this.invalidmessage ? 'true' : 'false'}\n aria-errormessage=${ifDefined(\n this.invalidmessage ? this.validationId : undefined\n )}\n maxlength=\"${this.length}\"\n ?autofocus=\"${this.autofocus}\"\n ?disabled=\"${this.disabled}\"\n ?required=\"${this.required}\"\n pattern=${ifDefined(this.pattern)}\n inputmode=\"${this.inputmode}\"\n autocomplete=\"one-time-code\"\n @beforeinput=\"${this.handleBeforeInput}\"\n @paste=\"${this.handlePaste}\"\n @input=\"${this.handleInput}\"\n @change=\"${this.handleChange}\"\n @keydown=\"${this.handleKeydown}\"\n @focus=\"${this.handleFocus}\"\n @blur=\"${this.handleBlur}\"\n />\n </div>\n <div\n class=\"validation-message ${classMap({\n 'validation-message--visible': !!this.invalidmessage,\n })}\"\n part=\"validation-message\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n >\n ${this.invalidmessage\n ? html`<mid-icon\n name=\"xmark-octagon-fill\"\n class=\"validation-icon\"\n ></mid-icon>\n ${this.invalidmessage}`\n : nothing}\n </div>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAI,eAAe;AAEnB,MAAM,SAAS;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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"}
|
|
@@ -25,6 +25,7 @@ declare const MinidTextfield_base: import('../types/mixin-constructor.ts').Const
|
|
|
25
25
|
* @csspart field - The element that wraps the label, input, and help text.
|
|
26
26
|
* @csspart clear-button - The clear button
|
|
27
27
|
* @csspart password-toggle-button - The button for toggling password visibility
|
|
28
|
+
* @csspart validation-message - The error message shown by `invalidmessage`.
|
|
28
29
|
*/
|
|
29
30
|
export declare class MinidTextfield extends MinidTextfield_base {
|
|
30
31
|
private readonly inputId;
|
|
@@ -1 +1 @@
|
|
|
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;;
|
|
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;;AAoCD;;;;;;;;;;;;;;;;;;;;GAoBG;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;CAiJhB"}
|
|
@@ -42,6 +42,17 @@ const styles = [
|
|
|
42
42
|
.ds-field-affixes {
|
|
43
43
|
background: var(--ds-color-neutral-background-tinted);
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
/* The validation message stays in the DOM so its text lands in a live region
|
|
47
|
+
the screen reader is already watching - WebKit does not reliably announce
|
|
48
|
+
one revealed at the same moment the text arrives. When empty it must paint
|
|
49
|
+
nothing and take no room: the element drops the ds-validation-message class
|
|
50
|
+
(whose ::before paints an error icon regardless of the text) and this rule
|
|
51
|
+
cancels the sibling spacing from .ds-field > * + *, which the .ds-field >
|
|
52
|
+
prefix is enough to outrank without !important. */
|
|
53
|
+
.ds-field > .validation-message--empty {
|
|
54
|
+
margin-top: 0;
|
|
55
|
+
}
|
|
45
56
|
`
|
|
46
57
|
];
|
|
47
58
|
let nextUniqueId = 0;
|
|
@@ -230,6 +241,7 @@ let MinidTextfield = class extends FormControlMixin(styled(LitElement, styles))
|
|
|
230
241
|
.value=${live(this.value)}
|
|
231
242
|
?disabled=${this.disabled}
|
|
232
243
|
?readonly=${this.readonly}
|
|
244
|
+
?required=${this.required}
|
|
233
245
|
?autofocus=${this.autofocus}
|
|
234
246
|
autocomplete=${ifDefined(this.autocomplete)}
|
|
235
247
|
type=${this.type === "password" && this.passwordvisible ? "text" : this.type}
|
|
@@ -292,10 +304,13 @@ let MinidTextfield = class extends FormControlMixin(styled(LitElement, styles))
|
|
|
292
304
|
${hasSuffix ? html`<span part="suffix" class="ds-field-affix"><slot name="suffix"></slot></span>` : html`<slot name="suffix"></slot>`}
|
|
293
305
|
</div>
|
|
294
306
|
<p
|
|
295
|
-
class="
|
|
307
|
+
class="${classMap({
|
|
308
|
+
"ds-validation-message": !!this.invalidmessage,
|
|
309
|
+
"validation-message--empty": !this.invalidmessage
|
|
310
|
+
})}"
|
|
311
|
+
part="validation-message"
|
|
296
312
|
id="${this.validationId}"
|
|
297
313
|
aria-live="polite"
|
|
298
|
-
?hidden=${!this.invalidmessage}
|
|
299
314
|
>
|
|
300
315
|
${this.invalidmessage}
|
|
301
316
|
</p>
|
|
@@ -1 +1 @@
|
|
|
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 aria-hidden=\"true\"\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 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 /* The validation message stays in the DOM so its text lands in a live region\n the screen reader is already watching - WebKit does not reliably announce\n one revealed at the same moment the text arrives. When empty it must paint\n nothing and take no room: the element drops the ds-validation-message class\n (whose ::before paints an error icon regardless of the text) and this rule\n cancels the sibling spacing from .ds-field > * + *, which the .ds-field >\n prefix is enough to outrank without !important. */\n .ds-field > .validation-message--empty {\n margin-top: 0;\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 * @csspart validation-message - The error message shown by `invalidmessage`.\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 aria-hidden=\"true\"\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 ?required=${this.required}\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=\"${classMap({\n 'ds-validation-message': !!this.invalidmessage,\n 'validation-message--empty': !this.invalidmessage,\n })}\"\n part=\"validation-message\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n >\n ${this.invalidmessage}\n </p>\n </ds-field>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|