@protobase/ui 0.21.8 → 0.21.10

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 (65) hide show
  1. package/dist/account/account-security-page.js +5 -4
  2. package/dist/app/app.js +1 -0
  3. package/dist/app/charts/chart-view.js +3 -1
  4. package/dist/app/displays/calendar-controls.js +2 -1
  5. package/dist/app/displays/calendar-display.js +2 -1
  6. package/dist/app/displays/calendar-event.js +2 -1
  7. package/dist/app/displays/calendar-range.js +18 -14
  8. package/dist/app/export/cells.js +6 -4
  9. package/dist/app/field-editor.js +13 -1
  10. package/dist/app/import/convert.js +2 -12
  11. package/dist/app/import/locale-formats.js +2 -1
  12. package/dist/app/incoming-card.js +35 -0
  13. package/dist/app/incoming-relations.js +36 -0
  14. package/dist/app/list-chart.js +3 -1
  15. package/dist/app/pages/field-value.js +9 -1
  16. package/dist/app/pages/record-actions.js +34 -16
  17. package/dist/app/record-page.js +26 -18
  18. package/dist/app/runtime/runtime-status.js +5 -4
  19. package/dist/app/search/navigation-hits.js +45 -0
  20. package/dist/app/search/use-global-search.js +13 -4
  21. package/dist/app/use-incoming-counts.js +38 -0
  22. package/dist/app/use-related-records.js +3 -10
  23. package/dist/app-shell/app-shell.js +9 -2
  24. package/dist/app-shell/index.d.ts +1 -0
  25. package/dist/app-shell/logo.d.ts +5 -1
  26. package/dist/app-shell/logo.js +10 -3
  27. package/dist/app-shell/sidebar.js +3 -2
  28. package/dist/app-shell/top-bar-slot.js +11 -0
  29. package/dist/app-shell/top-bar.d.ts +3 -0
  30. package/dist/app-shell/top-bar.js +27 -19
  31. package/dist/auth/auth-messages.js +2 -1
  32. package/dist/auth/auth-provider.js +8 -3
  33. package/dist/data-grid/cells.js +8 -1
  34. package/dist/data-grid/grid-header.js +17 -16
  35. package/dist/data-grid/header-menu.js +16 -6
  36. package/dist/data-grid/row-menu.js +2 -39
  37. package/dist/format/date.js +29 -9
  38. package/dist/format/number-text.js +16 -0
  39. package/dist/format/zone.js +62 -0
  40. package/dist/live/columns-from-model.js +2 -0
  41. package/dist/live/contact-link.js +25 -0
  42. package/dist/live/contact-links.js +42 -0
  43. package/dist/live/display-value.js +14 -4
  44. package/dist/live/field-values.js +20 -9
  45. package/dist/live/filter-string.js +30 -30
  46. package/dist/package.js +1 -1
  47. package/dist/primitives/popover-menu.js +56 -0
  48. package/dist/record-view/action-menu.js +59 -0
  49. package/dist/record-view/record-header.js +2 -6
  50. package/dist/record-view/record-sidebar.js +2 -30
  51. package/dist/shell/assets/app-9imuOKuW.js +69 -0
  52. package/dist/shell/assets/export-worker-BoAr3vuF.js +2 -0
  53. package/dist/shell/assets/{index-xN6_oZU2.js → index-C_o0i6I2.js} +1 -1
  54. package/dist/shell/assets/index-CzqIlZPP.css +2 -0
  55. package/dist/shell/assets/{maplibre-Ba9RapjY.js → maplibre-DLYsHwYU.js} +1 -1
  56. package/dist/shell/assets/{markdown-content-BUxrbovf.js → markdown-content-B410ow-t.js} +1 -1
  57. package/dist/shell/assets/{record-map-14zotZ2s.js → record-map-DvgWFyLn.js} +1 -1
  58. package/dist/shell/assets/{records-map-wi-0pXqF.js → records-map-CLj0uHGq.js} +1 -1
  59. package/dist/shell/assets/{shared-protobase-ui-BVwhKZk9.js → shared-protobase-ui-Bf1h2ktk.js} +1 -1
  60. package/dist/shell/index.html +4 -4
  61. package/dist/shell/protobase.shell.json +1 -1
  62. package/package.json +4 -4
  63. package/dist/shell/assets/app-C01lazBK.js +0 -69
  64. package/dist/shell/assets/export-worker-BnOpS_4Q.js +0 -2
  65. package/dist/shell/assets/index-CBGigFxb.css +0 -2
