@jirawatpyk/aura-react 4.17.0 → 4.19.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.
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { Button } from "./Button.js";
4
+ import { cx } from "./internal.js";
5
+ import { useStrings } from "./locale.js";
6
+ const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
7
+ const t = useStrings();
8
+ const bulk = props.selected != null;
9
+ const idle = bulk && !props.selected;
10
+ const count = bulk && props.selected ? t.selectedCount(props.selected) : null;
11
+ const cameFrom = React.useRef(null);
12
+ const own = React.useRef(null);
13
+ function clear() {
14
+ props.onClearSelection();
15
+ setTimeout(function() {
16
+ const back = cameFrom.current;
17
+ const a = document.activeElement;
18
+ if ((!a || a === document.body || !a.isConnected) && back && back.isConnected) back.focus();
19
+ }, 0);
20
+ }
21
+ return /* @__PURE__ */ React.createElement(
22
+ "div",
23
+ {
24
+ ref: function(el) {
25
+ own.current = el;
26
+ if (typeof ref === "function") ref(el);
27
+ else if (ref) ref.current = el;
28
+ },
29
+ onFocus: function(e) {
30
+ const from = e.relatedTarget;
31
+ if (from && own.current && !own.current.contains(from)) cameFrom.current = from;
32
+ },
33
+ role: "region",
34
+ "aria-label": props.label || t.actions,
35
+ className: cx(
36
+ "aura-actionbar",
37
+ "aura-actionbar--" + (props.position || "viewport"),
38
+ idle && "is-idle",
39
+ props.className
40
+ )
41
+ },
42
+ /* @__PURE__ */ React.createElement("div", { className: "aura-actionbar__inner" }, /* @__PURE__ */ React.createElement("div", { className: "aura-actionbar__status", role: "status" }, count, count && props.status ? " \xB7 " : null, props.status), !idle ? /* @__PURE__ */ React.createElement("div", { className: "aura-actionbar__actions" }, count && props.onClearSelection ? /* @__PURE__ */ React.createElement(Button, { variant: "ghost", size: "sm", onClick: clear }, t.clear()) : null, props.children) : null)
43
+ );
44
+ });
45
+ export {
46
+ ActionBar
47
+ };
@@ -26,7 +26,7 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
26
26
  collapsed: false,
27
27
  collapsible: false
28
28
  }) : props.nav;
29
- return /* @__PURE__ */ React.createElement("div", { ref, className: cx("aura-shell", props.className) }, props.nav ? /* @__PURE__ */ React.createElement("div", { className: "aura-shell__nav" }, props.nav) : null, props.nav ? /* @__PURE__ */ React.createElement(
29
+ return /* @__PURE__ */ React.createElement("div", { ref, className: cx("aura-shell", props.bottomNav && "aura-shell--bottomnav", props.className) }, props.nav ? /* @__PURE__ */ React.createElement("div", { className: "aura-shell__nav" }, props.nav) : null, props.nav ? /* @__PURE__ */ React.createElement(
30
30
  Drawer,
31
31
  {
32
32
  open,
@@ -51,7 +51,7 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
51
51
  },
52
52
  "aria-expanded": open
53
53
  }
54
- ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React.createElement("main", { className: "aura-shell__content", id: props.mainId || "main" }, props.children)));
54
+ ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React.createElement("main", { className: "aura-shell__content", id: props.mainId || "main" }, props.children), props.bottomNav || null));
55
55
  });
