@jirawatpyk/aura-react 5.33.0 → 5.35.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.
@@ -35,6 +35,7 @@ const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
35
35
  },
36
36
  role: "region",
37
37
  "aria-label": props.label || t.actions,
38
+ "data-aura-hide-bottomnav": props.hidesBottomNav && !idle ? "" : void 0,
38
39
  className: cx(
39
40
  "aura-actionbar",
40
41
  "aura-actionbar--" + (props.position || "viewport"),
@@ -5,6 +5,7 @@ import { IconButton } from "./IconButton.js";
5
5
  import { cx, useIsoLayoutEffect, useMergedRef } from "./internal.js";
6
6
  import { useStrings } from "./locale.js";
7
7
  import { useBreakpoint } from "./responsive.js";
8
+ import { useHideOnScroll } from "./scrollHide.js";
8
9
  import { IconMenu } from "./icons.js";
9
10
  const AppShell = React.forwardRef(function AppShell2(props, ref) {
10
11
  const t = useStrings();
@@ -29,13 +30,24 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
29
30
  const mergedRef = useMergedRef(ref, rootRef);
30
31
  const hasBar = !!(props.header || props.nav);
31
32
  const barH = React.useState(null);
33
+ const away = useHideOnScroll(!!props.headerHideOnScroll && hasBar, barRef, "(max-width: 1023.98px)", barH[0] || 56);
34
+ const awayRef = React.useRef(away);
35
+ awayRef.current = away;
36
+ useIsoLayoutEffect(
37
+ function() {
38
+ const root = rootRef.current, bar = barRef.current;
39
+ if (!root || !bar) return;
40
+ root.style.setProperty("--aura-shell-bar-height", away ? "0px" : bar.getBoundingClientRect().height + "px");
41
+ },
42
+ [away]
43
+ );
32
44
  useIsoLayoutEffect(
33
45
  function() {
34
46
  const root = rootRef.current, bar = barRef.current;
35
47
  if (!root || !bar) return;
36
48
  function sync() {
37
49
  const h = bar.getBoundingClientRect().height;
38
- root.style.setProperty("--aura-shell-bar-height", h + "px");
50
+ root.style.setProperty("--aura-shell-bar-height", awayRef.current ? "0px" : h + "px");
39
51
  if (h > 0) barH[1](Math.round(h));
40
52
  }
41
53
  sync();
@@ -103,7 +115,9 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
103
115
  ref: barRef,
104
116
  className: cx(
105
117
  "aura-shell__bar",
106
- (!props.header || props.headerHideFrom === "lg") && "aura-shell__bar--menu-only"
118
+ (!props.header || props.headerHideFrom === "lg") && "aura-shell__bar--menu-only",
119
+ props.headerHideOnScroll && "aura-shell__bar--hides",
120
+ away && "is-away"
107
121
  )
108
122
  },
109
123
  props.nav ? /* @__PURE__ */ React.createElement(
@@ -3,6 +3,8 @@ import * as React from "react";
3
3
  import { Icon } from "./Icon.js";
4
4
  import { cx, devWarnOnce, plainClick, useMaybeControlled } from "./internal.js";
5
5
  import { useLinkComponent, useStrings } from "./locale.js";
6
+ import { useHideOnScroll } from "./scrollHide.js";
7
+ import { breakpoints } from "./breakpoints.js";
6
8
  const BottomNav = React.forwardRef(function BottomNav2(props, ref) {
7
9
  const t = useStrings();
8
10
  const Link = useLinkComponent(props.linkComponent);
@@ -13,11 +15,33 @@ const BottomNav = React.forwardRef(function BottomNav2(props, ref) {
13
15
  );
14
16
  const active = st[0];
15
17
  const hide = props.hideFrom === false ? "always" : "below-" + (props.hideFrom || "lg");
18
+ const own = React.useRef(null);
19
+ const hf = props.hideFrom === false ? null : props.hideFrom || "lg";
20
+ const away = useHideOnScroll(
21
+ !!props.hideOnScroll,
22
+ own,
23
+ hf ? "(max-width: " + (breakpoints[hf] - 0.02) + "px)" : "all",
24
+ 64
25
+ );
26
+ const setRef = React.useCallback(
27
+ function(el) {
28
+ own.current = el;
29
+ if (typeof ref === "function") ref(el);
30
+ else if (ref) ref.current = el;
31
+ },
32
+ [ref]
33
+ );
16
34
  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
35
  "nav",
18
36
  {
19
- ref,
20
- className: cx("aura-bottomnav", "aura-bottomnav--" + hide, props.className),
37
+ ref: setRef,
38
+ className: cx(
39
+ "aura-bottomnav",
40
+ "aura-bottomnav--" + hide,
41
+ props.hideOnScroll && "aura-bottomnav--hides",
42
+ away && "is-away",
43
+ props.className
44
+ ),
21
45
  "aria-label": props.label || t.mainNav
22
46
  },
23
47
  /* @__PURE__ */ React.createElement("ul", { className: "aura-bottomnav__list" }, props.items.map(function(it) {
@@ -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,
@@ -0,0 +1,96 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ const STEP = 8;
4
+ function useHideOnScroll(enabled, el, media, from) {
5
+ const st = React.useState(false), hidden = st[0], setHidden = st[1];
6
+ React.useEffect(
7
+ function() {
8
+ if (!enabled || typeof window === "undefined") {
9
+ setHidden(false);
10
+ return;
11
+ }
12
+ const mq = window.matchMedia ? window.matchMedia(media) : null;
13
+ let last = window.scrollY, lastH = window.innerHeight, resizedAt = -1e9, run = 0;
14
+ let restore = null;
15
+ function update() {
16
+ if (restore) {
17
+ const r = restore;
18
+ if (performance.now() > r.until || window.scrollY >= r.y - 1) restore = null;
19
+ else {
20
+ restore = null;
21
+ last = r.y;
22
+ window.scrollTo(window.scrollX, r.y);
23
+ return;
24
+ }
25
+ }
26
+ const y = window.scrollY, dy = y - last;
27
+ last = y;
28
+ const node2 = el.current;
29
+ if (mq && !mq.matches || y <= from || node2 && document.activeElement && node2.contains(document.activeElement)) {
30
+ run = 0;
31
+ setHidden(false);
32
+ return;
33
+ }
34
+ if (window.innerHeight !== lastH || performance.now() - resizedAt < 150) {
35
+ lastH = window.innerHeight;
36
+ resizedAt = performance.now();
37
+ run = 0;
38
+ return;
39
+ }
40
+ if (y + window.innerHeight > document.documentElement.scrollHeight + 1) return;
41
+ run = dy > 0 === run > 0 ? run + dy : dy;
42
+ if (run > STEP) setHidden(true);
43
+ else if (run < -STEP) setHidden(false);
44
+ }
45
+ let tabbing = false;
46
+ function disarm() {
47
+ restore = null;
48
+ }
49
+ function onKey(e) {
50
+ if (e.key !== "Tab" && e.code !== "Tab") {
51
+ if (e.key !== "Shift") restore = null;
52
+ return;
53
+ }
54
+ tabbing = true;
55
+ requestAnimationFrame(function() {
56
+ tabbing = false;
57
+ });
58
+ }
59
+ function reveal() {
60
+ const n = el.current;
61
+ if (n && n.classList.contains("is-away")) {
62
+ n.classList.remove("is-away");
63
+ if (tabbing) {
64
+ if (window.scrollY < last) window.scrollTo(window.scrollX, last);
65
+ else restore = { y: last, until: performance.now() + 400 };
66
+ }
67
+ }
68
+ setHidden(false);
69
+ }
70
+ window.addEventListener("scroll", update, { passive: true });
71
+ window.addEventListener("resize", update);
72
+ document.addEventListener("keydown", onKey, true);
73
+ window.addEventListener("wheel", disarm, { passive: true, capture: true });
74
+ window.addEventListener("touchstart", disarm, { passive: true, capture: true });
75
+ window.addEventListener("pointerdown", disarm, true);
76
+ const node = el.current;
77
+ if (node) node.addEventListener("focusin", reveal);
78
+ if (mq && mq.addEventListener) mq.addEventListener("change", update);
79
+ return function() {
80
+ window.removeEventListener("scroll", update);
81
+ window.removeEventListener("resize", update);
82
+ document.removeEventListener("keydown", onKey, true);
83
+ window.removeEventListener("wheel", disarm, true);
84
+ window.removeEventListener("touchstart", disarm, true);
85
+ window.removeEventListener("pointerdown", disarm, true);
86
+ if (node) node.removeEventListener("focusin", reveal);
87
+ if (mq && mq.removeEventListener) mq.removeEventListener("change", update);
88
+ };
89
+ },
90
+ [enabled, el, media, from]
91
+ );
92
+ return enabled && hidden;
93
+ }
94
+ export {
95
+ useHideOnScroll
96
+ };
@@ -127,6 +127,11 @@ 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",
134
+ statusUnknown: "No data",
130
135
  accepts: function(list, max) {
131
136
  return [list, max && "up to " + max + " each"].filter(Boolean).join(", ");
132
137
  }
@@ -123,6 +123,11 @@ 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",
130
+ statusUnknown: "Ingen data",
126
131
  accepts: function(list, max) {
127
132
  return [list, max && "h\xF6gst " + max + " per fil"].filter(Boolean).join(", ");
128
133
  }
@@ -123,6 +123,11 @@ 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",
130
+ statusUnknown: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25",
126
131
  accepts: function(list, max) {
127
132
  return [list, max && "\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 " + max + " \u0E15\u0E48\u0E2D\u0E44\u0E1F\u0E25\u0E4C"].filter(Boolean).join(" \xB7 ");
128
133
  }
@@ -0,0 +1,220 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { Icon } from "./Icon.js";
4
+ import { cx, devWarnOnce } from "./classes.js";
5
+ import { respVars } from "./breakpoints.js";
6
+ import { STRINGS } from "./strings.js";
7
+ import { IconCircleAlert, IconCircleCheck, IconCircleDotDashed, 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
+ unknown: IconCircleDotDashed
15
+ };
16
+ const STATUS_TONE = {
17
+ down: "danger",
18
+ problem: "warning",
19
+ maintenance: "accent",
20
+ ok: "default",
21
+ unknown: "default"
22
+ };
23
+ const STATUS_WORD = {
24
+ down: "statusDown",
25
+ problem: "statusProblem",
26
+ maintenance: "statusMaintenance",
27
+ ok: "statusOk",
28
+ unknown: "statusUnknown"
29
+ };
30
+ function statusWord(status, t) {
31
+ return String(t[STATUS_WORD[status]] || STATUS_WORD[status]);
32
+ }
33
+ function attrs(props) {
34
+ const out = {};
35
+ Object.keys(props).forEach(function(k) {
36
+ if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k))
37
+ out[k] = props[k];
38
+ });
39
+ return out;
40
+ }
41
+ const comma = h("span", { className: "aura-status-tile__sep" }, ",");
42
+ function statusTileElement(props, ref, Link, t, titleRef) {
43
+ const status = STATUS_ICON[props.status] ? props.status : "unknown";
44
+ if (status !== props.status)
45
+ devWarnOnce(
46
+ "status-tile-status-" + String(props.status),
47
+ 'StatusTile status="' + String(props.status) + '" is not down, problem, maintenance, ok or unknown: it shows as unknown ("No data"). Map your value first.'
48
+ );
49
+ const valueTone = props.valueTone || STATUS_TONE[status];
50
+ const word = props.statusLabel || statusWord(status, t);
51
+ const markers = (props.markers || []).filter(Boolean);
52
+ const has = function(v) {
53
+ return v != null && v !== false && v !== "";
54
+ };
55
+ const hasValue = has(props.value), hasMeta = has(props.meta);
56
+ const Tag = props.href ? Link : "div";
57
+ return h(
58
+ Tag,
59
+ Object.assign(attrs(props), {
60
+ ref,
61
+ href: props.href,
62
+ className: cx("aura-status-tile", "aura-status-tile--" + status, props.href && "is-interactive", props.className)
63
+ }),
64
+ h(
65
+ "span",
66
+ { className: "aura-status-tile__head" },
67
+ h(Icon, { name: h(STATUS_ICON[status]), size: 16, className: "aura-status-tile__icon" }),
68
+ h("span", { className: "aura-status-tile__title", ref: titleRef }, props.title, comma),
69
+ h("span", { className: "aura-sr-only" }, word + (hasValue || hasMeta || markers.length ? "," : "")),
70
+ hasValue ? h(
71
+ "span",
72
+ { className: cx("aura-status-tile__value", "is-" + valueTone) },
73
+ props.value,
74
+ hasMeta || markers.length ? comma : null
75
+ ) : null
76
+ ),
77
+ hasMeta || markers.length ? h(
78
+ "span",
79
+ { className: "aura-status-tile__foot" },
80
+ hasMeta ? h("span", { className: "aura-status-tile__meta" }, props.meta, markers.length ? comma : null) : null,
81
+ markers.length ? h(
82
+ "span",
83
+ { className: "aura-status-tile__markers" },
84
+ markers.map(function(m, i) {
85
+ return h(
86
+ "span",
87
+ {
88
+ key: i,
89
+ className: cx("aura-status-tile__marker", "is-" + (m.tone || "neutral")),
90
+ "data-aura-tip": m.label
91
+ },
92
+ h(Icon, { name: m.icon, size: 14 }),
93
+ h("span", { className: "aura-sr-only" }, m.label + (i < markers.length - 1 ? "," : ""))
94
+ );
95
+ })
96
+ ) : null
97
+ ) : null
98
+ );
99
+ }
100
+ function ServerStatusTile(props) {
101
+ return statusTileElement(props, void 0, props.linkComponent || "a", STRINGS.en);
102
+ }
103
+ const TileGrid = React.forwardRef(function TileGrid2(props, ref) {
104
+ const style = Object.assign(
105
+ {},
106
+ respVars("aura-grid-cols", props.columns == null ? { base: 2, md: 3 } : props.columns),
107
+ props.style
108
+ );
109
+ return h(
110
+ "ul",
111
+ Object.assign(attrs(props), {
112
+ ref,
113
+ role: "list",
114
+ className: cx("aura-grid-layout", "aura-tile-grid", props.className),
115
+ style
116
+ }),
117
+ /* toArray drops null and booleans and keys each element; a Fragment's children are items too. */
118
+ flat(props.children).map(function(c, i) {
119
+ return h("li", { key: React.isValidElement(c) && c.key != null ? c.key : i }, c);
120
+ })
121
+ );
122
+ });
123
+ function flat(children) {
124
+ const out = [];
125
+ React.Children.toArray(children).forEach(function(c) {
126
+ if (React.isValidElement(c) && c.type === React.Fragment)
127
+ flat(c.props.children).forEach(function(x) {
128
+ out.push(React.isValidElement(x) ? React.cloneElement(x, { key: String(c.key) + "/" + String(x.key) }) : x);
129
+ });
130
+ else if (c !== "") out.push(c);
131
+ });
132
+ return out;
133
+ }
134
+ const SIZES = { sm: [80, 24], md: [120, 32] };
135
+ const PAD = 2;
136
+ function r(n) {
137
+ return Math.round(n * 100) / 100;
138
+ }
139
+ function num(v) {
140
+ return typeof v === "number" && isFinite(v) ? v : null;
141
+ }
142
+ const Sparkline = React.forwardRef(function Sparkline2(props, ref) {
143
+ const wh = SIZES[props.size || "sm"] || SIZES.sm;
144
+ const W = wh[0], H = wh[1];
145
+ const data = (props.data || []).map(num);
146
+ const n = data.length;
147
+ const vals = data.filter(function(v) {
148
+ return v != null;
149
+ });
150
+ let lo = num(props.min), hi = num(props.max);
151
+ if (lo == null) lo = vals.length ? Math.min.apply(null, vals) : 0;
152
+ if (hi == null) hi = vals.length ? Math.max.apply(null, vals) : 0;
153
+ if (lo > hi) {
154
+ const s = lo;
155
+ lo = hi;
156
+ hi = s;
157
+ }
158
+ const step = n > 1 ? (W - 2 * PAD) / (n - 1) : 0;
159
+ const x = function(i) {
160
+ return n > 1 ? PAD + i * step : W / 2;
161
+ };
162
+ const y = function(v) {
163
+ if (hi === lo) return H / 2;
164
+ const k = Math.max(0, Math.min(1, (v - lo) / (hi - lo)));
165
+ return H - PAD - k * (H - 2 * PAD);
166
+ };
167
+ let d = "";
168
+ const dots = [];
169
+ data.forEach(function(v, i) {
170
+ if (v == null) return;
171
+ const prev = i > 0 && data[i - 1] != null, next = i < n - 1 && data[i + 1] != null;
172
+ if (!prev && !next) dots.push(h("circle", { key: "d" + i, cx: r(x(i)), cy: r(y(v)), r: 1.5 }));
173
+ else d += (prev ? "L" : "M") + r(x(i)) + " " + r(y(v));
174
+ });
175
+ const mode = props.failures || "none";
176
+ const fails = [];
177
+ if (mode !== "none" && props.failed)
178
+ data.forEach(function(_v, i) {
179
+ if (!props.failed[i]) return;
180
+ if (mode === "band") {
181
+ const w = Math.max(2, step || W), left = Math.max(0, x(i) - w / 2), right = Math.min(W, x(i) + w / 2);
182
+ fails.push(h("rect", { key: "f" + i, x: r(left), y: 0, width: r(right - left), height: H }));
183
+ } else
184
+ fails.push(
185
+ h("rect", {
186
+ key: "f" + i,
187
+ x: r(Math.max(0, Math.min(W - 1.5, x(i) - 0.75))),
188
+ y: H - 6,
189
+ width: 1.5,
190
+ height: 6
191
+ })
192
+ );
193
+ });
194
+ const named = !!props.label;
195
+ return h(
196
+ "svg",
197
+ Object.assign(attrs(props), {
198
+ ref,
199
+ className: cx("aura-sparkline", "is-" + (props.tone || "neutral"), props.className),
200
+ width: W,
201
+ height: H,
202
+ viewBox: "0 0 " + W + " " + H,
203
+ role: named ? "img" : void 0,
204
+ "aria-label": named ? props.label : void 0,
205
+ "aria-hidden": named ? void 0 : true,
206
+ focusable: "false"
207
+ }),
208
+ fails.length && mode === "band" ? h("g", { className: "aura-sparkline__band" }, fails) : null,
209
+ d ? h("path", { className: "aura-sparkline__line", d }) : null,
210
+ dots.length ? h("g", { className: "aura-sparkline__dots" }, dots) : null,
211
+ fails.length && mode === "ticks" ? h("g", { className: "aura-sparkline__ticks" }, fails) : null
212
+ );
213
+ });
214
+ export {
215
+ ServerStatusTile,
216
+ Sparkline,
217
+ TileGrid,
218
+ statusTileElement,
219
+ statusWord
220
+ };