@protobase/ui 0.19.4 → 0.19.5

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.
Files changed (55) hide show
  1. package/dist/account/backup-codes.js +2 -9
  2. package/dist/app/displays/list-displays.js +2 -1
  3. package/dist/app/filled-fields.js +5 -0
  4. package/dist/app/gallery/details-open-storage.js +10 -0
  5. package/dist/app/gallery/gallery-layout.js +3 -1
  6. package/dist/app/gallery/lightbox.js +107 -61
  7. package/dist/app/import/convert.js +151 -0
  8. package/dist/app/import/csv-parser.js +119 -0
  9. package/dist/app/import/failed-rows.js +21 -0
  10. package/dist/app/import/import-button.js +31 -0
  11. package/dist/app/import/import-check-step.js +123 -0
  12. package/dist/app/import/import-counts.js +19 -0
  13. package/dist/app/import/import-dialog.js +152 -0
  14. package/dist/app/import/import-file-step.js +65 -0
  15. package/dist/app/import/import-mapping-step.js +195 -0
  16. package/dist/app/import/import-result-step.js +86 -0
  17. package/dist/app/import/import-select.js +35 -0
  18. package/dist/app/import/locale-formats.js +15 -0
  19. package/dist/app/import/lookups.js +48 -0
  20. package/dist/app/import/mapping.js +78 -0
  21. package/dist/app/import/parse-worker.d.ts +1 -0
  22. package/dist/app/import/parse-worker.js +39 -0
  23. package/dist/app/import/prepare-rows.js +129 -0
  24. package/dist/app/import/run-import.js +130 -0
  25. package/dist/app/import/sheet-cell.js +17 -0
  26. package/dist/app/import/sheet-file.js +58 -0
  27. package/dist/app/import/sheet-source.js +72 -0
  28. package/dist/app/import/use-import-flow.js +225 -0
  29. package/dist/app/import/xlsx-reader.js +43 -0
  30. package/dist/app/import/xlsx-xml.js +169 -0
  31. package/dist/app/import/zip-reader.js +72 -0
  32. package/dist/app/list-page.js +8 -1
  33. package/dist/app/named-icon.js +9 -1
  34. package/dist/app/record-page.js +11 -2
  35. package/dist/auth/sign-in-prompt.js +1 -1
  36. package/dist/data/api-provider.js +8 -2
  37. package/dist/lib/save-file.js +12 -0
  38. package/dist/lib/use-focus-trap.js +7 -1
  39. package/dist/package.js +1 -1
  40. package/dist/primitives/sheet-swipe.js +5 -0
  41. package/dist/primitives/sheet.js +40 -12
  42. package/dist/record-view/key-facts.js +29 -0
  43. package/dist/shell/assets/app-CZ4drn7G.js +67 -0
  44. package/dist/shell/assets/index-BoeKjvo8.css +2 -0
  45. package/dist/shell/assets/{index-CEvfMgFJ.js → index-BzCCIfII.js} +1 -1
  46. package/dist/shell/assets/{maplibre-D6zfLfTV.js → maplibre-BOsAtlAo.js} +1 -1
  47. package/dist/shell/assets/parse-worker-BtcY0dQw.js +5 -0
  48. package/dist/shell/assets/{record-map-B6_rbCcG.js → record-map-BK_02Lmk.js} +1 -1
  49. package/dist/shell/assets/{records-map-bQbuIc13.js → records-map-Dn72A_l-.js} +1 -1
  50. package/dist/shell/assets/{shared-protobase-ui-8pJgwjfc.js → shared-protobase-ui-B6lrj7eA.js} +1 -1
  51. package/dist/shell/index.html +4 -4
  52. package/dist/shell/protobase.shell.json +1 -1
  53. package/package.json +4 -4
  54. package/dist/shell/assets/app-BYFiTXK6.js +0 -66
  55. package/dist/shell/assets/index-CiGP6kle.css +0 -2
@@ -2,9 +2,11 @@ import { lockPageScroll } from "./page-scroll-lock.js";
2
2
  import { useEffect, useRef } from "react";
3
3
  //#region src/lib/use-focus-trap.ts
4
4
  const focusable = "a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
5
+ const stack = [];
5
6
  /**
6
7
  * While `active`: moves focus into `container`, keeps Tab inside it, locks page scrolling (see `lockPageScroll`),
7
- * calls `onEscape` on Escape, and returns focus to the previously focused element afterwards.
8
+ * calls `onEscape` on Escape, and returns focus to the previously focused element afterwards. A trap opened while
9
+ * another is active takes Tab and Escape until it ends.
8
10
  */
