@felleslosninger/minid-elements 0.0.99 → 0.0.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/alert.component.d.ts +2 -6
- package/dist/components/alert.component.d.ts.map +1 -1
- package/dist/components/alert.js +16 -55
- package/dist/components/alert.js.map +1 -1
- package/dist/components/checkbox.component.d.ts +46 -6
- package/dist/components/checkbox.component.d.ts.map +1 -1
- package/dist/components/checkbox.js +115 -87
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/code-input.component.d.ts +16 -15
- package/dist/components/code-input.component.d.ts.map +1 -1
- package/dist/components/code-input.js +105 -105
- package/dist/components/code-input.js.map +1 -1
- package/dist/components/combobox.component.d.ts +6 -9
- package/dist/components/combobox.component.d.ts.map +1 -1
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/dialog.js +2 -2
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/menu.js +1 -1
- package/dist/components/menu.js.map +1 -1
- package/dist/components/phone-input.component.d.ts +5 -3
- package/dist/components/phone-input.component.d.ts.map +1 -1
- package/dist/components/phone-input.js +22 -34
- package/dist/components/phone-input.js.map +1 -1
- package/dist/components/popup.component.d.ts +1 -1
- package/dist/components/popup.component.d.ts.map +1 -1
- package/dist/components/popup.js +10 -19
- package/dist/components/popup.js.map +1 -1
- package/dist/components/search.js +1 -1
- package/dist/components/search.js.map +1 -1
- package/dist/components/spinner.component.d.ts.map +1 -1
- package/dist/components/spinner.js +9 -1
- package/dist/components/spinner.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 +9 -7
- package/dist/components/textfield.js.map +1 -1
- package/dist/designsystemet-tailwind.css +1 -1
- package/dist/mixins/form-controller.mixin.d.ts.map +1 -1
- package/dist/mixins/form-controller.mixin.js +0 -3
- package/dist/mixins/form-controller.mixin.js.map +1 -1
- package/dist/mixins/tailwind.mixin.js +1 -1
- package/package.json +9 -8
|
@@ -6,6 +6,7 @@ import { live } from "lit/directives/live.js";
|
|
|
6
6
|
import { webOtpApiInit, webOtpApiClose } from "../utilities/web-otp-api.js";
|
|
7
7
|
import { styled } from "../mixins/tailwind.mixin.js";
|
|
8
8
|
import { ConstraintsValidationMixin } from "../mixins/form-controller.mixin.js";
|
|
9
|
+
import "./icon/icon.js";
|
|
9
10
|
var __defProp = Object.defineProperty;
|
|
10
11
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
12
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -19,9 +20,10 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
19
20
|
const styles = [
|
|
20
21
|
css`
|
|
21
22
|
:host {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
22
25
|
container: otc / inline-size;
|
|
23
26
|
text-align: left;
|
|
24
|
-
width: 30rem;
|
|
25
27
|
--otc-background: white;
|
|
26
28
|
--otc-error-background: white;
|
|
27
29
|
--otc-length: 5;
|
|
@@ -39,6 +41,7 @@ const styles = [
|
|
|
39
41
|
letter-spacing: 2ch;
|
|
40
42
|
padding-block: 0.25ch;
|
|
41
43
|
padding-inline-start: calc(0.5ch * 1.5);
|
|
44
|
+
flex-grow: 1;
|
|
42
45
|
|
|
43
46
|
&:focus-visible:focus {
|
|
44
47
|
outline-style: none;
|
|
@@ -59,12 +62,6 @@ const styles = [
|
|
|
59
62
|
input.error {
|
|
60
63
|
background: var(--otc-error-background);
|
|
61
64
|
}
|
|
62
|
-
|
|
63
|
-
#error-box {
|
|
64
|
-
color: rgb(179, 38, 30);
|
|
65
|
-
font-size: 18px;
|
|
66
|
-
font-weight: 400;
|
|
67
|
-
}
|
|
68
65
|
`
|
|
69
66
|
];
|
|
70
67
|
let nextUniqueId = 0;
|
|
@@ -83,16 +80,33 @@ let MinidCodeInput = class extends ConstraintsValidationMixin(
|
|
|
83
80
|
this.required = false;
|
|
84
81
|
this.disabled = false;
|
|
85
82
|
this.inputmode = "numeric";
|
|
86
|
-
this.
|
|
83
|
+
this.invalidmessage = "";
|
|
87
84
|
this.length = 5;
|
|
88
|
-
this.
|
|
85
|
+
this.fontsize = "11.45cqw";
|
|
89
86
|
this.renderError = false;
|
|
90
|
-
this.
|
|
87
|
+
this.localErrorNode = null;
|
|
88
|
+
this.handleFocusIn = () => {
|
|
89
|
+
const currentChar = this.value.length + 1;
|
|
90
|
+
this.inputRef.value?.style.setProperty(
|
|
91
|
+
`--char-${currentChar}-color`,
|
|
92
|
+
this.caretHighlightColor
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
this.handleChange = (e) => {
|
|
96
|
+
this.value = e.target.value;
|
|
97
|
+
this.dispatchEvent(
|
|
98
|
+
new Event("input", {
|
|
99
|
+
bubbles: true,
|
|
100
|
+
cancelable: true,
|
|
101
|
+
composed: true
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
};
|
|
91
105
|
this.addEventListener("invalid", (e) => {
|
|
92
106
|
this.renderError = true;
|
|
93
|
-
if (this.
|
|
107
|
+
if (this.localErrorNode) {
|
|
94
108
|
e.preventDefault();
|
|
95
|
-
this.
|
|
109
|
+
this.localErrorNode.textContent = this.validationMessage || "Error";
|
|
96
110
|
}
|
|
97
111
|
});
|
|
98
112
|
}
|
|
@@ -126,7 +140,7 @@ let MinidCodeInput = class extends ConstraintsValidationMixin(
|
|
|
126
140
|
inputStyle?.setProperty("--otc-background", gradientStyle);
|
|
127
141
|
const gradientErrorStyle = `linear-gradient(90deg, var(--color-danger-surface-active) calc(${this.length}ch / 2), transparent 0) 0 0 / 3ch 100%`;
|
|
128
142
|
inputStyle?.setProperty("--otc-error-background", gradientErrorStyle);
|
|
129
|
-
inputStyle?.setProperty("--otc-width", this.
|
|
143
|
+
inputStyle?.setProperty("--otc-width", this.fontsize);
|
|
130
144
|
}
|
|
131
145
|
autoFillEventHandler(e) {
|
|
132
146
|
e.animationName === "onAutoFillStart" && (this.value = this.inputRef.value.value);
|
|
@@ -134,15 +148,7 @@ let MinidCodeInput = class extends ConstraintsValidationMixin(
|
|
|
134
148
|
get selectionEnd() {
|
|
135
149
|
return this.inputRef.value?.selectionEnd;
|
|
136
150
|
}
|
|
137
|
-
|
|
138
|
-
this.focus();
|
|
139
|
-
webOtpApiInit(this.renderRoot);
|
|
140
|
-
}
|
|
141
|
-
focus(options) {
|
|
142
|
-
const notMobile = !window.matchMedia("only screen and (max-width: 768px)").matches;
|
|
143
|
-
notMobile && this.inputRef.value?.focus(options);
|
|
144
|
-
}
|
|
145
|
-
onFocusOut() {
|
|
151
|
+
handleFocusOut() {
|
|
146
152
|
for (let i = 0; i < this.length; i++) {
|
|
147
153
|
this.inputRef.value?.style.setProperty(
|
|
148
154
|
`--char-${i + 1}-color`,
|
|
@@ -150,37 +156,12 @@ let MinidCodeInput = class extends ConstraintsValidationMixin(
|
|
|
150
156
|
);
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
|
-
|
|
154
|
-
const currentChar = this.value.length + 1;
|
|
155
|
-
this.inputRef.value?.style.setProperty(
|
|
156
|
-
`--char-${currentChar}-color`,
|
|
157
|
-
this.caretHighlightColor
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
updated(_changedProperties) {
|
|
161
|
-
for (let i = 0; i < this.length; i++) {
|
|
162
|
-
const color = i === this.value.length ? this.caretHighlightColor : this.caretColor;
|
|
163
|
-
this.inputRef.value?.style.setProperty(`--char-${i + 1}-color`, color);
|
|
164
|
-
}
|
|
165
|
-
if (_changedProperties.has("_forcedErrorMessage")) {
|
|
166
|
-
this.setCustomValidity(this._forcedErrorMessage);
|
|
167
|
-
}
|
|
168
|
-
this.setFormValue(this.value);
|
|
169
|
-
this.setValidity(
|
|
170
|
-
this.inputRef.value.validity,
|
|
171
|
-
this.inputRef.value.validationMessage,
|
|
172
|
-
this.inputRef.value
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
setCustomValidity(error) {
|
|
176
|
-
this.inputRef.value?.setCustomValidity(error);
|
|
177
|
-
}
|
|
178
|
-
onClick() {
|
|
159
|
+
handleClick() {
|
|
179
160
|
this.value = this.value.substring(0, this.selectionEnd || 0);
|
|
180
161
|
this.renderError = false;
|
|
181
162
|
this.setCustomValidity("");
|
|
182
|
-
if (this.
|
|
183
|
-
this.
|
|
163
|
+
if (this.localErrorNode) {
|
|
164
|
+
this.localErrorNode.textContent = "";
|
|
184
165
|
}
|
|
185
166
|
this.setFormValue(this.value);
|
|
186
167
|
this.setValidity({});
|
|
@@ -198,76 +179,95 @@ let MinidCodeInput = class extends ConstraintsValidationMixin(
|
|
|
198
179
|
handleSlotchange(e) {
|
|
199
180
|
const slot = e.target;
|
|
200
181
|
const childNodes = slot.assignedNodes({ flatten: true });
|
|
201
|
-
this.
|
|
202
|
-
if (this.
|
|
182
|
+
this.localErrorNode = this.findErrorMessageNode(childNodes);
|
|
183
|
+
if (this.localErrorNode && this.invalidmessage) {
|
|
203
184
|
this.renderError = true;
|
|
204
|
-
this.
|
|
185
|
+
this.localErrorNode.textContent = this.invalidmessage;
|
|
205
186
|
this.setValidity({});
|
|
206
187
|
}
|
|
207
188
|
}
|
|
208
|
-
|
|
189
|
+
findErrorMessageNode(nodes) {
|
|
209
190
|
for (const node of nodes) {
|
|
210
191
|
if (node instanceof Element && node.classList.contains("error-message")) {
|
|
211
192
|
return node;
|
|
212
193
|
}
|
|
213
194
|
const childNodesArray = Array.from(node.childNodes);
|
|
214
|
-
const foundNode = this.
|
|
195
|
+
const foundNode = this.findErrorMessageNode(childNodesArray);
|
|
215
196
|
if (foundNode) {
|
|
216
197
|
return foundNode;
|
|
217
198
|
}
|
|
218
199
|
}
|
|
219
200
|
return null;
|
|
220
201
|
}
|
|
202
|
+
firstUpdated(_changedProperties) {
|
|
203
|
+
this.focus();
|
|
204
|
+
webOtpApiInit(this.renderRoot);
|
|
205
|
+
}
|
|
206
|
+
updated(_changedProperties) {
|
|
207
|
+
for (let i = 0; i < this.length; i++) {
|
|
208
|
+
const color = i === this.value.length ? this.caretHighlightColor : this.caretColor;
|
|
209
|
+
this.inputRef.value?.style.setProperty(`--char-${i + 1}-color`, color);
|
|
210
|
+
}
|
|
211
|
+
if (_changedProperties.has("_forcedErrorMessage")) {
|
|
212
|
+
this.setCustomValidity(this.invalidmessage);
|
|
213
|
+
}
|
|
214
|
+
this.setFormValue(this.value);
|
|
215
|
+
this.setValidity(
|
|
216
|
+
this.inputRef.value.validity,
|
|
217
|
+
this.inputRef.value.validationMessage,
|
|
218
|
+
this.inputRef.value
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
focus(options) {
|
|
222
|
+
const notMobile = !window.matchMedia("only screen and (max-width: 768px)").matches;
|
|
223
|
+
notMobile && this.inputRef.value?.focus(options);
|
|
224
|
+
}
|
|
225
|
+
setCustomValidity(error) {
|
|
226
|
+
this.inputRef.value?.setCustomValidity(error);
|
|
227
|
+
}
|
|
221
228
|
render() {
|
|
222
229
|
return html`
|
|
223
|
-
<
|
|
224
|
-
|
|
225
|
-
class="${classMap({
|
|
230
|
+
<label
|
|
231
|
+
class="${classMap({
|
|
226
232
|
"sr-only": this.hidelabel,
|
|
227
|
-
"font-medium": true,
|
|
228
233
|
"mb-2": !!this.label
|
|
234
|
+
})} font-medium"
|
|
235
|
+
for="${this.inputId}"
|
|
236
|
+
>${this.label}
|
|
237
|
+
</label>
|
|
238
|
+
<input
|
|
239
|
+
${ref(this.inputRef)}
|
|
240
|
+
id=${this.inputId}
|
|
241
|
+
.value="${live(this.value)}"
|
|
242
|
+
class="${classMap({
|
|
243
|
+
error: this.invalidmessage
|
|
229
244
|
})}"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
@focusout="${() => {
|
|
257
|
-
this.onFocusOut();
|
|
258
|
-
}}"
|
|
259
|
-
@focusin="${() => {
|
|
260
|
-
this.onFocusIn();
|
|
261
|
-
}}"
|
|
262
|
-
@keydown="${this.handleKeydown}"
|
|
263
|
-
@click="${this.onClick}"
|
|
264
|
-
?disabled="${this.disabled}"
|
|
265
|
-
?required="${this.required}"
|
|
266
|
-
minlength=${this.length}
|
|
267
|
-
maxlength="${this.length}"
|
|
268
|
-
/>
|
|
269
|
-
<slot name="error-message" @slotchange=${this.handleSlotchange}></slot>
|
|
270
|
-
</div>
|
|
245
|
+
autocomplete="${"one-time-code"}"
|
|
246
|
+
inputmode="${this.inputmode}"
|
|
247
|
+
@input="${this.handleChange}"
|
|
248
|
+
@change="${this.handleChange}"
|
|
249
|
+
@focusout="${this.handleFocusOut}"
|
|
250
|
+
@focusin="${this.handleFocusIn}"
|
|
251
|
+
@keydown="${this.handleKeydown}"
|
|
252
|
+
@click="${this.handleClick}"
|
|
253
|
+
minlength="${this.length}"
|
|
254
|
+
maxlength="${this.length}"
|
|
255
|
+
?disabled="${this.disabled}"
|
|
256
|
+
?required="${this.required}"
|
|
257
|
+
/>
|
|
258
|
+
<slot name="error-message" @slotchange=${this.handleSlotchange}>
|
|
259
|
+
<div
|
|
260
|
+
class="text-danger-subtle mt-2 flex gap-1"
|
|
261
|
+
aria-live="polite"
|
|
262
|
+
?hidden=${!this.invalidmessage}
|
|
263
|
+
>
|
|
264
|
+
<mid-icon
|
|
265
|
+
name="xmark-octagon-fill"
|
|
266
|
+
class="mt-1 min-h-5 min-w-5"
|
|
267
|
+
></mid-icon>
|
|
268
|
+
${this.invalidmessage}
|
|
269
|
+
</div>
|
|
270
|
+
</slot>
|
|
271
271
|
`;
|
|
272
272
|
}
|
|
273
273
|
};
|
|
@@ -290,20 +290,20 @@ __decorateClass([
|
|
|
290
290
|
property({ type: String })
|
|
291
291
|
], MinidCodeInput.prototype, "inputmode", 2);
|
|
292
292
|
__decorateClass([
|
|
293
|
-
property(
|
|
294
|
-
], MinidCodeInput.prototype, "
|
|
293
|
+
property()
|
|
294
|
+
], MinidCodeInput.prototype, "invalidmessage", 2);
|
|
295
295
|
__decorateClass([
|
|
296
296
|
property({ type: Number })
|
|
297
297
|
], MinidCodeInput.prototype, "length", 2);
|
|
298
298
|
__decorateClass([
|
|
299
|
-
property(
|
|
300
|
-
], MinidCodeInput.prototype, "
|
|
299
|
+
property()
|
|
300
|
+
], MinidCodeInput.prototype, "fontsize", 2);
|
|
301
301
|
__decorateClass([
|
|
302
302
|
state()
|
|
303
303
|
], MinidCodeInput.prototype, "renderError", 2);
|
|
304
304
|
__decorateClass([
|
|
305
305
|
state()
|
|
306
|
-
], MinidCodeInput.prototype, "
|
|
306
|
+
], MinidCodeInput.prototype, "localErrorNode", 2);
|
|
307
307
|
MinidCodeInput = __decorateClass([
|
|
308
308
|
customElement("mid-code-input")
|
|
309
309
|
], 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, state } from 'lit/decorators.js';\nimport { createRef, ref, Ref } from 'lit/directives/ref.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { webOtpApiClose, webOtpApiInit } from '../utilities/web-otp-api';\nimport { styled } from '../mixins/tailwind.mixin';\nimport { ConstraintsValidationMixin } from '../mixins/form-controller.mixin';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nconst styles = [\n css`\n :host {\n container: otc / inline-size;\n text-align: left;\n width: 30rem;\n --otc-background: white;\n --otc-error-background: white;\n --otc-length: 5;\n --otc-width: 11.45cqw;\n }\n\n input {\n all: unset;\n background: var(--otc-background);\n caret-color: transparent;\n clip-path: inset(0% 1ch 0% 0%);\n font-family: ui-monospace, monospace;\n font-size: var(--otc-width);\n inline-size: calc(var(--otc-length) * 3ch);\n letter-spacing: 2ch;\n padding-block: 0.25ch;\n padding-inline-start: calc(0.5ch * 1.5);\n\n &:focus-visible:focus {\n outline-style: none;\n }\n\n &:-webkit-autofill {\n animation-name: onAutoFillStart;\n }\n }\n\n @keyframes onAutoFillStart {\n from {\n }\n to {\n }\n }\n\n input.error {\n background: var(--otc-error-background);\n }\n\n #error-box {\n color: rgb(179, 38, 30);\n font-size: 18px;\n font-weight: 400;\n }\n `,\n];\n\nlet nextUniqueId = 0;\n\n@customElement('mid-code-input')\nexport class MinidCodeInput extends ConstraintsValidationMixin(\n styled(LitElement, styles)\n) {\n caretColor = 'var(--color-neutral-surface-tinted)';\n caretHighlightColor = 'var(--color-accent-surface-active)';\n inputId = `mid-code-input-${nextUniqueId++}`;\n\n public inputRef: Ref<HTMLInputElement> = createRef();\n\n @property({ type: String, reflect: true })\n value = '';\n\n @property()\n label = '';\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 required = false;\n\n @property({ type: Boolean })\n disabled = false;\n\n @property({ type: String })\n inputmode = 'numeric';\n\n /**\n * Display custom error message, and force invalid state\n */\n @property({ type: String, attribute: 'error-message' })\n _forcedErrorMessage = '';\n\n /**\n * The length of the code input\n */\n @property({ type: Number })\n length = 5;\n\n @property({ type: String, attribute: 'font-size' })\n fontSize = '3cqw';\n\n @state()\n renderError = false;\n\n @state()\n _localErrorNode: Node | null = null;\n\n constructor() {\n super();\n this.addEventListener('invalid', (e) => {\n this.renderError = true;\n if (this._localErrorNode) {\n e.preventDefault();\n this._localErrorNode.textContent = this.validationMessage || 'Error';\n }\n });\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this._whenSettled();\n }\n\n async _whenSettled() {\n await this.updateComplete;\n this.inputRef.value?.addEventListener(\n 'animationstart',\n this.autoFillEventHandler.bind(this)\n );\n this.calcInputStyle();\n }\n\n override disconnectedCallback() {\n webOtpApiClose();\n this.inputRef.value?.removeEventListener(\n 'animationstart',\n this.autoFillEventHandler.bind(this)\n );\n }\n\n calcInputStyle() {\n const inputStyle = this.inputRef.value?.style;\n\n inputStyle?.setProperty('--otc-length', this.length.toString());\n\n let gradientStyle = 'linear-gradient(90deg, ';\n for (let i = 0; i < this.length; i++) {\n gradientStyle += `var(--char-${i + 1}-color) ${i ? i * 3 + 'ch' : '0'} ${i * 3 + 2.5}ch, transparent ${i * 3 + 2.5}ch ${i * 3 + 3}ch${i + 1 < this.length ? ', ' : ''}`;\n }\n gradientStyle += `) no-repeat 0 0 / ${this.length * 3}ch 100%`;\n inputStyle?.setProperty('--otc-background', gradientStyle);\n\n const gradientErrorStyle = `linear-gradient(90deg, var(--color-danger-surface-active) calc(${this.length}ch / 2), transparent 0) 0 0 / 3ch 100%`;\n inputStyle?.setProperty('--otc-error-background', gradientErrorStyle);\n\n inputStyle?.setProperty('--otc-width', this.fontSize);\n }\n\n autoFillEventHandler(e: AnimationEvent) {\n e.animationName === 'onAutoFillStart' &&\n (this.value = (this.inputRef.value as HTMLInputElement).value);\n }\n\n get selectionEnd() {\n return this.inputRef.value?.selectionEnd;\n }\n\n firstUpdated(_changedProperties: PropertyValues) {\n this.focus();\n webOtpApiInit(this.renderRoot);\n }\n\n focus(options?: FocusOptions) {\n const notMobile = !window.matchMedia('only screen and (max-width: 768px)')\n .matches;\n notMobile && this.inputRef.value?.focus(options);\n }\n\n onFocusOut() {\n for (let i = 0; i < this.length; i++) {\n this.inputRef.value?.style.setProperty(\n `--char-${i + 1}-color`,\n this.caretColor\n );\n }\n }\n\n onFocusIn() {\n const currentChar = this.value.length + 1;\n this.inputRef.value?.style.setProperty(\n `--char-${currentChar}-color`,\n this.caretHighlightColor\n );\n }\n\n updated(_changedProperties: PropertyValues): void {\n for (let i = 0; i < this.length; i++) {\n const color =\n i === this.value.length ? this.caretHighlightColor : this.caretColor;\n this.inputRef.value?.style.setProperty(`--char-${i + 1}-color`, color);\n }\n\n if (_changedProperties.has('_forcedErrorMessage')) {\n this.setCustomValidity(this._forcedErrorMessage);\n }\n\n this.setFormValue(this.value);\n this.setValidity(\n this.inputRef.value!.validity,\n this.inputRef.value!.validationMessage,\n this.inputRef!.value\n );\n }\n\n setCustomValidity(error: string) {\n this.inputRef!.value?.setCustomValidity(error);\n }\n\n onClick() {\n this.value = this.value.substring(0, this.selectionEnd || 0);\n\n this.renderError = false;\n this.setCustomValidity('');\n if (this._localErrorNode) {\n this._localErrorNode.textContent = '';\n }\n\n this.setFormValue(this.value);\n this.setValidity({} as ValidityState);\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.internals.form?.requestSubmit();\n }\n });\n }\n }\n\n handleSlotchange(e: Event) {\n const slot = e.target as HTMLSlotElement;\n const childNodes = slot.assignedNodes({ flatten: true });\n\n this._localErrorNode = this._findErrorMessageNode(childNodes);\n if (this._localErrorNode && this._forcedErrorMessage) {\n // display if slot set, and error override in effect\n this.renderError = true;\n this._localErrorNode.textContent = this._forcedErrorMessage;\n this.setValidity({} as ValidityState); // cancel built-in visual feedback\n }\n }\n\n _findErrorMessageNode(nodes: Node[]): Node | null {\n for (const node of nodes) {\n if (node instanceof Element && node.classList.contains('error-message')) {\n return node;\n }\n const childNodesArray = Array.from(node.childNodes);\n const foundNode = this._findErrorMessageNode(childNodesArray);\n if (foundNode) {\n return foundNode;\n }\n }\n return null;\n }\n\n override render() {\n return html`\n <div class=\"flex flex-col\">\n <label\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n 'font-medium': true,\n 'mb-2': !!this.label,\n })}\"\n for=\"${this.inputId}\"\n >${this.label}\n </label>\n <input\n ${ref(this.inputRef)}\n id=${this.inputId}\n class=\"${classMap({\n 'w-full': true,\n error: this._forcedErrorMessage,\n })}\"\n .value=${live(this.value)}\n autocomplete=\"${'one-time-code' as any}\"\n inputmode=${this.inputmode}\n @input=\"${(e: InputEvent) => {\n this.value = (e.target as HTMLInputElement).value;\n }}\"\n @change=\"${(e: Event) => {\n this.value = (e.target as HTMLInputElement).value;\n this.dispatchEvent(\n new Event('input', {\n bubbles: true,\n cancelable: true,\n composed: true,\n })\n );\n }}\"\n @focusout=\"${() => {\n this.onFocusOut();\n }}\"\n @focusin=\"${() => {\n this.onFocusIn();\n }}\"\n @keydown=\"${this.handleKeydown}\"\n @click=\"${this.onClick}\"\n ?disabled=\"${this.disabled}\"\n ?required=\"${this.required}\"\n minlength=${this.length}\n maxlength=\"${this.length}\"\n />\n <slot name=\"error-message\" @slotchange=${this.handleSlotchange}></slot>\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, PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { createRef, ref, Ref } from 'lit/directives/ref.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { webOtpApiClose, webOtpApiInit } from '../utilities/web-otp-api';\nimport { styled } from '../mixins/tailwind.mixin';\nimport { ConstraintsValidationMixin } from '../mixins/form-controller.mixin';\nimport './icon/icon.component';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n container: otc / inline-size;\n text-align: left;\n --otc-background: white;\n --otc-error-background: white;\n --otc-length: 5;\n --otc-width: 11.45cqw;\n }\n\n input {\n all: unset;\n background: var(--otc-background);\n caret-color: transparent;\n clip-path: inset(0% 1ch 0% 0%);\n font-family: ui-monospace, monospace;\n font-size: var(--otc-width);\n inline-size: calc(var(--otc-length) * 3ch);\n letter-spacing: 2ch;\n padding-block: 0.25ch;\n padding-inline-start: calc(0.5ch * 1.5);\n flex-grow: 1;\n\n &:focus-visible:focus {\n outline-style: none;\n }\n\n &:-webkit-autofill {\n animation-name: onAutoFillStart;\n }\n }\n\n @keyframes onAutoFillStart {\n from {\n }\n to {\n }\n }\n\n input.error {\n background: var(--otc-error-background);\n }\n `,\n];\n\nlet nextUniqueId = 0;\n\n@customElement('mid-code-input')\nexport class MinidCodeInput extends ConstraintsValidationMixin(\n styled(LitElement, styles)\n) {\n private readonly caretColor = 'var(--color-neutral-surface-tinted)';\n private readonly caretHighlightColor = 'var(--color-accent-surface-active)';\n private readonly inputId = `mid-code-input-${nextUniqueId++}`;\n\n public inputRef: Ref<HTMLInputElement> = createRef();\n\n @property({ type: String, reflect: true })\n value = '';\n\n @property()\n label = '';\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 required = false;\n\n @property({ type: Boolean })\n disabled = false;\n\n @property({ type: String })\n inputmode = 'numeric';\n\n /**\n * Display custom error message, and force invalid state\n */\n @property()\n invalidmessage = '';\n\n /**\n * The length of the code input\n */\n @property({ type: Number })\n length = 5;\n\n @property()\n fontsize = '11.45cqw';\n\n @state()\n renderError = false;\n\n @state()\n localErrorNode: Node | null = null;\n\n constructor() {\n super();\n this.addEventListener('invalid', (e) => {\n this.renderError = true;\n if (this.localErrorNode) {\n e.preventDefault();\n this.localErrorNode.textContent = this.validationMessage || 'Error';\n }\n });\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this._whenSettled();\n }\n\n async _whenSettled() {\n await this.updateComplete;\n this.inputRef.value?.addEventListener(\n 'animationstart',\n this.autoFillEventHandler.bind(this)\n );\n this.calcInputStyle();\n }\n\n override disconnectedCallback() {\n webOtpApiClose();\n this.inputRef.value?.removeEventListener(\n 'animationstart',\n this.autoFillEventHandler.bind(this)\n );\n }\n\n private calcInputStyle() {\n const inputStyle = this.inputRef.value?.style;\n\n inputStyle?.setProperty('--otc-length', this.length.toString());\n\n let gradientStyle = 'linear-gradient(90deg, ';\n for (let i = 0; i < this.length; i++) {\n gradientStyle += `var(--char-${i + 1}-color) ${i ? i * 3 + 'ch' : '0'} ${i * 3 + 2.5}ch, transparent ${i * 3 + 2.5}ch ${i * 3 + 3}ch${i + 1 < this.length ? ', ' : ''}`;\n }\n gradientStyle += `) no-repeat 0 0 / ${this.length * 3}ch 100%`;\n inputStyle?.setProperty('--otc-background', gradientStyle);\n\n const gradientErrorStyle = `linear-gradient(90deg, var(--color-danger-surface-active) calc(${this.length}ch / 2), transparent 0) 0 0 / 3ch 100%`;\n inputStyle?.setProperty('--otc-error-background', gradientErrorStyle);\n\n inputStyle?.setProperty('--otc-width', this.fontsize);\n }\n\n private autoFillEventHandler(e: AnimationEvent) {\n e.animationName === 'onAutoFillStart' &&\n (this.value = (this.inputRef.value as HTMLInputElement).value);\n }\n\n get selectionEnd() {\n return this.inputRef.value?.selectionEnd;\n }\n\n private handleFocusOut() {\n for (let i = 0; i < this.length; i++) {\n this.inputRef.value?.style.setProperty(\n `--char-${i + 1}-color`,\n this.caretColor\n );\n }\n }\n\n private handleFocusIn = () => {\n const currentChar = this.value.length + 1;\n this.inputRef.value?.style.setProperty(\n `--char-${currentChar}-color`,\n this.caretHighlightColor\n );\n };\n\n private handleClick() {\n this.value = this.value.substring(0, this.selectionEnd || 0);\n\n this.renderError = false;\n this.setCustomValidity('');\n if (this.localErrorNode) {\n this.localErrorNode.textContent = '';\n }\n\n this.setFormValue(this.value);\n this.setValidity({} as ValidityState);\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.internals.form?.requestSubmit();\n }\n });\n }\n }\n\n private handleChange = (e: Event) => {\n this.value = (e.target as HTMLInputElement).value;\n this.dispatchEvent(\n new Event('input', {\n bubbles: true,\n cancelable: true,\n composed: true,\n })\n );\n };\n\n private handleSlotchange(e: Event) {\n const slot = e.target as HTMLSlotElement;\n const childNodes = slot.assignedNodes({ flatten: true });\n\n this.localErrorNode = this.findErrorMessageNode(childNodes);\n if (this.localErrorNode && this.invalidmessage) {\n // display if slot set, and error override in effect\n this.renderError = true;\n this.localErrorNode.textContent = this.invalidmessage;\n this.setValidity({} as ValidityState); // cancel built-in visual feedback\n }\n }\n\n private findErrorMessageNode(nodes: Node[]): Node | null {\n for (const node of nodes) {\n if (node instanceof Element && node.classList.contains('error-message')) {\n return node;\n }\n const childNodesArray = Array.from(node.childNodes);\n const foundNode = this.findErrorMessageNode(childNodesArray);\n if (foundNode) {\n return foundNode;\n }\n }\n return null;\n }\n\n firstUpdated(_changedProperties: PropertyValues) {\n this.focus();\n webOtpApiInit(this.renderRoot);\n }\n\n updated(_changedProperties: PropertyValues): void {\n for (let i = 0; i < this.length; i++) {\n const color =\n i === this.value.length ? this.caretHighlightColor : this.caretColor;\n this.inputRef.value?.style.setProperty(`--char-${i + 1}-color`, color);\n }\n\n if (_changedProperties.has('_forcedErrorMessage')) {\n this.setCustomValidity(this.invalidmessage);\n }\n\n this.setFormValue(this.value);\n this.setValidity(\n this.inputRef.value!.validity,\n this.inputRef.value!.validationMessage,\n this.inputRef!.value\n );\n }\n\n focus(options?: FocusOptions) {\n const notMobile = !window.matchMedia('only screen and (max-width: 768px)')\n .matches;\n notMobile && this.inputRef.value?.focus(options);\n }\n\n setCustomValidity(error: string) {\n this.inputRef!.value?.setCustomValidity(error);\n }\n\n override render() {\n return html`\n <label\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n 'mb-2': !!this.label,\n })} font-medium\"\n for=\"${this.inputId}\"\n >${this.label}\n </label>\n <input\n ${ref(this.inputRef)}\n id=${this.inputId}\n .value=\"${live(this.value)}\"\n class=\"${classMap({\n error: this.invalidmessage,\n })}\"\n autocomplete=\"${'one-time-code' as any}\"\n inputmode=\"${this.inputmode}\"\n @input=\"${this.handleChange}\"\n @change=\"${this.handleChange}\"\n @focusout=\"${this.handleFocusOut}\"\n @focusin=\"${this.handleFocusIn}\"\n @keydown=\"${this.handleKeydown}\"\n @click=\"${this.handleClick}\"\n minlength=\"${this.length}\"\n maxlength=\"${this.length}\"\n ?disabled=\"${this.disabled}\"\n ?required=\"${this.required}\"\n />\n <slot name=\"error-message\" @slotchange=${this.handleSlotchange}>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n </slot>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { LitElement, PropertyValues } from 'lit';
|
|
2
|
-
import { MinidPopup } from './popup.component';
|
|
3
2
|
import { MinidMenu } from '../components/menu.component';
|
|
4
|
-
import { MinidPhoneInput } from '../components/phone-input.component';
|
|
5
|
-
import { MinidTextfield } from '../components/textfield.component';
|
|
6
3
|
declare global {
|
|
7
4
|
interface HTMLElementTagNameMap {
|
|
8
5
|
'mid-combobox': MinidCombobox;
|
|
@@ -16,10 +13,10 @@ declare const MinidCombobox_base: typeof LitElement;
|
|
|
16
13
|
*/
|
|
17
14
|
export declare class MinidCombobox extends MinidCombobox_base {
|
|
18
15
|
private closeWatcher?;
|
|
19
|
-
popup
|
|
20
|
-
trigger
|
|
21
|
-
panel
|
|
22
|
-
triggerElements
|
|
16
|
+
private popup;
|
|
17
|
+
private trigger;
|
|
18
|
+
private panel;
|
|
19
|
+
private triggerElements;
|
|
23
20
|
/**
|
|
24
21
|
* By default, the combobox is closed when an item is selected. This attribute will keep it open instead. Useful for
|
|
25
22
|
* comboboxs that allow for multiple interactions.
|
|
@@ -44,14 +41,14 @@ export declare class MinidCombobox extends MinidCombobox_base {
|
|
|
44
41
|
*/
|
|
45
42
|
hoist: boolean;
|
|
46
43
|
disabled: boolean;
|
|
47
|
-
triggerElement
|
|
44
|
+
private triggerElement;
|
|
48
45
|
/**
|
|
49
46
|
* The combobox will close when the user interacts outside of this element (e.g. clicking). Useful for composing other
|
|
50
47
|
* components that use a combobox internally.
|
|
51
48
|
*/
|
|
52
49
|
containingElement?: HTMLElement;
|
|
53
50
|
connectedCallback(): void;
|
|
54
|
-
|
|
51
|
+
firstUpdated(_changedProperties: PropertyValues): void;
|
|
55
52
|
disconnectedCallback(): void;
|
|
56
53
|
focusOnTrigger(): void;
|
|
57
54
|
getMenu(): MinidMenu | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.component.d.ts","sourceRoot":"","sources":["../../src/components/combobox.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAQ5D,OAAO,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"combobox.component.d.ts","sourceRoot":"","sources":["../../src/components/combobox.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAQ5D,OAAO,mBAAmB,CAAC;AAY3B,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAIzD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,aAAa,CAAC;KAC/B;CACF;;AAUD;;;;GAIG;AACH,qBACa,aAAc,SAAQ,kBAA0B;IAC3D,OAAO,CAAC,YAAY,CAAC,CAAe;IAGpC,OAAO,CAAC,KAAK,CAAc;IAG3B,OAAO,CAAC,OAAO,CAAmB;IAGlC,OAAO,CAAC,KAAK,CAAmB;IAGhC,OAAO,CAAC,eAAe,CAInB;IAEJ;;;OAGG;IAEH,gBAAgB,UAAS;IAEzB;;OAEG;IAEH,IAAI,UAAS;IAGb,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAEhC;;OAEG;IAEH,QAAQ,SAAK;IAEb;;OAEG;IAEH,QAAQ,SAAK;IAEb;;;OAGG;IAEH,KAAK,UAAS;IAGd,QAAQ,UAAS;IAGjB,OAAO,CAAC,cAAc,CAAwD;IAE9E;;;OAGG;IAEH,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAEhC,iBAAiB;IAQjB,YAAY,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI;IAsBtD,oBAAoB;IAMpB,cAAc;IAUd,OAAO,IAID,SAAS,GACT,SAAS;IAGf,OAAO,CAAC,kBAAkB,CAWxB;IAEF,OAAO,CAAC,aAAa,CASnB;IAEF,OAAO,CAAC,qBAAqB,CA2C3B;IAEF,OAAO,CAAC,uBAAuB,CAM7B;IAEF,OAAO,CAAC,iBAAiB,CAiBvB;IAEF,kBAAkB;IAaZ,oBAAoB,CAAC,KAAK,EAAE,aAAa;IA4D/C,kBAAkB,CAAC,KAAK,EAAE,aAAa;IAOvC,uBAAuB;IAIvB;;;OAGG;IACH,UAAU;IAIV,gBAAgB;IAchB,mBAAmB;IAMnB;;OAEG;IACG,IAAI;IASV;;OAEG;IACG,IAAI;IAmBV,uBAAuB;IA0BjB,gBAAgB;IA0Cb,MAAM;CAuChB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","sources":["../../src/components/combobox.component.ts"],"sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit';\nimport {\n customElement,\n property,\n query,\n queryAssignedElements,\n state,\n} from 'lit/decorators.js';\nimport './popup.component';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { MinidPopup } from './popup.component';\nimport { waitForEvent } from '../internal/event';\nimport { watch } from '../internal/watch';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry';\nimport { animateTo, stopAnimations } from '../internal/animate';\nimport { getTabbableBoundary } from '../internal/tabbable';\nimport { MinidButton } from './button.component';\nimport { MinidMenu } from '../components/menu.component';\nimport { MinidPhoneInput } from '../components/phone-input.component';\nimport { MinidTextfield } from '../components/textfield.component';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-combobox': MinidCombobox;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: flex;\n }\n `,\n];\n\n/**\n * @slot -- Default slot for content of the dropdown panel\n * @slot trigger - Used for the button element that will be used to open the dropdown menu\n * @part panel - Select the dropdown panel host element\n */\n@customElement('mid-combobox')\nexport class MinidCombobox extends styled(LitElement, styles) {\n private closeWatcher?: CloseWatcher;\n\n @query('#combobox')\n popup!: MinidPopup;\n\n @query('.combobox__trigger')\n trigger!: HTMLSlotElement;\n\n @query('.combobox__panel')\n panel!: HTMLSlotElement;\n\n @queryAssignedElements({ slot: 'trigger' })\n triggerElements!: (MinidTextfield | MinidPhoneInput | HTMLInputElement)[];\n\n /**\n * By default, the combobox is closed when an item is selected. This attribute will keep it open instead. Useful for\n * comboboxs that allow for multiple interactions.\n */\n @property({ type: Boolean, reflect: true })\n stayopenonselect = false;\n\n /**\n * Indicates wether the combobox panel is open. You can use this or the show/hide methods.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Distance between trigger and combobox panel\n */\n @property({ type: Number })\n distance = 4;\n\n /**\n * Nudge the combobox panel position. Accepts a negative or positive number.\n */\n @property({ type: Number })\n skidding = 0;\n\n /**\n * Choose if position is `fixed` or `absolute`. `absolute` is more performant,\n * but `fixed` can solve issues with overflow clipping\n */\n @property({ type: Boolean })\n hoist = false;\n\n @property({ type: Boolean })\n disabled = false;\n\n @state()\n triggerElement: 'mid-textfield' | 'mid-phone-input' = 'mid-textfield';\n\n /**\n * The combobox will close when the user interacts outside of this element (e.g. clicking). Useful for composing other\n * components that use a combobox internally.\n */\n @property({ attribute: false })\n containingElement?: HTMLElement;\n\n connectedCallback() {\n super.connectedCallback();\n\n if (!this.containingElement) {\n this.containingElement = this;\n }\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n const input = this.triggerElements[0];\n if (input.tagName.toLowerCase() === 'mid-phone-input') {\n this.triggerElement = 'mid-phone-input';\n } else if (input.tagName.toLowerCase() === 'mid-textfield') {\n this.triggerElement = 'mid-textfield';\n }\n\n this.panel.hidden = !this.open;\n\n const menu = this.getMenu();\n if (menu) {\n menu.variant = 'combobox';\n }\n\n // If the combobox panel is visible on init, update its position\n if (this.open) {\n this.addOpenListeners();\n this.popup.active = true;\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeOpenListeners();\n this.hide();\n }\n\n focusOnTrigger() {\n const trigger = this.trigger.assignedElements({ flatten: true })[0] as\n | HTMLElement\n | undefined;\n\n if (typeof trigger?.focus === 'function') {\n trigger.focus();\n }\n }\n\n getMenu() {\n return this.panel\n .assignedElements({ flatten: true })\n .find((el) => el.tagName.toLowerCase() === 'mid-menu') as\n | MinidMenu\n | undefined;\n }\n\n private handleCountryClick = () => {\n const menu = this.getMenu();\n\n this.open ? this.hide() : this.show();\n if (this.open && menu && menu.searchable) {\n // Delay focus slightly to win the focus battle\n setTimeout(() => {\n menu.clearFilter();\n menu.focusSearchField();\n }, 1);\n }\n };\n\n private handleKeyDown = (event: KeyboardEvent) => {\n // Close when escape is pressed inside an open combobox. We need to listen on the panel itself and stop propagation\n // in case any ancestors are also listening for this key.\n if (this.open && event.key === 'Escape') {\n event.stopPropagation();\n this.hide();\n this.focusOnTrigger();\n return;\n }\n };\n\n private handleDocumentKeyDown = (event: KeyboardEvent) => {\n // Close when escape or tab is pressed\n if (event.key === 'Escape' && this.open && !this.closeWatcher) {\n event.stopPropagation();\n this.focusOnTrigger();\n this.hide();\n return;\n }\n\n // Handle tabbing\n if (event.key === 'Tab') {\n // Tabbing within an open menu should close the combobox and refocus the trigger\n if (\n this.open &&\n (document.activeElement?.tagName.toLowerCase() === 'mid-menu-item' ||\n document.activeElement?.tagName.toLowerCase() === 'mid-menu')\n ) {\n event.preventDefault();\n this.hide();\n this.focusOnTrigger();\n return;\n }\n\n // Tabbing outside of the containing element closes the panel\n //\n // If the combobox is used within a shadow DOM, we need to obtain the activeElement within that shadowRoot,\n // otherwise `document.activeElement` will only return the name of the parent shadow DOM element.\n setTimeout(() => {\n const activeElement =\n this.containingElement?.getRootNode() instanceof ShadowRoot\n ? document.activeElement?.shadowRoot?.activeElement\n : document.activeElement;\n\n if (\n !this.containingElement ||\n activeElement?.closest(\n this.containingElement.tagName.toLowerCase()\n ) !== this.containingElement\n ) {\n this.hide();\n }\n });\n }\n };\n\n private handleDocumentMouseDown = (event: MouseEvent) => {\n // Close when clicking outside of the containing element\n const path = event.composedPath();\n if (this.containingElement && !path.includes(this.containingElement)) {\n this.hide();\n }\n };\n\n private handlePanelSelect = (event: CustomEvent) => {\n if (this.triggerElement !== 'mid-phone-input') {\n return;\n }\n\n // Transfer selected country from panel to input field\n const input = this.triggerElements[0] as MinidPhoneInput;\n const country = event.detail.item.value;\n input.country = country;\n\n const target = event.target as HTMLElement;\n\n // Hide the combobox when a menu item is selected\n if (!this.stayopenonselect && target.tagName.toLowerCase() === 'mid-menu') {\n this.hide();\n this.focusOnTrigger();\n }\n };\n\n handleTriggerClick() {\n if (this.triggerElement === 'mid-phone-input') {\n return;\n }\n\n if (this.open) {\n this.hide();\n } else {\n this.show();\n this.focusOnTrigger();\n }\n }\n\n async handleTriggerKeyDown(event: KeyboardEvent) {\n // When spacebar/enter is pressed, show the panel but don't focus on the menu. This let's the user press the same\n // key again to hide the menu in case they don't want to make a selection.\n if ([' ', 'Enter'].includes(event.key)) {\n event.preventDefault();\n if (this.triggerElement === 'mid-textfield') {\n this.handleTriggerClick();\n }\n return;\n }\n\n const menu = this.getMenu();\n\n if (menu) {\n const menuItems = menu.getAllSelectableItems();\n const firstMenuItem = menuItems[0];\n const lastMenuItem = menuItems[menuItems.length - 1];\n\n // When up/down is pressed, we make the assumption that the user is familiar with the menu and plans to make a\n // selection. Rather than toggle the panel, we focus on the menu (if one exists) and activate the first item for\n // faster navigation.\n if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {\n event.preventDefault();\n\n // Show the menu if it's not already open\n if (!this.open) {\n this.show();\n\n // Wait for the combobox to open before focusing, but not the animation\n await this.updateComplete;\n }\n\n if (menuItems.length > 0) {\n // Focus on the first/last menu item after showing\n this.updateComplete.then(() => {\n if (event.key === 'ArrowDown' || event.key === 'Home') {\n menu.setCurrentItem(firstMenuItem);\n if (this.triggerElement === 'mid-textfield') {\n firstMenuItem.focus();\n } else {\n menu.clearFilter();\n menu.focusSearchField();\n }\n }\n\n if (event.key === 'ArrowUp' || event.key === 'End') {\n menu.setCurrentItem(lastMenuItem);\n if (this.triggerElement === 'mid-textfield') {\n lastMenuItem.focus();\n } else {\n menu.clearFilter();\n menu.focusSearchField();\n }\n }\n });\n }\n }\n }\n }\n\n handleTriggerKeyUp(event: KeyboardEvent) {\n // Prevent space from triggering a click event in Firefox\n if (event.key === ' ') {\n event.preventDefault();\n }\n }\n\n handleTriggerSlotChange() {\n this.updateAccessibleTrigger();\n }\n\n /**\n * Instructs the combobox menu to reposition. Useful when the position or size of the trigger changes when the menu\n * is activated.\n */\n reposition() {\n this.popup.reposition();\n }\n\n addOpenListeners() {\n if ('CloseWatcher' in window) {\n this.closeWatcher?.destroy();\n this.closeWatcher = new CloseWatcher();\n this.closeWatcher.onclose = () => {\n this.hide();\n this.focusOnTrigger();\n };\n }\n\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n document.addEventListener('mousedown', this.handleDocumentMouseDown);\n }\n\n removeOpenListeners() {\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n document.removeEventListener('mousedown', this.handleDocumentMouseDown);\n this.closeWatcher?.destroy();\n }\n\n /**\n * Shows the combobox panel.\n */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'mid-after-show');\n }\n\n /**\n * Hides the combobox panel\n */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'mid-after-hide');\n }\n\n //\n // Slotted triggers can be arbitrary content, but we need to link them to the combobox panel with `aria-haspopup` and\n // `aria-expanded`. These must be applied to the \"accessible trigger\" (the tabbable portion of the trigger element\n // that gets slotted in) so screen readers will understand them. The accessible trigger could be the slotted element,\n // a child of the slotted element, or an element in the slotted element's shadow root.\n //\n // For example, the accessible trigger of an <sl-button> is a <button> located inside its shadow root.\n //\n // To determine this, we assume the first tabbable element in the trigger slot is the \"accessible trigger.\"\n //\n updateAccessibleTrigger() {\n const assignedElements = this.trigger.assignedElements({\n flatten: true,\n }) as HTMLElement[];\n const accessibleTrigger = assignedElements.find(\n (el) => getTabbableBoundary(el).start\n );\n let target: HTMLElement;\n\n if (accessibleTrigger) {\n switch (accessibleTrigger.tagName.toLowerCase()) {\n // buttons have to update the internal button so it's announced correctly by screen readers\n case 'mid-button':\n target = (accessibleTrigger as MinidButton).button;\n break;\n\n default:\n target = accessibleTrigger;\n }\n\n target.setAttribute('aria-haspopup', 'true');\n target.setAttribute('aria-expanded', this.open ? 'true' : 'false');\n }\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.disabled) {\n this.open = false;\n return;\n }\n\n this.updateAccessibleTrigger();\n\n if (this.open) {\n // Show\n this.dispatchEvent(\n new Event('mid-show', { bubbles: true, composed: true })\n );\n this.addOpenListeners();\n\n await stopAnimations(this);\n this.panel.hidden = false;\n this.popup.active = true;\n const { keyframes, options } = getAnimation(this, 'combobox.show');\n await animateTo(this.popup.popup, keyframes, options);\n\n this.dispatchEvent(\n new Event('mid-after-show', { bubbles: true, composed: true })\n );\n } else {\n // Hide\n this.dispatchEvent(\n new Event('mid-hide', { bubbles: true, composed: true })\n );\n this.removeOpenListeners();\n await stopAnimations(this);\n const { keyframes, options } = getAnimation(this, 'combobox.hide');\n await animateTo(this.popup.popup, keyframes, options);\n this.panel.hidden = true;\n this.popup.active = false;\n\n this.dispatchEvent(\n new Event('mid-after-hide', { bubbles: true, composed: true })\n );\n }\n }\n\n override render() {\n return html`\n <mid-popup\n id=\"combobox\"\n distance=${this.distance}\n placement=\"bottom-end\"\n skidding=${this.skidding}\n strategy=${this.hoist ? 'fixed' : 'absolute'}\n flip\n shift\n auto-size=\"vertical\"\n auto-size-padding=\"10\"\n sync=\"width\"\n ?active=${this.open}\n >\n <slot\n class=\"combobox__trigger\"\n slot=\"anchor\"\n name=\"trigger\"\n @click=${this.handleTriggerClick}\n @keydown=${this.handleTriggerKeyDown}\n @keyup=${this.handleTriggerKeyUp}\n @slotchange=${this.handleTriggerSlotChange}\n @mid-country-click=${this.handleCountryClick}\n ></slot>\n <div\n aria-hidden=${this.open ? 'false' : 'true'}\n aria-labelledby=\"combobox\"\n >\n <slot\n class=\"combobox__panel\"\n part=\"panel\"\n @keydown=${this.handleKeyDown}\n @mid-select=${this.handlePanelSelect}\n ></slot>\n </div>\n </mid-popup>\n `;\n }\n}\n\nsetDefaultAnimation('combobox.show', {\n keyframes: [\n { opacity: 0, scale: 0.9 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 100, easing: 'ease' },\n});\n\nsetDefaultAnimation('combobox.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.9 },\n ],\n options: { duration: 100, easing: 'ease' },\n});\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"combobox.js","sources":["../../src/components/combobox.component.ts"],"sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit';\nimport {\n customElement,\n property,\n query,\n queryAssignedElements,\n state,\n} from 'lit/decorators.js';\nimport './popup.component';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { MinidPopup } from './popup.component';\nimport { waitForEvent } from '../internal/event';\nimport { watch } from '../internal/watch';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry';\nimport { animateTo, stopAnimations } from '../internal/animate';\nimport { getTabbableBoundary } from '../internal/tabbable';\nimport { MinidButton } from './button.component';\nimport { MinidMenu } from '../components/menu.component';\nimport { MinidPhoneInput } from '../components/phone-input.component';\nimport { MinidTextfield } from '../components/textfield.component';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-combobox': MinidCombobox;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: flex;\n }\n `,\n];\n\n/**\n * @slot -- Default slot for content of the dropdown panel\n * @slot trigger - Used for the button element that will be used to open the dropdown menu\n * @part panel - Select the dropdown panel host element\n */\n@customElement('mid-combobox')\nexport class MinidCombobox extends styled(LitElement, styles) {\n private closeWatcher?: CloseWatcher;\n\n @query('#combobox')\n private popup!: MinidPopup;\n\n @query('.combobox__trigger')\n private trigger!: HTMLSlotElement;\n\n @query('.combobox__panel')\n private panel!: HTMLSlotElement;\n\n @queryAssignedElements({ slot: 'trigger' })\n private triggerElements!: (\n | MinidTextfield\n | MinidPhoneInput\n | HTMLInputElement\n )[];\n\n /**\n * By default, the combobox is closed when an item is selected. This attribute will keep it open instead. Useful for\n * comboboxs that allow for multiple interactions.\n */\n @property({ type: Boolean, reflect: true })\n stayopenonselect = false;\n\n /**\n * Indicates wether the combobox panel is open. You can use this or the show/hide methods.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Distance between trigger and combobox panel\n */\n @property({ type: Number })\n distance = 4;\n\n /**\n * Nudge the combobox panel position. Accepts a negative or positive number.\n */\n @property({ type: Number })\n skidding = 0;\n\n /**\n * Choose if position is `fixed` or `absolute`. `absolute` is more performant,\n * but `fixed` can solve issues with overflow clipping\n */\n @property({ type: Boolean })\n hoist = false;\n\n @property({ type: Boolean })\n disabled = false;\n\n @state()\n private triggerElement: 'mid-textfield' | 'mid-phone-input' = 'mid-textfield';\n\n /**\n * The combobox will close when the user interacts outside of this element (e.g. clicking). Useful for composing other\n * components that use a combobox internally.\n */\n @property({ attribute: false })\n containingElement?: HTMLElement;\n\n connectedCallback() {\n super.connectedCallback();\n\n if (!this.containingElement) {\n this.containingElement = this;\n }\n }\n\n firstUpdated(_changedProperties: PropertyValues): void {\n const input = this.triggerElements[0];\n if (input.tagName.toLowerCase() === 'mid-phone-input') {\n this.triggerElement = 'mid-phone-input';\n } else if (input.tagName.toLowerCase() === 'mid-textfield') {\n this.triggerElement = 'mid-textfield';\n }\n\n this.panel.hidden = !this.open;\n\n const menu = this.getMenu();\n if (menu) {\n menu.variant = 'combobox';\n }\n\n // If the combobox panel is visible on init, update its position\n if (this.open) {\n this.addOpenListeners();\n this.popup.active = true;\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeOpenListeners();\n this.hide();\n }\n\n focusOnTrigger() {\n const trigger = this.trigger.assignedElements({ flatten: true })[0] as\n | HTMLElement\n | undefined;\n\n if (typeof trigger?.focus === 'function') {\n trigger.focus();\n }\n }\n\n getMenu() {\n return this.panel\n .assignedElements({ flatten: true })\n .find((el) => el.tagName.toLowerCase() === 'mid-menu') as\n | MinidMenu\n | undefined;\n }\n\n private handleCountryClick = () => {\n const menu = this.getMenu();\n\n this.open ? this.hide() : this.show();\n if (this.open && menu && menu.searchable) {\n // Delay focus slightly to win the focus battle\n setTimeout(() => {\n menu.clearFilter();\n menu.focusSearchField();\n }, 1);\n }\n };\n\n private handleKeyDown = (event: KeyboardEvent) => {\n // Close when escape is pressed inside an open combobox. We need to listen on the panel itself and stop propagation\n // in case any ancestors are also listening for this key.\n if (this.open && event.key === 'Escape') {\n event.stopPropagation();\n this.hide();\n this.focusOnTrigger();\n return;\n }\n };\n\n private handleDocumentKeyDown = (event: KeyboardEvent) => {\n // Close when escape or tab is pressed\n if (event.key === 'Escape' && this.open && !this.closeWatcher) {\n event.stopPropagation();\n this.focusOnTrigger();\n this.hide();\n return;\n }\n\n // Handle tabbing\n if (event.key === 'Tab') {\n // Tabbing within an open menu should close the combobox and refocus the trigger\n if (\n this.open &&\n (document.activeElement?.tagName.toLowerCase() === 'mid-menu-item' ||\n document.activeElement?.tagName.toLowerCase() === 'mid-menu')\n ) {\n event.preventDefault();\n this.hide();\n this.focusOnTrigger();\n return;\n }\n\n // Tabbing outside of the containing element closes the panel\n //\n // If the combobox is used within a shadow DOM, we need to obtain the activeElement within that shadowRoot,\n // otherwise `document.activeElement` will only return the name of the parent shadow DOM element.\n setTimeout(() => {\n const activeElement =\n this.containingElement?.getRootNode() instanceof ShadowRoot\n ? document.activeElement?.shadowRoot?.activeElement\n : document.activeElement;\n\n if (\n !this.containingElement ||\n activeElement?.closest(\n this.containingElement.tagName.toLowerCase()\n ) !== this.containingElement\n ) {\n this.hide();\n }\n });\n }\n };\n\n private handleDocumentMouseDown = (event: MouseEvent) => {\n // Close when clicking outside of the containing element\n const path = event.composedPath();\n if (this.containingElement && !path.includes(this.containingElement)) {\n this.hide();\n }\n };\n\n private handlePanelSelect = (event: CustomEvent) => {\n if (this.triggerElement !== 'mid-phone-input') {\n return;\n }\n\n // Transfer selected country from panel to input field\n const input = this.triggerElements[0] as MinidPhoneInput;\n const country = event.detail.item.value;\n input.country = country;\n\n const target = event.target as HTMLElement;\n\n // Hide the combobox when a menu item is selected\n if (!this.stayopenonselect && target.tagName.toLowerCase() === 'mid-menu') {\n this.hide();\n this.focusOnTrigger();\n }\n };\n\n handleTriggerClick() {\n if (this.triggerElement === 'mid-phone-input') {\n return;\n }\n\n if (this.open) {\n this.hide();\n } else {\n this.show();\n this.focusOnTrigger();\n }\n }\n\n async handleTriggerKeyDown(event: KeyboardEvent) {\n // When spacebar/enter is pressed, show the panel but don't focus on the menu. This let's the user press the same\n // key again to hide the menu in case they don't want to make a selection.\n if ([' ', 'Enter'].includes(event.key)) {\n event.preventDefault();\n if (this.triggerElement === 'mid-textfield') {\n this.handleTriggerClick();\n }\n return;\n }\n\n const menu = this.getMenu();\n\n if (menu) {\n const menuItems = menu.getAllSelectableItems();\n const firstMenuItem = menuItems[0];\n const lastMenuItem = menuItems[menuItems.length - 1];\n\n // When up/down is pressed, we make the assumption that the user is familiar with the menu and plans to make a\n // selection. Rather than toggle the panel, we focus on the menu (if one exists) and activate the first item for\n // faster navigation.\n if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {\n event.preventDefault();\n\n // Show the menu if it's not already open\n if (!this.open) {\n this.show();\n\n // Wait for the combobox to open before focusing, but not the animation\n await this.updateComplete;\n }\n\n if (menuItems.length > 0) {\n // Focus on the first/last menu item after showing\n this.updateComplete.then(() => {\n if (event.key === 'ArrowDown' || event.key === 'Home') {\n menu.setCurrentItem(firstMenuItem);\n if (this.triggerElement === 'mid-textfield') {\n firstMenuItem.focus();\n } else {\n menu.clearFilter();\n menu.focusSearchField();\n }\n }\n\n if (event.key === 'ArrowUp' || event.key === 'End') {\n menu.setCurrentItem(lastMenuItem);\n if (this.triggerElement === 'mid-textfield') {\n lastMenuItem.focus();\n } else {\n menu.clearFilter();\n menu.focusSearchField();\n }\n }\n });\n }\n }\n }\n }\n\n handleTriggerKeyUp(event: KeyboardEvent) {\n // Prevent space from triggering a click event in Firefox\n if (event.key === ' ') {\n event.preventDefault();\n }\n }\n\n handleTriggerSlotChange() {\n this.updateAccessibleTrigger();\n }\n\n /**\n * Instructs the combobox menu to reposition. Useful when the position or size of the trigger changes when the menu\n * is activated.\n */\n reposition() {\n this.popup.reposition();\n }\n\n addOpenListeners() {\n if ('CloseWatcher' in window) {\n this.closeWatcher?.destroy();\n this.closeWatcher = new CloseWatcher();\n this.closeWatcher.onclose = () => {\n this.hide();\n this.focusOnTrigger();\n };\n }\n\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n document.addEventListener('mousedown', this.handleDocumentMouseDown);\n }\n\n removeOpenListeners() {\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n document.removeEventListener('mousedown', this.handleDocumentMouseDown);\n this.closeWatcher?.destroy();\n }\n\n /**\n * Shows the combobox panel.\n */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'mid-after-show');\n }\n\n /**\n * Hides the combobox panel\n */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'mid-after-hide');\n }\n\n //\n // Slotted triggers can be arbitrary content, but we need to link them to the combobox panel with `aria-haspopup` and\n // `aria-expanded`. These must be applied to the \"accessible trigger\" (the tabbable portion of the trigger element\n // that gets slotted in) so screen readers will understand them. The accessible trigger could be the slotted element,\n // a child of the slotted element, or an element in the slotted element's shadow root.\n //\n // For example, the accessible trigger of an <sl-button> is a <button> located inside its shadow root.\n //\n // To determine this, we assume the first tabbable element in the trigger slot is the \"accessible trigger.\"\n //\n updateAccessibleTrigger() {\n const assignedElements = this.trigger.assignedElements({\n flatten: true,\n }) as HTMLElement[];\n const accessibleTrigger = assignedElements.find(\n (el) => getTabbableBoundary(el).start\n );\n let target: HTMLElement;\n\n if (accessibleTrigger) {\n switch (accessibleTrigger.tagName.toLowerCase()) {\n // buttons have to update the internal button so it's announced correctly by screen readers\n case 'mid-button':\n target = (accessibleTrigger as MinidButton).button;\n break;\n\n default:\n target = accessibleTrigger;\n }\n\n target.setAttribute('aria-haspopup', 'true');\n target.setAttribute('aria-expanded', this.open ? 'true' : 'false');\n }\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.disabled) {\n this.open = false;\n return;\n }\n\n this.updateAccessibleTrigger();\n\n if (this.open) {\n // Show\n this.dispatchEvent(\n new Event('mid-show', { bubbles: true, composed: true })\n );\n this.addOpenListeners();\n\n await stopAnimations(this);\n this.panel.hidden = false;\n this.popup.active = true;\n const { keyframes, options } = getAnimation(this, 'combobox.show');\n await animateTo(this.popup.popup, keyframes, options);\n\n this.dispatchEvent(\n new Event('mid-after-show', { bubbles: true, composed: true })\n );\n } else {\n // Hide\n this.dispatchEvent(\n new Event('mid-hide', { bubbles: true, composed: true })\n );\n this.removeOpenListeners();\n await stopAnimations(this);\n const { keyframes, options } = getAnimation(this, 'combobox.hide');\n await animateTo(this.popup.popup, keyframes, options);\n this.panel.hidden = true;\n this.popup.active = false;\n\n this.dispatchEvent(\n new Event('mid-after-hide', { bubbles: true, composed: true })\n );\n }\n }\n\n override render() {\n return html`\n <mid-popup\n id=\"combobox\"\n distance=${this.distance}\n placement=\"bottom-end\"\n skidding=${this.skidding}\n strategy=${this.hoist ? 'fixed' : 'absolute'}\n flip\n shift\n auto-size=\"vertical\"\n auto-size-padding=\"10\"\n sync=\"width\"\n ?active=${this.open}\n >\n <slot\n class=\"combobox__trigger\"\n slot=\"anchor\"\n name=\"trigger\"\n @click=${this.handleTriggerClick}\n @keydown=${this.handleTriggerKeyDown}\n @keyup=${this.handleTriggerKeyUp}\n @slotchange=${this.handleTriggerSlotChange}\n @mid-country-click=${this.handleCountryClick}\n ></slot>\n <div\n aria-hidden=${this.open ? 'false' : 'true'}\n aria-labelledby=\"combobox\"\n >\n <slot\n class=\"combobox__panel\"\n part=\"panel\"\n @keydown=${this.handleKeyDown}\n @mid-select=${this.handlePanelSelect}\n ></slot>\n </div>\n </mid-popup>\n `;\n }\n}\n\nsetDefaultAnimation('combobox.show', {\n keyframes: [\n { opacity: 0, scale: 0.9 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 100, easing: 'ease' },\n});\n\nsetDefaultAnimation('combobox.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.9 },\n ],\n options: { duration: 100, easing: 'ease' },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -120,7 +120,7 @@ let MinidDialog = class extends styled(LitElement, styles) {
|
|
|
120
120
|
<dialog
|
|
121
121
|
part="base"
|
|
122
122
|
id="dialog"
|
|
123
|
-
class="text-
|
|
123
|
+
class="text-neutral m-auto max-h-[calc(100%---spacing(8))] w-(--width) max-w-[calc(100%---spacing(8))] flex-col rounded-lg p-6 shadow-xl backdrop:bg-black/50 open:flex open:animate-none"
|
|
124
124
|
@cancel=${this.handleDialogCancel}
|
|
125
125
|
@click=${this.handleBackdropClick}
|
|
126
126
|
>
|
|
@@ -130,7 +130,7 @@ let MinidDialog = class extends styled(LitElement, styles) {
|
|
|
130
130
|
<button
|
|
131
131
|
autofocus
|
|
132
132
|
@click="${() => this.requestClose("close-button")}"
|
|
133
|
-
class="text-body-md focus-visible:focus-ring text-neutral hover:bg-neutral-surface-hover float-right flex size-12
|
|
133
|
+
class="text-body-md focus-visible:focus-ring text-neutral hover:bg-neutral-surface-hover float-right flex size-12 translate-x-3 -translate-y-3 items-center justify-center rounded"
|
|
134
134
|
>
|
|
135
135
|
<mid-icon class="size-6" name="xmark"></mid-icon>
|
|
136
136
|
</button>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.js","sources":["../../src/components/dialog.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { waitForEvent } from '../internal/event';\nimport { watch } from '../internal/watch';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry';\nimport { animateTo, stopAnimations } from '../internal/animate';\nimport { lockBodyScrolling, unlockBodyScrolling } from '../internal/scroll';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-dialog': MinidDialog;\n }\n}\n\nconst styles = [\n css`\n :host {\n --width: 40rem;\n display: block;\n }\n `,\n];\n\n/**\n *\n * @event mid-show - Emitted when the dialog opens.\n * @event mid-after-show - Emitted after the dialog opens and all animations are complete.\n * @event mid-hide - Emitted when the dialog closes.\n * @event mid-after-hide - Emitted after the dialog closes and all animations are complete.\n * @event {{ source: 'close-button' | 'keyboard' | 'overlay' }} mid-request-close - Emitted when the user attempts to\n * close the dialog by clicking the close button, clicking the overlay, or pressing escape. Calling\n * `event.preventDefault()` will keep the dialog open. Avoid using this unless closing the dialog will result in\n * destructive behavior such as data loss.\n *\n * @csspart base - Select the base `dialog` element\n * @csspart header - Select the `header` element\n * @csspart body - Select the `article` element\n * @csspart footer - Select the `footer` element\n *\n * @slot -- The default slot for the body content of the dialog\n * @slot heading - The content inside the `h2` element\n * @slot footer - The content inside the `footer` element\n *\n * @animation dialog.show - The animation to use when showing the dialog.\n * @animation dialog.hide - The animation to use when hiding the dialog.\n * @animation dialog.denyClose - The animation to use when closing the dialog is prevented.\n *\n */\n@customElement('mid-dialog')\nexport class MinidDialog extends styled(LitElement, styles) {\n @query('#dialog')\n dialog!: HTMLDialogElement;\n\n /**\n * Indicates whether or not the dialog is open. You can toggle this attribute to show and hide the dialog, or you can\n * use the `show()` and `hide()` methods and this attribute will reflect the dialog's open state.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * The dialog's label as displayed in the header. You should always include a relevant label even when using\n * `no-header`, as it is required for proper accessibility. If you need to display HTML, use the `label` slot instead.\n */\n @property({ reflect: true })\n heading = '';\n\n private requestClose(source: 'close-button' | 'keyboard' | 'overlay') {\n const requestCloseEvent = new CustomEvent('mid-request-close', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { source },\n });\n this.dispatchEvent(requestCloseEvent);\n\n if (requestCloseEvent.defaultPrevented) {\n const { keyframes, options } = getAnimation(this, 'dialog.denyClose');\n animateTo(this.dialog, keyframes, options);\n return;\n }\n\n this.hide();\n }\n\n handleDialogCancel = (event: Event) => {\n event.preventDefault();\n\n if (event.defaultPrevented) {\n this.requestClose('keyboard');\n } else {\n this.hide();\n }\n };\n\n private handleBackdropClick({ target }: Event) {\n // if the target is the dialog, the backdrop was clicked\n if (target === this.dialog) {\n this.requestClose('overlay');\n }\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.open) {\n // Show\n this.dispatchEvent(\n new Event('mid-show', { composed: true, bubbles: true })\n );\n // this.addOpenListeners();\n this.dialog.showModal();\n\n lockBodyScrolling(this);\n\n const panelAnimation = getAnimation(this, 'dialog.show');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\n ),\n this.dispatchEvent(\n new Event('mid-after-show', { bubbles: true, composed: true })\n );\n } else {\n // Hide\n this.dispatchEvent(\n new Event('mid-hide', { bubbles: true, composed: true })\n );\n\n await Promise.all([stopAnimations(this.dialog)]);\n const panelAnimation = getAnimation(this, 'dialog.hide');\n\n // The backdrop can only be animated with css because it's a pseudo element\n // so we add a animation class to trigger it at the same time as the dialog animation\n this.dialog.classList.add('backdrop:animate-fade-out');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\n );\n this.dialog.classList.remove('backdrop:animate-fade-out');\n this.dialog.close();\n this.dialog.hidden = false;\n unlockBodyScrolling(this);\n this.dispatchEvent(\n new Event('mid-after-hide', { composed: true, bubbles: true })\n );\n }\n }\n\n /**\n * Shows the dialog.\n */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'mid-after-show');\n }\n\n /**\n * Hides the dialog\n */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'mid-after-hide');\n }\n\n override render() {\n return html`\n <dialog\n part=\"base\"\n id=\"dialog\"\n class=\"text-body-md text-neutral m-auto max-h-[calc(100%---spacing(8))] w-(--width) max-w-[calc(100%---spacing(8))] flex-col rounded-lg p-6 shadow-xl backdrop:bg-black/50 open:flex open:animate-none\"\n @cancel=${this.handleDialogCancel}\n @click=${this.handleBackdropClick}\n >\n <header part=\"header\" class=\"text-heading-sm flex justify-between\">\n <slot name=\"heading\"></slot>\n <div class=\"h-0\">\n <button\n autofocus\n @click=\"${() => this.requestClose('close-button')}\"\n class=\"text-body-md focus-visible:focus-ring text-neutral hover:bg-neutral-surface-hover float-right flex size-12 -translate-y-3 translate-x-3 items-center justify-center rounded\"\n >\n <mid-icon class=\"size-6\" name=\"xmark\"></mid-icon>\n </button>\n </div>\n </header>\n <div part=\"body\" class=\"overflow-auto\">\n <slot> </slot>\n </div>\n <footer part=\"footer\">\n <slot name=\"footer\"> </slot>\n </footer>\n </dialog>\n `;\n }\n}\n\nsetDefaultAnimation('dialog.show', {\n keyframes: [\n { opacity: 0, scale: 0.8 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.8 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.denyClose', {\n keyframes: [{ scale: 1 }, { scale: 1.03 }, { scale: 1 }],\n options: { duration: 100 },\n});\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dialog.js","sources":["../../src/components/dialog.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { waitForEvent } from '../internal/event';\nimport { watch } from '../internal/watch';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './icon/icon.component';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry';\nimport { animateTo, stopAnimations } from '../internal/animate';\nimport { lockBodyScrolling, unlockBodyScrolling } from '../internal/scroll';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-dialog': MinidDialog;\n }\n}\n\nconst styles = [\n css`\n :host {\n --width: 40rem;\n display: block;\n }\n `,\n];\n\n/**\n *\n * @event mid-show - Emitted when the dialog opens.\n * @event mid-after-show - Emitted after the dialog opens and all animations are complete.\n * @event mid-hide - Emitted when the dialog closes.\n * @event mid-after-hide - Emitted after the dialog closes and all animations are complete.\n * @event {{ source: 'close-button' | 'keyboard' | 'overlay' }} mid-request-close - Emitted when the user attempts to\n * close the dialog by clicking the close button, clicking the overlay, or pressing escape. Calling\n * `event.preventDefault()` will keep the dialog open. Avoid using this unless closing the dialog will result in\n * destructive behavior such as data loss.\n *\n * @csspart base - Select the base `dialog` element\n * @csspart header - Select the `header` element\n * @csspart body - Select the `article` element\n * @csspart footer - Select the `footer` element\n *\n * @slot -- The default slot for the body content of the dialog\n * @slot heading - The content inside the `h2` element\n * @slot footer - The content inside the `footer` element\n *\n * @animation dialog.show - The animation to use when showing the dialog.\n * @animation dialog.hide - The animation to use when hiding the dialog.\n * @animation dialog.denyClose - The animation to use when closing the dialog is prevented.\n *\n */\n@customElement('mid-dialog')\nexport class MinidDialog extends styled(LitElement, styles) {\n @query('#dialog')\n dialog!: HTMLDialogElement;\n\n /**\n * Indicates whether or not the dialog is open. You can toggle this attribute to show and hide the dialog, or you can\n * use the `show()` and `hide()` methods and this attribute will reflect the dialog's open state.\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * The dialog's label as displayed in the header. You should always include a relevant label even when using\n * `no-header`, as it is required for proper accessibility. If you need to display HTML, use the `label` slot instead.\n */\n @property({ reflect: true })\n heading = '';\n\n private requestClose(source: 'close-button' | 'keyboard' | 'overlay') {\n const requestCloseEvent = new CustomEvent('mid-request-close', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { source },\n });\n this.dispatchEvent(requestCloseEvent);\n\n if (requestCloseEvent.defaultPrevented) {\n const { keyframes, options } = getAnimation(this, 'dialog.denyClose');\n animateTo(this.dialog, keyframes, options);\n return;\n }\n\n this.hide();\n }\n\n handleDialogCancel = (event: Event) => {\n event.preventDefault();\n\n if (event.defaultPrevented) {\n this.requestClose('keyboard');\n } else {\n this.hide();\n }\n };\n\n private handleBackdropClick({ target }: Event) {\n // if the target is the dialog, the backdrop was clicked\n if (target === this.dialog) {\n this.requestClose('overlay');\n }\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.open) {\n // Show\n this.dispatchEvent(\n new Event('mid-show', { composed: true, bubbles: true })\n );\n // this.addOpenListeners();\n this.dialog.showModal();\n\n lockBodyScrolling(this);\n\n const panelAnimation = getAnimation(this, 'dialog.show');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\n ),\n this.dispatchEvent(\n new Event('mid-after-show', { bubbles: true, composed: true })\n );\n } else {\n // Hide\n this.dispatchEvent(\n new Event('mid-hide', { bubbles: true, composed: true })\n );\n\n await Promise.all([stopAnimations(this.dialog)]);\n const panelAnimation = getAnimation(this, 'dialog.hide');\n\n // The backdrop can only be animated with css because it's a pseudo element\n // so we add a animation class to trigger it at the same time as the dialog animation\n this.dialog.classList.add('backdrop:animate-fade-out');\n await animateTo(\n this.dialog,\n panelAnimation.keyframes,\n panelAnimation.options\n );\n this.dialog.classList.remove('backdrop:animate-fade-out');\n this.dialog.close();\n this.dialog.hidden = false;\n unlockBodyScrolling(this);\n this.dispatchEvent(\n new Event('mid-after-hide', { composed: true, bubbles: true })\n );\n }\n }\n\n /**\n * Shows the dialog.\n */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'mid-after-show');\n }\n\n /**\n * Hides the dialog\n */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'mid-after-hide');\n }\n\n override render() {\n return html`\n <dialog\n part=\"base\"\n id=\"dialog\"\n class=\"text-neutral m-auto max-h-[calc(100%---spacing(8))] w-(--width) max-w-[calc(100%---spacing(8))] flex-col rounded-lg p-6 shadow-xl backdrop:bg-black/50 open:flex open:animate-none\"\n @cancel=${this.handleDialogCancel}\n @click=${this.handleBackdropClick}\n >\n <header part=\"header\" class=\"text-heading-sm flex justify-between\">\n <slot name=\"heading\"></slot>\n <div class=\"h-0\">\n <button\n autofocus\n @click=\"${() => this.requestClose('close-button')}\"\n class=\"text-body-md focus-visible:focus-ring text-neutral hover:bg-neutral-surface-hover float-right flex size-12 translate-x-3 -translate-y-3 items-center justify-center rounded\"\n >\n <mid-icon class=\"size-6\" name=\"xmark\"></mid-icon>\n </button>\n </div>\n </header>\n <div part=\"body\" class=\"overflow-auto\">\n <slot> </slot>\n </div>\n <footer part=\"footer\">\n <slot name=\"footer\"> </slot>\n </footer>\n </dialog>\n `;\n }\n}\n\nsetDefaultAnimation('dialog.show', {\n keyframes: [\n { opacity: 0, scale: 0.8 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.8 },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('dialog.denyClose', {\n keyframes: [{ scale: 1 }, { scale: 1.03 }, { scale: 1 }],\n options: { duration: 100 },\n});\n"],"names":[],"mappings":"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"}
|