@protobase/ui 0.19.5 → 0.19.7

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 (144) hide show
  1. package/dist/account/account-section.js +2 -2
  2. package/dist/account/account-security-page.js +2 -2
  3. package/dist/account/backup-codes.js +1 -1
  4. package/dist/account/passkeys-section.js +2 -2
  5. package/dist/account/password-dialog.js +1 -1
  6. package/dist/account/sign-in-policy-form.js +2 -2
  7. package/dist/account/sign-in-policy-page.js +2 -2
  8. package/dist/account/sign-in-providers-section.js +1 -1
  9. package/dist/account/staff-sign-in-log.js +3 -3
  10. package/dist/account/two-factor-setup.js +6 -6
  11. package/dist/action-card/action-card.js +1 -1
  12. package/dist/activity-chart/activity-chart.js +2 -2
  13. package/dist/app/delete/dialogs.js +3 -3
  14. package/dist/app/displays/display-controls.js +1 -1
  15. package/dist/app/displays/display-frame.js +1 -1
  16. package/dist/app/displays/list-cards.js +1 -1
  17. package/dist/app/displays/map-display.js +1 -1
  18. package/dist/app/displays/record-card.js +1 -1
  19. package/dist/app/embedded-list/embedded-list.js +2 -2
  20. package/dist/app/error-banner.js +1 -1
  21. package/dist/app/export/builder-port.js +54 -0
  22. package/dist/app/export/builder.js +61 -0
  23. package/dist/app/export/cells.js +93 -0
  24. package/dist/app/export/csv.js +17 -0
  25. package/dist/app/export/export-dialog.js +235 -0
  26. package/dist/app/export/export-options.js +49 -0
  27. package/dist/app/export/export-worker.d.ts +1 -0
  28. package/dist/app/export/export-worker.js +9 -0
  29. package/dist/app/export/run-export.js +62 -0
  30. package/dist/app/export/sink.js +91 -0
  31. package/dist/app/export/use-export-flow.js +139 -0
  32. package/dist/app/export/xlsx.js +91 -0
  33. package/dist/app/field-editor.js +6 -12
  34. package/dist/app/file-field.js +4 -4
  35. package/dist/app/gallery/lightbox.js +2 -2
  36. package/dist/app/gallery/photo-details.js +1 -1
  37. package/dist/app/import/import-check-step.js +2 -2
  38. package/dist/app/import/import-file-step.js +2 -2
  39. package/dist/app/import/import-mapping-step.js +1 -1
  40. package/dist/app/import/import-result-step.js +2 -2
  41. package/dist/app/import/import-select.js +2 -2
  42. package/dist/app/list-page.js +28 -3
  43. package/dist/app/meta-gate.js +3 -3
  44. package/dist/app/pages/blocks/card-frame.js +4 -4
  45. package/dist/app/pages/blocks/field.js +2 -5
  46. package/dist/app/pages/blocks/stat.js +2 -2
  47. package/dist/app/pages/problem.js +1 -1
  48. package/dist/app/pages/render-node.js +1 -1
  49. package/dist/app/record-page.js +2 -2
  50. package/dist/app/record-row/record-row-body.js +3 -3
  51. package/dist/app/record-row/saved-record-row.js +1 -1
  52. package/dist/app/related-section.js +1 -1
  53. package/dist/app/relation-picker.js +1 -1
  54. package/dist/app/runtime/runtime-update.js +3 -3
  55. package/dist/app/saved/saved-list.js +1 -1
  56. package/dist/app/searches/saved-search-rows.js +2 -2
  57. package/dist/app/searches/saved-search-section.js +1 -1
  58. package/dist/app/searches/saved-searches.js +1 -1
  59. package/dist/app/searches/search-controls.js +2 -2
  60. package/dist/app/searches/search-name-dialog.js +1 -1
  61. package/dist/app/searches/update-search-dialog.js +16 -19
  62. package/dist/app/sensitive-field.js +1 -1
  63. package/dist/app/source-notice.js +3 -3
  64. package/dist/app/staff-banner.js +1 -1
  65. package/dist/app-shell/breadcrumb.js +1 -1
  66. package/dist/app-shell/global-search.js +1 -1
  67. package/dist/app-shell/page-header.js +1 -1
  68. package/dist/app-shell/profile-menu.js +3 -3
  69. package/dist/app-shell/sidebar-group.js +1 -1
  70. package/dist/app-shell/sidebar-item.js +1 -1
  71. package/dist/app-shell/sidebar.js +2 -2
  72. package/dist/assistant-dock/part-view.js +1 -4
  73. package/dist/assistant-dock/widget-view.js +1 -4
  74. package/dist/auth/auth-gate.js +2 -2
  75. package/dist/auth/auth-layout.js +1 -1
  76. package/dist/auth/code-form.js +2 -2
  77. package/dist/auth/first-run-page.js +1 -1
  78. package/dist/auth/forgot-password-form.js +2 -2
  79. package/dist/auth/provider-sign-in-page.js +1 -1
  80. package/dist/auth/reset-password-form.js +3 -3
  81. package/dist/auth/setup-required-form.js +2 -2
  82. package/dist/auth/setup-required-page.js +1 -1
  83. package/dist/auth/sign-in-form.js +5 -5
  84. package/dist/auth/sign-in-prompt.js +2 -2
  85. package/dist/auth/sign-up-details-form.js +3 -3
  86. package/dist/auth/sign-up-email-form.js +4 -4
  87. package/dist/auth/staff-sign-in-form.js +3 -3
  88. package/dist/auth/two-factor-form.js +5 -5
  89. package/dist/chat/chat-message.js +1 -1
  90. package/dist/chat/chat-thread.js +1 -1
  91. package/dist/data/query-keys.js +7 -0
  92. package/dist/data-grid/grid-row.js +1 -1
  93. package/dist/data-grid/header-menu.js +1 -1
  94. package/dist/data-grid/row-menu.js +1 -1
  95. package/dist/filter-panel/facet-combobox.js +1 -1
  96. package/dist/filter-panel/filter-menu.js +1 -1
  97. package/dist/filter-panel/filter-panel.js +2 -2
  98. package/dist/inline-child-table/line-menu.js +1 -1
  99. package/dist/inline-child-table/line-row.js +4 -4
  100. package/dist/inline-child-table/number-cell.js +1 -1
  101. package/dist/inline-child-table/totals-footer.js +2 -2
  102. package/dist/organizations/app-roles-picker.js +1 -1
  103. package/dist/organizations/invitation-page.js +3 -3
  104. package/dist/organizations/invitations-page.js +2 -2
  105. package/dist/organizations/members-page.js +2 -2
  106. package/dist/organizations/organization-page.js +1 -1
  107. package/dist/organizations/organizations-page.js +2 -2
  108. package/dist/package.js +1 -1
  109. package/dist/plugins/before-sign-in.js +1 -1
  110. package/dist/plugins/plugin-gate.js +1 -1
  111. package/dist/plugins/plugin-notice.js +1 -1
  112. package/dist/primitives/button.js +1 -1
  113. package/dist/primitives/dialog.js +2 -2
  114. package/dist/primitives/input.js +1 -1
  115. package/dist/primitives/menu-select.js +2 -2
  116. package/dist/primitives/responsive-dialog.js +1 -1
  117. package/dist/primitives/segmented.js +1 -1
  118. package/dist/primitives/sheet.js +1 -1
  119. package/dist/primitives/textarea.js +1 -1
  120. package/dist/record-view/action-rail.js +1 -1
  121. package/dist/record-view/field.js +1 -1
  122. package/dist/record-view/key-facts.js +2 -2
  123. package/dist/record-view/record-sidebar.js +2 -2
  124. package/dist/record-view/section.js +2 -2
  125. package/dist/record-view/spec-table.js +1 -1
  126. package/dist/shell/assets/app-BRVJlz_E.js +68 -0
  127. package/dist/shell/assets/export-worker-CVd5saLq.js +2 -0
  128. package/dist/shell/assets/{index-BzCCIfII.js → index-CafsxSWx.js} +1 -1
  129. package/dist/shell/assets/index-Cuulz26c.css +2 -0
  130. package/dist/shell/assets/maplibre-Cb7ks8SG.js +814 -0
  131. package/dist/shell/assets/{record-map-BK_02Lmk.js → record-map-dXyPrmGg.js} +1 -1
  132. package/dist/shell/assets/{records-map-Dn72A_l-.js → records-map-bGH18FRn.js} +1 -1
  133. package/dist/shell/assets/{shared-protobase-ui-B6lrj7eA.js → shared-protobase-ui-e-G14mxb.js} +1 -1
  134. package/dist/shell/index.html +4 -4
  135. package/dist/shell/protobase.shell.json +1 -1
  136. package/dist/side-panel/side-panel.js +1 -1
  137. package/dist/step-list/step-list.js +1 -1
  138. package/dist/styles.css +1 -1
  139. package/dist/theme.css +2 -0
  140. package/dist/toasts/toast.js +2 -2
  141. package/package.json +5 -4
  142. package/dist/shell/assets/app-CZ4drn7G.js +0 -67
  143. package/dist/shell/assets/index-BoeKjvo8.css +0 -2
  144. package/dist/shell/assets/maplibre-BOsAtlAo.js +0 -814