9
11
  const useFocusTrap = (container, active, onEscape) => {
10
12
  const escape = useRef(onEscape);
@@ -14,9 +16,12 @@ const useFocusTrap = (container, active, onEscape) => {
14
16
  const root = container.current;
15
17
  const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
16
18
  const unlock = lockPageScroll();
19
+ const token = {};
20
+ stack.push(token);
17
21
  const items = () => [...root.querySelectorAll(focusable)];
18
22
  (items()[0] ?? root).focus();
19
23
  const onKey = (event) => {
24
+ if (stack.at(-1) !== token) return;
20
25
  if (event.key === "Escape") return escape.current();
21
26
  if (event.key !== "Tab") return;
22
27
  const list = items();
@@ -37,6 +42,7 @@ const useFocusTrap = (container, active, onEscape) => {
37
42
  document.addEventListener("keydown", onKey);
38
43
  return () => {
39
44
  document.removeEventListener("keydown", onKey);
45
+ stack.splice(stack.indexOf(token), 1);
40
46
  unlock();
41
47
  previous?.focus();
42
48
  };
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.19.4";
2
+ var version = "0.19.5";
3
3
  var protobase = { "pluginApi": 1 };
4
4
  //#endregion
5
5
  export { protobase, version };
@@ -0,0 +1,5 @@
1
+ //#region src/primitives/sheet-swipe.ts
2
+ /** Whether a drag closes a sheet: mostly downwards, by 60 pixels or more. */
3
+ const closesSheet = (dx, dy) => dy >= 60 && dy > Math.abs(dx);
4
+ //#endregion
5
+ export { closesSheet };
@@ -1,13 +1,31 @@
1
1
  import { useFocusTrap } from "../lib/use-focus-trap.js";
2
+ import { closesSheet } from "./sheet-swipe.js";
2
3
  import { useRef } from "react";
3
4
  import { X } from "lucide-react";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
6
  //#region src/primitives/sheet.tsx
6
- /** A panel that rises from the bottom of the screen, for the filter panel on phones. */
7
+ /**
8
+ * A panel that rises from the bottom of the screen, for the filter panel on mobile screens. It closes on Escape, the
9
+ * close button, a press above it and a swipe down on its header. Its content scrolls inside it when taller than the
10
+ * panel, which stops short of the top so the screen behind stays in sight.
11
+ */
7
12
  const Sheet = ({ title, open, onClose, children }) => {
8
13
  const panel = useRef(null);
14
+ const start = useRef(void 0);
9
15
  useFocusTrap(panel, open, onClose);
10
16
  if (!open) return null;
17
+ const down = (event) => {
18
+ if (event.pointerType === "touch") start.current = {
19
+ x: event.clientX,
20
+ y: event.clientY
21
+ };
22
+ };
23
+ const up = (event) => {
24
+ if (!start.current) return;
25
+ const closes = closesSheet(event.clientX - start.current.x, event.clientY - start.current.y);
26
+ start.current = void 0;
27
+ if (closes) onClose();
28
+ };
11
29
  return /* @__PURE__ */ jsxs("div", {
12
30
  className: "fixed inset-0 z-[80]",
13
31
  children: [/* @__PURE__ */ jsx("div", {
@@ -22,17 +40,27 @@ const Sheet = ({ title, open, onClose, children }) => {
22
40
  tabIndex: -1,
23
41
  className: "absolute inset-x-0 bottom-0 flex max-h-[85vh] flex-col rounded-t-xl border-t bg-background shadow-pop outline-none",
24
42
  children: [/* @__PURE__ */ jsxs("header", {
25
- className: "flex shrink-0 items-center justify-between border-b px-4",
26
- children: [/* @__PURE__ */ jsx("h2", {
27
- className: "text-[15px] font-semibold",
28
- children: title
29
- }), /* @__PURE__ */ jsx("button", {
30
- type: "button",
31
- "aria-label": "Close",
32
- onClick: onClose,
33
- className: "-mr-2 inline-flex size-11 items-center justify-center rounded-md text-muted-foreground hover:bg-muted",
34
- children: /* @__PURE__ */ jsx(X, { className: "size-5" })
35
- })]
43
+ className: "relative flex shrink-0 touch-none items-center justify-between border-b px-4",
44
+ onPointerDown: down,
45
+ onPointerUp: up,
46
+ onPointerCancel: () => start.current = void 0,
47
+ children: [
48
+ /* @__PURE__ */ jsx("span", {
49
+ className: "absolute left-1/2 top-1.5 h-1 w-9 -translate-x-1/2 rounded-full bg-border-strong",
50
+ "aria-hidden": true
51
+ }),
52
+ /* @__PURE__ */ jsx("h2", {
53
+ className: "text-[15px] font-semibold",
54
+ children: title
55
+ }),
56
+ /* @__PURE__ */ jsx("button", {
57
+ type: "button",
58
+ "aria-label": "Close",
59
+ onClick: onClose,
60
+ className: "-mr-2 inline-flex size-11 items-center justify-center rounded-md text-muted-foreground hover:bg-muted",
61
+ children: /* @__PURE__ */ jsx(X, { className: "size-5" })
62
+ })
63
+ ]
36
64
  }), /* @__PURE__ */ jsx("div", {
37
65
  className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 pb-6",
38
66
  children
@@ -0,0 +1,29 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ //#region src/record-view/key-facts.tsx
3
+ /**
4
+ * A record's key facts side by side, as the bedrooms, area and energy label of a listing on a real estate site: each
5
+ * value under its icon, or under its label without one, wrapping onto more rows as needed, two to a row on a mobile
6
+ * screen.
7
+ */
8
+ const KeyFacts = ({ facts }) => /* @__PURE__ */ jsx("dl", {
9
+ className: "grid grid-cols-2 gap-x-4 gap-y-5 text-[13px] sm:flex sm:flex-wrap sm:gap-x-10",
10
+ children: facts.map(({ label, value, icon: Icon }) => /* @__PURE__ */ jsxs("div", {
11
+ title: label,
12
+ className: "flex min-w-0 flex-col gap-1.5",
13
+ children: [/* @__PURE__ */ jsx("dt", {
14
+ className: "text-muted-foreground",
15
+ children: Icon ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, {
16
+ className: "size-5",
17
+ "aria-hidden": true
18
+ }), /* @__PURE__ */ jsx("span", {
19
+ className: "sr-only",
20
+ children: label
21
+ })] }) : label
22
+ }), /* @__PURE__ */ jsx("dd", {
23
+ className: "min-w-0 break-words text-[15px] font-semibold text-foreground",
24
+ children: value
25
+ })]
26
+ }, label))
27
+ });
28
+ //#endregion
29
+ export { KeyFacts };