@protobase/ui 0.21.10 → 0.21.12

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/app/app.js +1 -1
  2. package/dist/app/comments/comment-composer.js +1 -1
  3. package/dist/app/create/create-page.js +1 -1
  4. package/dist/app/create/create-values.js +4 -2
  5. package/dist/app/current-address.d.ts +1 -0
  6. package/dist/app/current-address.js +2 -1
  7. package/dist/app/displays/board-column.js +1 -1
  8. package/dist/app/displays/calendar-display.js +1 -1
  9. package/dist/app/displays/list-cards.js +1 -1
  10. package/dist/app/displays/map-display.js +1 -1
  11. package/dist/app/embedded-list/embedded-list.js +1 -1
  12. package/dist/app/field-editor.js +3 -3
  13. package/dist/app/gallery/detail-fields.js +2 -1
  14. package/dist/app/gallery/gallery-section.js +1 -1
  15. package/dist/app/gallery/photo-details.js +1 -1
  16. package/dist/app/group-open.js +7 -0
  17. package/dist/app/hand-order/hand-sorted-list.js +1 -1
  18. package/dist/app/incoming-relations.js +2 -1
  19. package/dist/app/list-page.js +1 -1
  20. package/dist/app/pages/action-inputs/action-inputs-dialog.js +1 -1
  21. package/dist/app/pages/blocks/card-row.js +1 -1
  22. package/dist/app/pages/blocks/modal-form.js +1 -1
  23. package/dist/app/pages/blocks/record-card.js +1 -1
  24. package/dist/app/pages/blocks/show.js +5 -34
  25. package/dist/app/pages/record-actions.js +1 -1
  26. package/dist/app/pages/use-conditions.js +49 -0
  27. package/dist/app/record-mode/record-mode.js +4 -1
  28. package/dist/app/record-mode/shown-layout.js +25 -0
  29. package/dist/app/record-mode/use-shown-layout.js +14 -0
  30. package/dist/app/record-page.js +90 -72
  31. package/dist/app/record-row/record-row-body.js +1 -1
  32. package/dist/app/record-row/saved-record-row.js +1 -1
  33. package/dist/app/related-section.js +10 -1
  34. package/dist/app/searches/saved-search-rows.js +1 -1
  35. package/dist/app/searches/saved-searches.js +1 -1
  36. package/dist/app/sensitive-field.js +1 -1
  37. package/dist/app/use-app-address.d.ts +1 -0
  38. package/dist/app/use-record-editor.js +1 -1
  39. package/dist/forms/public-form-page.js +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/live/field-values.js +1 -1
  42. package/dist/package.js +1 -1
  43. package/dist/record-view/group-section.js +35 -0
  44. package/dist/shell/assets/app-IuP56Dep.js +69 -0
  45. package/dist/shell/assets/{index-CzqIlZPP.css → index-DhW8t8wq.css} +1 -1
  46. package/dist/shell/assets/{index-C_o0i6I2.js → index-GB5YRjlo.js} +1 -1
  47. package/dist/shell/assets/{maplibre-DLYsHwYU.js → maplibre-BLm41BrA.js} +1 -1
  48. package/dist/shell/assets/{markdown-content-B410ow-t.js → markdown-content-Cia4jbSB.js} +1 -1
  49. package/dist/shell/assets/{record-map-DvgWFyLn.js → record-map-C-Svn7nc.js} +1 -1
  50. package/dist/shell/assets/{records-map-CLj0uHGq.js → records-map-D5LZhC54.js} +1 -1
  51. package/dist/shell/assets/{shared-protobase-ui-Bf1h2ktk.js → shared-protobase-ui-D16YbnPr.js} +1 -1
  52. package/dist/shell/index.html +4 -4
  53. package/dist/shell/protobase.shell.json +1 -1
  54. package/package.json +4 -4
  55. package/dist/shell/assets/app-9imuOKuW.js +0 -69
@@ -13,12 +13,6 @@ import { Field } from "../record-view/field.js";
13
13
  import { Section } from "../record-view/section.js";
14
14
  import { MetadataCard } from "../record-view/record-sidebar.js";
15
15
  import { RecordHeader } from "../record-view/record-header.js";
16
- import { SpecTable } from "../record-view/spec-table.js";
17
- import { KeyFacts } from "../record-view/key-facts.js";
18
- import { fromDraft, isRequiredOnEdit } from "../live/field-values.js";
19
- import { fieldHelp, helpShown, recordShown, whenShown } from "./record-mode/record-mode.js";
20
- import { isChosen, keyValue } from "./create/create-values.js";
21
- import { ErrorBanner } from "./error-banner.js";
22
16
  import { isMarkdown } from "../markdown/markdown-hint.js";
