@jirawatpyk/aura-react 5.32.0 → 5.34.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.
@@ -28,12 +28,15 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
28
28
  const barRef = React.useRef(null);
29
29
  const mergedRef = useMergedRef(ref, rootRef);
30
30
  const hasBar = !!(props.header || props.nav);
31
+ const barH = React.useState(null);
31
32
  useIsoLayoutEffect(
32
33
  function() {
33
34
  const root = rootRef.current, bar = barRef.current;
34
35
  if (!root || !bar) return;
35
36
  function sync() {
36
- root.style.setProperty("--aura-shell-bar-height", bar.getBoundingClientRect().height + "px");
37
+ const h = bar.getBoundingClientRect().height;
38
+ root.style.setProperty("--aura-shell-bar-height", h + "px");
39
+ if (h > 0) barH[1](Math.round(h));
37
40
  }
38
41
  sync();
39
42
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
@@ -71,6 +74,8 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
71
74
  /* 5.14: no top bar at all, or one that only holds the menu button (gone from lg up): the bar-height token is 0. */
72
75
  !props.header && !props.nav && "aura-shell--no-bar",
73
76
  !props.header && props.nav && "aura-shell--menu-bar",
77
+ /* 5.33 (DxT Monitor #6): a header bar for phones only. */
78
+ props.header && props.headerHideFrom === "lg" && "aura-shell--menu-bar",
74
79
  props.className
75
80
  )
76
81
  },
@@ -85,23 +90,37 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
85
90
  side: "left",
86
91
  size: "nav",
87
92
  "aria-label": props.navLabel || t.navigation,
88
- dismissible: true
93
+ dismissible: true,
94
+ closeProps: { touchHeight: true },
95
+ className: navEl && navEl.props.headerDivider && navEl.props.header ? "aura-drawer--nav-divided" : void 0,
96
+ style: barH[0] ? { "--aura-shell-bar-height": barH[0] + "px" } : void 0
89
97
  },
90
98
  drawerNav
91
99
  ) : null,
