@jirawatpyk/aura-react 5.1.1 → 5.3.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.
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
- import { useStrings } from "./locale.js";
3
+ import { useStrings, useDensity } from "./locale.js";
4
4
  import { createPortal } from "react-dom";
5
5
  import { cx, uid, useMaybeControlled, useMounted, useIsoLayoutEffect, useMergedRef } from "./internal.js";
6
6
  import { Icon } from "./Icon.js";
@@ -24,6 +24,7 @@ const Combobox = React.forwardRef(
24
24
  const multi = all.multiple === true;
25
25
  const mp = all;
26
26
  const t = useStrings();
27
+ const density = useDensity();
27
28
  const auto = uid(), id = props.id || auto, listId = id + "-list";
28
29
  const options = (props.options || []).map(toOpt);
29
30
  const st = useMaybeControlled(
@@ -187,7 +188,7 @@ const Combobox = React.forwardRef(
187
188
  return id + "-opt-" + i;
188
189
  };
189
190
  const list = open && mounted && posState[0] ? createPortal(
190
- /* @__PURE__ */ React.createElement("div", { ref: listRef, className: "aura-combo__popover", style: posState[0] }, live.length ? /* @__PURE__ */ React.createElement(
191
+ /* @__PURE__ */ React.createElement("div", { ref: listRef, "data-density": density, className: "aura-combo__popover", style: posState[0] }, live.length ? /* @__PURE__ */ React.createElement(
191
192
  "ul",
192
193
  {
193
194
  id: listId,
@@ -243,11 +243,12 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
243
243
  if (lv && boxWidth[0] == null) hideTerms += " + " + w + "px * var(--aura-h" + lv + "-on, 1)";
244
244
  else fixedSum += w;
245
245
  });
246
- let pinOffsets = {}, acc = 0;
246
+ let pinOffsets = {}, acc = "0px";
247
247
  vis.forEach(function(c) {
248
248
  if (isPinned(c)) {
249
249
  pinOffsets[c.key] = acc;
250
- acc += widthOf(c);
250
+ const lv = hideLevel(c);
251
+ acc += " + " + widthOf(c) + "px" + (lv && boxWidth[0] == null ? " * var(--aura-h" + lv + "-on, 1)" : "");
251
252
  }
252
253
  });
253
254
  const selW = selectable ? " + var(--aura-table-select-width)" : "";
@@ -262,7 +263,7 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
262
263
  s["--aura-cell-flex"] = !hasFlex && i === vis.length - 1 ? "1 0 auto" : "none";
263
264
  s["--aura-cell-w"] = w + "px";
264
265
  }
265
- if (isPinned(c)) s["--aura-cell-left"] = "calc(var(--aura-space-6)" + selW + " + " + pinOffsets[c.key] + "px)";
266
+ if (isPinned(c)) s["--aura-cell-left"] = "calc(var(--aura-space-6)" + selW + " + " + pinOffsets[c.key] + ")";
266
267
  return s;
267
268
  }
268
269
  const sortCol = sort && sort.key ? byKey[sort.key] : void 0;
@@ -308,6 +309,20 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
308
309
  const pageRows = pageSize && !manual ? view.slice(first, first + pageSize) : view;
309
310
  const canSortAny = !busy && (manual ? total > 1 : rows.length > 1);
310
311
  const shownTotal = manual && props.totalRows == null ? first + rows.length : total;
312
+ const prevCount = React.useRef(pageCount);
313
+ React.useEffect(
314
+ function() {
315
+ if (busy) return;
316
+ const before = prevCount.current;
317
+ prevCount.current = pageCount;
318
+ const asked = pageState[0] || 1;
319
+ if (asked === page || pageCount >= before || asked > before) return;
320
+ if (props.getPageHref && !props.onPageChange && !props.onStateChange) return;
321
+ pageState[1](page);
322
+ emit(sort, page);
323
+ },
324
+ [pageState[0], page, busy, pageCount]
325
+ );
311
326
  const linkPaging = !!props.getPageHref && !props.onPageChange && !oneCallback;
312
327
  const prevLink = React.useRef(null), nextLink = React.useRef(null), jumpLink = React.useRef(null);
313
328
  const jumpState = React.useState(null);
@@ -376,9 +391,10 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
376
391
  const visibleRows = Math.max(1, Math.floor(bodyH / ROW_H));
377
392
  const nCols = vis.length + (selectable ? 1 : 0);
378
393
  const nRows = loading ? 0 : pageRows.length;
394
+ const hasTotal = !!(props.footer && rows.length && !loading), T = nRows + 1, lastR = nRows + (hasTotal ? 1 : 0);
379
395
  const active = activeState[0];
380
- const ar = Math.min(active.r, nRows), ac = Math.min(active.c, nCols - 1);
381
- const activeRendered = ar === 0 || ar - 1 >= start && ar - 1 < end;
396
+ const ar = Math.min(active.r, lastR), ac = Math.min(active.c, nCols - 1);
397
+ const activeRendered = ar === 0 || hasTotal && ar === T || ar - 1 >= start && ar - 1 < end;
382
398
  function colAt(ci) {
383
399
  return selectable ? ci === 0 ? null : vis[ci - 1] : vis[ci];
384
400
  }
@@ -409,12 +425,33 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
409
425
  }
410
426
  });
411
427
  function focusCell(r, c) {
412
- r = Math.max(0, Math.min(r, nRows));
428
+ r = Math.max(0, Math.min(r, lastR));
413
429
  c = Math.max(0, Math.min(c, nCols - 1));
414
430
  if (stacked && r === 0 && nRows > 0 && !(selectable && c === 0)) r = 1;
431
+ if (gridRef.current && r === T && hasTotal) {
432
+ const shown2 = function(cc) {
433
+ const e = gridRef.current.querySelector('[data-rc="' + r + ":" + cc + '"]');
434
+ return !!e && e.getClientRects().length > 0;
435
+ };
436
+ if (!shown2(c))
437
+ for (let d = 1; d < nCols; d++) {
438
+ if (c + d < nCols && shown2(c + d)) {
439
+ c = c + d;
440
+ break;
441
+ }
442
+ if (c - d >= 0 && shown2(c - d)) {
443
+ c = c - d;
444
+ break;
445
+ }
446
+ }
447
+ }
415
448
  activeState[1]({ r, c });
416
449
  pending.current = { r, c };
417
- if (virtual && r > 0) {
450
+ if (virtual && hasTotal && r === T && !props.stickyFooter) {
451
+ const sc = scrollRef.current;
452
+ sc.scrollTop = sc.scrollHeight;
453
+ setScrollTop(sc.scrollTop);
454
+ } else if (virtual && r > 0 && r <= nRows) {
418
455
  const sc = scrollRef.current, top = (r - 1) * ROW_H;
419
456
  if (top < sc.scrollTop) sc.scrollTop = top;
420
457
  else if (top + ROW_H > sc.scrollTop + bodyH) sc.scrollTop = top + ROW_H - bodyH;
@@ -657,7 +694,7 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
657
694
  return;
658
695
  }
659
696
  const p = rc.split(":"), r = +p[0], c = +p[1], k = e.key, col = colAt(c);
660
- const row = r > 0 ? pageRows[r - 1] : null;
697
+ const row = r > 0 && r <= nRows ? pageRows[r - 1] : null, isTotal = hasTotal && r === T;
661
698
  let handled = true;
662
699
  if (r === 0 && col && e.altKey && (k === "ArrowLeft" || k === "ArrowRight") && canResize(col))
663
700
  setW(col, widthOf(col) + (k === "ArrowLeft" ? -1 : 1) * (e.shiftKey ? 48 : 16), true);
@@ -668,21 +705,23 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
668
705
  else if (k === "ArrowRight") focusCell(r, c + 1);
669
706
  else if (k === "ArrowLeft") focusCell(r, c - 1);
670
707
  else if (k === "ArrowDown") {
671
- if (r < nRows) focusCell(r + 1, c);
708
+ if (r < lastR) focusCell(r + 1, c);
672
709
  else if (pageSize && page < pageCount && goPage(page + 1, { r: 1, c })) activeState[1]({ r: 1, c });
673
710
  } else if (k === "ArrowUp") {
674
711
  if (r > 1 || r === 1 && !(pageSize && page > 1)) focusCell(r - 1, c);
675
712
  else if (r === 1 && goPage(page - 1, { r: pageSize, c })) activeState[1]({ r: pageSize, c });
676
713
  } else if (k === "Home") focusCell(e.ctrlKey ? 1 : r, 0);
677
- else if (k === "End") focusCell(e.ctrlKey ? nRows : r, nCols - 1);
714
+ else if (k === "End") focusCell(e.ctrlKey ? lastR : r, nCols - 1);
678
715
  else if (k === "PageDown") {
679
716
  if (pageSize) {
680
717
  if (goPage(page + 1, { r: 1, c })) activeState[1]({ r: 1, c });
681
- } else focusCell(Math.min(nRows, r + visibleRows), c);
718
+ } else focusCell(Math.min(lastR, r + visibleRows), c);
682
719
  } else if (k === "PageUp") {
683
720
  if (pageSize) {
684
721
  if (goPage(page - 1, { r: 1, c })) activeState[1]({ r: 1, c });
685
722
  } else focusCell(Math.max(1, r - visibleRows), c);
723
+ } else if (isTotal && (k === " " || k === "Enter" || k === "F2")) {
724
+ handled = false;
686
725
  } else if (k === "F2" && r > 0) {
687
726
  const inner = target.querySelector("button, a[href], input, select, textarea");
688
727
  if (inner) inner.focus();
@@ -1053,9 +1092,10 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
1053
1092
  }
1054
1093
  );
1055
1094
  }