56
56
  export {
57
57
  AppShell
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { Icon } from "./Icon.js";
4
+ import { cx, useMaybeControlled } from "./internal.js";
5
+ import { useLinkComponent, useStrings } from "./locale.js";
6
+ const BottomNav = React.forwardRef(function BottomNav2(props, ref) {
7
+ const t = useStrings();
8
+ const Link = useLinkComponent(props.linkComponent);
9
+ const st = useMaybeControlled(
10
+ props.value,
11
+ props.defaultValue,
12
+ props.onChange
13
+ );
14
+ const active = st[0];
15
+ const hide = props.hideFrom === false ? "always" : "below-" + (props.hideFrom || "lg");
16
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: cx("aura-bottomnav-spacer", "aura-bottomnav--" + hide), "aria-hidden": "true" }), /* @__PURE__ */ React.createElement(
17
+ "nav",
18
+ {
19
+ ref,
20
+ className: cx("aura-bottomnav", "aura-bottomnav--" + hide, props.className),
21
+ "aria-label": props.label || t.mainNav
22
+ },
23
+ /* @__PURE__ */ React.createElement("ul", { className: "aura-bottomnav__list" }, props.items.map(function(it) {
24
+ const on = active === it.id;
25
+ const count = it.count != null && it.count > 0 ? it.count > 99 ? "99+" : String(it.count) : null;
26
+ const common = {
27
+ className: cx("aura-bottomnav__item", on && "is-active"),
28
+ "aria-current": on ? "page" : void 0,
29
+ onClick: function(e) {
30
+ if (!it.href) e.preventDefault();
31
+ st[1](it.id);
32
+ }
33
+ };
34
+ const inner = [
35
+ /* @__PURE__ */ React.createElement("span", { key: "i", className: "aura-bottomnav__icon" }, /* @__PURE__ */ React.createElement(Icon, { name: it.icon, size: "md" }), count ? /* @__PURE__ */ React.createElement("span", { className: "aura-bottomnav__count", "aria-hidden": "true" }, count) : it.badge ? /* @__PURE__ */ React.createElement("span", { className: "aura-bottomnav__dot", "aria-hidden": "true" }) : null),
36
+ /* @__PURE__ */ React.createElement("span", { key: "l", className: "aura-bottomnav__label" }, it.label),
37
+ count || it.badge && it.badgeLabel ? /* @__PURE__ */ React.createElement("span", { key: "s", className: "aura-sr-only" }, " (" + (count || it.badgeLabel) + ")") : null
38
+ ];
39
+ return /* @__PURE__ */ React.createElement("li", { key: it.id, className: "aura-bottomnav__cell" }, it.href ? /* @__PURE__ */ React.createElement(Link, { href: it.href, ...common }, inner) : /* @__PURE__ */ React.createElement("button", { type: "button", ...common }, inner));
40
+ }))
41
+ ));
42
+ });
43
+ export {
44
+ BottomNav
45
+ };
@@ -155,8 +155,8 @@ function Command(props) {
155
155
  "data-autofocus": "",
156
156
  type: "text",
157
157
  role: "combobox",
158
- "aria-expanded": true,
159
- "aria-controls": listId,
158
+ "aria-expanded": flat.length > 0,
159
+ "aria-controls": flat.length ? listId : void 0,
160
160
  "aria-autocomplete": "list",
161
161
  "aria-activedescendant": active >= 0 ? optId(active) : void 0,
162
162
  "aria-label": props.label || t.commandMenu,
@@ -172,17 +172,15 @@ function Command(props) {
172
172
  onKeyDown: onKey
173
173
  }
174
174
  ), /* @__PURE__ */ React.createElement("kbd", { className: "aura-command__kbd" }, "Esc")),
175
- /* @__PURE__ */ React.createElement(
175
+ /* @__PURE__ */ React.createElement("div", { className: "aura-command__list", "aria-busy": props.loading || void 0 }, props.loading ? /* @__PURE__ */ React.createElement("div", { className: "aura-command__loading" }, /* @__PURE__ */ React.createElement(Icon, { name: "loader-circle", className: "aura-spin" }), t.searching) : null, !flat.length ? props.loading ? null : /* @__PURE__ */ React.createElement("div", { className: "aura-command__empty" }, props.empty != null ? props.empty : props.emptyText || t.noMatches) : /* @__PURE__ */ React.createElement(
176
176
  "div",
177
177
  {
178
- className: "aura-command__list",
179
178
  id: listId,
180
179
  role: "listbox",
181
180
  "aria-label": props.label || t.commandMenu,
182
181
  "aria-busy": props.loading || void 0
183
182
  },
184
- props.loading ? /* @__PURE__ */ React.createElement("div", { className: "aura-command__loading", role: "presentation" }, /* @__PURE__ */ React.createElement(Icon, { name: "loader-circle", className: "aura-spin" }), t.searching) : null,
185
- !flat.length ? props.loading ? null : /* @__PURE__ */ React.createElement("div", { className: "aura-command__empty", role: "presentation" }, props.empty != null ? props.empty : props.emptyText || t.noMatches) : groups.map(function(g, gi) {
183
+ groups.map(function(g, gi) {
186
184
  const gid = id + "-g" + gi;
187
185
  return /* @__PURE__ */ React.createElement(
188
186
  "div",
@@ -204,7 +202,11 @@ function Command(props) {
204
202
  role: "option",
205
203
  "aria-selected": n === active,
206
204
  "aria-disabled": it.disabled || void 0,
207
- className: cx("aura-command__item", n === active && "is-active", it.disabled && "is-disabled"),
205
+ className: cx(
206
+ "aura-command__item",
207
+ n === active && "is-active",
208
+ it.disabled && "is-disabled"
209
+ ),
208
210
  onPointerDown: function(e) {
209
211
  e.preventDefault();
210
212
  },
@@ -222,8 +224,8 @@ function Command(props) {
222
224
  })
223
225
  );
224
226
  })
225
- ),
226
- /* @__PURE__ */ React.createElement("span", { className: "aura-sr-only", role: "status" }, props.loading ? t.searching : props.loading === false && query ? t.results(flat.length) : ""),
227
+ )),
228
+ /* @__PURE__ */ React.createElement("span", { className: "aura-sr-only", role: "status" }, props.loading ? t.searching : query && !flat.length ? t.noMatches : props.loading === false && query ? t.results(flat.length) : ""),
227
229
  /* @__PURE__ */ React.createElement("div", { className: "aura-command__foot", "aria-hidden": true }, t.commandHint, /* @__PURE__ */ React.createElement("span", { className: "aura-command__mod" }, isMac() ? "\u2318K" : "Ctrl K"))
228
230
  )
229
231
  ),
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
+ import { createPortal } from "react-dom";
3
4
  import { useStrings, useLinkComponent } from "./locale.js";
