@sken-ds/primitives 0.4.6 → 0.6.0
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/catalog-y40FMic1-DY2BFupW.js +153 -0
- package/dist/catalog-y40FMic1-DY2BFupW.js.map +1 -0
- package/dist/{decorate-D4FKzyDw.js → decorate-C1e2sg49.js} +1 -1
- package/dist/index.js +16 -12
- package/dist/ix-bridge.css +53 -191
- package/dist/primitives.css +2 -0
- package/dist/rolldown-runtime-BRfZIaNm.js +17 -0
- package/dist/sken-button.js +3 -3
- package/dist/sken-button.js.map +1 -1
- package/dist/sken-checkbox.js +14 -4
- package/dist/sken-checkbox.js.map +1 -1
- package/dist/sken-combobox-group.js +1 -1
- package/dist/sken-combobox-group.js.map +1 -1
- package/dist/sken-combobox-item.js +1 -1
- package/dist/sken-combobox-item.js.map +1 -1
- package/dist/sken-combobox.js +120 -99
- package/dist/sken-combobox.js.map +1 -1
- package/dist/{sken-datatable-CEXcvhM-.js → sken-datatable-DSXSyrNf.js} +219 -251
- package/dist/sken-datatable-DSXSyrNf.js.map +1 -0
- package/dist/sken-datatable.js +1 -1
- package/dist/sken-date-picker.js +1 -1
- package/dist/sken-date-picker.js.map +1 -1
- package/dist/sken-dialog.js +251 -2
- package/dist/sken-dialog.js.map +1 -0
- package/dist/sken-filter-chip.js +1 -1
- package/dist/sken-filter-chip.js.map +1 -1
- package/dist/sken-input.js +69 -44
- package/dist/sken-input.js.map +1 -1
- package/dist/sken-layout-region.js +1 -1
- package/dist/sken-layout-region.js.map +1 -1
- package/dist/sken-layout.js +35 -32
- package/dist/sken-layout.js.map +1 -1
- package/dist/sken-nav-group.js +306 -0
- package/dist/sken-nav-group.js.map +1 -0
- package/dist/sken-nav-item.js +224 -0
- package/dist/sken-nav-item.js.map +1 -0
- package/dist/sken-nav.js +233 -0
- package/dist/sken-nav.js.map +1 -0
- package/dist/sken-number-input.js +15 -7
- package/dist/sken-number-input.js.map +1 -1
- package/dist/sken-switch.js +27 -7
- package/dist/sken-switch.js.map +1 -1
- package/dist/sken-textarea.js +108 -52
- package/dist/sken-textarea.js.map +1 -1
- package/dist/sken-tooltip.js +70 -0
- package/dist/sken-tooltip.js.map +1 -0
- package/package.json +35 -16
- package/dist/directive-BcLtPdVO.js +0 -263
- package/dist/directive-BcLtPdVO.js.map +0 -1
- package/dist/sken-datatable-CEXcvhM-.js.map +0 -1
- package/dist/sken-dialog-BvRZxwSk.js +0 -258
- package/dist/sken-dialog-BvRZxwSk.js.map +0 -1
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
import { t as e } from "./decorate-D4FKzyDw.js";
|
|
2
|
-
import { i as t, n, r, t as i } from "./directive-BcLtPdVO.js";
|
|
3
|
-
import { LitElement as a, css as o, html as s, nothing as c } from "lit";
|
|
4
|
-
import { customElement as l, property as u, query as d } from "lit/decorators.js";
|
|
5
|
-
//#region ../../node_modules/.pnpm/lit-html@3.3.3/node_modules/lit-html/directives/class-map.js
|
|
6
|
-
var f = i(class extends n {
|
|
7
|
-
constructor(e) {
|
|
8
|
-
if (super(e), e.type !== r.ATTRIBUTE || e.name !== "class" || e.strings?.length > 2) throw Error("`classMap()` can only be used in the `class` attribute and must be the only part in the attribute.");
|
|
9
|
-
}
|
|
10
|
-
render(e) {
|
|
11
|
-
return " " + Object.keys(e).filter((t) => e[t]).join(" ") + " ";
|
|
12
|
-
}
|
|
13
|
-
update(e, [n]) {
|
|
14
|
-
if (this.st === void 0) {
|
|
15
|
-
this.st = /* @__PURE__ */ new Set(), e.strings !== void 0 && (this.nt = new Set(e.strings.join(" ").split(/\s/).filter((e) => e !== "")));
|
|
16
|
-
for (let e in n) n[e] && !this.nt?.has(e) && this.st.add(e);
|
|
17
|
-
return this.render(n);
|
|
18
|
-
}
|
|
19
|
-
let r = e.element.classList;
|
|
20
|
-
for (let e of this.st) e in n || (r.remove(e), this.st.delete(e));
|
|
21
|
-
for (let e in n) {
|
|
22
|
-
let t = !!n[e];
|
|
23
|
-
t === this.st.has(e) || this.nt?.has(e) || (t ? (r.add(e), this.st.add(e)) : (r.remove(e), this.st.delete(e)));
|
|
24
|
-
}
|
|
25
|
-
return t;
|
|
26
|
-
}
|
|
27
|
-
}), p = class extends a {
|
|
28
|
-
constructor(...e) {
|
|
29
|
-
super(...e), this.open = !1, this.size = "md", this.dismissable = "dismissable", this.ariaLabel = null, this.ariaDescribedBy = null, this.#e = null, this.#t = null, this.#n = !1, this.#r = !1, this.#a = (e) => {
|
|
30
|
-
if (this.dismissable === "persistent") {
|
|
31
|
-
e.preventDefault();
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
this.#l("sken-close", "escape");
|
|
35
|
-
}, this.#o = () => {
|
|
36
|
-
this.#l("sken-closed");
|
|
37
|
-
}, this.#s = (e) => {
|
|
38
|
-
e.target === this._dialog && this.dismissable !== "persistent" && this.#l("sken-close", "backdrop");
|
|
39
|
-
}, this.#c = () => {
|
|
40
|
-
this.#l("sken-close", "close-button");
|
|
41
|
-
}, this.#u = (e) => {
|
|
42
|
-
let t = e.target;
|
|
43
|
-
this.#r = t.assignedNodes({ flatten: !0 }).length > 0, this.requestUpdate();
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
#e;
|
|
47
|
-
#t;
|
|
48
|
-
#n;
|
|
49
|
-
#r;
|
|
50
|
-
static {
|
|
51
|
-
this.styles = o`
|
|
52
|
-
:host {
|
|
53
|
-
display: contents;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
dialog {
|
|
57
|
-
/* Reset native styles. */
|
|
58
|
-
padding: 0;
|
|
59
|
-
border: none;
|
|
60
|
-
background: transparent;
|
|
61
|
-
color: inherit;
|
|
62
|
-
max-width: none;
|
|
63
|
-
max-height: none;
|
|
64
|
-
margin: auto;
|
|
65
|
-
outline: none;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/* Open animation (entry). The browser fires the open attribute
|
|
69
|
-
on showModal(); with transition-behavior: allow-discrete we
|
|
70
|
-
can animate the top-layer entry. Falls back to no animation
|
|
71
|
-
in browsers without support. */
|
|
72
|
-
dialog[open] {
|
|
73
|
-
animation: sken-dialog-enter 150ms ease-out;
|
|
74
|
-
}
|
|
75
|
-
@keyframes sken-dialog-enter {
|
|
76
|
-
from {
|
|
77
|
-
opacity: 0;
|
|
78
|
-
transform: scale(0.96);
|
|
79
|
-
}
|
|
80
|
-
to {
|
|
81
|
-
opacity: 1;
|
|
82
|
-
transform: scale(1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* Backdrop. Native ::backdrop is a pseudo-element on the
|
|
87
|
-
<dialog> when shown via showModal(). */
|
|
88
|
-
dialog::backdrop {
|
|
89
|
-
background: rgba(15, 18, 24, 0.55);
|
|
90
|
-
animation: sken-dialog-backdrop-enter 150ms ease-out;
|
|
91
|
-
}
|
|
92
|
-
@keyframes sken-dialog-backdrop-enter {
|
|
93
|
-
from {
|
|
94
|
-
opacity: 0;
|
|
95
|
-
}
|
|
96
|
-
to {
|
|
97
|
-
opacity: 1;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.panel {
|
|
102
|
-
background: var(--sken-color-surface, #ffffff);
|
|
103
|
-
color: var(--sken-color-text, #1a1a1a);
|
|
104
|
-
border-radius: 12px;
|
|
105
|
-
box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.25);
|
|
106
|
-
display: flex;
|
|
107
|
-
flex-direction: column;
|
|
108
|
-
max-height: 90vh;
|
|
109
|
-
max-width: 90vw;
|
|
110
|
-
overflow: hidden;
|
|
111
|
-
font-family: var(--sken-font-sans, system-ui, sans-serif);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
.panel.sm {
|
|
115
|
-
width: 400px;
|
|
116
|
-
}
|
|
117
|
-
.panel.md {
|
|
118
|
-
width: 560px;
|
|
119
|
-
}
|
|
120
|
-
.panel.lg {
|
|
121
|
-
width: 800px;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
header {
|
|
125
|
-
display: flex;
|
|
126
|
-
align-items: flex-start;
|
|
127
|
-
justify-content: space-between;
|
|
128
|
-
gap: 16px;
|
|
129
|
-
padding: 20px 24px 8px;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
header ::slotted([slot='title']) {
|
|
133
|
-
font-size: 18px;
|
|
134
|
-
font-weight: 600;
|
|
135
|
-
line-height: 1.3;
|
|
136
|
-
margin: 0;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
.body {
|
|
140
|
-
padding: 8px 24px 16px;
|
|
141
|
-
overflow-y: auto;
|
|
142
|
-
flex: 1;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
footer {
|
|
146
|
-
display: flex;
|
|
147
|
-
align-items: center;
|
|
148
|
-
justify-content: flex-end;
|
|
149
|
-
gap: 8px;
|
|
150
|
-
padding: 12px 24px 20px;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/* Only render the footer divider if there is content. */
|
|
154
|
-
footer:not(:has(*)) {
|
|
155
|
-
display: none;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.close-button {
|
|
159
|
-
appearance: none;
|
|
160
|
-
background: transparent;
|
|
161
|
-
border: none;
|
|
162
|
-
cursor: pointer;
|
|
163
|
-
width: 32px;
|
|
164
|
-
height: 32px;
|
|
165
|
-
display: inline-flex;
|
|
166
|
-
align-items: center;
|
|
167
|
-
justify-content: center;
|
|
168
|
-
border-radius: 6px;
|
|
169
|
-
color: inherit;
|
|
170
|
-
opacity: 0.6;
|
|
171
|
-
transition:
|
|
172
|
-
opacity 100ms,
|
|
173
|
-
background 100ms;
|
|
174
|
-
flex-shrink: 0;
|
|
175
|
-
}
|
|
176
|
-
.close-button:hover {
|
|
177
|
-
opacity: 1;
|
|
178
|
-
background: rgba(0, 0, 0, 0.05);
|
|
179
|
-
}
|
|
180
|
-
.close-button:focus-visible {
|
|
181
|
-
outline: 2px solid var(--sken-color-focus, #2e6fc6);
|
|
182
|
-
outline-offset: 1px;
|
|
183
|
-
}
|
|
184
|
-
`;
|
|
185
|
-
}
|
|
186
|
-
connectedCallback() {
|
|
187
|
-
super.connectedCallback(), this.#e = this.parentNode, this.#t = this.nextSibling;
|
|
188
|
-
}
|
|
189
|
-
disconnectedCallback() {
|
|
190
|
-
super.disconnectedCallback(), this.#n && this.#e && (this.#t && this.#t.parentNode === this.#e ? this.#e.insertBefore(this, this.#t) : this.#e.appendChild(this), this.#n = !1);
|
|
191
|
-
}
|
|
192
|
-
updated(e) {
|
|
193
|
-
e.has("open") && this._dialog && (this.open ? this.#i() : this._dialog.open && this._dialog.close());
|
|
194
|
-
}
|
|
195
|
-
#i() {
|
|
196
|
-
this.#n === !1 && this.parentNode !== document.body && (document.body.appendChild(this), this.#n = !0), this._dialog.open || (this._dialog.showModal(), this.#l("sken-opened"), queueMicrotask(() => {
|
|
197
|
-
this.dismissable === "dismissable" && this._closeButton ? this._closeButton.focus() : this._dialog.querySelector("button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])")?.focus();
|
|
198
|
-
}));
|
|
199
|
-
}
|
|
200
|
-
closeDialog(e = "close-button") {
|
|
201
|
-
this.#l("sken-close", e);
|
|
202
|
-
}
|
|
203
|
-
#a;
|
|
204
|
-
#o;
|
|
205
|
-
#s;
|
|
206
|
-
#c;
|
|
207
|
-
#l(e, t) {
|
|
208
|
-
this.dispatchEvent(new CustomEvent(e, {
|
|
209
|
-
detail: t,
|
|
210
|
-
bubbles: !0,
|
|
211
|
-
composed: !0
|
|
212
|
-
}));
|
|
213
|
-
}
|
|
214
|
-
render() {
|
|
215
|
-
let e = {
|
|
216
|
-
panel: !0,
|
|
217
|
-
[this.size]: !0
|
|
218
|
-
}, t = this.#r || this.dismissable === "dismissable", n = this.ariaLabel ?? "";
|
|
219
|
-
return s`
|
|
220
|
-
<dialog
|
|
221
|
-
aria-label=${n || c}
|
|
222
|
-
aria-describedby=${this.ariaDescribedBy || c}
|
|
223
|
-
@cancel=${this.#a}
|
|
224
|
-
@close=${this.#o}
|
|
225
|
-
@click=${this.#s}
|
|
226
|
-
>
|
|
227
|
-
<div class=${f(e)}>
|
|
228
|
-
${t ? s`<header>
|
|
229
|
-
<slot name="title" @slotchange=${this.#u}></slot>
|
|
230
|
-
${this.dismissable === "dismissable" ? s`<button
|
|
231
|
-
class="close-button"
|
|
232
|
-
type="button"
|
|
233
|
-
aria-label="Close dialog"
|
|
234
|
-
@click=${this.#c}
|
|
235
|
-
>
|
|
236
|
-
✕
|
|
237
|
-
</button>` : c}
|
|
238
|
-
</header>` : c}
|
|
239
|
-
<div class="body">
|
|
240
|
-
<slot></slot>
|
|
241
|
-
</div>
|
|
242
|
-
<footer>
|
|
243
|
-
<slot name="actions"></slot>
|
|
244
|
-
</footer>
|
|
245
|
-
</div>
|
|
246
|
-
</dialog>
|
|
247
|
-
`;
|
|
248
|
-
}
|
|
249
|
-
#u;
|
|
250
|
-
};
|
|
251
|
-
e([u({
|
|
252
|
-
reflect: !0,
|
|
253
|
-
type: Boolean
|
|
254
|
-
})], p.prototype, "open", void 0), e([u({ reflect: !0 })], p.prototype, "size", void 0), e([u({ reflect: !0 })], p.prototype, "dismissable", void 0), e([u({ attribute: "aria-label" })], p.prototype, "ariaLabel", void 0), e([u({ attribute: "aria-describedby" })], p.prototype, "ariaDescribedBy", void 0), e([d("dialog")], p.prototype, "_dialog", void 0), e([d(".close-button")], p.prototype, "_closeButton", void 0), p = e([l("sken-dialog")], p);
|
|
255
|
-
//#endregion
|
|
256
|
-
export { p as t };
|
|
257
|
-
|
|
258
|
-
//# sourceMappingURL=sken-dialog-BvRZxwSk.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sken-dialog-BvRZxwSk.js","names":["s","t","r","#dispatch","#hasTitle","#originalParent","#originalNextSibling","#portaled","#showModal","#onCancel","#onClose","#onClick","#onTitleSlotChange","#onCloseButton"],"sources":["../../../node_modules/.pnpm/lit-html@3.3.3/node_modules/lit-html/directives/class-map.js","../src/components/sken-dialog.ts"],"sourcesContent":["import{noChange as t}from\"../lit-html.js\";import{directive as s,Directive as i,PartType as r}from\"../directive.js\";\n/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const e=s(class extends i{constructor(t){if(super(t),t.type!==r.ATTRIBUTE||\"class\"!==t.name||t.strings?.length>2)throw Error(\"`classMap()` can only be used in the `class` attribute and must be the only part in the attribute.\")}render(t){return\" \"+Object.keys(t).filter(s=>t[s]).join(\" \")+\" \"}update(s,[i]){if(void 0===this.st){this.st=new Set,void 0!==s.strings&&(this.nt=new Set(s.strings.join(\" \").split(/\\s/).filter(t=>\"\"!==t)));for(const t in i)i[t]&&!this.nt?.has(t)&&this.st.add(t);return this.render(i)}const r=s.element.classList;for(const t of this.st)t in i||(r.remove(t),this.st.delete(t));for(const t in i){const s=!!i[t];s===this.st.has(t)||this.nt?.has(t)||(s?(r.add(t),this.st.add(t)):(r.remove(t),this.st.delete(t)))}return t}});export{e as classMap};\n//# sourceMappingURL=class-map.js.map\n","// ── <sken-dialog> — WAI-ARIA modal built on <dialog> ──────────────────\n// A thin Sken wrapper around the native HTML <dialog> element.\n//\n// Why <dialog>:\n// The browser already implements the WAI-ARIA dialog pattern when\n// you call showModal(): focus trap, Tab cycling, ESC handling,\n// ::backdrop pseudo-element, top-layer rendering, and inert\n// siblings. Re-implementing those is what v1 of this file did\n// and it produced a worse result (Math.random() ids, position:\n// fixed hacks, hand-rolled scroll lock, manual ESC listener).\n// v2 uses the platform. Less code, fewer bugs, better a11y.\n//\n// Why controlled only:\n// The consumer owns the `open` state. The primitive never flips\n// it on its own. To close, the consumer listens for `sken-close`\n// and sets `open = false`. Same model as Radix Dialog, Headless\n// UI Dialog, Reach UI Dialog.\n//\n// Portal:\n// On first open, the host element is re-parented into\n// document.body. showModal() requires the <dialog> to be in the\n// top layer; if it sits inside a transformed / overflow:hidden\n// ancestor it can be clipped. Re-parenting is the robust fix.\n// The element is restored to its original parent on disconnect.\n\nimport type {\n SkenDialogCloseReason,\n SkenDialogDismissable,\n SkenDialogSize,\n} from '@sken-ds/contracts'\nimport { LitElement, css, html, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\n\n@customElement('sken-dialog')\nexport class SkenDialog extends LitElement {\n @property({ reflect: true, type: Boolean }) open = false\n @property({ reflect: true }) size: SkenDialogSize = 'md'\n @property({ reflect: true }) dismissable: SkenDialogDismissable = 'dismissable'\n @property({ attribute: 'aria-label' }) ariaLabel: string | null = null\n @property({ attribute: 'aria-describedby' }) ariaDescribedBy: string | null = null\n\n @query('dialog') private _dialog!: HTMLDialogElement\n @query('.close-button') private _closeButton!: HTMLButtonElement | null\n\n /** Original parent of the host element. Restored on disconnect. */\n #originalParent: Node | null = null\n /** Next sibling in the original parent. Used to restore position. */\n #originalNextSibling: Node | null = null\n /** Has the host been moved into document.body? */\n #portaled = false\n /** Has the title slot been filled? Updated via the slotchange\n * event on the title <slot>. */\n #hasTitle = false\n\n static styles = css`\n :host {\n display: contents;\n }\n\n dialog {\n /* Reset native styles. */\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n max-width: none;\n max-height: none;\n margin: auto;\n outline: none;\n }\n\n /* Open animation (entry). The browser fires the open attribute\n on showModal(); with transition-behavior: allow-discrete we\n can animate the top-layer entry. Falls back to no animation\n in browsers without support. */\n dialog[open] {\n animation: sken-dialog-enter 150ms ease-out;\n }\n @keyframes sken-dialog-enter {\n from {\n opacity: 0;\n transform: scale(0.96);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* Backdrop. Native ::backdrop is a pseudo-element on the\n <dialog> when shown via showModal(). */\n dialog::backdrop {\n background: rgba(15, 18, 24, 0.55);\n animation: sken-dialog-backdrop-enter 150ms ease-out;\n }\n @keyframes sken-dialog-backdrop-enter {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n\n .panel {\n background: var(--sken-color-surface, #ffffff);\n color: var(--sken-color-text, #1a1a1a);\n border-radius: 12px;\n box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.25);\n display: flex;\n flex-direction: column;\n max-height: 90vh;\n max-width: 90vw;\n overflow: hidden;\n font-family: var(--sken-font-sans, system-ui, sans-serif);\n }\n\n .panel.sm {\n width: 400px;\n }\n .panel.md {\n width: 560px;\n }\n .panel.lg {\n width: 800px;\n }\n\n header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n padding: 20px 24px 8px;\n }\n\n header ::slotted([slot='title']) {\n font-size: 18px;\n font-weight: 600;\n line-height: 1.3;\n margin: 0;\n }\n\n .body {\n padding: 8px 24px 16px;\n overflow-y: auto;\n flex: 1;\n }\n\n footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 24px 20px;\n }\n\n /* Only render the footer divider if there is content. */\n footer:not(:has(*)) {\n display: none;\n }\n\n .close-button {\n appearance: none;\n background: transparent;\n border: none;\n cursor: pointer;\n width: 32px;\n height: 32px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: inherit;\n opacity: 0.6;\n transition:\n opacity 100ms,\n background 100ms;\n flex-shrink: 0;\n }\n .close-button:hover {\n opacity: 1;\n background: rgba(0, 0, 0, 0.05);\n }\n .close-button:focus-visible {\n outline: 2px solid var(--sken-color-focus, #2e6fc6);\n outline-offset: 1px;\n }\n `\n\n connectedCallback(): void {\n super.connectedCallback()\n // Capture original parent so we can restore on disconnect.\n this.#originalParent = this.parentNode\n this.#originalNextSibling = this.nextSibling\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback()\n if (this.#portaled && this.#originalParent) {\n // Restore original position. If originalNextSibling is null,\n // appendChild puts us at the end of originalParent.\n if (\n this.#originalNextSibling &&\n this.#originalNextSibling.parentNode === this.#originalParent\n ) {\n this.#originalParent.insertBefore(this, this.#originalNextSibling)\n } else {\n this.#originalParent.appendChild(this)\n }\n this.#portaled = false\n }\n }\n\n updated(changed: Map<string, unknown>): void {\n if (!changed.has('open')) return\n if (!this._dialog) return\n\n if (this.open) {\n this.#showModal()\n } else if (this._dialog.open) {\n this._dialog.close()\n }\n }\n\n /** Open the native <dialog>. Re-parents the host to <body> first. */\n #showModal(): void {\n if (this.#portaled === false && this.parentNode !== document.body) {\n document.body.appendChild(this)\n this.#portaled = true\n }\n if (!this._dialog.open) {\n this._dialog.showModal()\n this.#dispatch('sken-opened')\n // Focus the close button if dismissable, else the first focusable.\n queueMicrotask(() => {\n if (this.dismissable === 'dismissable' && this._closeButton) {\n this._closeButton.focus()\n } else {\n const first = this._dialog.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n )\n first?.focus()\n }\n })\n }\n }\n\n /** Programmatic close request. Dispatches `sken-close` with the\n * given reason. Does NOT close the native <dialog> directly —\n * the consumer is expected to set `open = false` in response,\n * which the reactive `updated()` hook will translate into a\n * native close. This keeps the controlled-only contract honest:\n * the consumer always owns the `open` state.\n *\n * Use for cases where the close is initiated by code, not by\n * the user (form submission success, async operation complete,\n * etc.). */\n closeDialog(reason: SkenDialogCloseReason = 'close-button'): void {\n this.#dispatch('sken-close', reason)\n }\n\n /** Native <dialog> event: fired when the user presses ESC. We\n * translate to sken-close with reason 'escape'. The consumer\n * then sets `open = false` which calls _dialog.close() (a\n * no-op since it's already closed by the browser). */\n #onCancel = (e: Event): void => {\n if (this.dismissable === 'persistent') {\n // Prevent the browser from closing. The dialog stays open.\n e.preventDefault()\n return\n }\n // Browser will close. We dispatch sken-close; the consumer's\n // `open` prop will then become false and the next render\n // is a no-op since the dialog is already closed.\n this.#dispatch('sken-close', 'escape')\n }\n\n /** Native <dialog> event: fired on close (ESC, backdrop click,\n * close button, or .close()). We use it to fire sken-closed. */\n #onClose = (): void => {\n this.#dispatch('sken-closed')\n }\n\n /** Click handler on the <dialog> itself. If the click target is\n * the <dialog> (not a descendant), the user clicked the\n * backdrop. We treat it as a close request unless persistent. */\n #onClick = (e: MouseEvent): void => {\n if (e.target !== this._dialog) return\n if (this.dismissable === 'persistent') return\n this.#dispatch('sken-close', 'backdrop')\n }\n\n /** Click handler for the close button. Always visible when\n * dismissable; hidden when persistent. */\n #onCloseButton = (): void => {\n this.#dispatch('sken-close', 'close-button')\n }\n\n /** Lightweight event dispatcher with the conventions: composed\n * (crosses shadow boundary), bubbles (reaches ancestors). */\n #dispatch(name: 'sken-close', detail: SkenDialogCloseReason): void\n #dispatch(name: 'sken-opened' | 'sken-closed', detail?: undefined): void\n #dispatch(name: string, detail?: unknown): void {\n this.dispatchEvent(\n new CustomEvent(name, {\n detail,\n bubbles: true,\n composed: true,\n }),\n )\n }\n\n render() {\n const panelClasses = {\n panel: true,\n [this.size]: true,\n }\n // We render the header only when there is a title slot OR the\n // dialog is dismissable (so the close button has somewhere to\n // live). A persistent dialog with no title renders body + footer\n // directly, no header. Slot presence is detected via\n // slotchange on the title slot.\n const showHeader = this.#hasTitle || this.dismissable === 'dismissable'\n // aria-label is only set when explicitly provided. Otherwise the\n // consumer should set a title slot so the dialog has an\n // accessible name via aria-labelledby. We always set the\n // attribute to a non-empty string (or omit it) so that a missing\n // name is detectable in dev tools.\n const ariaLabelAttr = this.ariaLabel ?? ''\n return html`\n <dialog\n aria-label=${ariaLabelAttr || nothing}\n aria-describedby=${this.ariaDescribedBy || nothing}\n @cancel=${this.#onCancel}\n @close=${this.#onClose}\n @click=${this.#onClick}\n >\n <div class=${classMap(panelClasses)}>\n ${\n showHeader\n ? html`<header>\n <slot name=\"title\" @slotchange=${this.#onTitleSlotChange}></slot>\n ${\n this.dismissable === 'dismissable'\n ? html`<button\n class=\"close-button\"\n type=\"button\"\n aria-label=\"Close dialog\"\n @click=${this.#onCloseButton}\n >\n ✕\n </button>`\n : nothing\n }\n </header>`\n : nothing\n }\n <div class=\"body\">\n <slot></slot>\n </div>\n <footer>\n <slot name=\"actions\"></slot>\n </footer>\n </div>\n </dialog>\n `\n }\n\n #onTitleSlotChange = (e: Event): void => {\n const slot = e.target as HTMLSlotElement\n this.#hasTitle = slot.assignedNodes({ flatten: true }).length > 0\n this.requestUpdate()\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-dialog': SkenDialog\n }\n}\n"],"x_google_ignoreList":[0],"mappings":";;;;;AAKG,IAAM,IAAEA,EAAE,cAAc,EAAC;CAAC,YAAY,GAAE;EAAC,IAAG,MAAMC,CAAC,GAAEA,EAAE,SAAOC,EAAE,aAAqBD,EAAE,SAAZ,WAAkBA,EAAE,SAAS,SAAO,GAAE,MAAM,MAAM,oGAAoG;CAAC;CAAC,OAAO,GAAE;EAAC,OAAM,MAAI,OAAO,KAAK,CAAC,CAAC,CAAC,QAAO,MAAG,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,IAAE;CAAG;CAAC,OAAO,GAAE,CAAC,IAAG;EAAC,IAAY,KAAK,OAAd,KAAK,GAAY;GAAC,KAAK,qBAAG,IAAI,IAAE,GAAW,EAAE,YAAX,KAAK,MAAgB,KAAK,KAAG,IAAI,IAAI,EAAE,QAAQ,KAAK,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAO,MAAQ,MAAL,EAAM,CAAC;GAAG,KAAI,IAAM,KAAK,GAAE,EAAE,MAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAG,KAAK,GAAG,IAAI,CAAC;GAAE,OAAO,KAAK,OAAO,CAAC;EAAC;EAAC,IAAM,IAAE,EAAE,QAAQ;EAAU,KAAI,IAAM,KAAK,KAAK,IAAG,KAAK,MAAI,EAAE,OAAO,CAAC,GAAE,KAAK,GAAG,OAAO,CAAC;EAAG,KAAI,IAAM,KAAK,GAAE;GAAC,IAAM,IAAE,CAAC,CAAC,EAAE;GAAG,MAAI,KAAK,GAAG,IAAI,CAAC,KAAG,KAAK,IAAI,IAAI,CAAC,MAAI,KAAG,EAAE,IAAI,CAAC,GAAE,KAAK,GAAG,IAAI,CAAC,MAAI,EAAE,OAAO,CAAC,GAAE,KAAK,GAAG,OAAO,CAAC;EAAG;EAAC,OAAOA;CAAC;AAAC,CAAC,GC8B7tB,IAAN,cAAyB,EAAW;;EA8UnB,aA7U6B,KAAA,OAAA,IACC,KAAA,OAAA,MACc,KAAA,cAAA,eACA,KAAA,YAAA,MACY,KAAA,kBAAA,MAM/C,KAAA,KAAA,MAEK,KAAA,KAAA,MAExB,KAAA,KAAA,IAGA,KAAA,KAAA,IAqNC,KAAA,MAAA,MAAmB;GAC9B,IAAI,KAAK,gBAAgB,cAAc;IAErC,EAAE,eAAe;IACjB;GACF;GAIA,KAAKE,GAAU,cAAc,QAAQ;EACvC,GAIuB,KAAA,WAAA;GACrB,KAAKA,GAAU,aAAa;EAC9B,GAKY,KAAA,MAAA,MAAwB;GAC9B,EAAE,WAAW,KAAK,WAClB,KAAK,gBAAgB,gBACzB,KAAKA,GAAU,cAAc,UAAU;EACzC,GAI6B,KAAA,WAAA;GAC3B,KAAKA,GAAU,cAAc,cAAc;EAC7C,GAwEsB,KAAA,MAAA,MAAmB;GACvC,IAAM,IAAO,EAAE;GAEf,AADA,KAAKC,KAAY,EAAK,cAAc,EAAE,SAAS,GAAK,CAAC,CAAC,CAAC,SAAS,GAChE,KAAK,cAAc;EACrB;;CAvUA;CAEA;CAEA;CAGA;;EAEgB,KAAA,SAAA,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuInB,oBAA0B;EAIxB,AAHA,MAAM,kBAAkB,GAExB,KAAKC,KAAkB,KAAK,YAC5B,KAAKC,KAAuB,KAAK;CACnC;CAEA,uBAA6B;EAE3B,AADA,MAAM,qBAAqB,GACvB,KAAKC,MAAa,KAAKF,OAIvB,KAAKC,MACL,KAAKA,GAAqB,eAAe,KAAKD,KAE9C,KAAKA,GAAgB,aAAa,MAAM,KAAKC,EAAoB,IAEjE,KAAKD,GAAgB,YAAY,IAAI,GAEvC,KAAKE,KAAY;CAErB;CAEA,QAAQ,GAAqC;EACtC,EAAQ,IAAI,MAAM,KAClB,KAAK,YAEN,KAAK,OACP,KAAKC,GAAW,IACP,KAAK,QAAQ,QACtB,KAAK,QAAQ,MAAM;CAEvB;CAGA,KAAmB;EAKjB,AAJI,KAAKD,OAAc,MAAS,KAAK,eAAe,SAAS,SAC3D,SAAS,KAAK,YAAY,IAAI,GAC9B,KAAKA,KAAY,KAEd,KAAK,QAAQ,SAChB,KAAK,QAAQ,UAAU,GACvB,KAAKJ,GAAU,aAAa,GAE5B,qBAAqB;GACnB,AAAI,KAAK,gBAAgB,iBAAiB,KAAK,eAC7C,KAAK,aAAa,MAAM,IAKxB,KAHmB,QAAQ,cACzB,4EAEF,CAAA,EAAO,MAAM;EAEjB,CAAC;CAEL;CAYA,YAAY,IAAgC,gBAAsB;EAChE,KAAKA,GAAU,cAAc,CAAM;CACrC;CAMA;CAcA;CAOA;CAQA;CAQA,GAAU,GAAc,GAAwB;EAC9C,KAAK,cACH,IAAI,YAAY,GAAM;GACpB;GACA,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;CAEA,SAAS;EACP,IAAM,IAAe;GACnB,OAAO;IACN,KAAK,OAAO;EACf,GAMM,IAAa,KAAKC,MAAa,KAAK,gBAAgB,eAMpD,IAAgB,KAAK,aAAa;EACxC,OAAO,CAAI;;qBAEM,KAAiB,EAAQ;2BACnB,KAAK,mBAAmB,EAAQ;kBACzC,KAAKK,GAAU;iBAChB,KAAKC,GAAS;iBACd,KAAKC,GAAS;;qBAEV,EAAS,CAAY,EAAE;YAEhC,IACI,CAAI;mDAC+B,KAAKC,GAAmB;oBAEvD,KAAK,gBAAgB,gBACjB,CAAI;;;;mCAIO,KAAKC,GAAe;;;qCAI/B,EACL;6BAEH,EACL;;;;;;;;;;CAUT;CAEA;AAKF;AAlVG,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAC1B,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA,GAC1B,EAAA,CAAA,EAAS,EAAE,WAAW,aAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GACpC,EAAA,CAAA,EAAS,EAAE,WAAW,mBAAmB,CAAC,CAAA,GAAA,EAAA,WAAA,mBAAA,KAAA,CAAA,GAE1C,EAAA,CAAA,EAAM,QAAQ,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACd,EAAA,CAAA,EAAM,eAAe,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GATvB,IAAA,EAAA,CAAA,EAAc,aAAa,CAAA,GAAA,CAAA"}
|