1095
+ const openTotal = manual && props.totalRows == null && !!pageSize && rows.length >= pageSize;
1056
1096
  if (pageSize && (rows.length || busy || page > 1)) {
1057
1097
  const from = rows.length ? first + 1 : 0, to = manual ? first + rows.length : Math.min(first + pageSize, view.length);
1058
- foot = /* @__PURE__ */ React.createElement("div", { className: "aura-table__foot" }, /* @__PURE__ */ React.createElement("span", { "aria-live": "polite" }, busy ? t.loading : t.range(from, to, shownTotal)), /* @__PURE__ */ React.createElement("span", { className: "aura-table__pager" }, /* @__PURE__ */ React.createElement("span", null, t.page(page, pageCount)), pagerButton(-1), pagerButton(1)));
1098
+ foot = /* @__PURE__ */ React.createElement("div", { className: "aura-table__foot" }, /* @__PURE__ */ React.createElement("span", { "aria-live": "polite" }, busy ? t.loading : openTotal ? t.rangeOpen(from, to) : t.range(from, to, shownTotal)), /* @__PURE__ */ React.createElement("span", { className: "aura-table__pager" }, /* @__PURE__ */ React.createElement("span", null, openTotal ? t.pageOpen(page) : t.page(page, pageCount)), pagerButton(-1), pagerButton(1)));
1059
1099
  } else if (height && rows.length && !loading) {
1060
1100
  foot = /* @__PURE__ */ React.createElement("div", { className: "aura-table__foot" }, /* @__PURE__ */ React.createElement("span", null, t.rowCount(shownTotal)), selectable && selected.length ? /* @__PURE__ */ React.createElement("span", null, t.selectedCount(selected.length)) : /* @__PURE__ */ React.createElement("span", null));
1061
1101
  }