4
5
  import { cx, useMaybeControlled, compare, useIsoLayoutEffect, useMergedRef } from "./internal.js";
5
6
  import { Icon } from "./Icon.js";
@@ -116,6 +117,29 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
116
117
  return px != null && boxWidth[0] < px;
117
118
  }
118
119
  const scrollRef = React.useRef(null);
120
+ const tipState = React.useState(null), tip = tipState[0], setTip = tipState[1];
121
+ function showFull(e) {
122
+ const el = e.target.closest ? e.target.closest(".aura-table__td, .aura-table__card-fields dd") : null;
123
+ if (!el || el.scrollWidth <= el.clientWidth + 1 || el.querySelector("button, input, .aura-pill"))
124
+ return setTip(null);
125
+ const r = el.getBoundingClientRect();
126
+ setTip({ text: (el.textContent || "").trim(), left: r.left, top: r.top });
127
+ }
128
+ function hideFull() {
129
+ setTip(null);
130
+ }
131
+ const tipEl = tip && typeof document !== "undefined" ? createPortal(
132
+ /* @__PURE__ */ React.createElement(
133
+ "div",
134
+ {
135
+ className: "aura-tooltip aura-tooltip--above",
136
+ "aria-hidden": "true",
137
+ style: { left: tip.left, top: tip.top - 6 }
138
+ },
139
+ tip.text
140
+ ),
141
+ document.body
142
+ ) : null;
119
143
  const rowH = React.useState(ROW_H_DEFAULT);
120
144
  const ROW_H = rowH[0];
121
145
  useIsoLayoutEffect(function() {
@@ -984,7 +1008,7 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
984
1008
  return /* @__PURE__ */ React.createElement("span", { key: c.key, className: "aura-table__card-actions" }, cellVal(c, r));
985
1009
  })),
986
1010
  rest.length ? /* @__PURE__ */ React.createElement("dl", { className: "aura-table__card-fields" }, rest.map(function(c) {
987
- return /* @__PURE__ */ React.createElement("div", { key: c.key }, /* @__PURE__ */ React.createElement("dt", null, c.label), /* @__PURE__ */ React.createElement("dd", { className: c.mono ? "aura-table__mono" : void 0 }, cellVal(c, r)));
1011
+ return /* @__PURE__ */ React.createElement("div", { key: c.key }, /* @__PURE__ */ React.createElement("dt", null, c.label), /* @__PURE__ */ React.createElement("dd", { className: cx(c.mono && "aura-table__mono", c.align === "end" && "is-end") }, cellVal(c, r)));
988
1012
  })) : null
989
1013
  );
990
1014
  }));
@@ -995,6 +1019,10 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
995
1019
  ref: wrapRefArg,
996
1020
  "data-density": props.density,
997
1021
  className: cx("aura-table aura-table--stacked", refreshing && "is-refreshing", props.className),
1022
+ onMouseOver: showFull,
1023
+ onMouseLeave: hideFull,
1024
+ onFocus: showFull,
1025
+ onBlur: hideFull,
998
1026
  role: "region",
