bank20baht-ui 0.11.0 → 0.12.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/README.md +3 -3
- package/dist/components/primitives/baht-datepicker.d.ts +4 -1
- package/dist/components/primitives/baht-datepicker.js +29 -26
- package/dist/components/primitives/baht-filter.d.ts +12 -1
- package/dist/components/primitives/baht-filter.js +42 -32
- package/dist/components/primitives/baht-modal.d.ts +14 -0
- package/dist/components/primitives/baht-modal.js +42 -37
- package/dist/components/primitives/baht-select.d.ts +4 -0
- package/dist/components/primitives/baht-select.js +50 -46
- package/dist/components/primitives/baht-swipe-row.d.ts +62 -0
- package/dist/components/primitives/baht-swipe-row.js +174 -0
- package/dist/components/primitives/index.d.ts +3 -2
- package/dist/core/i18n.d.ts +1 -0
- package/dist/core/i18n.js +2 -0
- package/dist/core/types.d.ts +3 -1
- package/dist/css/components.css +205 -0
- package/dist/custom-elements.json +450 -6
- package/dist/index.js +118 -116
- package/dist/react.d.ts +10 -1
- package/dist/register.d.ts +1 -0
- package/dist/register.js +1 -0
- package/dist/ssr.js +3 -2
- package/dist/tokens.css +205 -0
- package/dist/vscode.html-custom-data.json +33 -5
- package/dist/web-types.json +66 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -261,7 +261,7 @@ near-black ink (`#171717`) on white, hairline neutral borders, 44px controls, on
|
|
|
261
261
|
(`#444FBF`), status as tint pills, hand-drawn koboyo spot illustrations for empty /
|
|
262
262
|
error / upload states, IBM Plex Sans Thai / IBM Plex Mono (load the
|
|
263
263
|
fonts yourself), borders-over-shadows, "paper" easing — plus an opt-in dark theme
|
|
264
|
-
(`<html data-baht-theme="dark">`).
|
|
264
|
+
(`<html data-baht-theme="dark">`). 59 elements:
|
|
265
265
|
|
|
266
266
|
```html
|
|
267
267
|
<baht-button variant="secondary" size="sm">Cancel</baht-button>
|
|
@@ -269,7 +269,7 @@ fonts yourself), borders-over-shadows, "paper" easing — plus an opt-in dark th
|
|
|
269
269
|
<baht-table></baht-table> <baht-modal></baht-modal> <baht-toast></baht-toast> …
|
|
270
270
|
```
|
|
271
271
|
|
|
272
|
-
- **Data (server-side paging)** — `baht-table` · `baht-list` · `baht-pagination` · `baht-filter`.
|
|
272
|
+
- **Data (server-side paging)** — `baht-table` · `baht-list` · `baht-swipe-row` · `baht-pagination` · `baht-filter`.
|
|
273
273
|
`baht-table` ships a ServiceNow-style column picker with dot-walking into reference columns (`requester.department`) and emits `baht-columns-change` so the host can persist the layout.
|
|
274
274
|
`items` is one page; `baht-page-change` asks your app to fetch the next one.
|
|
275
275
|
- **Feedback** — `baht-modal` · `baht-toast` · `baht-alert` · `baht-tooltip` · `baht-progress` ·
|
|
@@ -347,7 +347,7 @@ no hand-written type declarations in your app:
|
|
|
347
347
|
| **Angular** | template binding on properties/events | `CUSTOM_ELEMENTS_SCHEMA`, see below |
|
|
348
348
|
| **Vue 3** | keep Vue from treating `baht-*` as components | `isCustomElement`, see below |
|
|
349
349
|
| **Phoenix / Rails / plain HTML** | it's just HTML — works as-is | none |
|
|
350
|
-
| **Tooling** (Storybook, docgen, custom) | machine-readable API of all
|
|
350
|
+
| **Tooling** (Storybook, docgen, custom) | machine-readable API of all 59 elements | read `dist/custom-elements.json` ([CEM standard](https://github.com/webcomponents/custom-elements-manifest)) |
|
|
351
351
|
|
|
352
352
|
**VS Code** — `.vscode/settings.json`:
|
|
353
353
|
|
|
@@ -15,7 +15,10 @@ import { BahtFieldBase } from '../field-base.js';
|
|
|
15
15
|
* Give a clipping ancestor (`overflow: hidden`) room, or it hides the popup.
|
|
16
16
|
*
|
|
17
17
|
* A footer under the grid carries **Today** (picks today — greyed out when
|
|
18
|
-
* min/max/disabled rules exclude it) and **Clear** (empties the value).
|
|
18
|
+
* min/max/disabled rules exclude it) and **Clear** (empties the value). With
|
|
19
|
+
* `field.enable_time` the first button reads **Now** (i18n key `now`) and picks
|
|
20
|
+
* today at the current time, to the minute (seconds dropped), under the same
|
|
21
|
+
* min/max/disabled rules; like Today it closes the calendar. Both
|
|
19
22
|
* `await el.updateComplete` resolves only once the calendar is attached (the
|
|
20
23
|
* lazy flatpickr load is folded into it), so hosts and tests need no extra wait.
|
|
21
24
|
* Today / Clear go through flatpickr, so they emit exactly like a click on a day. `disableMobile`
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { html as
|
|
2
|
-
import { customElement as
|
|
3
|
-
import { ifDefined as
|
|
1
|
+
import { html as y } from "lit";
|
|
2
|
+
import { customElement as g } from "lit/decorators.js";
|
|
3
|
+
import { ifDefined as D } from "lit/directives/if-defined.js";
|
|
4
4
|
import { BahtFieldBase as w } from "../field-base.js";
|
|
5
|
-
import { formatIsoDateTime as u, formatIsoDate as c, dateModeOf as h, parseIsoDate as l, isoDaysOf as
|
|
5
|
+
import { formatIsoDateTime as u, formatIsoDate as c, dateModeOf as h, parseIsoDate as l, isoDaysOf as k, parseIsoDateTime as C, parseDisabledEntry as v } from "../../core/dates.js";
|
|
6
6
|
import { t as p } from "../../core/i18n.js";
|
|
7
|
-
import { renderIcon as
|
|
8
|
-
var
|
|
9
|
-
for (var i = s > 1 ? void 0 : s ?
|
|
7
|
+
import { renderIcon as _ } from "./icons.js";
|
|
8
|
+
var I = Object.getOwnPropertyDescriptor, B = (t, e, a, s) => {
|
|
9
|
+
for (var i = s > 1 ? void 0 : s ? I(e, a) : e, n = t.length - 1, r; n >= 0; n--)
|
|
10
10
|
(r = t[n]) && (i = r(i) || i);
|
|
11
11
|
return i;
|
|
12
12
|
};
|
|
13
|
-
let f,
|
|
14
|
-
function
|
|
15
|
-
return
|
|
13
|
+
let f, O;
|
|
14
|
+
function x() {
|
|
15
|
+
return O ?? (O = import("flatpickr").then((t) => f = t.default));
|
|
16
16
|
}
|
|
17
17
|
let m = class extends w {
|
|
18
18
|
constructor() {
|
|
@@ -25,20 +25,20 @@ let m = class extends w {
|
|
|
25
25
|
return t;
|
|
26
26
|
}
|
|
27
27
|
renderControl() {
|
|
28
|
-
return
|
|
28
|
+
return y`<span class="baht-datepicker-field">
|
|
29
29
|
<input
|
|
30
30
|
class="baht-control baht-control--date"
|
|
31
31
|
id=${this.controlId}
|
|
32
32
|
type="text"
|
|
33
33
|
autocomplete="off"
|
|
34
|
-
placeholder=${
|
|
34
|
+
placeholder=${D(this.field.placeholder)}
|
|
35
35
|
?disabled=${this.disabled}
|
|
36
36
|
?readonly=${this.readonly}
|
|
37
37
|
?required=${this.required}
|
|
38
38
|
aria-invalid=${this.invalid}
|
|
39
39
|
aria-describedby=${this.describedBy}
|
|
40
40
|
/>
|
|
41
|
-
<span class="baht-datepicker-field-icon" aria-hidden="true">${
|
|
41
|
+
<span class="baht-datepicker-field-icon" aria-hidden="true">${_("calendar")}</span>
|
|
42
42
|
</span>`;
|
|
43
43
|
}
|
|
44
44
|
connectedCallback() {
|
|
@@ -56,7 +56,7 @@ let m = class extends w {
|
|
|
56
56
|
}
|
|
57
57
|
if (((s = this.fp) == null ? void 0 : s.input) !== e || t.has("field") || t.has("disabled") || t.has("readonly")) {
|
|
58
58
|
if (this.teardown(), !f) {
|
|
59
|
-
this.pendingLoad ?? (this.pendingLoad =
|
|
59
|
+
this.pendingLoad ?? (this.pendingLoad = x().catch((i) => {
|
|
60
60
|
console.warn("[bahtui] <baht-datepicker> needs the `flatpickr` peer dependency", i);
|
|
61
61
|
}).then(() => {
|
|
62
62
|
this.pendingLoad = void 0, this.isConnected && this.requestUpdate();
|
|
@@ -119,7 +119,7 @@ let m = class extends w {
|
|
|
119
119
|
const e = document.createElement("div");
|
|
120
120
|
e.className = "baht-datepicker-footer";
|
|
121
121
|
const a = document.createElement("button");
|
|
122
|
-
a.type = "button", a.className = "baht-button baht-button--sm baht-datepicker-today", a.textContent = p("today"), a.addEventListener("click", () => {
|
|
122
|
+
a.type = "button", a.className = "baht-button baht-button--sm baht-datepicker-today", a.textContent = p(this.field.enable_time ? "now" : "today"), a.addEventListener("click", () => {
|
|
123
123
|
this.pickToday();
|
|
124
124
|
});
|
|
125
125
|
const s = document.createElement("button");
|
|
@@ -136,18 +136,18 @@ let m = class extends w {
|
|
|
136
136
|
}
|
|
137
137
|
todayAllowed() {
|
|
138
138
|
const t = o(/* @__PURE__ */ new Date()), e = l(this.field.min), a = l(this.field.max);
|
|
139
|
-
return e && t < o(e) || a && t > o(a) ? !1 : !(b(this.field) ?? []).some((s) =>
|
|
139
|
+
return e && t < o(e) || a && t > o(a) ? !1 : !(b(this.field) ?? []).some((s) => L(s, t));
|
|
140
140
|
}
|
|
141
141
|
pickToday() {
|
|
142
142
|
const t = this.fp;
|
|
143
143
|
if (!t || !this.todayAllowed()) return;
|
|
144
|
-
const e = o(/* @__PURE__ */ new Date());
|
|
144
|
+
const e = this.field.enable_time ? E(/* @__PURE__ */ new Date()) : o(/* @__PURE__ */ new Date());
|
|
145
145
|
switch (h(this.field)) {
|
|
146
146
|
case "range":
|
|
147
147
|
t.setDate([e, e], !0);
|
|
148
148
|
break;
|
|
149
149
|
case "multiple": {
|
|
150
|
-
t.selectedDates.some((s) =>
|
|
150
|
+
t.selectedDates.some((s) => this.sameInstants([s], [e])) || t.setDate([...t.selectedDates, e], !0);
|
|
151
151
|
break;
|
|
152
152
|
}
|
|
153
153
|
case "single":
|
|
@@ -164,8 +164,8 @@ let m = class extends w {
|
|
|
164
164
|
* a host may not always have a time to feed back (an edited record that
|
|
165
165
|
* predates this field, for one). */
|
|
166
166
|
datesOf(t) {
|
|
167
|
-
const e = (a) => (this.field.enable_time ?
|
|
168
|
-
return
|
|
167
|
+
const e = (a) => (this.field.enable_time ? C(a) : null) ?? l(a);
|
|
168
|
+
return k(t).map(e).filter((a) => a !== null);
|
|
169
169
|
}
|
|
170
170
|
/** flatpickr's selection -> the value shape of the field's mode. */
|
|
171
171
|
toValue(t) {
|
|
@@ -180,17 +180,20 @@ let m = class extends w {
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
};
|
|
183
|
-
m =
|
|
184
|
-
|
|
183
|
+
m = B([
|
|
184
|
+
g("baht-datepicker")
|
|
185
185
|
], m);
|
|
186
186
|
function o(t) {
|
|
187
187
|
return new Date(t.getFullYear(), t.getMonth(), t.getDate());
|
|
188
188
|
}
|
|
189
|
-
function
|
|
190
|
-
return
|
|
189
|
+
function E(t) {
|
|
190
|
+
return new Date(t.getFullYear(), t.getMonth(), t.getDate(), t.getHours(), t.getMinutes());
|
|
191
191
|
}
|
|
192
192
|
function F(t, e) {
|
|
193
|
-
|
|
193
|
+
return c(t) === c(e);
|
|
194
|
+
}
|
|
195
|
+
function L(t, e) {
|
|
196
|
+
if (t instanceof Date) return F(t, e);
|
|
194
197
|
if (typeof t == "function") return t(e);
|
|
195
198
|
if (typeof t == "object" && "from" in t) {
|
|
196
199
|
const a = o(new Date(t.from)), s = o(new Date(t.to));
|
|
@@ -201,7 +204,7 @@ function F(t, e) {
|
|
|
201
204
|
function b(t) {
|
|
202
205
|
const e = [];
|
|
203
206
|
for (const s of t.disabled_dates ?? []) {
|
|
204
|
-
const i =
|
|
207
|
+
const i = v(s);
|
|
205
208
|
i && e.push(i[0].getTime() === i[1].getTime() ? i[0] : { from: i[0], to: i[1] });
|
|
206
209
|
}
|
|
207
210
|
const a = t.disabled_weekdays;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { TemplateResult } from 'lit';
|
|
2
2
|
import { BahtElement } from '../base.js';
|
|
3
3
|
import { FieldOption } from '../../core/types.js';
|
|
4
|
+
export type FilterVariant = 'chips' | 'segmented';
|
|
4
5
|
/**
|
|
5
6
|
* Filter chip group. Controlled: emits `baht-change { selected }` (array of
|
|
6
7
|
* option keys), host re-feeds `selected`. Typical use: above an <baht-table>,
|
|
@@ -10,11 +11,21 @@ import { FieldOption } from '../../core/types.js';
|
|
|
10
11
|
* f.options = [{ key: 'running', label: 'Running' }, { key: 'failed', label: 'Failed' }];
|
|
11
12
|
* f.selected = ['running'];
|
|
12
13
|
* f.addEventListener('baht-change', (e) => refetch({ status: e.detail.selected }));
|
|
14
|
+
*
|
|
15
|
+
* `variant="segmented"` draws the same options as one joined segmented
|
|
16
|
+
* control (a single bordered group, active segment filled with the ink
|
|
17
|
+
* colour) — for a period switch like Week / Month / Year. Pair it with
|
|
18
|
+
* `multiple="false"`: a segmented control always holds one value, so clicking
|
|
19
|
+
* the active segment does nothing (no `baht-change`) instead of clearing it.
|
|
13
20
|
*/
|
|
14
21
|
export declare class BahtFilter extends BahtElement {
|
|
15
22
|
options: FieldOption[];
|
|
16
23
|
selected: string[];
|
|
17
|
-
/**
|
|
24
|
+
/** Look: `'chips'` (default) = separate pill chips; `'segmented'` = one joined
|
|
25
|
+
* segmented control. With `multiple=false` a segmented control never clears. */
|
|
26
|
+
variant: FilterVariant;
|
|
27
|
+
/** false = radio behavior (max one active; clicking it again clears — except
|
|
28
|
+
* with `variant="segmented"`, where the active segment stays selected). */
|
|
18
29
|
multiple: boolean;
|
|
19
30
|
disabled: boolean;
|
|
20
31
|
/** Accessible name for the chip group. */
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import { html as h } from "lit";
|
|
2
|
-
import { property as
|
|
3
|
-
import { boolOff as
|
|
4
|
-
var
|
|
5
|
-
for (var e =
|
|
6
|
-
(n =
|
|
7
|
-
return
|
|
2
|
+
import { property as o, customElement as d } from "lit/decorators.js";
|
|
3
|
+
import { boolOff as c, BahtElement as b } from "../base.js";
|
|
4
|
+
var m = Object.defineProperty, u = Object.getOwnPropertyDescriptor, l = (s, t, r, a) => {
|
|
5
|
+
for (var e = a > 1 ? void 0 : a ? u(t, r) : t, p = s.length - 1, n; p >= 0; p--)
|
|
6
|
+
(n = s[p]) && (e = (a ? n(t, r, e) : n(e)) || e);
|
|
7
|
+
return a && e && m(t, r, e), e;
|
|
8
8
|
};
|
|
9
|
-
let
|
|
9
|
+
let i = class extends b {
|
|
10
10
|
constructor() {
|
|
11
|
-
super(...arguments), this.options = [], this.selected = [], this.multiple = !0, this.disabled = !1, this.label = "Filters";
|
|
11
|
+
super(...arguments), this.options = [], this.selected = [], this.variant = "chips", this.multiple = !0, this.disabled = !1, this.label = "Filters";
|
|
12
12
|
}
|
|
13
|
-
toggle(
|
|
14
|
-
const
|
|
15
|
-
let
|
|
16
|
-
|
|
13
|
+
toggle(s) {
|
|
14
|
+
const t = this.selected.includes(s);
|
|
15
|
+
let r;
|
|
16
|
+
if (this.multiple)
|
|
17
|
+
r = t ? this.selected.filter((e) => e !== s) : [...this.selected, s], r = this.options.map((e) => e.key).filter((e) => r.includes(e));
|
|
18
|
+
else {
|
|
19
|
+
if (t && this.variant === "segmented") return;
|
|
20
|
+
r = t ? [] : [s];
|
|
21
|
+
}
|
|
22
|
+
this.emit("baht-change", { selected: r });
|
|
17
23
|
}
|
|
18
24
|
render() {
|
|
19
|
-
|
|
25
|
+
const s = this.variant === "segmented" ? " baht-filter--segmented" : "";
|
|
26
|
+
return h`<div class="baht-filter${s}" role="group" aria-label=${this.label}>
|
|
20
27
|
${this.options.map(
|
|
21
28
|
(t) => h`<button
|
|
22
29
|
type="button"
|
|
@@ -30,24 +37,27 @@ let r = class extends b {
|
|
|
30
37
|
</div>`;
|
|
31
38
|
}
|
|
32
39
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
],
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
],
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
],
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
],
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
],
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
],
|
|
40
|
+
l([
|
|
41
|
+
o({ attribute: !1 })
|
|
42
|
+
], i.prototype, "options", 2);
|
|
43
|
+
l([
|
|
44
|
+
o({ attribute: !1 })
|
|
45
|
+
], i.prototype, "selected", 2);
|
|
46
|
+
l([
|
|
47
|
+
o()
|
|
48
|
+
], i.prototype, "variant", 2);
|
|
49
|
+
l([
|
|
50
|
+
o({ converter: c })
|
|
51
|
+
], i.prototype, "multiple", 2);
|
|
52
|
+
l([
|
|
53
|
+
o({ type: Boolean })
|
|
54
|
+
], i.prototype, "disabled", 2);
|
|
55
|
+
l([
|
|
56
|
+
o()
|
|
57
|
+
], i.prototype, "label", 2);
|
|
58
|
+
i = l([
|
|
59
|
+
d("baht-filter")
|
|
60
|
+
], i);
|
|
51
61
|
export {
|
|
52
|
-
|
|
62
|
+
i as BahtFilter
|
|
53
63
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { TemplateResult } from 'lit';
|
|
2
2
|
import { BahtElement } from '../base.js';
|
|
3
|
+
/** Where the dialog panel sits. */
|
|
4
|
+
export type ModalPlacement = 'center' | 'sheet' | 'side';
|
|
3
5
|
/**
|
|
4
6
|
* Modal dialog (20baht: 0.4 ink scrim, no blur; float shadow; 20px radius).
|
|
5
7
|
* Controlled: the host flips `open`. Children become the body.
|
|
@@ -9,6 +11,15 @@ import { BahtElement } from '../base.js';
|
|
|
9
11
|
* </baht-modal>
|
|
10
12
|
* modal.open = true;
|
|
11
13
|
* modal.addEventListener('baht-close', (e) => (modal.open = false));
|
|
14
|
+
*
|
|
15
|
+
* `placement` moves the panel: `'center'` (default) is the dialog above;
|
|
16
|
+
* `'sheet'` docks it to the bottom as a bottom sheet below 600px viewport
|
|
17
|
+
* width (full width, rounded top corners, a grab handle, max 90dvh with the
|
|
18
|
+
* body scrolling, slides up) and is a centered dialog from 600px up; `'side'`
|
|
19
|
+
* is a full-height drawer at the inline end, `min(420px, 100vw)` wide, sliding
|
|
20
|
+
* in from that edge. Scrim, focus trap/restore and `baht-close` are the same in
|
|
21
|
+
* every placement. Modifier classes: `.baht-modal--sheet` / `.baht-modal--side`
|
|
22
|
+
* on the panel, `.baht-modal-scrim--sheet` / `.baht-modal-scrim--side` on the scrim.
|
|
12
23
|
*/
|
|
13
24
|
export declare class BahtModal extends BahtElement {
|
|
14
25
|
open: boolean;
|
|
@@ -16,6 +27,9 @@ export declare class BahtModal extends BahtElement {
|
|
|
16
27
|
/** One muted line under the heading; also becomes the dialog's aria-describedby. */
|
|
17
28
|
description: string;
|
|
18
29
|
showClose: boolean;
|
|
30
|
+
/** `'center'` (default) dialog, `'sheet'` bottom sheet below 600px (centered
|
|
31
|
+
* from 600px up), or `'side'` full-height drawer at the inline end. */
|
|
32
|
+
placement: ModalPlacement;
|
|
19
33
|
/**
|
|
20
34
|
* Scrim click requests close. Off by default: a stray click outside the panel
|
|
21
35
|
* must not throw away what the user typed — close via ×, Escape or your buttons.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { nothing as
|
|
2
|
-
import { property as c, query as
|
|
1
|
+
import { nothing as r, html as h } from "lit";
|
|
2
|
+
import { property as c, query as m, state as f, customElement as b } from "lit/decorators.js";
|
|
3
3
|
import { boolOff as y, BahtElement as v, hasDom as p, adoptLightChildren as u } from "../base.js";
|
|
4
4
|
import { afterExit as g } from "../motion.js";
|
|
5
5
|
import { t as $ } from "../../core/i18n.js";
|
|
6
6
|
import { renderIllustration as k } from "./illustrations.js";
|
|
7
|
-
var C = Object.defineProperty, S = Object.getOwnPropertyDescriptor,
|
|
8
|
-
for (var
|
|
9
|
-
(d = t[
|
|
10
|
-
return n &&
|
|
7
|
+
var C = Object.defineProperty, S = Object.getOwnPropertyDescriptor, l = (t, o, e, n) => {
|
|
8
|
+
for (var i = n > 1 ? void 0 : n ? S(o, e) : o, a = t.length - 1, d; a >= 0; a--)
|
|
9
|
+
(d = t[a]) && (i = (n ? d(o, e, i) : d(i)) || i);
|
|
10
|
+
return n && i && C(o, e, i), i;
|
|
11
11
|
};
|
|
12
12
|
const E = {
|
|
13
13
|
fromAttribute: (t) => t !== null && t !== "false",
|
|
@@ -15,7 +15,7 @@ const E = {
|
|
|
15
15
|
};
|
|
16
16
|
let s = class extends v {
|
|
17
17
|
constructor() {
|
|
18
|
-
super(...arguments), this.open = !1, this.heading = "", this.description = "", this.showClose = !0, this.closeOnScrim = !1, this.closing = !1, this.closeToken = 0, this.previousFocus = null, this.onKeydown = (t) => {
|
|
18
|
+
super(...arguments), this.open = !1, this.heading = "", this.description = "", this.showClose = !0, this.placement = "center", this.closeOnScrim = !1, this.closing = !1, this.closeToken = 0, this.previousFocus = null, this.onKeydown = (t) => {
|
|
19
19
|
!this.open || s.openStack.at(-1) !== this || (t.key === "Escape" ? this.requestClose("escape") : t.key === "Tab" && this.trapFocus(t));
|
|
20
20
|
};
|
|
21
21
|
}
|
|
@@ -35,17 +35,17 @@ let s = class extends v {
|
|
|
35
35
|
}
|
|
36
36
|
/** Keep Tab cycling inside the dialog (no keyboard escape to the page behind). */
|
|
37
37
|
trapFocus(t) {
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
38
|
+
const o = this.focusables(), e = this.querySelector(".baht-modal");
|
|
39
|
+
if (o.length === 0) {
|
|
40
40
|
e == null || e.focus(), t.preventDefault();
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
-
const n =
|
|
44
|
-
if (!this.contains(
|
|
43
|
+
const n = o[0], i = o[o.length - 1], a = document.activeElement;
|
|
44
|
+
if (!this.contains(a)) {
|
|
45
45
|
n.focus(), t.preventDefault();
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
-
t.shiftKey && (
|
|
48
|
+
t.shiftKey && (a === n || a === e) ? (i.focus(), t.preventDefault()) : !t.shiftKey && a === i && (n.focus(), t.preventDefault());
|
|
49
49
|
}
|
|
50
50
|
connectedCallback() {
|
|
51
51
|
super.connectedCallback(), p() && document.addEventListener("keydown", this.onKeydown);
|
|
@@ -66,14 +66,14 @@ let s = class extends v {
|
|
|
66
66
|
// already under `.baht-modal-body`) and keeps that content inside the body
|
|
67
67
|
// instead of leaking it to render outside the modal entirely.
|
|
68
68
|
updated(t) {
|
|
69
|
-
var
|
|
69
|
+
var o;
|
|
70
70
|
if (u(this, this.bodyEl), t.has("open") && (s.openStack = s.openStack.filter((e) => e !== this), this.open && s.openStack.push(this)), t.has("open") && !this.open && this.closing) {
|
|
71
|
-
const e = ++this.closeToken, n = this.querySelector(".baht-modal-scrim"),
|
|
71
|
+
const e = ++this.closeToken, n = this.querySelector(".baht-modal-scrim"), i = () => {
|
|
72
72
|
e === this.closeToken && !this.open && (this.closing = !1);
|
|
73
73
|
};
|
|
74
|
-
n ? g(n,
|
|
74
|
+
n ? g(n, i) : i();
|
|
75
75
|
}
|
|
76
|
-
if (t.has("open") && this.open && (this.previousFocus = document.activeElement, (
|
|
76
|
+
if (t.has("open") && this.open && (this.previousFocus = document.activeElement, (o = this.querySelector(".baht-modal")) == null || o.focus()), t.has("open") && !this.open && t.get("open") === !0) {
|
|
77
77
|
const e = this.previousFocus;
|
|
78
78
|
this.previousFocus = null, e != null && e.isConnected && (!document.activeElement || document.activeElement === document.body || this.contains(document.activeElement)) && e.focus();
|
|
79
79
|
}
|
|
@@ -83,59 +83,64 @@ let s = class extends v {
|
|
|
83
83
|
this.emit("baht-close", { reason: t });
|
|
84
84
|
}
|
|
85
85
|
render() {
|
|
86
|
+
const t = this.placement === "sheet" || this.placement === "side" ? this.placement : void 0;
|
|
86
87
|
return h`<div
|
|
87
|
-
class="baht-modal-scrim${this.closing ? " baht-modal-scrim--closing" : ""}"
|
|
88
|
-
style=${this.open || this.closing ?
|
|
89
|
-
@click=${(
|
|
90
|
-
this.closeOnScrim &&
|
|
88
|
+
class="baht-modal-scrim${t ? ` baht-modal-scrim--${t}` : ""}${this.closing ? " baht-modal-scrim--closing" : ""}"
|
|
89
|
+
style=${this.open || this.closing ? r : "display:none"}
|
|
90
|
+
@click=${(o) => {
|
|
91
|
+
this.closeOnScrim && o.target === o.currentTarget && this.requestClose("scrim");
|
|
91
92
|
}}
|
|
92
93
|
>
|
|
93
94
|
<div
|
|
94
|
-
class="baht-modal"
|
|
95
|
+
class="baht-modal${t ? ` baht-modal--${t}` : ""}"
|
|
95
96
|
role="dialog"
|
|
96
97
|
aria-modal="true"
|
|
97
|
-
aria-labelledby=${this.heading ? this.titleId :
|
|
98
|
-
aria-label=${this.heading ?
|
|
99
|
-
aria-describedby=${this.description ? this.descriptionId :
|
|
98
|
+
aria-labelledby=${this.heading ? this.titleId : r}
|
|
99
|
+
aria-label=${this.heading ? r : "Dialog"}
|
|
100
|
+
aria-describedby=${this.description ? this.descriptionId : r}
|
|
100
101
|
tabindex="-1"
|
|
101
102
|
>
|
|
103
|
+
${t === "sheet" ? h`<div class="baht-modal-handle" aria-hidden="true"></div>` : r}
|
|
102
104
|
${this.heading || this.description || this.showClose ? h`<header class="baht-modal-header">
|
|
103
105
|
<div class="baht-modal-heading">
|
|
104
106
|
<div class="baht-modal-title" id=${this.titleId}>${this.heading}</div>
|
|
105
|
-
${this.description ? h`<p class="baht-modal-description" id=${this.descriptionId}>${this.description}</p>` :
|
|
107
|
+
${this.description ? h`<p class="baht-modal-description" id=${this.descriptionId}>${this.description}</p>` : r}
|
|
106
108
|
</div>
|
|
107
109
|
${this.showClose ? h`<button type="button" class="baht-modal-close" aria-label=${$("close")} @click=${() => {
|
|
108
110
|
this.requestClose("button");
|
|
109
|
-
}}>${k("cross-box")}</button>` :
|
|
110
|
-
</header>` :
|
|
111
|
+
}}>${k("cross-box")}</button>` : r}
|
|
112
|
+
</header>` : r}
|
|
111
113
|
<div class="baht-modal-body"></div>
|
|
112
114
|
</div>
|
|
113
115
|
</div>`;
|
|
114
116
|
}
|
|
115
117
|
};
|
|
116
118
|
s.openStack = [];
|
|
117
|
-
|
|
119
|
+
l([
|
|
118
120
|
c({ type: Boolean, reflect: !0 })
|
|
119
121
|
], s.prototype, "open", 2);
|
|
120
|
-
|
|
122
|
+
l([
|
|
121
123
|
c()
|
|
122
124
|
], s.prototype, "heading", 2);
|
|
123
|
-
|
|
125
|
+
l([
|
|
124
126
|
c()
|
|
125
127
|
], s.prototype, "description", 2);
|
|
126
|
-
|
|
128
|
+
l([
|
|
127
129
|
c({ attribute: "show-close", converter: y })
|
|
128
130
|
], s.prototype, "showClose", 2);
|
|
129
|
-
|
|
131
|
+
l([
|
|
132
|
+
c()
|
|
133
|
+
], s.prototype, "placement", 2);
|
|
134
|
+
l([
|
|
130
135
|
c({ attribute: "close-on-scrim", converter: E })
|
|
131
136
|
], s.prototype, "closeOnScrim", 2);
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
l([
|
|
138
|
+
m(".baht-modal-body")
|
|
134
139
|
], s.prototype, "bodyEl", 2);
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
l([
|
|
141
|
+
f()
|
|
137
142
|
], s.prototype, "closing", 2);
|
|
138
|
-
s =
|
|
143
|
+
s = l([
|
|
139
144
|
b("baht-modal")
|
|
140
145
|
], s);
|
|
141
146
|
export {
|
|
@@ -13,6 +13,10 @@ import { BahtFieldBase } from '../field-base.js';
|
|
|
13
13
|
* and moves on, typing jumps to the first option starting with those letters
|
|
14
14
|
* (while closed it picks it directly, like a native select).
|
|
15
15
|
*
|
|
16
|
+
* An option's `description` renders as a muted second line under its label in
|
|
17
|
+
* the list, and after the label on the closed trigger while it is selected
|
|
18
|
+
* (e.g. label "Food", description "฿580 left").
|
|
19
|
+
*
|
|
16
20
|
* Value contract unchanged: option `key`, or `null` for the placeholder row.
|
|
17
21
|
*/
|
|
18
22
|
export declare class BahtSelect extends BahtFieldBase {
|