@@ -22,12 +22,12 @@ const Control = ({ model, view, name, value, onChange }) => {
22
22
  if (field?.type !== "enum") throw new Error(`Not implemented: "${name}" is ${field?.type ?? "unknown"}, and a saved search's controls are enums or booleans`);
23
23
  return /* @__PURE__ */ jsxs("label", {
24
24
  htmlFor: id,
25
- className: "flex items-center gap-2 text-[13px] text-muted-foreground",
25
+ className: "flex items-center gap-2 text-muted-foreground",
26
26
  children: [label, /* @__PURE__ */ jsx("select", {
27
27
  id,
28
28
  value: String(value ?? ""),
29
29
  onChange: (event) => onChange(event.target.value),
30
- className: "h-8 rounded-md border border-border-strong bg-background px-2 text-[13px] text-foreground shadow-sm focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20",
30
+ className: "h-8 rounded-md border border-border-strong bg-background px-2 text-foreground shadow-sm focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20",
31
31
  children: (field.enumValues ?? []).map((option) => /* @__PURE__ */ jsx("option", {
32
32
  value: option,
33
33
  children: enumLabel(option, hints?.valueLabels)
@@ -34,7 +34,7 @@ const SearchNameDialog = ({ title, chips, label, required, initial = "", busy, o
34
34
  children: [chips.length > 0 && /* @__PURE__ */ jsx(FilterChipList, { chips }), /* @__PURE__ */ jsxs("div", {
35
35
  className: "flex flex-col gap-1.5",
36
36
  children: [/* @__PURE__ */ jsxs("div", {
37
- className: "flex items-baseline justify-between gap-2 text-[13px]",
37
+ className: "flex items-baseline justify-between gap-2",
38
38
  children: [/* @__PURE__ */ jsx("label", {
39
39
  htmlFor: id,
40
40
  className: "font-medium",
@@ -31,7 +31,7 @@ const changeStyle = {
31
31
  };
32
32
  const FilterChanges = ({ changes }) => /* @__PURE__ */ jsx("ul", {
33
33
  "aria-label": "Filter changes",
34
- className: "divide-y rounded-md border text-[13px]",
34
+ className: "divide-y rounded-md border",
35
35
  children: changes.map((change) => /* @__PURE__ */ jsxs("li", {
36
36
  className: "grid grid-cols-[72px_1fr] gap-3 px-3 py-2",
37
37
  children: [/* @__PURE__ */ jsx("span", {
@@ -70,7 +70,7 @@ const RecordsSide = ({ model, view, title, filter, total, plural }) => {
70
70
  className: "flex flex-col gap-2",
71
71
  children: [
72
72
  /* @__PURE__ */ jsxs("h3", {
73
- className: "text-[13px] font-semibold",
73
+ className: "font-semibold",
74
74
  children: [
75
75
  title,
76
76
  " ",
@@ -95,7 +95,7 @@ const RecordsSide = ({ model, view, title, filter, total, plural }) => {
95
95
  ]
96
96
  }),
97
97
  filter === null || total === 0 ? /* @__PURE__ */ jsxs("p", {
98
- className: "text-[13px] text-muted-foreground",
98
+ className: "text-muted-foreground",
99
99
  children: [
100
100
  "No ",
101
101
  plural,
@@ -156,22 +156,19 @@ const UpdateSearchDialog = ({ model, view, title, before, after, saveNewLabel, u
156
156
  className: "flex flex-col gap-4",
157
157
  children: [
158
158
  changes.length > 0 && /* @__PURE__ */ jsx(FilterChanges, { changes }),
159
- counted ? /* @__PURE__ */ jsxs("p", {
160
- className: "text-[13px]",
161
- children: [/* @__PURE__ */ jsx("span", {
162
- className: "font-semibold",
163
- children: netChange(addedCount, removedCount, singular, plural)
164
- }), /* @__PURE__ */ jsxs("span", {
165
- className: "text-muted-foreground",
166
- children: [
167
- ": ",
168
- count(addedCount, singular, plural),
169
- " added, ",
170
- removedCount,
171
- " removed"
172
- ]
173
- })]
174
- }) : /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" }),
159
+ counted ? /* @__PURE__ */ jsxs("p", { children: [/* @__PURE__ */ jsx("span", {
160
+ className: "font-semibold",
161
+ children: netChange(addedCount, removedCount, singular, plural)
162
+ }), /* @__PURE__ */ jsxs("span", {
163
+ className: "text-muted-foreground",
164
+ children: [
165
+ ": ",
166
+ count(addedCount, singular, plural),
167
+ " added, ",
168
+ removedCount,
169
+ " removed"
170
+ ]
171
+ })] }) : /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" }),
175
172
  /* @__PURE__ */ jsx(RecordsSide, {
176
173
  model,
177
174
  view,
@@ -42,7 +42,7 @@ const SensitiveField = ({ field, hints, value, reveal, locked, invalid, placehol
42
42
  })
43
43
  });
44
44
  if (locked) return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
45
- className: "flex items-center gap-2 py-1 text-[13px]",
45
+ className: "flex items-center gap-2 py-1",
46
46
  children: [/* @__PURE__ */ jsx("span", {
47
47
  className: cn(shown ? hints?.format === "code" ? "font-mono text-xs" : "" : "tracking-widest text-muted-foreground"),
48
48
  children: shown ? displayValue(field, stored.data, hints) : mask
@@ -14,7 +14,7 @@ const reason = (error) => {
14
14
  const SourceNotice = ({ status }) => {
15
15
  const queryClient = useQueryClient();
16
16
  if (status.state !== "error") return /* @__PURE__ */ jsxs("div", {
17
- className: "flex h-full min-h-48 flex-1 items-center justify-center gap-2 text-[13px] text-muted-foreground",
17
+ className: "flex h-full min-h-48 flex-1 items-center justify-center gap-2 text-muted-foreground",
18
18
  children: [
19
19
  /* @__PURE__ */ jsx(Spinner, {}),
20
20
  " Loading from ",
@@ -27,11 +27,11 @@ const SourceNotice = ({ status }) => {
27
27
  className: "max-w-md text-center",
28
28
  children: [
29
29
  /* @__PURE__ */ jsxs("h1", {
30
- className: "text-[15px] font-semibold",
30
+ className: "text-[16px] font-semibold",
31
31
  children: ["Cannot reach ", status.source.label]
32
32
  }),
33
33
  /* @__PURE__ */ jsxs("p", {
34
- className: "mt-1 text-[13px] text-muted-foreground",
34
+ className: "mt-1 text-muted-foreground",
35
35
  children: [reason(status.error), " The rest of the app works as before."]
36
36
  }),
37
37
  /* @__PURE__ */ jsx(Button, {
@@ -24,7 +24,7 @@ const StaffBanner = ({ signIn, onStop }) => {
24
24
  return /* @__PURE__ */ jsxs("div", {
25
25
  role: "region",
26
26
  "aria-label": "Staff session",
27
- className: "flex flex-wrap items-center gap-x-3 gap-y-2 border-b border-warning/40 bg-warning-soft px-4 py-2 text-[13px] text-warning-text",
27
+ className: "flex flex-wrap items-center gap-x-3 gap-y-2 border-b border-warning/40 bg-warning-soft px-4 py-2 text-warning-text",
28
28
  children: [
29
29
  /* @__PURE__ */ jsx(UserRoundCog, {
30
30
  "aria-hidden": true,
@@ -8,7 +8,7 @@ const inApp = (event) => event.button === 0 && !event.metaKey && !event.ctrlKey
8
8
  /** The trail of where you are; the last crumb, the current page, shows on phones too. */
9
9
  const Breadcrumb = ({ parts, onNavigate }) => /* @__PURE__ */ jsx("nav", {
10
10
  "aria-label": "Breadcrumb",
11
- className: "flex min-w-0 items-center gap-1.5 text-[13px]",
11
+ className: "flex min-w-0 items-center gap-1.5",
12
12
  children: parts.map((part, index) => {
13
13
  const last = index === parts.length - 1;
14
14
  const { label, href, loading } = typeof part === "string" ? {
@@ -94,7 +94,7 @@ const GlobalSearch = ({ search, className = "w-96", autoFocus, showShortcut = tr
94
94
  id: listId,
95
95
  role: "listbox",
96
96
  "aria-label": "Search results",
97
- className: "absolute right-0 top-full z-40 mt-1 max-h-96 w-full min-w-72 overflow-y-auto rounded-lg border bg-background py-1 text-[13px] shadow-pop",
97
+ className: "absolute right-0 top-full z-40 mt-1 max-h-96 w-full min-w-72 overflow-y-auto rounded-lg border bg-background py-1 shadow-pop",
98
98
  children: [search.groups.length === 0 && /* @__PURE__ */ jsx("p", {
99
99
  className: "px-3 py-2 text-muted-foreground",
100
100
  children: search.loading ? "Searching" : `No matches for “${search.query}”`
@@ -5,7 +5,7 @@ const PageHeader = ({ title, subtitle, aside, actions }) => {
5
5
  className: "text-xl font-semibold tracking-tight",
6
6
  children: title
7
7
  }), subtitle && /* @__PURE__ */ jsx("p", {
8
- className: "text-[13px] text-muted-foreground",
8
+ className: "text-muted-foreground",
9
9
  children: subtitle
10
10
  })] });
11
11
  return /* @__PURE__ */ jsxs("div", {
@@ -7,7 +7,7 @@ import { useEffect, useRef, useState } from "react";
7
7
  import { ChevronsUpDown, LogOut } from "lucide-react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/app-shell/profile-menu.tsx
10
- const menuRow = "flex min-h-11 w-full items-center gap-2.5 px-3 py-1.5 text-left text-[13px] text-muted-foreground hover:bg-muted md:min-h-0";
10
+ const menuRow = "flex min-h-11 w-full items-center gap-2.5 px-3 py-1.5 text-left text-muted-foreground hover:bg-muted md:min-h-0";
11
11
  /** The person at the bottom of the sidebar; the menu is fixed to the viewport so a narrow sidebar cannot clip it. */
12
12
  const ProfileMenu = ({ user, compact, open: controlled, items = [], onNavigate, onSignOut, organizations, roles, theme }) => {
13
13
  const activeRole = roles?.roles.find((role) => role.name === roles.active);
@@ -53,7 +53,7 @@ const ProfileMenu = ({ user, compact, open: controlled, items = [], onNavigate,
53
53
  }), !compact && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
54
54
  className: "min-w-0 flex-1 leading-tight",
55
55
  children: [/* @__PURE__ */ jsx("span", {
56
- className: "block truncate text-[13px] font-medium",
56
+ className: "block truncate font-medium",
57
57
  children: user.name
58
58
  }), /* @__PURE__ */ jsx(Badge, {
59
59
  tone: user.roleTone,
@@ -73,7 +73,7 @@ const ProfileMenu = ({ user, compact, open: controlled, items = [], onNavigate,
73
73
  /* @__PURE__ */ jsxs("div", {
74
74
  className: "border-b px-3 pb-2 pt-1.5",
75
75
  children: [/* @__PURE__ */ jsx("div", {
76
- className: "text-[13px] font-medium",
76
+ className: "font-medium",
77
77
  children: user.name
78
78
  }), /* @__PURE__ */ jsx("div", {
79
79
  className: "truncate text-xs text-muted-foreground",
@@ -7,7 +7,7 @@ import { ChevronRight } from "lucide-react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  //#region src/app-shell/sidebar-group.tsx
9
9
  const row = {
10
- "text-large": "h-8 gap-2.5 px-2.5 text-[13px]",
10
+ "text-large": "h-8 gap-2.5 px-2.5",
11
11
  "text-small": "h-7 gap-2 px-2 text-xs"
12
12
  };
13
13
  /** Lines the records up under the entry's icon. */
@@ -10,7 +10,7 @@ const layout = {
10
10
  icon: "size-9 justify-center",
11
11
  "icon-label": "w-full flex-col gap-0.5 py-1.5 text-[10px]",
12
12
  "icon-tooltip": "size-9 justify-center",
13
- "icon-expand": "h-8 gap-3 px-3 text-[13px]"
13
+ "icon-expand": "h-8 gap-3 px-3"
14
14
  };
15
15
  const SidebarItem = ({ item, mode, active, onNavigate, className }) => {
16
16
  const Icon = item.icon;
@@ -62,11 +62,11 @@ const Sidebar = ({ mode, activeItem, user, workspace, forceExpanded, profileMenu
62
62
  theme
63
63
  }) : /* @__PURE__ */ jsxs(Fragment, { children: [theme && inline && /* @__PURE__ */ jsx(ThemeSwitch, {
64
64
  theme,
65
- className: "flex min-h-11 w-full items-center gap-2.5 whitespace-nowrap p-1.5 text-[13px] text-muted-foreground md:min-h-0"
65
+ className: "flex min-h-11 w-full items-center gap-2.5 whitespace-nowrap p-1.5 text-muted-foreground md:min-h-0"
66
66
  }), signIn && /* @__PURE__ */ jsxs(RouteLink, {
67
67
  to: signIn,
68
68
  "aria-label": "Sign in",
69
- className: "flex min-h-11 w-full items-center gap-2.5 rounded-md p-1.5 text-left text-[13px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground md:min-h-0",
69
+ className: "flex min-h-11 w-full items-center gap-2.5 rounded-md p-1.5 text-left font-medium text-muted-foreground hover:bg-muted hover:text-foreground md:min-h-0",
70
70
  children: [/* @__PURE__ */ jsx(LogIn, { className: "size-4 shrink-0" }), inline && /* @__PURE__ */ jsx("span", {
71
71
  className: "whitespace-nowrap",
72
72
  children: "Sign in"
@@ -24,10 +24,7 @@ const PartView = ({ part, onAction }) => {
24
24
  actions: part.actions,
25
25
  onAction: (actionId) => onAction?.(part.id, actionId),
26
26
  children: [
27
- part.body && /* @__PURE__ */ jsx("p", {
28
- className: "text-[13px]",
29
- children: part.body
30
- }),
27
+ part.body && /* @__PURE__ */ jsx("p", { children: part.body }),
31
28
  part.code && /* @__PURE__ */ jsx("pre", {
32
29
  className: "overflow-x-auto rounded-md bg-surface px-2.5 py-2 font-mono text-[11px] whitespace-pre-wrap break-words",
33
30
  children: part.code
@@ -8,10 +8,7 @@ import { jsx } from "react/jsx-runtime";
8
8
  const Fallback = ({ part, note }) => part.fallback ? /* @__PURE__ */ jsx(ActionCard, {
9
9
  title: part.fallback.title,
10
10
  note,
11
- children: part.fallback.body && /* @__PURE__ */ jsx("p", {
12
- className: "text-[13px]",
13
- children: part.fallback.body
14
- })
11
+ children: part.fallback.body && /* @__PURE__ */ jsx("p", { children: part.fallback.body })
15
12
  }) : /* @__PURE__ */ jsx("p", {
16
13
  className: "text-xs text-muted-foreground",
17
14
  children: `${part.name}: ${note}`
@@ -130,13 +130,13 @@ const useAuthPage = (workspace, children) => {
130
130
  };
131
131
  switch (state.kind) {
132
132
  case "loading": return /* @__PURE__ */ jsxs("div", {
133
- className: "flex h-full min-h-48 items-center justify-center gap-2 text-[13px] text-muted-foreground",
133
+ className: "flex h-full min-h-48 items-center justify-center gap-2 text-muted-foreground",
134
134
  children: [/* @__PURE__ */ jsx(Spinner, {}), " Loading"]
135
135
  });
136
136
  case "error": return /* @__PURE__ */ jsxs("div", {
137
137
  className: "flex h-full min-h-48 flex-col items-center justify-center gap-3 p-8 text-center",
138
138
  children: [/* @__PURE__ */ jsxs("p", {
139
- className: "text-[13px] text-muted-foreground",
139
+ className: "text-muted-foreground",
140
140
  children: ["Cannot reach the server: ", state.message]
141
141
  }), /* @__PURE__ */ jsx(Button, {
142
142
  onClick: recheck,
@@ -15,7 +15,7 @@ const AuthLayout = ({ title, description, children }) => /* @__PURE__ */ jsx("di
15
15
  children: title
16
16
  }),
17
17
  description && /* @__PURE__ */ jsx("p", {
18
- className: "mt-1 text-[13px] text-muted-foreground",
18
+ className: "mt-1 text-muted-foreground",
19
19
  children: description
20
20
  })
21
21
  ]
@@ -16,7 +16,7 @@ const CodeForm = ({ title, description, explanation, submitLabel, onSubmit, onRe
16
16
  description,
17
17
  children: [
18
18
  /* @__PURE__ */ jsx("p", {
19
- className: "mb-4 text-[13px] text-muted-foreground",
19
+ className: "mb-4 text-muted-foreground",
20
20
  children: explanation
21
21
  }),
22
22
  notice && /* @__PURE__ */ jsx("p", {
@@ -32,7 +32,7 @@ const CodeForm = ({ title, description, explanation, submitLabel, onSubmit, onRe
32
32
  },
33
33
  children: [
34
34
  /* @__PURE__ */ jsxs("label", {
35
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
35
+ className: "flex flex-col gap-1.5 font-medium",
36
36
  children: ["Code", /* @__PURE__ */ jsx(OtpInput, {
37
37
  name: "code",
38
38
  required: true,
@@ -16,7 +16,7 @@ const FirstRunPage = ({ command = createAdminCommand, onCheckAgain, busy }) => {
16
16
  description: "This Protobase has no users to sign in with.",
17
17
  children: [
18
18
  /* @__PURE__ */ jsx("p", {
19
- className: "text-[13px] text-muted-foreground",
19
+ className: "text-muted-foreground",
20
20
  children: "Run this in the terminal where Protobase runs, then reload. The first admin is created on the server, not in the browser, so nobody else can claim a fresh URL."
21
21
  }),
22
22
  /* @__PURE__ */ jsxs("div", {
@@ -11,7 +11,7 @@ const ForgotPasswordForm = ({ onSubmit, back, busy, error, sentTo }) => {
11
11
  if (sentTo) return /* @__PURE__ */ jsxs(AuthLayout, {
12
12
  title: "Check your email",
13
13
  children: [/* @__PURE__ */ jsxs("p", {
14
- className: "text-[13px] text-muted-foreground",
14
+ className: "text-muted-foreground",
15
15
  children: [
16
16
  "If ",
17
17
  /* @__PURE__ */ jsx("span", {
@@ -37,7 +37,7 @@ const ForgotPasswordForm = ({ onSubmit, back, busy, error, sentTo }) => {
37
37
  },
38
38
  children: [
39
39
  /* @__PURE__ */ jsxs("label", {
40
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
40
+ className: "flex flex-col gap-1.5 font-medium",
41
41
  children: ["Email", /* @__PURE__ */ jsx(Input, {
42
42
  type: "email",
43
43
  name: "email",
@@ -13,7 +13,7 @@ const ProviderRedirect = ({ name, workspace }) => /* @__PURE__ */ jsx(AuthLayout
13
13
  description: workspace,
14
14
  children: /* @__PURE__ */ jsxs("p", {
15
15
  role: "status",
16
- className: "flex items-center justify-center gap-2 text-[13px] text-muted-foreground",
16
+ className: "flex items-center justify-center gap-2 text-muted-foreground",
17
17
  children: [
18
18
  /* @__PURE__ */ jsx(Spinner, {}),
19
19
  " Taking you to ",
@@ -10,7 +10,7 @@ const ResetPasswordForm = ({ onSubmit, invalidLink, onRequestNewLink, onBack, bu
10
10
  if (invalidLink) return /* @__PURE__ */ jsxs(AuthLayout, {
11
11
  title: "This link no longer works",
12
12
  children: [/* @__PURE__ */ jsx("p", {
13
- className: "text-[13px] text-muted-foreground",
13
+ className: "text-muted-foreground",
14
14
  children: "A reset link works once, for a limited time. Ask for a new one to choose your password."
15
15
  }), /* @__PURE__ */ jsxs("div", {
16
16
  className: "mt-4 flex flex-col gap-2",
@@ -40,7 +40,7 @@ const ResetPasswordForm = ({ onSubmit, invalidLink, onRequestNewLink, onBack, bu
40
40
  },
41
41
  children: [
42
42
  /* @__PURE__ */ jsxs("label", {
43
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
43
+ className: "flex flex-col gap-1.5 font-medium",
44
44
  children: ["New password", /* @__PURE__ */ jsx(Input, {
45
45
  type: "password",
46
46
  name: "new-password",
@@ -55,7 +55,7 @@ const ResetPasswordForm = ({ onSubmit, invalidLink, onRequestNewLink, onBack, bu
55
55
  })]
56
56
  }),
57
57
  /* @__PURE__ */ jsxs("label", {
58
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
58
+ className: "flex flex-col gap-1.5 font-medium",
59
59
  children: ["Repeat new password", /* @__PURE__ */ jsx(Input, {
60
60
  type: "password",
61
61
  name: "repeat-password",
@@ -16,7 +16,7 @@ const SetupRequiredForm = ({ step, twoFactor, onAddPasskey, busy, error, onSignO
16
16
  className: "flex flex-col gap-4",
17
17
  children: [
18
18
  /* @__PURE__ */ jsx("p", {
19
- className: "text-[13px] text-muted-foreground",
19
+ className: "text-muted-foreground",
20
20
  children: "A passkey signs you in with Face ID, Touch ID, Windows Hello, your phone or a security key. Your browser asks which one to use."
21
21
  }),
22
22
  error && /* @__PURE__ */ jsx("p", {
@@ -35,7 +35,7 @@ const SetupRequiredForm = ({ step, twoFactor, onAddPasskey, busy, error, onSignO
35
35
  }), /* @__PURE__ */ jsx("button", {
36
36
  type: "button",
37
37
  onClick: onSignOut,
38
- className: "mt-4 w-full text-center text-[13px] font-medium text-muted-foreground hover:underline",
38
+ className: "mt-4 w-full text-center font-medium text-muted-foreground hover:underline",
39
39
  children: "Sign out"
40
40
  })]
41
41
  });
@@ -28,7 +28,7 @@ const SetupRequiredPage = ({ missing }) => {
28
28
  }
29
29
  };
30
30
  if (!methods && !error) return /* @__PURE__ */ jsxs("div", {
31
- className: "flex h-full min-h-48 items-center justify-center gap-2 text-[13px] text-muted-foreground",
31
+ className: "flex h-full min-h-48 items-center justify-center gap-2 text-muted-foreground",
32
32
  children: [/* @__PURE__ */ jsx(Spinner, {}), " Loading"]
33
33
  });
34
34
  return /* @__PURE__ */ jsx(SetupRequiredForm, {
@@ -78,7 +78,7 @@ const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["pass
78
78
  },
79
79
  children: [
80
80
  /* @__PURE__ */ jsxs("label", {
81
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
81
+ className: "flex flex-col gap-1.5 font-medium",
82
82
  children: ["Email", /* @__PURE__ */ jsx(Input, {
83
83
  ref: emailInput,
84
84
  type: "email",
@@ -93,7 +93,7 @@ const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["pass
93
93
  })]
94
94
  }),
95
95
  withPassword && /* @__PURE__ */ jsxs("label", {
96
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
96
+ className: "flex flex-col gap-1.5 font-medium",
97
97
  children: ["Password", /* @__PURE__ */ jsx(Input, {
98
98
  type: "password",
99
99
  name: "password",
@@ -128,13 +128,13 @@ const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["pass
128
128
  }),
129
129
  withPassword && forgotPassword && /* @__PURE__ */ jsx(RouteLink, {
130
130
  to: forgotPassword,
131
- className: "self-center text-[13px] font-medium text-primary-text hover:underline",
131
+ className: "self-center font-medium text-primary-text hover:underline",
132
132
  children: "Forgot password?"
133
133
  })
134
134
  ]
135
135
  }),
136
136
  signUp && /* @__PURE__ */ jsxs("p", {
137
- className: "mt-4 text-center text-[13px] text-muted-foreground",
137
+ className: "mt-4 text-center text-muted-foreground",
138
138
  children: [
139
139
  "New here?",
140
140
  " ",
@@ -148,7 +148,7 @@ const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["pass
148
148
  onBrowse && /* @__PURE__ */ jsx("button", {
149
149
  type: "button",
150
150
  onClick: onBrowse,
151
- className: "mt-4 w-full text-center text-[13px] font-medium text-muted-foreground hover:text-foreground hover:underline",
151
+ className: "mt-4 w-full text-center font-medium text-muted-foreground hover:text-foreground hover:underline",
152
152
  children: "Continue without signing in"
153
153
  })
154
154
  ]
@@ -9,7 +9,7 @@ import { Check, LogIn } from "lucide-react";
9
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/auth/sign-in-prompt.tsx
11
11
  const Benefits = ({ benefits }) => benefits && benefits.length > 0 ? /* @__PURE__ */ jsx("ul", {
12
- className: "flex flex-col gap-2 text-left text-[13px]",
12
+ className: "flex flex-col gap-2 text-left",
13
13
  children: benefits.map((benefit) => /* @__PURE__ */ jsxs("li", {
14
14
  className: "flex items-start gap-2",
15
15
  children: [/* @__PURE__ */ jsx(Check, {
@@ -78,7 +78,7 @@ const SignInPrompt = (props) => {
78
78
  className: "text-lg font-semibold",
79
79
  children: prompt.title
80
80
  }), /* @__PURE__ */ jsx("p", {
81
- className: "text-[13px] text-muted-foreground",
81
+ className: "text-muted-foreground",
82
82
  children: prompt.description
83
83
  })]
84
84
  }),
@@ -15,7 +15,7 @@ const SignUpDetailsForm = ({ email, onSubmit, onBack, methods, busy, error }) =>
15
15
  title: "Your details",
16
16
  description: "One last step to create your account.",
17
17
  children: [/* @__PURE__ */ jsxs("p", {
18
- className: "mb-4 text-[13px] text-muted-foreground",
18
+ className: "mb-4 text-muted-foreground",
19
19
  children: [
20
20
  "The code was right: the account is for ",
21
21
  /* @__PURE__ */ jsx("span", {
@@ -35,7 +35,7 @@ const SignUpDetailsForm = ({ email, onSubmit, onBack, methods, busy, error }) =>
35
35
  },
36
36
  children: [
37
37
  /* @__PURE__ */ jsxs("label", {
38
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
38
+ className: "flex flex-col gap-1.5 font-medium",
39
39
  children: ["Your name", /* @__PURE__ */ jsx(Input, {
40
40
  name: "name",
41
41
  autoComplete: "name",
@@ -50,7 +50,7 @@ const SignUpDetailsForm = ({ email, onSubmit, onBack, methods, busy, error }) =>
50
50
  withPassword && /* @__PURE__ */ jsxs("div", {
51
51
  className: "flex flex-col gap-1.5",
52
52
  children: [/* @__PURE__ */ jsxs("label", {
53
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
53
+ className: "flex flex-col gap-1.5 font-medium",
54
54
  children: [passwordOptional ? "Password (optional)" : "Password", /* @__PURE__ */ jsx(Input, {
55
55
  type: "password",
56
56
  name: "password",
@@ -19,7 +19,7 @@ const SignUpEmailForm = ({ onSubmit, onSignIn, onBrowse, busy, error, workspace
19
19
  },
20
20
  children: [
21
21
  /* @__PURE__ */ jsxs("label", {
22
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
22
+ className: "flex flex-col gap-1.5 font-medium",
23
23
  children: ["Email", /* @__PURE__ */ jsx(Input, {
24
24
  type: "email",
25
25
  name: "email",
@@ -33,7 +33,7 @@ const SignUpEmailForm = ({ onSubmit, onSignIn, onBrowse, busy, error, workspace
33
33
  })]
34
34
  }),
35
35
  /* @__PURE__ */ jsx("p", {
36
- className: "text-[13px] text-muted-foreground",
36
+ className: "text-muted-foreground",
37
37
  children: "We email you a code to make sure the address is yours."
38
38
  }),
39
39
  error && /* @__PURE__ */ jsx("p", {
@@ -49,7 +49,7 @@ const SignUpEmailForm = ({ onSubmit, onSignIn, onBrowse, busy, error, workspace
49
49
  children: [/* @__PURE__ */ jsx(Mail, { className: "size-4" }), "Email me a code"]
50
50
  }),
51
51
  /* @__PURE__ */ jsxs("p", {
52
- className: "text-center text-[13px] text-muted-foreground",
52
+ className: "text-center text-muted-foreground",
53
53
  children: [
54
54
  "Have an account?",
55
55
  " ",
@@ -65,7 +65,7 @@ const SignUpEmailForm = ({ onSubmit, onSignIn, onBrowse, busy, error, workspace
65
65
  }), onBrowse && /* @__PURE__ */ jsx("button", {
66
66
  type: "button",
67
67
  onClick: onBrowse,
68
- className: "mt-4 w-full text-center text-[13px] font-medium text-muted-foreground hover:text-foreground hover:underline",
68
+ className: "mt-4 w-full text-center font-medium text-muted-foreground hover:text-foreground hover:underline",
69
69
  children: "Continue without an account"
70
70
  })]
71
71
  });
@@ -35,7 +35,7 @@ const StaffSignInForm = ({ operator, email: givenEmail = "", reason: givenReason
35
35
  },
36
36
  children: [
37
37
  /* @__PURE__ */ jsxs("label", {
38
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
38
+ className: "flex flex-col gap-1.5 font-medium",
39
39
  children: ["Their email", /* @__PURE__ */ jsx(Input, {
40
40
  type: "email",
41
41
  name: "email",
@@ -47,7 +47,7 @@ const StaffSignInForm = ({ operator, email: givenEmail = "", reason: givenReason
47
47
  })]
48
48
  }),
49
49
  /* @__PURE__ */ jsxs("label", {
50
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
50
+ className: "flex flex-col gap-1.5 font-medium",
51
51
  children: ["Reason", /* @__PURE__ */ jsx("textarea", {
52
52
  name: "reason",
53
53
  required: true,
@@ -56,7 +56,7 @@ const StaffSignInForm = ({ operator, email: givenEmail = "", reason: givenReason
56
56
  value: reason,
57
57
  placeholder: "Ticket 4211: the invoice totals look wrong",
58
58
  onChange: (event) => setReason(event.target.value),
59
- className: cn("resize-y rounded-md border bg-background px-2.5 py-1.5 text-[13px] font-normal shadow-sm outline-none placeholder:text-faint-foreground focus:border-primary focus:ring-2 focus:ring-primary/20", error ? "border-danger" : "border-border-strong")
59
+ className: cn("resize-y rounded-md border bg-background px-2.5 py-1.5 font-normal shadow-sm outline-none placeholder:text-faint-foreground focus:border-primary focus:ring-2 focus:ring-primary/20", error ? "border-danger" : "border-border-strong")
60
60
  })]
61
61
  }),
62
62
  /* @__PURE__ */ jsxs("p", {
@@ -29,7 +29,7 @@ const TwoFactorForm = ({ methods, onVerify, onSendCode, onBack, busy, error, cod
29
29
  className: "flex flex-col gap-4",
30
30
  children: [
31
31
  /* @__PURE__ */ jsx("p", {
32
- className: "text-[13px] text-muted-foreground",
32
+ className: "text-muted-foreground",
33
33
  children: "We email you a code to finish signing in."
34
34
  }),
35
35
  error && /* @__PURE__ */ jsx("p", {
@@ -57,11 +57,11 @@ const TwoFactorForm = ({ methods, onVerify, onSendCode, onBack, busy, error, cod
57
57
  },
58
58
  children: [
59
59
  /* @__PURE__ */ jsx("p", {
60
- className: "text-[13px] text-muted-foreground",
60
+ className: "text-muted-foreground",
61
61
  children: instructions[step]
62
62
  }),
63
63
  /* @__PURE__ */ jsxs("label", {
64
- className: "flex flex-col gap-1.5 text-[13px] font-medium",
64
+ className: "flex flex-col gap-1.5 font-medium",
65
65
  children: [step === "backup" ? "Backup code" : "Code", step === "backup" ? /* @__PURE__ */ jsx(Input, {
66
66
  name: "code",
67
67
  autoComplete: "off",
@@ -82,7 +82,7 @@ const TwoFactorForm = ({ methods, onVerify, onSendCode, onBack, busy, error, cod
82
82
  })]
83
83
  }),
84
84
  /* @__PURE__ */ jsxs("label", {
85
- className: "flex items-center gap-2 text-[13px] text-muted-foreground",
85
+ className: "flex items-center gap-2 text-muted-foreground",
86
86
  children: [/* @__PURE__ */ jsx(Checkbox, {
87
87
  checked: trustDevice,
88
88
  onChange: setTrustDevice,
@@ -103,7 +103,7 @@ const TwoFactorForm = ({ methods, onVerify, onSendCode, onBack, busy, error, cod
103
103
  })
104
104
  ]
105
105
  }), /* @__PURE__ */ jsxs("div", {
106
- className: "mt-4 flex flex-col items-center gap-2 border-t pt-4 text-[13px]",
106
+ className: "mt-4 flex flex-col items-center gap-2 border-t pt-4",
107
107
  children: [
108
108
  step !== "totp" && methods.includes("totp") && /* @__PURE__ */ jsx("button", {
109
109
  type: "button",
@@ -4,7 +4,7 @@ import { jsx } from "react/jsx-runtime";
4
4
  /** One message of a chat: the user's as a bubble on the right, the other side's as plain content, cards included. */
5
5
  const ChatMessage = ({ from, children }) => /* @__PURE__ */ jsx("div", {
6
6
  "data-from": from,
7
- className: cn("flex min-w-0 flex-col gap-2 whitespace-pre-wrap break-words text-[13px]", from === "user" ? "ml-8 self-end rounded-lg rounded-br-sm bg-primary px-3 py-2 text-primary-foreground shadow-sm" : "mr-4 text-foreground"),
7
+ className: cn("flex min-w-0 flex-col gap-2 whitespace-pre-wrap break-words", from === "user" ? "ml-8 self-end rounded-lg rounded-br-sm bg-primary px-3 py-2 text-primary-foreground shadow-sm" : "mr-4 text-foreground"),
8
8
  children
9
9
  });
10
10
  //#endregion
@@ -14,7 +14,7 @@ const ChatThread = ({ children, empty, length }) => {
14
14
  "aria-live": "polite",
15
15
  className: "flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto p-4",
16
16
  children: length === 0 && empty ? /* @__PURE__ */ jsx("div", {
17
- className: "m-auto max-w-60 text-center text-[13px] text-muted-foreground",
17
+ className: "m-auto max-w-60 text-center text-muted-foreground",
18
18
  children: empty
19
19
  }) : children
20
20
  });
@@ -90,6 +90,13 @@ const keys = {
90
90
  resource,
91
91
  filter
92
92
  ],
93
+ /** How many rows an export of the list would hold, exactly up to 10,000; starts with `list`, so it refreshes with the list. */
94
+ exportCount: (resource, filter) => [
95
+ "list",
96
+ resource,
97
+ filter,
98
+ "export-count"
99
+ ],
93
100
  firstRecord: (resource, filter, orderBy) => [
94
101
  "first-record",
95
102
  resource,