@protobase/ui 0.15.4 → 0.16.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.
Files changed (92) hide show
  1. package/dist/account/two-factor-setup.js +6 -5
  2. package/dist/app/app.js +2 -1
  3. package/dist/app/create/create-page.js +1 -0
  4. package/dist/app/create/create-record-form.js +2 -1
  5. package/dist/app/displays/custom-display.js +1 -1
  6. package/dist/app/displays/map-display.js +50 -34
  7. package/dist/app/displays/map-groups.js +12 -3
  8. package/dist/app/displays/measured-heights.js +23 -0
  9. package/dist/app/displays/record-card.js +2 -2
  10. package/dist/app/displays/virtual-cards.js +12 -14
  11. package/dist/app/field-editor.js +9 -1
  12. package/dist/app/index.html +2 -2
  13. package/dist/app/list-page.js +2 -2
  14. package/dist/app/map/approximate-position.js +76 -0
  15. package/dist/app/map/area-features.js +80 -0
  16. package/dist/app/map/maplibre.js +11 -0
  17. package/dist/app/map/position-areas.js +78 -0
  18. package/dist/app/map/record-map.js +2 -7
  19. package/dist/app/map/record-position.js +5 -4
  20. package/dist/app/map/records-map.js +24 -7
  21. package/dist/app/map/theme-color.js +23 -0
  22. package/dist/app/meta-gate.js +1 -1
  23. package/dist/app/nav-recent.js +1 -1
  24. package/dist/app/pages/blocks/card-frame.js +2 -2
  25. package/dist/app/pages/blocks/grid.js +10 -2
  26. package/dist/app/pages/blocks/link.js +1 -1
  27. package/dist/app/pages/blocks/page-block.js +1 -1
  28. package/dist/app/pages/blocks/stat.js +9 -5
  29. package/dist/app/pages/field-value.js +1 -1
  30. package/dist/app/record-page.js +8 -4
  31. package/dist/app/router.js +7 -8
  32. package/dist/app/saved/saved-records.js +1 -1
  33. package/dist/app/search/search-model.js +1 -1
  34. package/dist/app/searches/use-save-search.js +4 -3
  35. package/dist/app/source-notice.js +2 -2
  36. package/dist/app/use-record-editor.js +5 -3
  37. package/dist/app-shell/app-shell.d.ts +1 -0
  38. package/dist/app-shell/app-shell.js +6 -4
  39. package/dist/app-shell/page-scroll.js +21 -4
  40. package/dist/app-shell/sidebar.d.ts +1 -0
  41. package/dist/app-shell/sidebar.js +4 -4
  42. package/dist/app-shell/top-bar.js +4 -4
  43. package/dist/auth/auth-gate.js +18 -9
  44. package/dist/auth/auth-provider.js +1 -0
  45. package/dist/auth/code-form.js +77 -0
  46. package/dist/auth/email-code-form.js +18 -77
  47. package/dist/auth/forgot-password-form.js +10 -10
  48. package/dist/auth/forgot-password-page.js +2 -2
  49. package/dist/auth/resend-code-button.js +29 -0
  50. package/dist/auth/sign-in-form.js +7 -8
  51. package/dist/auth/sign-in-page.js +3 -3
  52. package/dist/auth/sign-in-prompt.js +13 -9
  53. package/dist/auth/sign-up-code-form.js +22 -0
  54. package/dist/auth/sign-up-details-form.js +81 -111
  55. package/dist/auth/sign-up-page.js +17 -8
  56. package/dist/auth/two-factor-form.js +3 -3
  57. package/dist/auth/use-sign-in-address.js +21 -8
  58. package/dist/index.d.ts +2 -1
  59. package/dist/index.js +2 -1
  60. package/dist/lib/flip-guard.js +43 -0
  61. package/dist/lib/page-scroll-lock.js +20 -0
  62. package/dist/lib/use-focus-trap.js +4 -4
  63. package/dist/organizations/invitation-page.js +7 -6
  64. package/dist/package.js +1 -1
  65. package/dist/primitives/otp-input.d.ts +21 -0
  66. package/dist/primitives/otp-input.js +117 -0
  67. package/dist/primitives/otp-value.js +23 -0
  68. package/dist/primitives/route-link.d.ts +1 -0
  69. package/dist/primitives/route-link.js +20 -0
  70. package/dist/primitives/textarea.js +36 -0
  71. package/dist/record-view/field.js +56 -53
  72. package/dist/shell/assets/app-DJAZP1yB.js +66 -0
  73. package/dist/shell/assets/index-C5pYkUfv.css +2 -0
  74. package/dist/shell/assets/{index-CrtAqGCx.js → index-LBhMBiK4.js} +1 -1
  75. package/dist/shell/assets/maplibre-Dy0ZTnFZ.js +814 -0
  76. package/dist/shell/assets/record-map-BiWSbqqT.js +1 -0
  77. package/dist/shell/assets/records-map-DabYc3ad.js +1 -0
  78. package/dist/shell/assets/shared-protobase-ui-BURelnPG.js +1 -0
  79. package/dist/shell/index.html +6 -6
  80. package/dist/shell/protobase.shell.json +1 -1
  81. package/dist/styles.css +15 -0
  82. package/dist/toasts/toast.js +22 -6
  83. package/package.json +4 -4
  84. package/dist/auth/code-input.js +0 -17
  85. package/dist/auth/sign-in-address.js +0 -47
  86. package/dist/shell/assets/app-CpFoFNtG.js +0 -66
  87. package/dist/shell/assets/index-ibaHR5wQ.css +0 -2
  88. package/dist/shell/assets/maplibre-gl-B_TZ9n3D.js +0 -1
  89. package/dist/shell/assets/record-map-B2mkMEcE.js +0 -814
  90. package/dist/shell/assets/records-map-CAj21Al1.js +0 -1
  91. package/dist/shell/assets/shared-protobase-ui-D942ARkw.js +0 -1
  92. /package/dist/shell/assets/{record-map-DBE96hFo.css → maplibre-DBE96hFo.css} +0 -0