999
1027
  "aria-label": props.label,
1000
1028
  "aria-busy": busy || void 0
@@ -1010,10 +1038,55 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
1010
1038
  }
1011
1039
  ), /* @__PURE__ */ React.createElement("span", null, nSel ? t.selectedCount(nSel) : t.selectAll)) : null,
1012
1040
  cardBody,
1013
- foot
1041
+ props.footer && rows.length && !loading ? /* @__PURE__ */ React.createElement("div", { className: "aura-table__card aura-table__card--total", role: "group", "aria-label": t.totals }, /* @__PURE__ */ React.createElement("dl", { className: "aura-table__card-fields" }, vis.filter(function(c) {
1042
+ return props.footer[c.key] != null;
1043
+ }).map(function(c) {
1044
+ return /* @__PURE__ */ React.createElement("div", { key: c.key }, /* @__PURE__ */ React.createElement("dt", null, c.label || t.totals), /* @__PURE__ */ React.createElement("dd", { className: cx(c.mono && "aura-table__mono", c.align === "end" && "is-end") }, props.footer[c.key]));
1045
+ }))) : null,
1046
+ foot,
1047
+ tipEl
1014
1048
  );
1015
1049
  }
1016
1050
  if (stacked) return renderStacked(wrapMerged);
1051
+ const totalRow = props.footer && rows.length && !loading ? /* @__PURE__ */ React.createElement(
1052
+ "div",
1053
+ {
1054
+ role: "row",
1055
+ "aria-rowindex": shownTotal + 2,
1056
+ "aria-label": t.totals,
1057
+ className: cx("aura-table__row aura-table__total", props.stickyFooter && "is-sticky"),
1058
+ style: rowStyle
1059
+ },
1060
+ /* @__PURE__ */ React.createElement("span", { className: "aura-table__gutter", "aria-hidden": true }),
1061
+ selectable ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-table__sel", nPinned && "is-pinned"), "aria-hidden": true }) : null,
1062
+ vis.map(function(c, j) {
1063
+ const pin = isPinned(c);
1064
+ return /* @__PURE__ */ React.createElement(
1065
+ "span",
1066
+ {
1067
+ key: c.key,
1068
+ role: "gridcell",
1069
+ "aria-colindex": j + (selectable ? 2 : 1),
1070
+ className: cx(
1071
+ "aura-table__td",
1072
+ c.mono && "aura-table__mono",
1073
+ c.align === "end" && "is-end",
1074
+ pin && "is-pinned",
1075
+ pin && j === nPinned - 1 && "is-pin-edge"
1076
+ ),
1077
+ style: cellStyle(c, j)
1078
+ },
1079
+ props.footer[c.key]
1080
+ );
1081
+ }),
1082
+ /* @__PURE__ */ React.createElement(
1083
+ "span",
1084
+ {
1085
+ className: cx("aura-table__gutter aura-table__gutter--end", controls && "has-picker"),
1086
+ "aria-hidden": true
1087
+ }
1088
+ )
1089
+ ) : null;
1017
1090
  const scrollStyle = {
1018
1091
  scrollPaddingLeft: "calc(var(--aura-space-6)" + selW + " + " + acc + "px)",
1019
1092
  scrollPaddingTop: ROW_H + "px"
@@ -1035,11 +1108,15 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
1035
1108
  gridRef.current = el;
1036
1109
  },
1037
1110
  className: "aura-table__scroll",
1111
+ onMouseOver: showFull,
1112
+ onMouseLeave: hideFull,
1113
+ onFocus: showFull,
1114
+ onBlur: hideFull,
1038
1115
  style: scrollStyle,
1039
1116
  role: "grid",
1040
1117
  "aria-label": props.label,
1041
1118
  "aria-busy": busy || void 0,
1042
- "aria-rowcount": loading ? -1 : shownTotal + 1,
1119
+ "aria-rowcount": loading ? -1 : shownTotal + 1 + (totalRow ? 1 : 0),
1043
1120
  "aria-colcount": nCols,
1044
1121
  "aria-multiselectable": selectable || void 0,
1045
1122
  onKeyDown: onGridKey,
@@ -1053,7 +1130,8 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
1053
1130
  }
1054
1131
  },
1055
1132
  /* @__PURE__ */ React.createElement("div", { className: "aura-table__head", role: "row", "aria-rowindex": 1, style: rowStyle }, head),
1056
- body
1133
+ body,
1134
+ totalRow
1057
1135
  ),