23
17
  import { recordTitle } from "../live/model-helpers.js";
24
18
  import { contactFormat } from "../live/contact-links.js";
@@ -27,6 +21,13 @@ import { displayValue, valueTitle } from "../live/display-value.js";
27
21
  import { filledFields } from "./filled-fields.js";
28
22
  import { Notice, useAdminMeta, usePermissions } from "./meta-gate.js";
29
23
  import { AppLink, useAppAddress } from "./use-app-address.js";
24
+ import { GroupSection } from "../record-view/group-section.js";
25
+ import { SpecTable } from "../record-view/spec-table.js";
26
+ import { KeyFacts } from "../record-view/key-facts.js";
27
+ import { fromDraft, isRequiredOnEdit } from "../live/field-values.js";
28
+ import { fieldHelp, helpShown, recordShown, whenShown } from "./record-mode/record-mode.js";
29
+ import { isChosen, keyValue } from "./create/create-values.js";
30
+ import { ErrorBanner } from "./error-banner.js";
30
31
  import { useProjectUi } from "./pages/project-ui.js";
31
32
  import { shownWidget } from "./field-types/shown-widget.js";
32
33
  import { WidgetPart } from "./field-types/widget-part.js";
@@ -45,6 +46,7 @@ import { auditField } from "../live/audit-fields.js";
45
46
  import { CustomSection } from "./custom-section.js";
46
47
  import { MapSection } from "./map/map-section.js";
47
48
  import { RecordActions } from "./pages/record-actions.js";
49
+ import { groupOpen, toggledOpen } from "./group-open.js";
48
50
  import { RecordLines, findLinesResource } from "./record-lines.js";
49
51
  import { draftStorageKey } from "./draft-storage.js";
50
52
  import { useLines } from "./use-lines.js";
@@ -52,6 +54,7 @@ import { useLinesDraft } from "./use-lines-draft.js";
52
54
  import { GallerySection } from "./gallery/gallery-section.js";
53
55
  import { HistorySection } from "./history/history-section.js";
54
56
  import { CommentsSection } from "./comments/comments-section.js";
57
+ import { useShownLayout } from "./record-mode/use-shown-layout.js";
55
58
  import { useRecordEditor } from "./use-record-editor.js";
56
59
  import { useRelatedRecords } from "./use-related-records.js";
57
60
  import { IncomingCard } from "./incoming-card.js";
@@ -149,15 +152,17 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
149
152
  const { shown, offersEdit, editing } = recordShown(view?.recordMode, canUpdate, address?.kind === "record" && address.edit === true);
150
153
  useNavigationGuard(editor.dirty && shown === "form");
151
154
  usePauseFocusRefresh(editor.dirty);
152
- const readAddress = {
155
+ const openGroups = address?.kind === "record" ? address.open : void 0;
156
+ const atEdit = address?.kind === "record" && address.edit === true;
157
+ const recordAt = (open = [], edit = false) => ({
153
158
  kind: "record",
154
159
  resource: model.name,
155
- key: recordKey
156
- };
157
- const editAddress = {
158
- ...readAddress,
159
- edit: true
160
- };
160
+ key: recordKey,
161
+ ...edit && { edit },
162
+ ...open.length > 0 && { open }
163
+ });
164
+ const readAddress = recordAt(openGroups);
165
+ const editAddress = recordAt(openGroups, true);
161
166
  const leavesForm = shown === "form" && view?.recordMode !== void 0 && view.recordMode !== "edit";
162
167
  const canDelete = can(permissions, "delete") && stored.permissions?.delete !== false;
163
168
  const remove = useDeleteFlow({
@@ -190,7 +195,14 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
190
195
  editor.change(name, keyValue(target, next.key));
191
196
  };
192
197
  const { fields: fieldTypes } = useProjectUi();
193
- const layout = layoutFor(model, view, shown === "read").filter((item) => whenShown(item.when, editing));
198
+ const scope = {
199
+ model,
200
+ record: stored.record,
201
+ key: recordKey,
202
+ etag: stored.etag,
203
+ permissions: stored.permissions
204
+ };
205
+ const layout = useShownLayout(layoutFor(model, view, shown === "read"), scope, editing, preview);
194
206
  const sidebarFields = layout.flatMap((item) => item.kind === "sidebar" ? item.fields : []);
195
207
  const hasStatus = model.fields.status?.type === "enum";
196
208
  const statusValue = stored.record.status;
@@ -307,13 +319,6 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
307
319
  }];
