@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.
- package/dist/account/account-security-page.js +5 -4
- package/dist/app/app.js +1 -0
- package/dist/app/charts/chart-view.js +3 -1
- package/dist/app/displays/calendar-controls.js +2 -1
- package/dist/app/displays/calendar-display.js +2 -1
- package/dist/app/displays/calendar-event.js +2 -1
- package/dist/app/displays/calendar-range.js +18 -14
- package/dist/app/export/cells.js +6 -4
- package/dist/app/field-editor.js +13 -1
- package/dist/app/import/convert.js +2 -12
- package/dist/app/import/locale-formats.js +2 -1
- package/dist/app/incoming-card.js +35 -0
- package/dist/app/incoming-relations.js +36 -0
- package/dist/app/list-chart.js +3 -1
- package/dist/app/pages/field-value.js +9 -1
- package/dist/app/pages/record-actions.js +34 -16
- package/dist/app/record-page.js +26 -18
- package/dist/app/runtime/runtime-status.js +5 -4
- package/dist/app/search/navigation-hits.js +45 -0
- package/dist/app/search/use-global-search.js +13 -4
- package/dist/app/use-incoming-counts.js +38 -0
- package/dist/app/use-related-records.js +3 -10
- package/dist/app-shell/app-shell.js +9 -2
- package/dist/app-shell/index.d.ts +1 -0
- package/dist/app-shell/logo.d.ts +5 -1
- package/dist/app-shell/logo.js +10 -3
- package/dist/app-shell/sidebar.js +3 -2
- package/dist/app-shell/top-bar-slot.js +11 -0
- package/dist/app-shell/top-bar.d.ts +3 -0
- package/dist/app-shell/top-bar.js +27 -19
- package/dist/auth/auth-messages.js +2 -1
- package/dist/auth/auth-provider.js +8 -3
- package/dist/data-grid/cells.js +8 -1
- package/dist/data-grid/grid-header.js +17 -16
- package/dist/data-grid/header-menu.js +16 -6
- package/dist/data-grid/row-menu.js +2 -39
- package/dist/format/date.js +29 -9
- package/dist/format/number-text.js +16 -0
- package/dist/format/zone.js +62 -0
- package/dist/live/columns-from-model.js +2 -0
- package/dist/live/contact-link.js +25 -0
- package/dist/live/contact-links.js +42 -0
- package/dist/live/display-value.js +14 -4
- package/dist/live/field-values.js +20 -9
- package/dist/live/filter-string.js +30 -30
- package/dist/package.js +1 -1
- package/dist/primitives/popover-menu.js +56 -0
- package/dist/record-view/action-menu.js +59 -0
- package/dist/record-view/record-header.js +2 -6
- package/dist/record-view/record-sidebar.js +2 -30
- package/dist/shell/assets/app-9imuOKuW.js +69 -0
- package/dist/shell/assets/export-worker-BoAr3vuF.js +2 -0
- package/dist/shell/assets/{index-xN6_oZU2.js → index-C_o0i6I2.js} +1 -1
- package/dist/shell/assets/index-CzqIlZPP.css +2 -0
- package/dist/shell/assets/{maplibre-Ba9RapjY.js → maplibre-DLYsHwYU.js} +1 -1
- package/dist/shell/assets/{markdown-content-BUxrbovf.js → markdown-content-B410ow-t.js} +1 -1
- package/dist/shell/assets/{record-map-14zotZ2s.js → record-map-DvgWFyLn.js} +1 -1
- package/dist/shell/assets/{records-map-wi-0pXqF.js → records-map-CLj0uHGq.js} +1 -1
- package/dist/shell/assets/{shared-protobase-ui-BVwhKZk9.js → shared-protobase-ui-Bf1h2ktk.js} +1 -1
- package/dist/shell/index.html +4 -4
- package/dist/shell/protobase.shell.json +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/app-C01lazBK.js +0 -69
- package/dist/shell/assets/export-worker-BnOpS_4Q.js +0 -2
- 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,
|
|
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:
|
|
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
|
|
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,
|
|
30
|
+
export { MetadataCard, MetadataList, SidebarCard };
|