@@ -0,0 +1,23 @@
1
+ //#region src/primitives/otp-value.ts
2
+ /** The digits of `text`, at most `length`. */
3
+ const digitsOf = (text, length) => text.replace(/\D/g, "").slice(0, length);
4
+ /**
5
+ * The field's new code after an edit left `edited` in it. Text inserted in one go that holds a whole code, as a paste,
6
+ * the keyboard's suggestion or the system's autofill does, is the code, whatever was in the field before; anything else
7
+ * keeps the field's digits.
8
+ */
9
+ const editedCode = (edited, inserted, length) => {
10
+ const whole = digitsOf(inserted ?? "", length);
11
+ return whole.length === length ? whole : digitsOf(edited, length);
12
+ };
13
+ /**
14
+ * The code after `pasted` went into `code` at box `start`: a whole code replaces the field's, and fewer digits fill the
15
+ * boxes from `start` on, over the digits they held.
16
+ */
17
+ const pastedCode = (code, pasted, start, length) => {
18
+ const digits = pasted.replace(/\D/g, "");
19
+ if (digits.length >= length) return digits.slice(0, length);
20
+ return digitsOf(code.slice(0, start) + digits + code.slice(start + digits.length), length);
21
+ };
22
+ //#endregion
23
+ export { digitsOf, editedCode, pastedCode };
@@ -0,0 +1 @@
1
+ import { AnchorHTMLAttributes } from "react";
@@ -0,0 +1,20 @@
1
+ import { inApp } from "../app-shell/breadcrumb.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/primitives/route-link.tsx
4
+ /**
5
+ * An ordinary anchor to `to.href`: a plain click follows it in place with `to.onFollow`, while a middle click or one
6
+ * with Ctrl, Cmd, Shift or Alt opens it in a new tab or window, or saves it, as on any link. Every navigation a click
7
+ * starts is one of these, never a button that moves the page, so the browser shows where it goes and can open it.
8
+ */
9
+ const RouteLink = ({ to, onClick, ...rest }) => /* @__PURE__ */ jsx("a", {
10
+ href: to.href,
11
+ onClick: (event) => {
12
+ onClick?.(event);
13
+ if (event.defaultPrevented || !inApp(event)) return;
14
+ event.preventDefault();
15
+ to.onFollow();
16
+ },
17
+ ...rest
18
+ });
19
+ //#endregion
20
+ export { RouteLink };
@@ -0,0 +1,36 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import { useEffect, useLayoutEffect, useRef } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/primitives/textarea.tsx
5
+ const fit = (box) => {
6
+ box.style.height = "auto";
7
+ box.style.height = `${box.scrollHeight + box.offsetHeight - box.clientHeight}px`;
8
+ };
9
+ /** A text box of several lines that grows with its text instead of scrolling inside. */
10
+ const Textarea = ({ invalid, className, rows = 3, value, ...rest }) => {
11
+ const ref = useRef(null);
12
+ useLayoutEffect(() => {
13
+ if (ref.current) fit(ref.current);
14
+ }, [value]);
15
+ useEffect(() => {
16
+ const box = ref.current;
17
+ if (!box) return;
18
+ let width = box.clientWidth;
19
+ const observer = new ResizeObserver(() => {
20
+ if (box.clientWidth === width) return;
21
+ width = box.clientWidth;
22
+ fit(box);
23
+ });
24
+ observer.observe(box);
25
+ return () => observer.disconnect();
26
+ }, []);
27
+ return /* @__PURE__ */ jsx("textarea", {
28
+ ref,
29
+ rows,
30
+ value,
31
+ className: cn("block w-full resize-none overflow-hidden rounded-md border bg-background px-2.5 py-1.5 text-[13px] text-foreground shadow-sm outline-none placeholder:text-faint-foreground focus:border-primary focus:ring-2 focus:ring-primary/20", invalid ? "border-danger" : "border-border-strong", className),
32
+ ...rest
33
+ });
34
+ };
35
+ //#endregion
36
+ export { Textarea };
@@ -3,60 +3,63 @@ import { Button } from "../primitives/button.js";
3
3
  import { TriangleAlert } from "lucide-react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  //#region src/record-view/field.tsx