@@ -0,0 +1,56 @@
1
+ import { useEffect, useLayoutEffect, useRef, useState } from "react";
2
+ //#region src/primitives/popover-menu.ts
3
+ const gap = 4;
4
+ /** Below the button, or above it when the viewport has no room underneath; its right edge at the button's. */
5
+ const placeMenu = (button, menuHeight) => {
6
+ const below = button.bottom + gap;
7
+ return {
8
+ top: below + menuHeight > window.innerHeight - gap ? Math.max(gap, button.top - gap - menuHeight) : below,
9
+ right: window.innerWidth - button.right
10
+ };
11
+ };
12
+ /**
13
+ * A menu opened by a button and drawn fixed, portalled to the body, under or over the button: it closes on a click
14
+ * outside, Escape, and a scroll or resize, which would move the button away from it. `place` is undefined until the
15
+ * menu is measured, so it is drawn hidden for that first frame.
16
+ */
17
+ const usePopoverMenu = () => {
18
+ const [open, setOpen] = useState(false);
19
+ const [place, setPlace] = useState();
20
+ const button = useRef(null);
21
+ const menu = useRef(null);
22
+ useLayoutEffect(() => {
23
+ if (!open || !button.current || !menu.current) {
24
+ setPlace(void 0);
25
+ return;
26
+ }
27
+ setPlace(placeMenu(button.current.getBoundingClientRect(), menu.current.offsetHeight));
28
+ }, [open]);
29
+ useEffect(() => {
30
+ if (!open) return;
31
+ const inside = (target) => button.current?.contains(target) || menu.current?.contains(target);
32
+ const close = (event) => {
33
+ if (event instanceof KeyboardEvent ? event.key === "Escape" : !inside(event.target)) setOpen(false);
34
+ };
35
+ const dismiss = () => setOpen(false);
36
+ document.addEventListener("mousedown", close);
37
+ document.addEventListener("keydown", close);
38
+ document.addEventListener("scroll", dismiss, true);
39
+ window.addEventListener("resize", dismiss);
40
+ return () => {
41
+ document.removeEventListener("mousedown", close);
42
+ document.removeEventListener("keydown", close);
43
+ document.removeEventListener("scroll", dismiss, true);
44
+ window.removeEventListener("resize", dismiss);
45
+ };
46
+ }, [open]);
47
+ return {
48
+ open,
49
+ setOpen,
50
+ place,
51
+ button,
52
+ menu
53
+ };
54
+ };
55
+ //#endregion
56
+ export { usePopoverMenu };
@@ -0,0 +1,59 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import { usePopoverMenu } from "../primitives/popover-menu.js";
3
+ import { MoreVertical } from "lucide-react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { createPortal } from "react-dom";
6
+ //#region src/record-view/action-menu.tsx
7
+ const itemClass = "flex w-full items-center gap-2 px-3 py-2.5 text-left hover:bg-muted disabled:cursor-default disabled:opacity-60";
8
+ /**
9
+ * The actions of an action rail as a menu behind a "..." button, as a mobile screen's top bar holds them: each item the
10
+ * rail's, a link where the rail draws one, disabled with its reason when it cannot run. `className` styles the button.
11
+ */
12
+ const ActionMenu = ({ actions, label = "Actions", className }) => {
13
+ const { open, setOpen, place, button, menu } = usePopoverMenu();
14
+ if (actions.length === 0) return null;
15
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
16
+ ref: button,
17
+ type: "button",
18
+ "aria-label": label,
19
+ "aria-haspopup": "menu",
20
+ "aria-expanded": open,
21
+ onClick: () => setOpen(!open),
22
+ className,
23
+ children: /* @__PURE__ */ jsx(MoreVertical, { className: "size-5" })
24
+ }), open && createPortal(/* @__PURE__ */ jsx("ul", {
25
+ ref: menu,
26
+ role: "menu",
27
+ "aria-label": label,
28
+ style: place ?? { visibility: "hidden" },
29
+ className: "fixed z-50 min-w-48 rounded-md border bg-background py-1 shadow-pop",
30
+ children: actions.map(({ name, icon: Icon, onRun, blocked, running, tone, render }) => {
31
+ const children = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, {
32
+ className: cn("size-4 shrink-0", tone === "danger" ? "text-danger-text" : "text-muted-foreground"),
33
+ "aria-hidden": true
34
+ }), /* @__PURE__ */ jsx("span", {
35
+ className: cn("font-medium", tone === "danger" && "text-danger-text"),
36
+ children: name
37
+ })] });
38
+ return /* @__PURE__ */ jsx("li", {
39
+ role: "none",
40
+ onClick: () => setOpen(false),
41
+ children: render ? render({
42
+ className: itemClass,
43
+ children,
44
+ role: "menuitem"
45
+ }) : /* @__PURE__ */ jsx("button", {
46
+ type: "button",
47
+ role: "menuitem",
48
+ onClick: onRun,
49
+ disabled: Boolean(blocked) || running,
50
+ title: blocked,
51
+ className: itemClass,
52
+ children
53
+ })
54
+ }, name);
55
+ })
56
+ }), document.body)] });
57
+ };
58
+ //#endregion
59
+ export { ActionMenu };
@@ -2,11 +2,7 @@ import { AvatarStack } from "../primitives/avatar.js";
2
2
  import { Badge } from "../primitives/badge.js";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/record-view/record-header.tsx