@@ -1069,15 +1109,32 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
1069
1109
  style: rowStyle
1070
1110
  },
1071
1111
  /* @__PURE__ */ React.createElement("span", { className: "aura-table__gutter", "aria-hidden": true }),
1072
- selectable ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-table__sel", nPinned && "is-pinned"), "aria-hidden": true }) : null,
1112
+ selectable ? /* @__PURE__ */ React.createElement(
1113
+ "span",
1114
+ {
1115
+ role: "gridcell",
1116
+ "aria-colindex": 1,
1117
+ className: cx("aura-table__sel", nPinned && "is-pinned"),
1118
+ tabIndex: tabFor(T, 0),
1119
+ "data-rc": T + ":0",
1120
+ onFocus: function() {
1121
+ activeState[1]({ r: T, c: 0 });
1122
+ }
1123
+ }
1124
+ ) : null,
1073
1125
  vis.map(function(c, j) {
1074
- const pin = isPinned(c);
1126
+ const pin = isPinned(c), ci = j + (selectable ? 1 : 0);
1075
1127
  return /* @__PURE__ */ React.createElement(
1076
1128
  "span",
1077
1129
  {
1078
1130
  key: c.key,
1079
1131
  role: "gridcell",
1080
1132
  "aria-colindex": j + (selectable ? 2 : 1),
1133
+ tabIndex: tabFor(T, ci),
1134
+ "data-rc": T + ":" + ci,
1135
+ onFocus: function() {
1136
+ if (activeState[0].r !== T || activeState[0].c !== ci) activeState[1]({ r: T, c: ci });
1137
+ },
1081
1138
  className: cx(
1082
1139
  "aura-table__td",
1083
1140
  c.mono && "aura-table__mono",
@@ -1103,7 +1160,7 @@ const DataTable = React.forwardRef(function DataTable2(props, ref) {
1103
1160
  )
1104
1161
  ) : null;
1105
1162
  const scrollStyle = {
1106
- scrollPaddingLeft: "calc(var(--aura-space-6)" + selW + " + " + acc + "px)",
1163
+ scrollPaddingLeft: "calc(var(--aura-space-6)" + selW + " + " + acc + ")",
1107
1164
  scrollPaddingTop: ROW_H + "px",
1108
1165
  scrollPaddingBottom: stickyTotal ? ROW_H + "px" : void 0
1109
1166
  };
@@ -294,16 +294,16 @@ function useCalendarPopover(boxRef) {
294
294
  const pos = React.useState(null), popRef = React.useRef(null), mounted = useMounted();
295
295
  function place() {
296
296
  if (!boxRef.current) return;
297
- const r = boxRef.current.getBoundingClientRect(), H = 380;
298
- const up = window.innerHeight - r.bottom < H && r.top > H;
299
- const left = Math.max(8, Math.min(r.left, window.innerWidth - 320 - 8));
297
+ const el = popRef.current, r = boxRef.current.getBoundingClientRect(), W = el ? el.offsetWidth : 320, H = el ? el.offsetHeight : 380;
298
+ const up = window.innerHeight - r.bottom < H + 12 && r.top > H + 12;
299
+ const left = Math.max(8, Math.min(r.left, window.innerWidth - W - 8));
300
300
  pos[1](up ? { left, bottom: window.innerHeight - r.top + 4 } : { left, top: r.bottom + 4 });
301
301
  }
302
302
  useIsoLayoutEffect(
303
303
  function() {
304
304
  if (open) place();
305
305
  },
306
- [open]
306
+ [open, !!pos[0]]
307
307
  );
308
308
  React.useEffect(
309
309
  function() {
@@ -62,6 +62,7 @@ const FileUpload = React.forwardRef(function FileUpload2(props, ref) {
62
62
  [items, props.name]
63
63
  );
64
64
  function thumb(it) {
65
+ if (!it.file && it.url && /^image\//.test(it.type || "")) return it.url;
65
66
  if (!it.file || !/^image\//.test(it.type || "") || typeof URL === "undefined" || !URL.createObjectURL) return null;
66
67
  if (!urls.current[it.id]) urls.current[it.id] = URL.createObjectURL(it.file);
67
68
  return urls.current[it.id];
@@ -167,7 +168,7 @@ const FileUpload = React.forwardRef(function FileUpload2(props, ref) {
167
168
  ),
168
169
  items.length ? /* @__PURE__ */ React.createElement("ul", { className: "aura-upload__list", "aria-live": "polite" }, items.map(function(it) {
169
170
  const src = thumb(it);
170
- return /* @__PURE__ */ React.createElement("li", { key: it.id, className: cx("aura-upload__item", it.error && "is-error") }, src ? /* @__PURE__ */ React.createElement("img", { className: "aura-upload__thumb", src, alt: "" }) : /* @__PURE__ */ React.createElement("span", { className: "aura-upload__thumb is-icon", "aria-hidden": true }, /* @__PURE__ */ React.createElement(Icon, { name: /^image\//.test(it.type || "") ? "image" : "file", size: "md" })), /* @__PURE__ */ React.createElement("span", { className: "aura-upload__meta" }, /* @__PURE__ */ React.createElement("span", { className: "aura-upload__name" }, it.name), /* @__PURE__ */ React.createElement("span", { className: "aura-upload__sub" }, it.error ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Icon, { name: "circle-alert", size: 12 }), it.error) : it.status === "uploading" ? t.uploading + (it.progress != null ? " " + Math.round(it.progress) + "%" : "") : it.status === "done" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Icon, { name: "circle-check", size: 12 }), formatBytes(it.size)) : formatBytes(it.size)), it.status === "uploading" ? /* @__PURE__ */ React.createElement(
171
+ return /* @__PURE__ */ React.createElement("li", { key: it.id, className: cx("aura-upload__item", it.error && "is-error") }, src ? /* @__PURE__ */ React.createElement("img", { className: "aura-upload__thumb", src, alt: "" }) : /* @__PURE__ */ React.createElement("span", { className: "aura-upload__thumb is-icon", "aria-hidden": true }, /* @__PURE__ */ React.createElement(Icon, { name: /^image\//.test(it.type || "") ? "image" : "file", size: "md" })), /* @__PURE__ */ React.createElement("span", { className: "aura-upload__meta" }, it.url && !it.error ? /* @__PURE__ */ React.createElement("a", { className: "aura-upload__name", href: it.url, target: "_blank", rel: "noreferrer" }, it.name) : /* @__PURE__ */ React.createElement("span", { className: "aura-upload__name" }, it.name), /* @__PURE__ */ React.createElement("span", { className: "aura-upload__sub" }, it.error ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Icon, { name: "circle-alert", size: 12 }), it.error) : it.status === "uploading" ? t.uploading + (it.progress != null ? " " + Math.round(it.progress) + "%" : "") : it.status === "done" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Icon, { name: "circle-check", size: 12 }), formatBytes(it.size)) : formatBytes(it.size)), it.status === "uploading" ? /* @__PURE__ */ React.createElement(
171
172
  "span",
172
173
  {
173
174
  className: "aura-upload__bar",
@@ -14,13 +14,20 @@ import {
14
14
  import { useDensity, useStrings } from "./locale.js";
15
15
  import { createPortal } from "react-dom";
16
16
  function position(anchor, pop, placement) {
17
- const r = anchor.getBoundingClientRect(), pw = pop.offsetWidth, ph = pop.offsetHeight, vw = window.innerWidth, vh = window.innerHeight, gap = 6;
17
+ const r = anchor.getBoundingClientRect(), pw = pop.offsetWidth, ph = pop.scrollHeight, vw = window.innerWidth, vh = window.innerHeight, gap = 6;
18
18
  let side = (placement || "bottom-start").split("-")[0], align = (placement || "bottom-start").split("-")[1] || "start";
19
19
  if (side === "bottom" && r.bottom + gap + ph > vh - 8 && r.top - gap - ph > 8) side = "top";
20
20
  else if (side === "top" && r.top - gap - ph < 8 && r.bottom + gap + ph < vh - 8) side = "bottom";
21
- const top = side === "top" ? r.top - gap - ph : r.bottom + gap;
21
+ const below = vh - r.bottom - gap - 8, above = r.top - gap - 8;
22
+ let maxHeight;
23
+ if (ph > below && ph > above) {
24
+ side = above > below ? "top" : "bottom";
25
+ maxHeight = Math.max(120, side === "top" ? above : below);
26
+ }
27
+ const h = maxHeight ? Math.min(ph, maxHeight) : ph;
28
+ const top = side === "top" ? r.top - gap - h : r.bottom + gap;
22
29
  const left = align === "end" ? r.right - pw : align === "center" ? r.left + r.width / 2 - pw / 2 : r.left;
23
- return { top: Math.max(8, top), left: Math.max(8, Math.min(left, vw - pw - 8)), side };
30
+ return { top: Math.max(8, top), left: Math.max(8, Math.min(left, vw - pw - 8)), side, maxHeight };
24
31
  }
25
32
  const Popover = React.forwardRef(function Popover2(props, ref) {
26
33
  const t = useStrings();
@@ -100,7 +107,11 @@ const Popover = React.forwardRef(function Popover2(props, ref) {
100
107
  },
101
108
  className: cx("aura-popover", pos[0] && "is-" + pos[0].side, props.className),
102
109
  style: Object.assign(
103
- { top: pos[0] ? pos[0].top : -9999, left: pos[0] ? pos[0].left : -9999 },
110
+ {
111
+ top: pos[0] ? pos[0].top : -9999,
112
+ left: pos[0] ? pos[0].left : -9999,
113
+ maxHeight: pos[0] && pos[0].maxHeight ? pos[0].maxHeight : void 0
114
+ },
104
115
  props.width ? { width: props.width } : null
105
116
  ),
106
117
  onKeyDown: function(e) {