1058
1136
  busy ? /* @__PURE__ */ React.createElement("span", { className: "aura-sr-only", role: "status" }, t.loadingRows) : null,
1059
1137
  controls ? /* @__PURE__ */ React.createElement("div", { className: "aura-table__picker" }, /* @__PURE__ */ React.createElement(
@@ -1076,7 +1154,8 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
1076
1154
  label: menu.kind === "picker" ? t.columns : t.column(byKey[menu.key] && byKey[menu.key].label),
1077
1155
  items: menu.kind === "picker" ? pickerItems() : byKey[menu.key] ? columnMenuItems(byKey[menu.key]) : []
1078
1156
  }
1079
- ) : null
1157
+ ) : null,
1158
+ tipEl
1080
1159
  );
1081
1160
  if (!dual) return gridEl;
1082
1161
  return /* @__PURE__ */ React.createElement("div", { ref: wrapMerged, className: "aura-table-dual", "data-stack-below": props.stackBelow }, renderStacked(void 0), gridEl);
@@ -18,7 +18,8 @@ import {
18
18
  localeTag,
19
19
  parseDate,
20
20
  same,
21
- toISO
21
+ toISO,
22
+ todayIn
22
23
  } from "./dates.js";
23
24
  import { formatDate as formatDate2, parseDate as parseDate2 } from "./dates.js";