6
- const Field = ({ label, required, help, example, error, conflict, children }) => /* @__PURE__ */ jsxs("div", { children: [
7
- /* @__PURE__ */ jsxs("div", {
8
- className: "mb-1.5 flex items-center gap-2",
9
- children: [/* @__PURE__ */ jsxs("label", {
10
- className: "text-[13px] font-medium text-foreground",
11
- children: [label, required && /* @__PURE__ */ jsx("span", {
12
- className: "ml-0.5 text-danger-text",
13
- "aria-label": "required",
14
- children: "*"
6
+ const Field = ({ label, required, help, example, error, conflict, wide, children }) => /* @__PURE__ */ jsxs("div", {
7
+ className: wide ? "sm:col-span-2" : void 0,
8
+ children: [
9
+ /* @__PURE__ */ jsxs("div", {
10
+ className: "mb-1.5 flex items-center gap-2",
11
+ children: [/* @__PURE__ */ jsxs("label", {
12
+ className: "text-[13px] font-medium text-foreground",
13
+ children: [label, required && /* @__PURE__ */ jsx("span", {
14
+ className: "ml-0.5 text-danger-text",
15
+ "aria-label": "required",
16
+ children: "*"
17
+ })]
18
+ }), conflict && /* @__PURE__ */ jsxs("span", {
19
+ className: "inline-flex items-center gap-1.5 text-warning-text",
20
+ title: `${conflict.user.name} saved a different value`,
21
+ children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "size-3.5" }), /* @__PURE__ */ jsx(Avatar, {
22
+ initials: conflict.user.initials,
23
+ hue: conflict.user.hue,
24
+ size: "xs"
25
+ })]
15
26
  })]
16
- }), conflict && /* @__PURE__ */ jsxs("span", {
17
- className: "inline-flex items-center gap-1.5 text-warning-text",
18
- title: `${conflict.user.name} saved a different value`,
19
- children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "size-3.5" }), /* @__PURE__ */ jsx(Avatar, {
20
- initials: conflict.user.initials,
21
- hue: conflict.user.hue,
22
- size: "xs"
27
+ }),
28
+ children,
29
+ help && /* @__PURE__ */ jsx("p", {
30
+ className: "mt-1.5 text-xs text-muted-foreground",
31
+ children: help
32
+ }),
33
+ example && /* @__PURE__ */ jsxs("p", {
34
+ className: "mt-0.5 text-xs text-faint-foreground",
35
+ children: ["Example: ", example]
36
+ }),
37
+ error && /* @__PURE__ */ jsx("p", {
38
+ className: "mt-1.5 text-xs font-medium text-danger-text",
39
+ children: error
40
+ }),
41
+ conflict && /* @__PURE__ */ jsxs("div", {
42
+ className: "mt-2 flex items-center justify-between gap-3 rounded-md border border-warning/30 bg-warning-soft px-3 py-2 text-xs text-warning-text",
43
+ children: [/* @__PURE__ */ jsxs("span", { children: [
44
+ /* @__PURE__ */ jsx("strong", { children: conflict.user.name }),
45
+ " saved this ",
46
+ conflict.ago,
47
+ ": ",
48
+ /* @__PURE__ */ jsx("strong", { children: conflict.theirValue })
49
+ ] }), /* @__PURE__ */ jsxs("span", {
50
+ className: "flex gap-1.5",
51
+ children: [/* @__PURE__ */ jsx(Button, {
52
+ size: "sm",
53
+ onClick: conflict.onKeepMine,
54
+ children: "Keep mine"
55
+ }), /* @__PURE__ */ jsx(Button, {
56
+ size: "sm",
57
+ onClick: conflict.onUseTheirs,
58
+ children: "Use theirs"
59
+ })]
23
60
  })]
24
- })]
25
- }),
26
- children,
27
- help && /* @__PURE__ */ jsx("p", {
28
- className: "mt-1.5 text-xs text-muted-foreground",
29
- children: help
30
- }),
31
- example && /* @__PURE__ */ jsxs("p", {
32
- className: "mt-0.5 text-xs text-faint-foreground",
33
- children: ["Example: ", example]
34
- }),
35
- error && /* @__PURE__ */ jsx("p", {
36
- className: "mt-1.5 text-xs font-medium text-danger-text",
37
- children: error
38
- }),
39
- conflict && /* @__PURE__ */ jsxs("div", {
40
- className: "mt-2 flex items-center justify-between gap-3 rounded-md border border-warning/30 bg-warning-soft px-3 py-2 text-xs text-warning-text",
41
- children: [/* @__PURE__ */ jsxs("span", { children: [
42
- /* @__PURE__ */ jsx("strong", { children: conflict.user.name }),
43
- " saved this ",
44
- conflict.ago,
45
- ": ",
46
- /* @__PURE__ */ jsx("strong", { children: conflict.theirValue })
47
- ] }), /* @__PURE__ */ jsxs("span", {
48
- className: "flex gap-1.5",
49
- children: [/* @__PURE__ */ jsx(Button, {
50
- size: "sm",
51
- onClick: conflict.onKeepMine,
52
- children: "Keep mine"
53
- }), /* @__PURE__ */ jsx(Button, {
54
- size: "sm",
55
- onClick: conflict.onUseTheirs,
56
- children: "Use theirs"
57
- })]
58
- })]
59
- })
60
- ] });
61
+ })
62
+ ]
63
+ });
61
64
  //#endregion
62
65
  export { Field };