5
- const RecordHeader = ({ collection, title, titleHidden, status, lastEditedBy, presence = [], actions }) => {
6
- if (titleHidden && !collection && !status && !lastEditedBy && presence.length === 0 && !actions) return /* @__PURE__ */ jsx("h1", {
7
- className: "sr-only",
8
- children: title
9
- });
5
+ const RecordHeader = ({ collection, title, status, lastEditedBy, presence = [], actions }) => {
10
6
  return /* @__PURE__ */ jsxs("header", {
11
7
  className: "flex flex-col gap-4 border-b border-border pb-6 md:flex-row md:items-end md:justify-between md:gap-6",
12
8
  children: [/* @__PURE__ */ jsxs("div", { children: [
@@ -17,7 +13,7 @@ const RecordHeader = ({ collection, title, titleHidden, status, lastEditedBy, pr
17
13
  /* @__PURE__ */ jsxs("div", {
18
14
  className: "flex flex-wrap items-center gap-x-3 gap-y-1",
19
15
  children: [/* @__PURE__ */ jsx("h1", {
20
- className: titleHidden ? "sr-only" : "text-xl font-semibold tracking-tight text-foreground md:text-2xl",
16
+ className: "text-xl font-semibold tracking-tight text-foreground md:text-2xl",
21
17
  children: title
22
18
  }), status && /* @__PURE__ */ jsx(Badge, {
23
19
  tone: status.tone,
@@ -1,4 +1,4 @@
1
- import { ChevronRight } from "lucide-react";
1
+ import "lucide-react";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  //#region src/record-view/record-sidebar.tsx
4
4
  const MetadataList = ({ rows }) => /* @__PURE__ */ jsx("dl", {
@@ -14,34 +14,6 @@ const MetadataList = ({ rows }) => /* @__PURE__ */ jsx("dl", {
14
14
  })]
15
15
  }, row.label))
16
16
  });
17
- const RelatedRecords = ({ records, onNavigate }) => /* @__PURE__ */ jsx("ul", {
18
- className: "-mx-2",
19
- children: records.map((record) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", {
20
- href: record.href ?? "#",
21
- onClick: (event) => {
22
- event.preventDefault();
23
- if (record.href) onNavigate?.(record.href);
24
- },
25
- className: "group flex items-center justify-between gap-3 rounded-md px-2 py-2 hover:bg-muted",
26
- children: [/* @__PURE__ */ jsxs("span", {
27
- className: "min-w-0",
28
- children: [
29
- /* @__PURE__ */ jsx("span", {
30
- className: "block text-[11px] uppercase tracking-wide text-faint-foreground",
31
- children: record.kind
32
- }),
33
- /* @__PURE__ */ jsx("span", {
34
- className: "block truncate font-medium text-primary-text",
35
- children: record.label
36
- }),
37
- record.meta && /* @__PURE__ */ jsx("span", {
38
- className: "block text-xs text-muted-foreground",
39
- children: record.meta
40
- })
41
- ]
42
- }), /* @__PURE__ */ jsx(ChevronRight, { className: "size-4 shrink-0 text-faint-foreground group-hover:text-foreground" })]
43
- }) }, record.label))
44
- });
45
17
  const SidebarCard = ({ title, children }) => /* @__PURE__ */ jsxs("div", {
46
18
  className: "rounded-lg border border-border bg-background p-4",
47
19
  children: [/* @__PURE__ */ jsx("h3", {
@@ -55,4 +27,4 @@ const MetadataCard = ({ title, rows }) => rows.length === 0 ? null : /* @__PURE_
55
27
  children: /* @__PURE__ */ jsx(MetadataList, { rows })
56
28
  });
57
29
  //#endregion
58
- export { MetadataCard, MetadataList, RelatedRecords, SidebarCard };
30
+ export { MetadataCard, MetadataList, SidebarCard };