24
25
  function useFormatDate() {
@@ -40,9 +41,9 @@ function useFormatDate() {
40
41
  const Calendar = React.forwardRef(function Calendar2(props, ref) {
41
42
  const ctx = useAuraLocale(), locale = props.locale || ctx.locale || "en", calendar = props.calendar || ctx.calendar || defaultCalendar(locale), tag = localeTag(locale, calendar);
42
43
  const weekStart = props.weekStartsOn == null ? locale === "sv" ? 1 : 0 : props.weekStartsOn;
43
- let today = /* @__PURE__ */ new Date();
44
- today = new Date(today.getFullYear(), today.getMonth(), today.getDate());
45
- const min = fromISO(props.min), max = fromISO(props.max);
44
+ const todayISO = props.today || todayIn(props.timeZone || ctx.timeZone);
45
+ const today = fromISO(todayISO);
46
+ const min = fromISO(props.min === "today" ? todayISO : props.min), max = fromISO(props.max === "today" ? todayISO : props.max);
46
47
  const start = fromISO(props.start), end = fromISO(props.end);
47
48
  const focusState = React.useState(fromISO(props.focus) || start || today);
48
49
  const focusDate = focusState[0], setFocus = focusState[1];
@@ -428,6 +429,8 @@ const DatePicker = React.forwardRef(function DatePicker2(props, ref) {
428
429
  weekStartsOn: props.weekStartsOn,
429
430
  min: props.min,
430
431
  max: props.max,
432
+ timeZone: props.timeZone,
433
+ today: props.today,
431
434
  isDateDisabled: props.isDateDisabled,
432
435
  start: st[0],
433
436
  focus: st[0],
@@ -544,6 +547,8 @@ const DateRangePicker = React.forwardRef(
544
547
  weekStartsOn: props.weekStartsOn,
545
548
  min: props.min,
546
549
  max: props.max,
550
+ timeZone: props.timeZone,
551
+ today: props.today,
547
552
  isDateDisabled: props.isDateDisabled,
548
553
  start: draft[0] || v.start,
549
554
  end: draft[0] ? null : v.end,
@@ -23,6 +23,7 @@ const DropdownMenu = React.forwardRef(function DropdownMenu2(props, ref) {
23
23
  anchor,
24
24
  label: props.label,
25
25
  items: props.items,
26
+ linkComponent: props.linkComponent,
26
27
  onClose: function(restore) {
27
28
  setAnchor(null);
28
29
  if (restore && typeof anchor.focus === "function") anchor.focus();
package/dist/esm/Menu.js CHANGED
@@ -3,12 +3,14 @@ import * as React from "react";
3
3
  import { createPortal } from "react-dom";
4
4
  import { cx, useIsoLayoutEffect, useMounted, useMergedRef } from "./internal.js";
5
5
  import { Icon } from "./Icon.js";
6
+ import { useLinkComponent } from "./locale.js";
6
7
  const Menu = React.forwardRef(function Menu2(props, ref) {
7
8
  const own = React.useRef(null), merged = useMergedRef(ref, own);
8
9
  const posState = React.useState(null);
9
10
  const pos = posState[0], setPos = posState[1];
10
11
  const items = props.items || [];
11
12
  const mounted = useMounted();
13
+ const Link = useLinkComponent(props.linkComponent);
12
14
  useIsoLayoutEffect(
13
15
  function() {
14
16
  const a = props.anchor, m = own.current;
@@ -69,6 +71,63 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
69
71
  }
70
72
  e.stopPropagation();
71
73
  }
74
+ function groupItems(list) {
75
+ const out = [];
76
+ list.forEach(function(it, i) {
77
+ const g = it.type === "radio" && it.group ? it.group : null;
78
+ const last = out[out.length - 1];
79
+ if (last && last.group === g && g !== null) last.items.push({ it, i });
80
+ else out.push({ group: g, items: [{ it, i }] });
81
+ });
82
+ return out;
83
+ }
84
+ function renderItem(it, i) {
85
+ if (it.separator) return /* @__PURE__ */ React.createElement("div", { key: "s" + i, role: "separator", className: "aura-menu__sep" });
86
+ const isRadio = it.type === "radio";
87
+ const isCheck = !isRadio && it.checked !== void 0;
88
+ const lead = isRadio ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-menu__radio", it.checked && "is-on") }) : isCheck ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React.createElement(Icon, { name: "check", size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React.createElement(Icon, { name: it.icon }) : /* @__PURE__ */ React.createElement("span", { className: "aura-menu__blank" });
89
+ const body = [
90
+ /* @__PURE__ */ React.createElement(React.Fragment, { key: "l" }, lead),
91
+ /* @__PURE__ */ React.createElement("span", { key: "t", className: "aura-menu__label" }, it.label),
92
+ it.hint ? /* @__PURE__ */ React.createElement("span", { key: "h", className: "aura-menu__hint" }, it.hint) : null
93
+ ];
94
+ const cls = cx("aura-menu__item", it.tone === "danger" && "aura-menu__item--danger");
95
+ if (it.href && !it.disabled)
96
+ return /* @__PURE__ */ React.createElement(
97
+ Link,
98
+ {
99
+ key: i,
100
+ href: it.href,
101
+ target: it.target,
102
+ rel: it.target === "_blank" ? "noreferrer" : void 0,
103
+ tabIndex: -1,
104
+ role: "menuitem",
105
+ className: cls,
106
+ onClick: function() {
107
+ if (it.onSelect) it.onSelect();
108
+ props.onClose(false);
109
+ }
110
+ },
111
+ body
112
+ );
113
+ return /* @__PURE__ */ React.createElement(
114
+ "button",
115
+ {
116
+ key: i,
117
+ type: "button",
118
+ tabIndex: -1,
119
+ disabled: it.disabled,
120
+ role: isRadio ? "menuitemradio" : isCheck ? "menuitemcheckbox" : "menuitem",
121
+ "aria-checked": isRadio || isCheck ? !!it.checked : void 0,
122
+ className: cls,
123
+ onClick: function() {
124
+ if (it.onSelect) it.onSelect();
125
+ if (!it.keepOpen) props.onClose(true);
126
+ }
127
+ },
128
+ body
129
+ );
130
+ }
72
131
  const el = /* @__PURE__ */ React.createElement(
73
132
  "div",
74
133
  {
@@ -79,28 +138,11 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
79
138
  onKeyDown,
80
139
  style: { top: pos ? pos.top : -9999, left: pos ? pos.left : -9999 }
81
140
  },
82
- items.map(function(it, i) {
83
- if (it.separator) return /* @__PURE__ */ React.createElement("div", { key: "s" + i, role: "separator", className: "aura-menu__sep" });
84
- const isCheck = it.checked !== void 0;
85
- return /* @__PURE__ */ React.createElement(
86
- "button",
87
- {
88
- key: i,
89
- type: "button",
90
- tabIndex: -1,
91
- disabled: it.disabled,
92
- role: isCheck ? "menuitemcheckbox" : "menuitem",
93
- "aria-checked": isCheck ? !!it.checked : void 0,
94
- className: "aura-menu__item",
95
- onClick: function() {
96
- it.onSelect();
97
- if (!it.keepOpen) props.onClose(true);
98
- }
99
- },
100
- isCheck ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React.createElement(Icon, { name: "check", size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React.createElement(Icon, { name: it.icon }) : /* @__PURE__ */ React.createElement("span", { className: "aura-menu__blank" }),
101
- /* @__PURE__ */ React.createElement("span", { className: "aura-menu__label" }, it.label),
102
- it.hint ? /* @__PURE__ */ React.createElement("span", { className: "aura-menu__hint" }, it.hint) : null
103
- );
141
+ groupItems(items).map(function(block, bi) {
142
+ const rendered = block.items.map(function(x) {
143
+ return renderItem(x.it, x.i);
144
+ });
145
+ return block.group ? /* @__PURE__ */ React.createElement("div", { key: "g" + bi, role: "group", "aria-label": block.group, className: "aura-menu__group" }, rendered) : /* @__PURE__ */ React.createElement(React.Fragment, { key: "f" + bi }, rendered);
104
146
  })
105
147
  );
106
148
  return mounted ? createPortal(el, document.body) : null;
package/dist/esm/Tabs.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import * as React from "react";
3
3
  import { Icon } from "./Icon.js";
4
4
  import { cx, uid, useMaybeControlled } from "./internal.js";
5
+ import { useLinkComponent } from "./locale.js";
5
6
  const Tabs = React.forwardRef(function Tabs2(props, ref) {
6
7
  const items = props.tabs || [], base = uid();
7
8
  const st = useMaybeControlled(
@@ -13,6 +14,40 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
13
14
  const current = items.filter(function(t) {
14
15
  return t.id === st[0];
15
16
  })[0] || items[0];
17
+ const Link = useLinkComponent(props.linkComponent);
18
+ const asLinks = items.length > 0 && items.every(function(t) {
19
+ return !!t.href;
20
+ });
21
+ if (asLinks)
22
+ return /* @__PURE__ */ React.createElement(
23
+ "nav",
24
+ {
25
+ ref,
26
+ "aria-label": props.label,
27
+ className: cx("aura-tabs aura-tabs--links", props.className)
28
+ },
29
+ /* @__PURE__ */ React.createElement("div", { className: "aura-tabs__list" }, items.map(function(t) {
30
+ const on = current && t.id === current.id;
31
+ const inner = [
32
+ t.icon ? /* @__PURE__ */ React.createElement(Icon, { key: "i", name: t.icon }) : null,
33
+ t.label,
34
+ t.count != null ? /* @__PURE__ */ React.createElement("span", { key: "c", className: "aura-tab__count" }, t.count) : null
35
+ ];
36
+ return t.disabled ? /* @__PURE__ */ React.createElement("span", { key: t.id, className: "aura-tab is-disabled", "aria-disabled": true }, inner) : /* @__PURE__ */ React.createElement(
37
+ Link,
38
+ {
39
+ key: t.id,
40
+ href: t.href,
41
+ className: cx("aura-tab", on && "is-active"),
42
+ "aria-current": on ? "page" : void 0,
43
+ onClick: function() {
44
+ st[1](t.id);
45
+ }
46
+ },
47
+ inner
48
+ );
49
+ }))
50
+ );
16
51
  function go(i) {
17
52
  const enabled = items.filter(function(t2) {
18
53
  return !t2.disabled;
@@ -6,11 +6,19 @@ import { IconButton } from "./IconButton.js";
6
6
  import { cx, useMounted } from "./internal.js";
7
7
  import { useStrings } from "./locale.js";
8
8
  import { createPortal } from "react-dom";
9
+ const MAX_VISIBLE = 3;
9
10
  const toastState = {
10
11
  list: [],
12
+ queue: [],
11
13
  subs: [],
12
14
  n: 0
13
15
  };
16
+ function promote() {
17
+ while (toastState.list.length < MAX_VISIBLE && toastState.queue.length) {
18
+ toastState.list = toastState.list.concat([toastState.queue[0]]);
19
+ toastState.queue = toastState.queue.slice(1);
20
+ }
21
+ }
14
22
  function emitToasts() {
15
23
  toastState.subs.forEach(function(f) {
16
24
  f(toastState.list.slice());
@@ -18,18 +26,24 @@ function emitToasts() {
18
26
  }
19
27
  function show(opts) {
20
28
  const id = opts.id || "t" + ++toastState.n;
21
- const at = toastState.list.findIndex(function(t) {
29
+ const byId = function(t) {
22
30
  return t.id === id;
23
- });
31
+ };
32
+ const at = toastState.list.findIndex(byId), queued = toastState.queue.findIndex(byId);
33
+ const prev = at >= 0 ? toastState.list[at] : queued >= 0 ? toastState.queue[queued] : null;
24
34
  const entry = Object.assign({ tone: "info" }, opts, {
25
35
  id,
26
36
  loading: !!opts.loading,
27
- rev: at >= 0 ? toastState.list[at].rev + 1 : 0
37
+ rev: prev ? prev.rev + 1 : 0
28
38
  });
29
39
  if (at >= 0) {
30
40
  toastState.list = toastState.list.slice();
31
41
  toastState.list[at] = entry;
32
- } else toastState.list = toastState.list.concat([entry]).slice(-3);
42
+ } else if (queued >= 0) {
43
+ toastState.queue = toastState.queue.slice();
44
+ toastState.queue[queued] = entry;
45
+ } else if (toastState.list.length < MAX_VISIBLE) toastState.list = toastState.list.concat([entry]);
46
+ else toastState.queue = toastState.queue.concat([entry]);
33
47
  emitToasts();
34
48
  return id;
35
49
  }
@@ -51,9 +65,12 @@ toast.loading = function(title, opts) {
51
65
  );
52
66
  };
53
67
  toast.dismiss = function(id) {
54
- toastState.list = toastState.list.filter(function(t) {
68
+ const keep = function(t) {
55
69
  return t.id !== id;
56
- });
70
+ };
71
+ toastState.list = toastState.list.filter(keep);
72
+ toastState.queue = toastState.queue.filter(keep);
73
+ promote();
57
74
  emitToasts();
58
75
  };
59
76
  function ToastItem(props) {
package/dist/esm/dates.js CHANGED
@@ -141,6 +141,16 @@ function parseDate(text) {
141
141
  const dt = new Date(y, mo - 1, d);
142
142
  return dt.getMonth() === mo - 1 && dt.getDate() === d ? toISO(dt) : null;
143
143
  }
144
+ function todayIn(timeZone) {
145
+ const now = /* @__PURE__ */ new Date();
146
+ if (!timeZone) return toISO(now);
147
+ return new Intl.DateTimeFormat("en-CA", {
148
+ timeZone,
149
+ year: "numeric",
150
+ month: "2-digit",
151
+ day: "2-digit"
152
+ }).format(now);
153
+ }
144
154
  export {
145
155
  DATE_TEXT,
146
156
  ERA,
@@ -160,5 +170,6 @@ export {
160
170
  pad,
161
171
  parseDate,
162
172
  same,
163
- toISO
173
+ toISO,
174
+ todayIn
164
175
  };
package/dist/esm/index.js CHANGED
@@ -14,6 +14,7 @@ import { RadioGroup } from "./RadioGroup.js";
14
14
  import { Switch } from "./Switch.js";
15
15
  import { Combobox, defaultFilter } from "./Combobox.js";
16
16
  import { DatePicker, DateRangePicker, Calendar, formatDate, parseDate, useFormatDate } from "./DatePicker.js";
17
+ import { todayIn } from "./dates.js";
17
18
  import { Alert } from "./Alert.js";
18
19
  import { Toaster, toast } from "./Toaster.js";
19
20
  import { PasswordField } from "./PasswordField.js";
@@ -32,6 +33,8 @@ import { Stack } from "./Stack.js";
32
33
  import { Grid } from "./Grid.js";
33
34
  import { Container } from "./Container.js";
34
35
  import { AppShell } from "./AppShell.js";
36
+ import { ActionBar } from "./ActionBar.js";
37
+ import { BottomNav } from "./BottomNav.js";
35
38
  import { useBreakpoint, useResponsive, breakpoints } from "./responsive.js";
36
39
  import { Surface } from "./Surface.js";
37
40
  import { AuraProvider, useAuraLocale, useDensity, STRINGS } from "./locale.js";
@@ -54,11 +57,13 @@ import { Stepper } from "./Stepper.js";
54
57
  import { SegmentedControl } from "./SegmentedControl.js";
55
58
  export {
56
59
  Accordion,
60
+ ActionBar,
57
61
  Alert,
58
62
  AppShell,
59
63
  AuraProvider,
60
64
  Avatar,
61
65
  Badge,
66
+ BottomNav,
62
67
  Breadcrumb,
63
68
  Button,
64
69
  Calendar,
@@ -123,6 +128,7 @@ export {
123
128
  parseTime,
124
129
  statusTone,
125
130
  toast,
131
+ todayIn,
126
132
  useAuraLocale,
127
133
  useBreakpoint,
128
134
  useColorScheme,