308
320
  })
309
321
  });
310
- const scope = {
311
- model,
312
- record: stored.record,
313
- key: recordKey,
314
- etag: stored.etag,
315
- permissions: stored.permissions
316
- };
317
322
  const save = async () => {
318
323
  if (await editor.save() && leavesForm) go(readAddress, { replace: true });
319
324
  };
@@ -343,6 +348,69 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
343
348
  children: "Unsaved changes"
344
349
  })
345
350
  ] });
351
+ const mainItem = (item, index) => {
352
+ if (item.kind === "group") {
353
+ const children = item.items.flatMap(mainItem);
354
+ if (children.length === 0) return [];
355
+ const open = groupOpen(item, openGroups, (name) => editing && (editor.errors[name] !== void 0 || editor.conflicts[name] !== void 0));
356
+ const toggle = item.collapsed ? recordAt(toggledOpen(openGroups, item.title), atEdit) : void 0;
357
+ return [/* @__PURE__ */ jsx(GroupSection, {
358
+ title: item.title,
359
+ open,
360
+ toggle,
361
+ children
362
+ }, `group:${item.title}`)];
363
+ }
364
+ if (item.kind === "related") return [/* @__PURE__ */ jsx(RelatedSection, {
365
+ item,
366
+ recordKey,
367
+ owner: model.name
368
+ }, `related:${item.title}`)];
369
+ if (preview && (item.kind === "custom" || item.kind === "map" || item.kind === "gallery")) return [];
370
+ if (item.kind === "custom") return item.sidebar ? [] : [/* @__PURE__ */ jsx(CustomSection, {
371
+ item,
372
+ scope
373
+ }, `custom:${index}`)];
374
+ if (item.kind === "map") return item.sidebar ? [] : [/* @__PURE__ */ jsx(MapSection, {
375
+ item,
376
+ record: stored.record
377
+ }, `map:${index}`)];
378
+ if (item.kind === "gallery") return [/* @__PURE__ */ jsx(GallerySection, {
379
+ item,
380
+ record: stored.record,
381
+ recordKey
382
+ }, `gallery:${index}`)];
383
+ if (item.kind === "history") return [/* @__PURE__ */ jsx(HistorySection, {
384
+ item,
385
+ model,
386
+ view,
387
+ recordKey,
388
+ etag: stored.etag
389
+ }, `history:${index}`)];
390
+ if (item.kind === "comments") return [/* @__PURE__ */ jsx(CommentsSection, {
391
+ item,
392
+ resource: model.name,
393
+ recordKey,
394
+ canWrite: auth.kind !== "visitor"
395
+ }, `comments:${index}`)];
396
+ if (item.kind !== "section") return [];
397
+ const visibleFields = item.fields.filter((name) => model.fields[name] && visible(name));
398
+ const facts = shown === "read" && item.presentation === "facts";
399
+ const fields = facts ? filledFields(stored.record, visibleFields) : visibleFields;
400
+ if (fields.length === 0) return [];
401
+ return [/* @__PURE__ */ jsx(Section, {
402
+ title: item.title,
403
+ help: helpShown(item.helpWhen, view, editing) ? item.help : void 0,
404
+ children: facts ? /* @__PURE__ */ jsx(KeyFacts, { facts: fields.map((name) => ({
405
+ label: readRow(name).label,
406
+ value: readRow(name).value,
407
+ icon: namedIcon(hint(name)?.icon)
408
+ })) }) : shown === "read" ? /* @__PURE__ */ jsx(SpecTable, { rows: fields.map(readRow) }) : /* @__PURE__ */ jsx("div", {
409
+ className: "grid grid-cols-1 gap-x-6 gap-y-5 sm:grid-cols-2",
410
+ children: fields.map(fieldView)
411
+ })
412
+ }, item.title)];
413
+ };
346
414
  return /* @__PURE__ */ jsxs("div", {
347
415
  ref: fieldsRef,
348
416
  className: "flex flex-1 flex-col",
@@ -411,57 +479,7 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
411
479
  className: "grid grid-cols-1 gap-8 md:grid-cols-[minmax(0,1fr)_300px] md:gap-12",
412
480
  children: [/* @__PURE__ */ jsxs("main", {
413
481
  className: "divide-y divide-border",
414
- children: [layout.flatMap((item, index) => {
415
- if (item.kind === "related") return [/* @__PURE__ */ jsx(RelatedSection, {
416
- item,
417
- recordKey,
418
- owner: model.name
419
- }, `related:${item.title}`)];
420
- if (preview && (item.kind === "custom" || item.kind === "map" || item.kind === "gallery")) return [];
421
- if (item.kind === "custom") return item.sidebar ? [] : [/* @__PURE__ */ jsx(CustomSection, {
422
- item,
423
- scope
424
- }, `custom:${index}`)];
425
- if (item.kind === "map") return item.sidebar ? [] : [/* @__PURE__ */ jsx(MapSection, {
426
- item,
427
- record: stored.record
428
- }, `map:${index}`)];
429
- if (item.kind === "gallery") return [/* @__PURE__ */ jsx(GallerySection, {
430
- item,
431
- record: stored.record,
432
- recordKey
433
- }, `gallery:${index}`)];
434
- if (item.kind === "history") return [/* @__PURE__ */ jsx(HistorySection, {
435
- item,
436
- model,
437
- view,
438
- recordKey,
439
- etag: stored.etag
440
- }, `history:${index}`)];
441
- if (item.kind === "comments") return [/* @__PURE__ */ jsx(CommentsSection, {
442
- item,
443
- resource: model.name,
444
- recordKey,
445
- canWrite: auth.kind !== "visitor"
446
- }, `comments:${index}`)];
447
- if (item.kind !== "section") return [];
448
- const visibleFields = item.fields.filter((name) => model.fields[name] && visible(name));
449
- const facts = shown === "read" && item.presentation === "facts";
450
- const fields = facts ? filledFields(stored.record, visibleFields) : visibleFields;
451
- if (fields.length === 0) return [];
452
- return [/* @__PURE__ */ jsx(Section, {
453
- title: item.title,
454
- help: helpShown(item.helpWhen, view, editing) ? item.help : void 0,
455
- children: facts ? /* @__PURE__ */ jsx(KeyFacts, { facts: fields.map((name) => ({
456
- label: readRow(name).label,
457
- value: readRow(name).value,
458
- icon: namedIcon(hint(name)?.icon)
459
- })) }) : shown === "read" ? /* @__PURE__ */ jsx(SpecTable, { rows: fields.map(readRow) }) : /* @__PURE__ */ jsx("div", {
460
- className: "grid grid-cols-1 gap-x-6 gap-y-5 sm:grid-cols-2",
461
- children: fields.map(fieldView)
462
- })
463
- }, item.title)];
464
- }), linesModel && !preview && /* @__PURE__ */ jsx(RecordLines, {
482
+ children: [layout.flatMap(mainItem), linesModel && !preview && /* @__PURE__ */ jsx(RecordLines, {
465
483
  lines: linesModel,
466
484
  draft: linesDraft,
467
485
  vatRate: Number(stored.record.vatRate ?? 21) / 100,
@@ -1,11 +1,11 @@
1
1
  import { useIsXs } from "../../lib/use-media-query.js";
2
2
  import { Skeleton } from "../../primitives/skeleton.js";
3
3
  import { humanize } from "../../live/naming.js";
4
- import { ErrorBanner } from "../error-banner.js";
5
4
  import { displaysOf, loadedFields } from "../displays/list-displays.js";
6
5
  import { defaultOrderBy } from "../list-order.js";
7
6
  import { useAdminMeta } from "../meta-gate.js";
8
7
  import { AppLink } from "../use-app-address.js";
8
+ import { ErrorBanner } from "../error-banner.js";
9
9
  import { useLiveRows } from "../../live/use-live-rows.js";
10
10
  import { viewAllAddress } from "../embedded-list/embedded-display.js";
11
11
  import { FilterChipList } from "../searches/filter-chip-list.js";
@@ -1,8 +1,8 @@
1
1
  import { Skeleton } from "../../primitives/skeleton.js";
2
2
  import { humanize } from "../../live/naming.js";
3
- import { ErrorBanner } from "../error-banner.js";
4
3
  import { listedResource } from "../current-address.js";
5
4
  import { useAdminMeta } from "../meta-gate.js";
5
+ import { ErrorBanner } from "../error-banner.js";
6
6
  import { savedScope } from "../saved/saved-records.js";
7
7
  import { useSavedRecords } from "../saved/use-saved-records.js";
8
8
  import { RecordRowBody } from "./record-row-body.js";
@@ -2,9 +2,10 @@ import { Skeleton } from "../primitives/skeleton.js";
2
2
  import { keys } from "../data/query-keys.js";
3
3
  import { useClient } from "../data/api-provider.js";
4
4
  import { Section } from "../record-view/section.js";
5
- import { ErrorBanner } from "./error-banner.js";
6
5
  import { listColumnNames } from "../live/columns-from-model.js";
7
6
  import { useAdminMeta, usePermissions } from "./meta-gate.js";
7
+ import { ErrorBanner } from "./error-banner.js";
8
+ import { countQuery } from "./pages/use-layout-data.js";
8
9
  import { searchAll } from "../live/search-all.js";
9
10
  import { relatedOpens } from "./related-opens.js";
10
11
  import { EmbeddedDisplaySwitch, EmbeddedList } from "./embedded-list/embedded-list.js";
@@ -82,7 +83,15 @@ const RelatedSection = ({ item, recordKey, owner }) => {
82
83
  const [display, pick] = useEmbeddedDisplay(view, `related:${owner}:${item.title}`, item.display);
83
84
  const permissions = usePermissions(item.resource);
84
85
  const [sorting, setSorting] = useState(false);
86
+ const client = useClient();
87
+ const counting = Boolean(item.hideEmpty && model && match.filter);
88
+ const count = useQuery({
89
+ queryKey: keys.count(item.resource, match.filter ?? ""),
90
+ enabled: counting,
91
+ queryFn: () => countQuery(client, model, match.filter ?? "").queryFn()
92
+ });
85
93
  if (!model) return null;
94
+ if (item.hideEmpty && (match.isPending || match.filter === null || counting && (count.isPending || count.data === 0))) return null;
86
95
  const opens = relatedOpens(item, model, resources);
87
96
  const columns = item.columns ?? listColumnNames(model, view).filter((name) => name !== item.field);
88
97
  const handOrder = relatedHandOrder(item, model, permissions);
@@ -1,9 +1,9 @@
1
1
  import { Skeleton } from "../../primitives/skeleton.js";
2
2
  import { humanize } from "../../live/naming.js";
3
- import { ErrorBanner } from "../error-banner.js";
4
3
  import { recordKey } from "../../live/model-helpers.js";
5
4
  import { useAdminMeta } from "../meta-gate.js";
6
5
  import { AppLink } from "../use-app-address.js";
6
+ import { ErrorBanner } from "../error-banner.js";
7
7
  import { InlineFilterChips } from "./filter-chip-list.js";
8
8
  import { RecordRowBody } from "../record-row/record-row-body.js";
9
9
  import { useSavedSearches } from "./use-saved-searches.js";
@@ -1,10 +1,10 @@
1
1
  import { Skeleton } from "../../primitives/skeleton.js";
2
2
  import { PageHeader } from "../../app-shell/page-header.js";
3
3
  import { humanize } from "../../live/naming.js";
4
- import { ErrorBanner } from "../error-banner.js";
5
4
  import { recordKey } from "../../live/model-helpers.js";
6
5
  import { Notice, useAdminMeta, usePermissions } from "../meta-gate.js";
7
6
  import { AppLink } from "../use-app-address.js";
7
+ import { ErrorBanner } from "../error-banner.js";
8
8
  import { can } from "../permissions.js";
9
9
  import { useSavedSearches } from "./use-saved-searches.js";
10
10
  import { useDeleteFlow } from "../delete/use-delete-flow.js";
@@ -2,9 +2,9 @@ import { cn } from "../lib/cn.js";
2
2
  import { Input } from "../primitives/input.js";
3
3
  import { Button } from "../primitives/button.js";
4
4
  import { humanize } from "../live/naming.js";
5
+ import { displayValue } from "../live/display-value.js";
5
6
  import { toDraft } from "../live/field-values.js";
6
7
  import { ErrorBanner } from "./error-banner.js";
7
- import { displayValue } from "../live/display-value.js";
8
8
  import { useState } from "react";
9
9
  import { Eye, EyeOff } from "lucide-react";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -21,6 +21,7 @@ export declare const useAppAddress: () => {
21
21
  /** A link to an address in the app: an ordinary anchor that the router follows without reloading the page. */
22
22
  export declare const AppLink: ({ to, ...rest }: AnchorHTMLAttributes<HTMLAnchorElement> & {
23
23
  to: AppAddress;
24
+ replace?: boolean;
24
25
  }) => import("react").JSX.Element;
25
26
  //#endregion
26
27
  export type { CurrentAddress, ListAddress, ListChange };
@@ -1,7 +1,7 @@
1
1
  import { keys } from "../data/query-keys.js";
2
2
  import { useClient } from "../data/api-provider.js";
3
- import { differs, toDraft, toPatchValue } from "../live/field-values.js";
4
3
  import { displayValue } from "../live/display-value.js";
4
+ import { differs, toDraft, toPatchValue } from "../live/field-values.js";
5
5
  import { fieldErrors } from "./field-errors.js";
6
6
  import { useLiveSave } from "./use-live-save.js";
7
7
  import { readDraft, writeDraft } from "./draft-storage.js";
@@ -5,10 +5,10 @@ import { useClient } from "../data/api-provider.js";
5
5
  import { AuthLayout } from "../auth/auth-layout.js";
6
6
  import { humanize } from "../live/naming.js";
7
7
  import { Field } from "../record-view/field.js";
8
+ import { Notice } from "../app/meta-gate.js";
8
9
  import { createBody, hasDatabaseDefault, initialDraft, isRequired } from "../app/create/create-values.js";
9
10
  import { useDocumentTitle } from "../app/document-title.js";
10
11
  import { ErrorBanner } from "../app/error-banner.js";
11
- import { Notice } from "../app/meta-gate.js";
12
12
  import { FieldEditor } from "../app/field-editor.js";
13
13
  import { fieldErrors, fieldMessage } from "../app/field-errors.js";
14
14
  import { useFocusFirstInvalid } from "../app/use-focus-first-invalid.js";
package/dist/index.js CHANGED
@@ -18,9 +18,9 @@ import { useApiToken } from "./auth/use-api-token.js";
18
18
  import { useRecord } from "./data/use-record.js";
19
19
  import { Field } from "./record-view/field.js";
20
20
  import { Section } from "./record-view/section.js";
21
- import { Textarea } from "./primitives/textarea.js";
22
21
  import { useMeta } from "./data/use-meta.js";
23
22
  import { AppLink, useAppAddress } from "./app/use-app-address.js";
23
+ import { Textarea } from "./primitives/textarea.js";
24
24
  import { useList } from "./data/use-list.js";
25
25
  import { definePlugin, defineUi } from "./app/pages/project-ui.js";
26
26
  import { ChatMessage } from "./chat/chat-message.js";
@@ -1,5 +1,5 @@
1
- import { localeDecimal, parseNumberText } from "../format/number-text.js";
2
1
  import { fileDiffers, filePatchValue } from "./file-values.js";
2
+ import { localeDecimal, parseNumberText } from "../format/number-text.js";
3
3
  //#region src/live/field-values.ts
4
4
  /** What the editor's text input holds for a stored value. */
5
5
  const toDraft = (value) => value === null || value === void 0 ? "" : typeof value === "object" ? JSON.stringify(value) : String(value);
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.21.10";
2
+ var version = "0.21.12";
3
3
  var protobase = { "pluginApi": 1 };
4
4
  //#endregion
5
5
  export { protobase, version };
@@ -0,0 +1,35 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import { AppLink } from "../app/use-app-address.js";
3
+ import { useId } from "react";
4
+ import { ChevronRight } from "lucide-react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/record-view/group-section.tsx
7
+ const headingClass = "text-[16px] font-semibold text-foreground";
8
+ /**
9
+ * A heading over sections of the record page. With `toggle`, the address that opens or closes it, the heading is a
10
+ * link, so a copied link opens the page with the group open; the items show only while `open`. Without it the group
11
+ * is always open.
12
+ */
13
+ const GroupSection = ({ title, open, toggle, children }) => {
14
+ const id = useId();
15
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
16
+ className: cn("py-8", open && "pb-0"),
17
+ children: toggle ? /* @__PURE__ */ jsxs(AppLink, {
18
+ to: toggle,
19
+ replace: true,
20
+ "aria-expanded": open,
21
+ "aria-controls": id,
22
+ className: cn("inline-flex items-center gap-1.5", headingClass),
23
+ children: [/* @__PURE__ */ jsx(ChevronRight, { className: cn("size-4 transition-transform", open && "rotate-90") }), title]
24
+ }) : /* @__PURE__ */ jsx("span", {
25
+ className: headingClass,
26
+ children: title
27
+ })
28
+ }), open && /* @__PURE__ */ jsx("div", {
29
+ id,
30
+ className: "divide-y divide-border",
31
+ children
32
+ })] });
33
+ };
34
+ //#endregion
35
+ export { GroupSection };