@jirawatpyk/aura-react 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,302 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { cx, uid, useMaybeControlled, useMounted, useIsoLayoutEffect, useMergedRef } from "./internal.js";
5
+ import { useStrings } from "./locale.js";
6
+ import { Icon } from "./Icon.js";
7
+ import { Field } from "./forms.js";
8
+ const h = React.createElement;
9
+ function pad(n) {
10
+ return (n < 10 ? "0" : "") + n;
11
+ }
12
+ function toMin(t) {
13
+ var m = /^(\d{2}):(\d{2})$/.exec(t || "");
14
+ return m ? +m[1] * 60 + +m[2] : null;
15
+ }
16
+ function fromMin(n) {
17
+ return pad(Math.floor(n / 60)) + ":" + pad(n % 60);
18
+ }
19
+ function parseTime(text) {
20
+ var s = String(text || "").trim().toLowerCase().replace(/\s*(น\.?|นาฬิกา)$/, "").trim();
21
+ var pm = /\s*(pm|p\.m\.)$/.test(s), am = /\s*(am|a\.m\.)$/.test(s);
22
+ s = s.replace(/\s*(am|pm|a\.m\.|p\.m\.)$/, "");
23
+ var m = /^(\d{1,2})(?:[:.](\d{2}))?$/.exec(s) || /^(\d{1,2})(\d{2})$/.exec(s);
24
+ if (!m) return null;
25
+ var hh = +m[1], mm = m[2] ? +m[2] : 0;
26
+ if (pm && hh < 12) hh += 12;
27
+ if (am && hh === 12) hh = 0;
28
+ if (hh > 23 || mm > 59) return null;
29
+ return pad(hh) + ":" + pad(mm);
30
+ }
31
+ const TimePicker = React.forwardRef(function TimePicker2(props, ref) {
32
+ var t = useStrings();
33
+ var auto = uid(), id = props.id || auto, listId = id + "-list";
34
+ var st = useMaybeControlled(props.value, props.defaultValue == null ? null : props.defaultValue, props.onChange);
35
+ var value = st[0];
36
+ var step = props.step || 30, lo = toMin(props.min) != null ? toMin(props.min) : 0, hi = toMin(props.max) != null ? toMin(props.max) : 24 * 60 - 1;
37
+ var slots = React.useMemo(function() {
38
+ var out = [];
39
+ for (var m = lo; m <= hi; m += step) out.push(fromMin(m));
40
+ return out;
41
+ }, [lo, hi, step]);
42
+ function blocked(v) {
43
+ var n = toMin(v);
44
+ return n == null || n < lo || n > hi || props.isTimeDisabled && props.isTimeDisabled(v);
45
+ }
46
+ var openState = React.useState(false), open = openState[0], setOpen = openState[1];
47
+ var editState = React.useState(null), editing = editState[0], setEditing = editState[1];
48
+ var aState = React.useState(0), active = aState[0], setActive = aState[1];
49
+ var errState = React.useState(null);
50
+ var pos = React.useState(null);
51
+ var boxRef = React.useRef(null), inputRef = React.useRef(null), listRef = React.useRef(null), inputMerged = useMergedRef(ref, inputRef);
52
+ var mounted = useMounted();
53
+ function nearest(v) {
54
+ var n = toMin(v);
55
+ if (n == null) return 0;
56
+ var best = 0;
57
+ slots.forEach(function(s, i) {
58
+ if (Math.abs(toMin(s) - n) < Math.abs(toMin(slots[best]) - n)) best = i;
59
+ });
60
+ return best;
61
+ }
62
+ function place() {
63
+ if (!boxRef.current) return;
64
+ var r = boxRef.current.getBoundingClientRect(), below = window.innerHeight - r.bottom - 8, up = below < 200 && r.top > below;
65
+ pos[1]({ left: r.left, width: Math.max(r.width, 160), top: up ? void 0 : r.bottom + 4, bottom: up ? window.innerHeight - r.top + 4 : void 0, maxHeight: Math.min(280, (up ? r.top : below) - 8) });
66
+ }
67
+ useIsoLayoutEffect(function() {
68
+ if (open) place();
69
+ }, [open]);
70
+ React.useEffect(function() {
71
+ if (!open) return;
72
+ function outside(e) {
73
+ if (boxRef.current && boxRef.current.contains(e.target) || listRef.current && listRef.current.contains(e.target)) return;
74
+ setOpen(false);
75
+ }
76
+ function onScroll(e) {
77
+ if (!listRef.current || !listRef.current.contains(e.target)) place();
78
+ }
79
+ document.addEventListener("pointerdown", outside, true);
80
+ window.addEventListener("scroll", onScroll, true);
81
+ window.addEventListener("resize", place);
82
+ return function() {
83
+ document.removeEventListener("pointerdown", outside, true);
84
+ window.removeEventListener("scroll", onScroll, true);
85
+ window.removeEventListener("resize", place);
86
+ };
87
+ }, [open]);
88
+ React.useEffect(function() {
89
+ if (!open || !listRef.current) return;
90
+ var el = listRef.current.querySelector('[data-idx="' + active + '"]');
91
+ if (el && el.scrollIntoView) el.scrollIntoView({ block: "nearest" });
92
+ }, [active, open]);
93
+ function show() {
94
+ if (open || props.disabled || props.readOnly) return;
95
+ setActive(nearest(value || props.suggest || fromMin(lo)));
96
+ setOpen(true);
97
+ }
98
+ function commit(v) {
99
+ if (v == null) {
100
+ errState[1](null);
101
+ st[1](null);
102
+ return true;
103
+ }
104
+ if (blocked(v)) {
105
+ errState[1](t.timeOutOfRange(fromMin(lo), fromMin(hi)));
106
+ return false;
107
+ }
108
+ errState[1](null);
109
+ st[1](v);
110
+ return true;
111
+ }
112
+ function choose(i) {
113
+ var v = slots[i];
114
+ if (!v || blocked(v)) return;
115
+ commit(v);
116
+ setEditing(null);
117
+ setOpen(false);
118
+ if (inputRef.current) inputRef.current.focus();
119
+ }
120
+ function commitTyped() {
121
+ if (editing == null) return;
122
+ var txt = editing.trim();
123
+ if (!txt) commit(null);
124
+ else {
125
+ var v = parseTime(txt);
126
+ if (v) commit(v);
127
+ else errState[1](t.timeInvalid);
128
+ }
129
+ setEditing(null);
130
+ }
131
+ function move(d) {
132
+ var i = active;
133
+ for (var k = 0; k < slots.length; k++) {
134
+ i = Math.min(slots.length - 1, Math.max(0, i + d));
135
+ if (!blocked(slots[i])) break;
136
+ }
137
+ setActive(i);
138
+ }
139
+ function onKeyDown(e) {
140
+ var k = e.key;
141
+ if (k === "ArrowDown") {
142
+ e.preventDefault();
143
+ if (!open) show();
144
+ else move(1);
145
+ } else if (k === "ArrowUp") {
146
+ e.preventDefault();
147
+ if (!open) show();
148
+ else move(-1);
149
+ } else if (k === "Home" && open) {
150
+ e.preventDefault();
151
+ setActive(0);
152
+ } else if (k === "End" && open) {
153
+ e.preventDefault();
154
+ setActive(slots.length - 1);
155
+ } else if (k === "PageDown" && open) {
156
+ e.preventDefault();
157
+ move(Math.max(1, Math.round(60 / step)));
158
+ } else if (k === "PageUp" && open) {
159
+ e.preventDefault();
160
+ move(-Math.max(1, Math.round(60 / step)));
161
+ } else if (k === "Enter") {
162
+ if (editing != null) {
163
+ e.preventDefault();
164
+ commitTyped();
165
+ setOpen(false);
166
+ } else if (open) {
167
+ e.preventDefault();
168
+ choose(active);
169
+ }
170
+ } else if (k === "Escape") {
171
+ if (open) {
172
+ e.preventDefault();
173
+ e.stopPropagation();
174
+ setOpen(false);
175
+ setEditing(null);
176
+ }
177
+ } else if (k === "Tab") {
178
+ if (open) setOpen(false);
179
+ }
180
+ }
181
+ var error = errState[0] || props.error;
182
+ var list = open && mounted && pos[0] ? createPortal(
183
+ h(
184
+ "div",
185
+ { ref: listRef, className: "aura-combo__popover aura-time__popover", style: pos[0] },
186
+ h(
187
+ "ul",
188
+ { id: listId, role: "listbox", "aria-label": props.label, className: "aura-combo__list" },
189
+ slots.map(function(s, i) {
190
+ var dis = blocked(s), sel = s === value;
191
+ return h(
192
+ "li",
193
+ {
194
+ key: s,
195
+ id: id + "-opt-" + i,
196
+ role: "option",
197
+ "data-idx": i,
198
+ "aria-selected": sel,
199
+ "aria-disabled": dis || void 0,
200
+ className: cx("aura-combo__option aura-time__option", i === active && "is-active", sel && "is-selected", dis && "is-disabled"),
201
+ onPointerDown: function(e) {
202
+ e.preventDefault();
203
+ },
204
+ onClick: function() {
205
+ choose(i);
206
+ },
207
+ onPointerMove: function() {
208
+ if (active !== i) setActive(i);
209
+ }
210
+ },
211
+ h("span", { className: "aura-combo__label" }, s),
212
+ sel ? h(Icon, { name: "check", className: "aura-combo__check" }) : null
213
+ );
214
+ })
215
+ )
216
+ ),
217
+ document.body
218
+ ) : null;
219
+ return h(
220
+ Field,
221
+ { id, label: props.label, hint: props.hint, error, required: props.required, optional: props.optional, disabled: props.disabled, className: props.className },
222
+ h(
223
+ "div",
224
+ { ref: boxRef, className: cx("aura-input aura-combo aura-time has-icon", open && "is-open") },
225
+ h(Icon, { name: "clock", className: "aura-input__icon" }),
226
+ h("input", {
227
+ ref: inputMerged,
228
+ id,
229
+ type: "text",
230
+ role: "combobox",
231
+ inputMode: "numeric",
232
+ autoComplete: "off",
233
+ className: "aura-input__control",
234
+ "aria-expanded": open,
235
+ "aria-controls": listId,
236
+ "aria-autocomplete": "none",
237
+ "aria-activedescendant": open && editing == null ? id + "-opt-" + active : void 0,
238
+ "aria-invalid": error ? true : void 0,
239
+ "aria-describedby": error ? id + "-error" : props.hint ? id + "-hint" : void 0,
240
+ placeholder: props.placeholder || t.timePlaceholder,
241
+ disabled: props.disabled,
242
+ readOnly: props.readOnly,
243
+ required: props.required,
244
+ name: props.name,
245
+ value: editing != null ? editing : value || "",
246
+ onChange: function(e) {
247
+ setEditing(e.target.value);
248
+ var v = parseTime(e.target.value);
249
+ if (v) {
250
+ if (!open) show();
251
+ setActive(nearest(v));
252
+ }
253
+ },
254
+ onClick: show,
255
+ onKeyDown,
256
+ onBlur: function() {
257
+ setTimeout(function() {
258
+ if (listRef.current && listRef.current.contains(document.activeElement)) return;
259
+ commitTyped();
260
+ setOpen(false);
261
+ }, 0);
262
+ }
263
+ }),
264
+ props.clearable !== false && value != null && !props.disabled ? h("button", {
265
+ type: "button",
266
+ className: "aura-combo__clear",
267
+ "aria-label": t.clear(props.label),
268
+ tabIndex: -1,
269
+ onClick: function() {
270
+ commit(null);
271
+ setEditing(null);
272
+ if (inputRef.current) inputRef.current.focus();
273
+ }
274
+ }, h(Icon, { name: "x" })) : null,
275
+ h(
276
+ "button",
277
+ {
278
+ type: "button",
279
+ tabIndex: -1,
280
+ "aria-hidden": true,
281
+ className: "aura-combo__toggle",
282
+ onPointerDown: function(e) {
283
+ e.preventDefault();
284
+ },
285
+ onClick: function() {
286
+ if (open) setOpen(false);
287
+ else {
288
+ show();
289
+ inputRef.current && inputRef.current.focus();
290
+ }
291
+ }
292
+ },
293
+ h(Icon, { name: "chevron-down" })
294
+ )
295
+ ),
296
+ list
297
+ );
298
+ });
299
+ export {
300
+ TimePicker,
301
+ parseTime
302
+ };
@@ -0,0 +1,328 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { cx, omit, uid, useMaybeControlled, useMergedRef, useMounted, useIsoLayoutEffect, trapTab, FOCUSABLE } from "./internal.js";
5
+ import { useStrings } from "./locale.js";
6
+ import { Icon } from "./Icon.js";
7
+ import { IconButton } from "./IconButton.js";
8
+ const h = React.createElement;
9
+ var TONES = ["neutral", "accent", "success", "warning", "danger"];
10
+ function tone(t) {
11
+ return TONES.indexOf(t) >= 0 ? t : "neutral";
12
+ }
13
+ const Badge = React.forwardRef(function Badge2(props, ref) {
14
+ var rest = omit(props, ["tone", "variant", "icon", "className", "children"]);
15
+ return h(
16
+ "span",
17
+ Object.assign({}, rest, { ref, className: cx("aura-badge", "aura-badge--" + tone(props.tone), props.variant === "solid" && "is-solid", props.variant === "outline" && "is-outline", props.className) }),
18
+ props.icon ? h(Icon, { name: props.icon, size: 12 }) : null,
19
+ props.children
20
+ );
21
+ });
22
+ const Tag = React.forwardRef(function Tag2(props, ref) {
23
+ var t = useStrings();
24
+ var selectable = props.onClick != null || props.selected != null;
25
+ var rest = omit(props, ["onRemove", "selected", "icon", "className", "children", "disabled", "removeLabel"]);
26
+ var inner = [props.icon ? h(Icon, { key: "i", name: props.icon, size: 14 }) : null, h("span", { key: "t", className: "aura-tag__text" }, props.children)];
27
+ if (selectable) {
28
+ return h(
29
+ "button",
30
+ Object.assign({}, rest, {
31
+ ref,
32
+ type: "button",
33
+ "aria-pressed": !!props.selected,
34
+ disabled: props.disabled,
35
+ className: cx("aura-tag is-selectable", props.selected && "is-selected", props.className)
36
+ }),
37
+ props.selected ? h(Icon, { name: "check", size: 14 }) : inner[0],
38
+ inner[1]
39
+ );
40
+ }
41
+ return h(
42
+ "span",
43
+ Object.assign({}, rest, { ref, className: cx("aura-tag", props.disabled && "is-disabled", props.className) }),
44
+ inner,
45
+ props.onRemove && !props.disabled ? h(
46
+ "button",
47
+ { type: "button", className: "aura-tag__remove", "aria-label": props.removeLabel || t.remove(typeof props.children === "string" ? props.children : ""), onClick: props.onRemove },
48
+ h(Icon, { name: "x", size: 12 })
49
+ ) : null
50
+ );
51
+ });
52
+ const Progress = React.forwardRef(function Progress2(props, ref) {
53
+ var auto = uid(), id = props.id || auto;
54
+ var max = props.max || 100, det = props.value != null;
55
+ var pct = det ? Math.max(0, Math.min(100, props.value / max * 100)) : 0;
56
+ var shown = props.valueLabel != null ? props.valueLabel : det ? Math.round(pct) + "%" : null;
57
+ return h(
58
+ "div",
59
+ { ref, className: cx("aura-progress", "aura-progress--" + tone(props.tone || "accent"), props.size === "sm" && "is-sm", props.className) },
60
+ props.label || props.showValue && shown ? h(
61
+ "div",
62
+ { className: "aura-progress__head" },
63
+ props.label ? h("span", { className: "aura-progress__label", id: id + "-label" }, props.label) : h("span"),
64
+ props.showValue && shown ? h("span", { className: "aura-progress__value" }, shown) : null
65
+ ) : null,
66
+ h(
67
+ "div",
68
+ {
69
+ className: cx("aura-progress__track", !det && "is-indeterminate"),
70
+ role: "progressbar",
71
+ "aria-labelledby": props.label ? id + "-label" : void 0,
72
+ "aria-label": props.label ? void 0 : props["aria-label"],
73
+ "aria-valuemin": det ? 0 : void 0,
74
+ "aria-valuemax": det ? max : void 0,
75
+ "aria-valuenow": det ? props.value : void 0,
76
+ "aria-valuetext": det && props.valueLabel != null ? String(props.valueLabel) : void 0
77
+ },
78
+ h("span", { className: "aura-progress__bar", style: det ? { width: pct + "%" } : void 0 })
79
+ ),
80
+ props.hint ? h("p", { className: "aura-progress__hint" }, props.hint) : null
81
+ );
82
+ });
83
+ const Skeleton = React.forwardRef(function Skeleton2(props, ref) {
84
+ var v = props.variant || "text";
85
+ if (v === "text" && (props.lines || 1) > 1) {
86
+ var n = props.lines, rows = [];
87
+ for (var i = 0; i < n; i++) rows.push(h("span", { key: i, className: "aura-skel aura-skel--text", style: { width: i === n - 1 ? "60%" : "100%" } }));
88
+ return h("span", { ref, className: cx("aura-skel-lines", props.className), "aria-hidden": true, style: props.width ? { width: props.width } : void 0 }, rows);
89
+ }
90
+ var style = { width: props.width, height: props.height };
91
+ if (v === "circle") {
92
+ style.width = style.height = props.size || props.width || 40;
93
+ }
94
+ return h("span", { ref, "aria-hidden": true, className: cx("aura-skel", "aura-skel--" + v, props.className), style });
95
+ });
96
+ const EmptyState = React.forwardRef(function EmptyState2(props, ref) {
97
+ var HT = "h" + (props.headingLevel || 3);
98
+ return h(
99
+ "div",
100
+ { ref, className: cx("aura-empty", props.size === "sm" && "is-sm", props.bordered && "is-bordered", props.className) },
101
+ h("span", { className: "aura-empty__icon", "aria-hidden": true }, h(Icon, { name: props.icon || "inbox", size: props.size === "sm" ? "md" : "lg" })),
102
+ h(HT, { className: "aura-empty__title" }, props.title),
103
+ props.description ? h("p", { className: "aura-empty__text" }, props.description) : null,
104
+ props.action ? h("div", { className: "aura-empty__action" }, props.action) : null
105
+ );
106
+ });
107
+ function pageList(page, count, sib) {
108
+ var out = [], lo = Math.max(2, page - sib), hi = Math.min(count - 1, page + sib);
109
+ if (page - sib <= 3) {
110
+ lo = 2;
111
+ hi = Math.min(count - 1, Math.max(hi, 3 + 2 * sib));
112
+ }
113
+ if (page + sib >= count - 2) {
114
+ hi = count - 1;
115
+ lo = Math.max(2, Math.min(lo, count - 2 - 2 * sib));
116
+ }
117
+ out.push(1);
118
+ if (lo === 3) out.push(2);
119
+ else if (lo > 3) out.push("\u2026a");
120
+ for (var i = lo; i <= hi; i++) out.push(i);
121
+ if (hi === count - 2) out.push(count - 1);
122
+ else if (hi < count - 2) out.push("\u2026b");
123
+ if (count > 1) out.push(count);
124
+ return out;
125
+ }
126
+ const Pagination = React.forwardRef(function Pagination2(props, ref) {
127
+ var t = useStrings();
128
+ var count = Math.max(1, props.pageCount || 1);
129
+ var st = useMaybeControlled(props.page, props.defaultPage || 1, props.onChange);
130
+ var page = Math.min(count, Math.max(1, st[0]));
131
+ function go(p) {
132
+ if (p >= 1 && p <= count && p !== page) st[1](p);
133
+ }
134
+ var link = props.getHref;
135
+ function item(p, label, extra) {
136
+ var common = Object.assign({ className: cx("aura-page", p === page && "is-current"), "aria-current": p === page ? "page" : void 0, "aria-label": t.pageN(p) }, extra);
137
+ return link ? h("a", Object.assign({ href: link(p), onClick: function(e) {
138
+ if (props.onChange) {
139
+ e.preventDefault();
140
+ go(p);
141
+ }
142
+ } }, common), label) : h("button", Object.assign({ type: "button", onClick: function() {
143
+ go(p);
144
+ } }, common), label);
145
+ }
146
+ return h(
147
+ "nav",
148
+ { ref, className: cx("aura-pagination", props.className), "aria-label": props.label || t.pagination },
149
+ h(IconButton, { icon: "chevron-left", label: t.prevPage, disabled: page <= 1, onClick: function() {
150
+ go(page - 1);
151
+ } }),
152
+ h("ol", { className: "aura-pagination__list" }, pageList(page, count, props.siblingCount == null ? 1 : props.siblingCount).map(function(p) {
153
+ return typeof p === "number" ? h("li", { key: p }, item(p, p)) : h("li", { key: p, className: "aura-pagination__gap", "aria-hidden": true }, "\u2026");
154
+ })),
155
+ h("span", { className: "aura-pagination__compact", "aria-hidden": true }, t.page(page, count)),
156
+ h(IconButton, { icon: "chevron-right", label: t.nextPage, disabled: page >= count, onClick: function() {
157
+ go(page + 1);
158
+ } })
159
+ );
160
+ });
161
+ const Accordion = React.forwardRef(function Accordion2(props, ref) {
162
+ var auto = uid(), base = props.id || auto;
163
+ var multiple = props.type === "multiple";
164
+ var st = useMaybeControlled(props.value, props.defaultValue != null ? props.defaultValue : multiple ? [] : null, props.onChange);
165
+ var open = multiple ? st[0] || [] : st[0] ? [st[0]] : [];
166
+ var HT = "h" + (props.headingLevel || 3);
167
+ var items = props.items || [];
168
+ function toggle(id) {
169
+ var isOpen = open.indexOf(id) >= 0;
170
+ if (multiple) st[1](isOpen ? open.filter(function(x) {
171
+ return x !== id;
172
+ }) : open.concat([id]));
173
+ else st[1](isOpen ? props.collapsible === false ? id : null : id);
174
+ }
175
+ function onKey(e) {
176
+ var btns = Array.prototype.slice.call(e.currentTarget.querySelectorAll(":scope > .aura-accordion__item > .aura-accordion__heading > button:not([disabled])"));
177
+ var i = btns.indexOf(document.activeElement), k = e.key, n = null;
178
+ if (i < 0) return;
179
+ if (k === "ArrowDown") n = btns[(i + 1) % btns.length];
180
+ else if (k === "ArrowUp") n = btns[(i - 1 + btns.length) % btns.length];
181
+ else if (k === "Home") n = btns[0];
182
+ else if (k === "End") n = btns[btns.length - 1];
183
+ if (n) {
184
+ e.preventDefault();
185
+ n.focus();
186
+ }
187
+ }
188
+ return h(
189
+ "div",
190
+ { ref, className: cx("aura-accordion", props.className), onKeyDown: onKey },
191
+ items.map(function(it) {
192
+ var on = open.indexOf(it.id) >= 0, bid = base + "-btn-" + it.id, pid = base + "-panel-" + it.id;
193
+ return h(
194
+ "div",
195
+ { key: it.id, className: cx("aura-accordion__item", on && "is-open") },
196
+ h(
197
+ HT,
198
+ { className: "aura-accordion__heading" },
199
+ h(
200
+ "button",
201
+ { type: "button", id: bid, "aria-expanded": on, "aria-controls": pid, disabled: it.disabled, onClick: function() {
202
+ toggle(it.id);
203
+ } },
204
+ it.icon ? h(Icon, { name: it.icon, className: "aura-accordion__lead" }) : null,
205
+ h(
206
+ "span",
207
+ { className: "aura-accordion__title" },
208
+ it.title,
209
+ it.description ? h("span", { className: "aura-accordion__desc" }, it.description) : null
210
+ ),
211
+ h(Icon, { name: "chevron-down", className: "aura-accordion__chevron" })
212
+ )
213
+ ),
214
+ h("div", { id: pid, role: "region", "aria-labelledby": bid, className: "aura-accordion__panel", hidden: !on }, it.content)
215
+ );
216
+ })
217
+ );
218
+ });
219
+ function position(anchor, pop, placement) {
220
+ var r = anchor.getBoundingClientRect(), pw = pop.offsetWidth, ph = pop.offsetHeight, vw = window.innerWidth, vh = window.innerHeight, gap = 6;
221
+ var side = (placement || "bottom-start").split("-")[0], align = (placement || "bottom-start").split("-")[1] || "start";
222
+ if (side === "bottom" && r.bottom + gap + ph > vh - 8 && r.top - gap - ph > 8) side = "top";
223
+ else if (side === "top" && r.top - gap - ph < 8 && r.bottom + gap + ph < vh - 8) side = "bottom";
224
+ var top = side === "top" ? r.top - gap - ph : r.bottom + gap;
225
+ var left = align === "end" ? r.right - pw : align === "center" ? r.left + r.width / 2 - pw / 2 : r.left;
226
+ return { top: Math.max(8, top), left: Math.max(8, Math.min(left, vw - pw - 8)), side };
227
+ }
228
+ const Popover = React.forwardRef(function Popover2(props, ref) {
229
+ var t = useStrings();
230
+ var auto = uid(), id = props.id || auto;
231
+ var st = useMaybeControlled(props.open, !!props.defaultOpen, props.onOpenChange);
232
+ var open = !!st[0];
233
+ var wrap = React.useRef(null), pop = React.useRef(null), popMerged = useMergedRef(ref, pop);
234
+ var pos = React.useState(null), mounted = useMounted();
235
+ function trigger() {
236
+ return wrap.current && (wrap.current.querySelector('button, [role="button"], a, input') || wrap.current.firstElementChild);
237
+ }
238
+ function close(restore) {
239
+ st[1](false);
240
+ if (restore) {
241
+ var tr = trigger();
242
+ if (tr && tr.focus) tr.focus();
243
+ }
244
+ }
245
+ useIsoLayoutEffect(function() {
246
+ if (!open || !pop.current || !trigger()) return;
247
+ function place() {
248
+ if (pop.current && trigger()) pos[1](position(trigger(), pop.current, props.placement));
249
+ }
250
+ place();
251
+ window.addEventListener("resize", place);
252
+ window.addEventListener("scroll", place, true);
253
+ return function() {
254
+ window.removeEventListener("resize", place);
255
+ window.removeEventListener("scroll", place, true);
256
+ };
257
+ }, [open, mounted, props.placement]);
258
+ React.useEffect(function() {
259
+ if (!open || !mounted) return;
260
+ if (props.autoFocus !== false && pop.current) {
261
+ var f = pop.current.querySelector("[data-autofocus]") || pop.current.querySelector(FOCUSABLE);
262
+ (f || pop.current).focus();
263
+ }
264
+ function outside(e) {
265
+ if (pop.current && pop.current.contains(e.target)) return;
266
+ if (wrap.current && wrap.current.contains(e.target)) return;
267
+ close(false);
268
+ }
269
+ document.addEventListener("pointerdown", outside, true);
270
+ return function() {
271
+ document.removeEventListener("pointerdown", outside, true);
272
+ };
273
+ }, [open, mounted]);
274
+ var child = React.Children.only(props.trigger);
275
+ var panel = open && mounted ? createPortal(
276
+ h(
277
+ "div",
278
+ {
279
+ ref: popMerged,
280
+ id,
281
+ role: "dialog",
282
+ "aria-modal": false,
283
+ "aria-label": props.title ? void 0 : props.label,
284
+ "aria-labelledby": props.title ? id + "-title" : void 0,
285
+ tabIndex: -1,
286
+ className: cx("aura-popover", pos[0] && "is-" + pos[0].side, props.className),
287
+ style: Object.assign({ top: pos[0] ? pos[0].top : -9999, left: pos[0] ? pos[0].left : -9999 }, props.width ? { width: props.width } : null),
288
+ onKeyDown: function(e) {
289
+ if (e.key === "Escape") {
290
+ e.stopPropagation();
291
+ close(true);
292
+ } else trapTab(e, pop.current);
293
+ }
294
+ },
295
+ props.title ? h(
296
+ "div",
297
+ { className: "aura-popover__head" },
298
+ h("p", { className: "aura-popover__title", id: id + "-title" }, props.title),
299
+ h(IconButton, { icon: "x", label: t.close, onClick: function() {
300
+ close(true);
301
+ } })
302
+ ) : null,
303
+ h("div", { className: "aura-popover__body" }, typeof props.children === "function" ? props.children({ close: function() {
304
+ close(true);
305
+ } }) : props.children)
306
+ ),
307
+ document.body
308
+ ) : null;
309
+ return h(
310
+ "span",
311
+ { ref: wrap, className: "aura-popover-anchor" },
312
+ React.cloneElement(child, { onClick: function(e) {
313
+ if (child.props.onClick) child.props.onClick(e);
314
+ st[1](!open);
315
+ }, "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? id : void 0 }),
316
+ panel
317
+ );
318
+ });
319
+ export {
320
+ Accordion,
321
+ Badge,
322
+ EmptyState,
323
+ Pagination,
324
+ Popover,
325
+ Progress,
326
+ Skeleton,
327
+ Tag
328
+ };