92
- /* @__PURE__ */ React.createElement("div", { className: "aura-shell__main" }, props.header || props.nav ? /* @__PURE__ */ React.createElement("header", { ref: barRef, className: cx("aura-shell__bar", !props.header && "aura-shell__bar--menu-only") }, props.nav ? /* @__PURE__ */ React.createElement(
93
- IconButton,
100
+ /* @__PURE__ */ React.createElement("div", { className: "aura-shell__main" }, props.header || props.nav ? /* @__PURE__ */ React.createElement(
101
+ "header",
94
102
  {
95
- className: "aura-shell__menu",
96
- icon: /* @__PURE__ */ React.createElement(IconMenu, null),
97
- label: props.menuLabel || t.openNav,
98
- size: "md",
99
- onClick: function() {
100
- setOpen(true);
101
- },
102
- "aria-expanded": open
103
- }
104
- ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React.createElement(
103
+ ref: barRef,
104
+ className: cx(
105
+ "aura-shell__bar",
106
+ (!props.header || props.headerHideFrom === "lg") && "aura-shell__bar--menu-only"
107
+ )
108
+ },
109
+ props.nav ? /* @__PURE__ */ React.createElement(
110
+ IconButton,
111
+ {
112
+ className: "aura-shell__menu",
113
+ icon: /* @__PURE__ */ React.createElement(IconMenu, null),
114
+ label: props.menuLabel || t.openNav,
115
+ size: "md",
116
+ onClick: function() {
117
+ setOpen(true);
118
+ },
119
+ "aria-expanded": open
120
+ }
121
+ ) : null,
122
+ /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)
123
+ ) : null, /* @__PURE__ */ React.createElement(
105
124
  "main",
106
125
  {
107
126
  className: cx("aura-shell__content", props.contentPadding === false && "is-flush"),
@@ -15,6 +15,7 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
15
15
  h(
16
16
  "div",
17
17
  { className: "aura-page-header__text" },
18
+ props.breadcrumb != null && props.breadcrumb !== false ? h("div", { className: "aura-page-header__breadcrumb" }, props.breadcrumb) : null,
18
19
  props.eyebrow != null && props.eyebrow !== false ? h("p", { className: "aura-page-header__eyebrow" }, props.eyebrow) : null,
19
20
  h("h" + level, { className: "aura-page-header__title", id: props.titleId }, props.title),
20
21
  props.meta != null && props.meta !== false ? h("div", { className: "aura-page-header__meta" }, props.meta) : null
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { useLinkComponent, useStrings } from "./locale.js";
4
+ import { useAutoTip } from "./autoTip.js";
5
+ import { devWarnOnce } from "./classes.js";
6
+ import { statusTileElement } from "./tiles.js";
7
+ const useIsoLayoutEffect = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
8
+ const StatusTile = React.forwardRef(function StatusTile2(props, ref) {
9
+ const Link = useLinkComponent(props.linkComponent);
10
+ const t = useStrings();
11
+ useAutoTip();
12
+ if (!props.href && (props["aria-label"] || props["aria-labelledby"]))
13
+ devWarnOnce(
14
+ "status-tile-label",
15
+ "StatusTile `aria-label` needs `href`: without a link the tile is a plain box, where a name is not allowed."
16
+ );
17
+ const titleRef = React.useRef(null);
18
+ const check = React.useCallback(function() {
19
+ const el = titleRef.current;
20
+ if (!el) return;
21
+ const cut = el.scrollHeight > el.clientHeight + 1;
22
+ const text = (el.textContent || "").replace(/,$/, "").trim();
23
+ if (cut && text) el.setAttribute("data-aura-tip", text);
24
+ else el.removeAttribute("data-aura-tip");
25
+ }, []);
26
+ useIsoLayoutEffect(check, [props.title, check]);
27
+ const linked = !!props.href;
28
+ React.useEffect(
29
+ function() {
30
+ const el = titleRef.current;
31
+ if (!el) return;
32
+ let live = true;
33
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(check) : null;
34
+ const mo = typeof MutationObserver !== "undefined" ? new MutationObserver(check) : null;
35
+ if (ro) ro.observe(el);
36
+ if (mo) mo.observe(el, { characterData: true, childList: true, subtree: true });
37
+ if (document.fonts && document.fonts.ready)
38
+ document.fonts.ready.then(function() {
39
+ if (live) check();
40
+ });
41
+ return function() {
42
+ live = false;
43
+ if (ro) ro.disconnect();
44
+ if (mo) mo.disconnect();
45
+ };
46
+ },
47
+ [check, linked]
48
+ );
49
+ return statusTileElement(props, ref, Link, t, titleRef);
50
+ });
51
+ export {
52
+ StatusTile
53
+ };
@@ -22,6 +22,11 @@ function source(t) {
22
22
  const tag = el.closest(".aura-tag");
23
23
  if (tag) s = tag.querySelector(".aura-tag__text[" + ATTR + "]");
24
24
  }
25
+ if (!s) {
26
+ const tile = el.closest(".aura-status-tile");
27
+ const control = el.closest("a, button, input, select, textarea, [tabindex]");
28
+ if (tile && (!control || control === tile)) s = tile.querySelector(".aura-status-tile__title[" + ATTR + "]");
29
+ }
25
30
  if (!s || !s.getAttribute(ATTR) || !s.isConnected) return null;
26
31
  if (s.getAttribute("aria-expanded") === "true") return null;
27
32
  return s;
@@ -1,5 +1,22 @@
1
1
  'use client';
2
2
  const breakpoints = { sm: 640, md: 768, lg: 1024, xl: 1280 };
3
+ const ORDER = ["base", "sm", "md", "lg", "xl"];
4
+ function respVars(prefix, value, map) {
5
+ const style = {};
6
+ if (value == null) return style;
7
+ if (typeof value !== "object") value = { base: value };
8
+ let byBp = value, cur;
9
+ ORDER.forEach(function(k) {
10
+ if (byBp[k] !== void 0) cur = map ? map(byBp[k]) : byBp[k];
11
+ if (cur !== void 0) style["--" + prefix + "-" + k] = cur;
12
+ });
13
+ return style;
14
+ }
15
+ const space = function(v) {
16
+ return typeof v === "number" ? "var(--aura-space-" + v + ")" : v;
17
+ };
3
18
  export {
4
- breakpoints
19
+ breakpoints,
20
+ respVars,
21
+ space
5
22
  };
package/dist/esm/index.js CHANGED
@@ -36,6 +36,8 @@ import { Stack } from "./Stack.js";
36
36
  import { Grid } from "./Grid.js";
37
37
  import { Container } from "./Container.js";
38
38
  import { PageHeader } from "./PageHeader.js";
39
+ import { StatusTile } from "./StatusTile.js";
40
+ import { TileGrid, Sparkline } from "./tiles.js";
39
41
  import { AppShell } from "./AppShell.js";
40
42
  import { ActionBar } from "./ActionBar.js";
41
43
  import { Separator } from "./Separator.js";
@@ -111,9 +113,11 @@ export {
111
113
  Separator,
112
114
  SideNav,
113
115
  Skeleton,
116
+ Sparkline,
114
117
  Stack,
115
118
  Stat,
116
119
  StatusPill,
120
+ StatusTile,
117
121
  Stepper,
118
122
  Surface,
119
123
  Switch,
@@ -128,6 +132,7 @@ export {
128
132
  Textarea,
129
133
  Th,
130
134
  ThemeStyle,
135
+ TileGrid,
131
136
  TimePicker,
132
137
  Toaster,
133
138
  Tooltip,
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
- import { breakpoints } from "./breakpoints.js";
3
+ import { breakpoints, respVars, space } from "./breakpoints.js";
4
4
  const ORDER = ["base", "sm", "md", "lg", "xl"];
5
5
  function useBreakpoint() {
6
6
  return React.useSyncExternalStore(subscribe, current, function() {
@@ -27,20 +27,6 @@ function useResponsive(value) {
27
27
  for (let i = ORDER.indexOf(bp); i >= 0; i--) if (map[ORDER[i]] !== void 0) return map[ORDER[i]];
28
28
  return void 0;
29
29
  }
30
- function respVars(prefix, value, map) {
31
- const style = {};
32
- if (value == null) return style;
33
- if (typeof value !== "object") value = { base: value };
34
- let byBp = value, cur;
35
- ORDER.forEach(function(k) {
36
- if (byBp[k] !== void 0) cur = map ? map(byBp[k]) : byBp[k];
37
- if (cur !== void 0) style["--" + prefix + "-" + k] = cur;
38
- });
39
- return style;
40
- }
41
- const space = function(v) {
42
- return typeof v === "number" ? "var(--aura-space-" + v + ")" : v;
43
- };
44
30
  export {
45
31
  breakpoints,
46
32
  respVars,
@@ -127,6 +127,10 @@ const STRINGS = {
127
127
  },
128
128
  breadcrumbMore: "Show the full path",
129
129
  stepError: "has errors",
130
+ statusDown: "Down",
131
+ statusProblem: "Problem",
132
+ statusMaintenance: "Maintenance",
133
+ statusOk: "OK",
130
134
  accepts: function(list, max) {
131
135
  return [list, max && "up to " + max + " each"].filter(Boolean).join(", ");
132
136
  }
@@ -123,6 +123,10 @@ const sv = {
123
123
  },
124
124
  breadcrumbMore: "Visa hela s\xF6kv\xE4gen",
125
125
  stepError: "har fel",
126
+ statusDown: "Nere",
127
+ statusProblem: "Problem",
128
+ statusMaintenance: "Underh\xE5ll",
129
+ statusOk: "OK",
126
130
  accepts: function(list, max) {
127
131
  return [list, max && "h\xF6gst " + max + " per fil"].filter(Boolean).join(", ");
128
132
  }
@@ -123,6 +123,10 @@ const th = {
123
123
  },
124
124
  breadcrumbMore: "\u0E41\u0E2A\u0E14\u0E07\u0E40\u0E2A\u0E49\u0E19\u0E17\u0E32\u0E07\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14",
125
125
  stepError: "\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14",
126
+ statusDown: "\u0E25\u0E48\u0E21",
127
+ statusProblem: "\u0E21\u0E35\u0E1B\u0E31\u0E0D\u0E2B\u0E32",
128
+ statusMaintenance: "\u0E1B\u0E34\u0E14\u0E1B\u0E23\u0E31\u0E1A\u0E1B\u0E23\u0E38\u0E07",
129
+ statusOk: "\u0E1B\u0E01\u0E15\u0E34",
126
130
  accepts: function(list, max) {
127
131
  return [list, max && "\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 " + max + " \u0E15\u0E48\u0E2D\u0E44\u0E1F\u0E25\u0E4C"].filter(Boolean).join(" \xB7 ");
128
132
  }
@@ -0,0 +1,212 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { Icon } from "./Icon.js";
4
+ import { cx } from "./classes.js";
5
+ import { respVars } from "./breakpoints.js";
6
+ import { STRINGS } from "./strings.js";
7
+ import { IconCircleAlert, IconCircleCheck, IconTriangleAlert, IconWrench } from "./icons.js";
8
+ const h = React.createElement;
9
+ const STATUS_ICON = {
10
+ down: IconCircleAlert,
11
+ problem: IconTriangleAlert,
12
+ maintenance: IconWrench,
13
+ ok: IconCircleCheck
14
+ };
15
+ const STATUS_TONE = {
16
+ down: "danger",
17
+ problem: "warning",
18
+ maintenance: "accent",
19
+ ok: "default"
20
+ };
21
+ const STATUS_WORD = {
22
+ down: "statusDown",
23
+ problem: "statusProblem",
24
+ maintenance: "statusMaintenance",
25
+ ok: "statusOk"
26
+ };
27
+ function statusWord(status, t) {
28
+ return String(t[STATUS_WORD[status]] || STATUS_WORD[status]);
29
+ }
30
+ function attrs(props) {
31
+ const out = {};
32
+ Object.keys(props).forEach(function(k) {
33
+ if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k))
34
+ out[k] = props[k];
35
+ });
36
+ return out;
37
+ }
38
+ const comma = h("span", { className: "aura-status-tile__sep" }, ",");
39
+ function statusTileElement(props, ref, Link, t, titleRef) {
40
+ const status = STATUS_ICON[props.status] ? props.status : "ok";
41
+ const valueTone = props.valueTone || STATUS_TONE[status];
42
+ const word = props.statusLabel || statusWord(status, t);
43
+ const markers = (props.markers || []).filter(Boolean);
44
+ const has = function(v) {
45
+ return v != null && v !== false && v !== "";
46
+ };
47
+ const hasValue = has(props.value), hasMeta = has(props.meta);
48
+ const Tag = props.href ? Link : "div";
49
+ return h(
50
+ Tag,
51
+ Object.assign(attrs(props), {
52
+ ref,
53
+ href: props.href,
54
+ className: cx("aura-status-tile", "aura-status-tile--" + status, props.href && "is-interactive", props.className)
55
+ }),
56
+ h(
57
+ "span",
58
+ { className: "aura-status-tile__head" },
59
+ h(Icon, { name: h(STATUS_ICON[status]), size: 16, className: "aura-status-tile__icon" }),
60
+ h("span", { className: "aura-status-tile__title", ref: titleRef }, props.title, comma),
61
+ h("span", { className: "aura-sr-only" }, word + (hasValue || hasMeta || markers.length ? "," : "")),
62
+ hasValue ? h(
63
+ "span",
64
+ { className: cx("aura-status-tile__value", "is-" + valueTone) },
65
+ props.value,
66
+ hasMeta || markers.length ? comma : null
67
+ ) : null
68
+ ),
69
+ hasMeta || markers.length ? h(
70
+ "span",
71
+ { className: "aura-status-tile__foot" },
72
+ hasMeta ? h("span", { className: "aura-status-tile__meta" }, props.meta, markers.length ? comma : null) : null,
73
+ markers.length ? h(
74
+ "span",
75
+ { className: "aura-status-tile__markers" },
76
+ markers.map(function(m, i) {
77
+ return h(
78
+ "span",
79
+ {
80
+ key: i,
81
+ className: cx("aura-status-tile__marker", "is-" + (m.tone || "neutral")),
82
+ "data-aura-tip": m.label
83
+ },
84
+ h(Icon, { name: m.icon, size: 14 }),
85
+ h("span", { className: "aura-sr-only" }, m.label + (i < markers.length - 1 ? "," : ""))
86
+ );
87
+ })
88
+ ) : null
89
+ ) : null
90
+ );
91
+ }
92
+ function ServerStatusTile(props) {
93
+ return statusTileElement(props, void 0, props.linkComponent || "a", STRINGS.en);
94
+ }
95
+ const TileGrid = React.forwardRef(function TileGrid2(props, ref) {
96
+ const style = Object.assign(
97
+ {},
98
+ respVars("aura-grid-cols", props.columns == null ? { base: 2, md: 3 } : props.columns),
99
+ props.style
100
+ );
101
+ return h(
102
+ "ul",
103
+ Object.assign(attrs(props), {
104
+ ref,
105
+ role: "list",
106
+ className: cx("aura-grid-layout", "aura-tile-grid", props.className),
107
+ style
108
+ }),
109
+ /* toArray drops null and booleans and keys each element; a Fragment's children are items too. */
110
+ flat(props.children).map(function(c, i) {
111
+ return h("li", { key: React.isValidElement(c) && c.key != null ? c.key : i }, c);
112
+ })
113
+ );
114
+ });
115
+ function flat(children) {
116
+ const out = [];
117
+ React.Children.toArray(children).forEach(function(c) {
118
+ if (React.isValidElement(c) && c.type === React.Fragment)
119
+ flat(c.props.children).forEach(function(x) {
120
+ out.push(React.isValidElement(x) ? React.cloneElement(x, { key: String(c.key) + "/" + String(x.key) }) : x);
121
+ });
122
+ else if (c !== "") out.push(c);
123
+ });
124
+ return out;
125
+ }
126
+ const SIZES = { sm: [80, 24], md: [120, 32] };
127
+ const PAD = 2;
128
+ function r(n) {
129
+ return Math.round(n * 100) / 100;
130
+ }
131
+ function num(v) {
132
+ return typeof v === "number" && isFinite(v) ? v : null;
133
+ }
134
+ const Sparkline = React.forwardRef(function Sparkline2(props, ref) {
135
+ const wh = SIZES[props.size || "sm"] || SIZES.sm;
136
+ const W = wh[0], H = wh[1];
137
+ const data = (props.data || []).map(num);
138
+ const n = data.length;
139
+ const vals = data.filter(function(v) {
140
+ return v != null;
141
+ });
142
+ let lo = num(props.min), hi = num(props.max);
143
+ if (lo == null) lo = vals.length ? Math.min.apply(null, vals) : 0;
144
+ if (hi == null) hi = vals.length ? Math.max.apply(null, vals) : 0;
145
+ if (lo > hi) {
146
+ const s = lo;
147
+ lo = hi;
148
+ hi = s;
149
+ }
150
+ const step = n > 1 ? (W - 2 * PAD) / (n - 1) : 0;
151
+ const x = function(i) {
152
+ return n > 1 ? PAD + i * step : W / 2;
153
+ };
154
+ const y = function(v) {
155
+ if (hi === lo) return H / 2;
156
+ const k = Math.max(0, Math.min(1, (v - lo) / (hi - lo)));
157
+ return H - PAD - k * (H - 2 * PAD);
158
+ };
159
+ let d = "";
160
+ const dots = [];
161
+ data.forEach(function(v, i) {
162
+ if (v == null) return;
163
+ const prev = i > 0 && data[i - 1] != null, next = i < n - 1 && data[i + 1] != null;
164
+ if (!prev && !next) dots.push(h("circle", { key: "d" + i, cx: r(x(i)), cy: r(y(v)), r: 1.5 }));
165
+ else d += (prev ? "L" : "M") + r(x(i)) + " " + r(y(v));
166
+ });
167
+ const mode = props.failures || "none";
168
+ const fails = [];
169
+ if (mode !== "none" && props.failed)
170
+ data.forEach(function(_v, i) {
171
+ if (!props.failed[i]) return;
172
+ if (mode === "band") {
173
+ const w = Math.max(2, step || W), left = Math.max(0, x(i) - w / 2), right = Math.min(W, x(i) + w / 2);
174
+ fails.push(h("rect", { key: "f" + i, x: r(left), y: 0, width: r(right - left), height: H }));
175
+ } else
176
+ fails.push(
177
+ h("rect", {
178
+ key: "f" + i,
179
+ x: r(Math.max(0, Math.min(W - 1.5, x(i) - 0.75))),
180
+ y: H - 6,
181
+ width: 1.5,
182
+ height: 6
183
+ })
184
+ );
185
+ });
186
+ const named = !!props.label;
187
+ return h(
188
+ "svg",
189
+ Object.assign(attrs(props), {
190
+ ref,
191
+ className: cx("aura-sparkline", "is-" + (props.tone || "neutral"), props.className),
192
+ width: W,
193
+ height: H,
194
+ viewBox: "0 0 " + W + " " + H,
195
+ role: named ? "img" : void 0,
196
+ "aria-label": named ? props.label : void 0,
197
+ "aria-hidden": named ? void 0 : true,
198
+ focusable: "false"
199
+ }),
200
+ fails.length && mode === "band" ? h("g", { className: "aura-sparkline__band" }, fails) : null,
201
+ d ? h("path", { className: "aura-sparkline__line", d }) : null,
202
+ dots.length ? h("g", { className: "aura-sparkline__dots" }, dots) : null,
203
+ fails.length && mode === "ticks" ? h("g", { className: "aura-sparkline__ticks" }, fails) : null
204
+ );
205
+ });
206
+ export {
207
+ ServerStatusTile,
208
+ Sparkline,
209
+ TileGrid,
210
+ statusTileElement,
211
+ statusWord
212
+ };