@coffer-org/web-ui 4.0.0 → 6.0.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 (53) hide show
  1. package/dist/components/ui/copy-button.d.ts +6 -0
  2. package/dist/components/ui/copy-button.js +28 -0
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.js +2 -1
  5. package/dist/internal-link.d.ts +15 -0
  6. package/dist/internal-link.js +66 -0
  7. package/dist/layout.js +3 -3
  8. package/dist/registry.d.ts +2 -1
  9. package/dist/registry.js +1 -0
  10. package/dist/render/activate.d.ts +4 -0
  11. package/dist/render/activate.js +11 -0
  12. package/dist/render/blocks/balance.js +3 -2
  13. package/dist/render/blocks/block-shell.d.ts +1 -0
  14. package/dist/render/blocks/block-shell.js +4 -0
  15. package/dist/render/blocks/chart.js +2 -1
  16. package/dist/render/blocks/compare.js +2 -1
  17. package/dist/render/blocks/countdown.js +2 -1
  18. package/dist/render/blocks/idcard.js +2 -1
  19. package/dist/render/blocks/journal.js +2 -1
  20. package/dist/render/blocks/ledger.js +2 -2
  21. package/dist/render/blocks/manifest.js +2 -1
  22. package/dist/render/blocks/masthead.js +2 -1
  23. package/dist/render/blocks/meter.js +2 -2
  24. package/dist/render/blocks/nutrition.js +2 -2
  25. package/dist/render/blocks/plaque.js +2 -1
  26. package/dist/render/blocks/receipt.js +2 -2
  27. package/dist/render/blocks/score.js +2 -2
  28. package/dist/render/blocks/stats.js +3 -2
  29. package/dist/render/blocks/table.js +5 -4
  30. package/dist/render/chrome.d.ts +21 -3
  31. package/dist/render/chrome.js +46 -6
  32. package/dist/render/core/dimensions.js +1 -1
  33. package/dist/render/core/embed.js +8 -1
  34. package/dist/render/core/money.js +1 -1
  35. package/dist/render/core/range.js +1 -1
  36. package/dist/render/core/reminder.js +1 -1
  37. package/dist/render/core/text.js +57 -3
  38. package/dist/render/core/weight.js +1 -1
  39. package/dist/render/datum.d.ts +4 -0
  40. package/dist/render/datum.js +16 -0
  41. package/dist/render/dispatch.js +4 -2
  42. package/dist/render/field-frame.d.ts +1 -1
  43. package/dist/render/field-frame.js +20 -9
  44. package/dist/render/markdown-view.js +33 -4
  45. package/dist/render/popover-field.js +10 -19
  46. package/dist/render/widgets/display.js +2 -1
  47. package/dist/render/widgets/edit.js +2 -2
  48. package/dist/render/widgets/fixed-collection.js +2 -1
  49. package/dist/render/widgets/group-widgets.js +1 -1
  50. package/dist/render/widgets/group.js +2 -1
  51. package/dist/render/widgets/table-group.js +4 -3
  52. package/dist/types.d.ts +2 -0
  53. package/package.json +2 -2
@@ -15,7 +15,7 @@ import { Plus } from 'lucide-react';
15
15
  import { RecordInline } from "../../components/RecordInline.js";
16
16
  import { RemoveBtn, AddBtn, MultipleChips, CheckLegend, colsToCheckRow, checkRowToCols, Dash, } from "../shared.js";
17
17
  import { FieldSlot } from "../dispatch.js";
18
- import { FieldLabel } from "../chrome.js";
18
+ import { FieldLabel, CHROME_LABEL_CLS } from "../chrome.js";
19
19
  import { measuredChipContent, measuredUnitLabel } from "./display.js";
20
20
  import { ChecklistRow } from "./checklist-row.js";
21
21
  import { ChecklistContent, clientChecklistContentFields } from "./checklist-content.js";
@@ -238,7 +238,7 @@ export function KeyValueWidget({ value, onChange, multiple = true, option, keyLa
238
238
  const canAdd = multiple || rows.length < 1;
239
239
  return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(FlowRow, { items: rows.map((item, idx) => ({
240
240
  key: String(idx),
241
- node: (_jsxs("div", { className: "flex flex-col gap-0.5 w-56 max-w-full min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1 min-w-0", children: [_jsx(Input, { placeholder: kLabel, value: item.key, className: "h-6 px-1 min-w-0 text-[11px] font-semibold uppercase text-muted", autoComplete: "off", onChange: (e) => save(rows.map((x, i) => (i === idx ? { ...x, key: e.target.value } : x))) }), _jsx(RemoveBtn, { onClick: () => save(rows.filter((_, i) => i !== idx)) })] }), _jsx(FieldSlot, { bare: true, field: option, value: item.value, mode: "edit", onChange: (v) => updatePairValue(idx, String(v)), recordCtx: recordCtx })] })),
241
+ node: (_jsxs("div", { className: "flex flex-col gap-0.5 w-56 max-w-full min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1 min-w-0", children: [_jsx(Input, { placeholder: kLabel, value: item.key, className: `h-6 px-1 ${CHROME_LABEL_CLS}`, autoComplete: "off", onChange: (e) => save(rows.map((x, i) => (i === idx ? { ...x, key: e.target.value } : x))) }), _jsx(RemoveBtn, { onClick: () => save(rows.filter((_, i) => i !== idx)) })] }), _jsx(FieldSlot, { bare: true, field: option, value: item.value, mode: "edit", onChange: (v) => updatePairValue(idx, String(v)), recordCtx: recordCtx })] })),
242
242
  })) }), canAdd && (_jsxs(AddBtn, { onClick: () => setRows((r) => [...r, { key: '', value: '' }]), children: [kLabel, "/", vLabel] }))] }));
243
243
  }
244
244
  function parseMeasuredItems(value) {
@@ -8,6 +8,7 @@ import { FlowRow } from "./flow-row.js";
8
8
  import { subFull } from "./group.js";
9
9
  import { useGroupEdit } from "./group-edit.js";
10
10
  import { useHybridScope } from "../hybrid-scope.js";
11
+ import { datumClass } from "../datum.js";
11
12
  export function FixedCollection({ group, value, onChange, recordCtx, mode = 'edit', }) {
12
13
  const { t } = useTranslation();
13
14
  const depth = useGroupDepth();
@@ -29,6 +30,6 @@ export function FixedCollection({ group, value, onChange, recordCtx, mode = 'edi
29
30
  return (_jsxs("fieldset", { className: `${groupScopeClass(depth)} flex flex-col min-w-0 ${STACK}`, children: [_jsx(GroupTitle, { as: "legend", label: t(group.label), icon: groupIcon(group), actions: live ? null : g.actions }), _jsx("div", { className: `flex flex-col ${STACK}`, children: rows.map((row, idx) => (_jsx(Rail, { children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsxs("div", { className: "flex flex-col gap-0.5 min-w-0 shrink-0", children: [by.type.label ? _jsx(FieldLabel, { label: t(by.type.label) }) : null, _jsx("span", { className: "text-sm px-1 py-2", children: fmtOptionLabel(t, { options: byOpts }, String(row[by.key] ?? '')) })] }), _jsx("div", { className: "flex-1 min-w-0", children: _jsx(FlowRow, { items: valueFields.map((sub) => ({
30
31
  key: sub.key,
31
32
  full: subFull(sub.type),
32
- node: editing ? (_jsx("div", { className: "flex flex-col gap-0.5 min-w-0", children: _jsx(FieldSlot, { field: sub.type, value: row[sub.key] ?? '', onChange: (v) => update(idx, sub.key, v), label: sub.type.label ? t(sub.type.label) : undefined, mode: "edit", recordCtx: recordCtx }) })) : (_jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [sub.type.label ? _jsx(FieldLabel, { label: t(sub.type.label) }) : null, _jsx(FieldSlot, { field: sub.type, fieldKey: live ? sub.key : undefined, value: row[sub.key] ?? '', onChange: live ? (v) => update(idx, sub.key, v) : undefined, mode: "view", bare: !live, recordCtx: recordCtx })] })),
33
+ node: editing ? (_jsx("div", { className: "flex flex-col gap-0.5 min-w-0", children: _jsx(FieldSlot, { field: sub.type, value: row[sub.key] ?? '', onChange: (v) => update(idx, sub.key, v), label: sub.type.label ? t(sub.type.label) : undefined, mode: "edit", recordCtx: recordCtx }) })) : (_jsxs("div", { className: `flex flex-col gap-0.5 min-w-0 ${datumClass(sub.type)}`.trim(), children: [sub.type.label ? _jsx(FieldLabel, { label: t(sub.type.label) }) : null, _jsx(FieldSlot, { field: sub.type, fieldKey: live ? sub.key : undefined, value: row[sub.key] ?? '', onChange: live ? (v) => update(idx, sub.key, v) : undefined, mode: "view", bare: !live, recordCtx: recordCtx })] })),
33
34
  })) }) })] }) }, String(row[by.key])))) })] }));
34
35
  }
@@ -37,5 +37,5 @@ function ChecklistPage({ el, value, recordCtx, mode }) {
37
37
  return (_jsx(ChecklistGroup, { group: el, value: value, onChange: (v) => void write(v), recordCtx: recordCtx, mode: mode }));
38
38
  }
39
39
  registerRenderer({ kinds: ['per-weekday'], layout: 'block', Page: WeekdayGroupPage, editor: 'custom' });
40
- registerRenderer({ kinds: ['url'], layout: 'block', Page: UrlGroupPage });
40
+ registerRenderer({ kinds: ['url'], layout: 'block', Page: UrlGroupPage, activate: 'value' });
41
41
  registerRenderer({ kinds: ['checklist'], layout: 'block', Page: ChecklistPage, editor: 'custom' });
@@ -12,6 +12,7 @@ import { useFieldErrors } from "../field-errors.js";
12
12
  import { GroupField } from "./group-field.js";
13
13
  import { useGroupEdit } from "./group-edit.js";
14
14
  import { useHybridScope } from "../hybrid-scope.js";
15
+ import { datumClass } from "../datum.js";
15
16
  import { FlowRow } from "./flow-row.js";
16
17
  import { fieldLayout } from "../../registry.js";
17
18
  export const subFull = (f) => fieldLayout(f) === 'block';
@@ -75,7 +76,7 @@ function CollectionCell({ sub, row, group, recordCtx, onChange, }) {
75
76
  const { t } = useTranslation();
76
77
  const live = useHybridScope() && Boolean(onChange);
77
78
  const wired = live ? onChange : undefined;
78
- return (_jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [sub.type.label ? _jsx(FieldLabel, { label: t(sub.type.label) }) : null, _jsx(FieldSlot, { field: sub.type, fieldKey: live ? sub.key : undefined, value: row[sub.key] ?? '', mode: "view", bare: !live, recordCtx: recordCtx, onChange: wired })] }));
79
+ return (_jsxs("div", { className: `flex flex-col gap-0.5 min-w-0 ${datumClass(sub.type)}`.trim(), children: [sub.type.label ? _jsx(FieldLabel, { label: t(sub.type.label) }) : null, _jsx(FieldSlot, { field: sub.type, fieldKey: live ? sub.key : undefined, value: row[sub.key] ?? '', mode: "view", bare: !live, recordCtx: recordCtx, onChange: wired })] }));
79
80
  }
80
81
  export function CollectionView({ group, value, onChange, recordCtx, actions, editable = false, }) {
81
82
  const { t } = useTranslation();
@@ -6,10 +6,11 @@ import { hasValue, hasChildren, isNamedField, isStorageGroup } from '@coffer-org
6
6
  import { FieldSlot } from "../dispatch.js";
7
7
  import { useFieldErrors } from "../field-errors.js";
8
8
  import { AddBtn, usedElsewhere } from "../shared.js";
9
- import { GroupTitle, groupIcon, useGroupDepth, GroupDepthProvider, groupScopeClass } from "../chrome.js";
9
+ import { GroupTitle, groupIcon, useGroupDepth, GroupDepthProvider, groupScopeClass, ChromeLabel } from "../chrome.js";
10
10
  import { Button } from "../../components/ui/button.js";
11
11
  import { useGroupEdit } from "./group-edit.js";
12
12
  import { useHybridScope } from "../hybrid-scope.js";
13
+ import { datumClass } from "../datum.js";
13
14
  export function TableGroup({ group, value, onChange, recordCtx, mode, }) {
14
15
  const { t } = useTranslation();
15
16
  const errorAt = useFieldErrors();
@@ -49,8 +50,8 @@ export function TableGroup({ group, value, onChange, recordCtx, mode, }) {
49
50
  };
50
51
  const addRow = () => (live ? setPending((ps) => [...ps, {}]) : setRows([...rows, {}]));
51
52
  const rowTools = isEdit || live;
52
- const header = (_jsx("thead", { children: _jsxs("tr", { className: "border-b border-border/60 bg-muted/15", children: [subs.map((s, i) => (_jsx("th", { className: `text-left text-[11px] font-semibold text-muted uppercase tracking-wider px-3.5 py-2.5 ${isGrowCol(s, i) ? 'w-full min-w-[140px]' : 'whitespace-nowrap min-w-[90px]'}`, children: colLabel(s) ? t(colLabel(s)) : '' }, colKey(s)))), rowTools && _jsx("th", { className: "w-10 px-2", "aria-hidden": true })] }) }));
53
- const body = (_jsx("tbody", { className: "divide-y divide-border/30", children: rows.map((row, idx) => (_jsxs("tr", { className: "align-top hover:bg-muted/10 transition-colors", children: [subs.map((s, i) => (_jsx("td", { className: `px-3.5 py-2.5 min-h-10 ${isGrowCol(s, i) ? 'min-w-[140px]' : 'min-w-[90px]'}`, children: _jsx(FieldSlot, { ...colSlot(s), value: row[colKey(s)] ?? (hasValue(s) ? '' : null), excludeValues: usedElsewhere(rows, unique, colKey(s), idx), onChange: (v) => update(idx, colKey(s), v), fieldKey: live ? colKey(s) : undefined, mode: isEdit ? 'edit' : 'view', bare: !live, recordCtx: recordCtx, error: isStorageGroup(group) ? errorAt([group.key, idx, colKey(s)]) : undefined }) }, colKey(s)))), rowTools && (_jsx("td", { className: "px-2 py-2 min-h-10 w-10", children: _jsx(Button, { type: "button", variant: "outline", size: "iconSm", onClick: () => removeRow(idx), title: t('actions.delete'), className: "rounded-lg text-muted hover:border-danger hover:text-danger", children: _jsx(Trash2, { size: 14 }) }) }))] }, idx))) }));
53
+ const header = (_jsx("thead", { children: _jsxs("tr", { className: "border-b border-border/60 bg-muted/15", children: [subs.map((s, i) => (_jsx("th", { className: `text-left px-3.5 py-2.5 ${isGrowCol(s, i) ? 'w-full min-w-[140px]' : 'whitespace-nowrap min-w-[90px]'}`, children: _jsx(ChromeLabel, { children: colLabel(s) ? t(colLabel(s)) : '' }) }, colKey(s)))), rowTools && _jsx("th", { className: "w-10 px-2", "aria-hidden": true })] }) }));
54
+ const body = (_jsx("tbody", { className: "divide-y divide-border/30", children: rows.map((row, idx) => (_jsxs("tr", { className: "align-top hover:bg-muted/10 transition-colors", children: [subs.map((s, i) => (_jsx("td", { className: `px-3.5 py-2.5 min-h-10 ${isGrowCol(s, i) ? 'min-w-[140px]' : 'min-w-[90px]'} ${datumClass(colSlot(s).field)}`.trim(), children: _jsx(FieldSlot, { ...colSlot(s), value: row[colKey(s)] ?? (hasValue(s) ? '' : null), excludeValues: usedElsewhere(rows, unique, colKey(s), idx), onChange: (v) => update(idx, colKey(s), v), fieldKey: live ? colKey(s) : undefined, mode: isEdit ? 'edit' : 'view', bare: !live, recordCtx: recordCtx, error: isStorageGroup(group) ? errorAt([group.key, idx, colKey(s)]) : undefined }) }, colKey(s)))), rowTools && (_jsx("td", { className: "px-2 py-2 min-h-10 w-10", children: _jsx(Button, { type: "button", variant: "outline", size: "iconSm", onClick: () => removeRow(idx), title: t('actions.delete'), className: "rounded-lg text-muted hover:border-danger hover:text-danger", children: _jsx(Trash2, { size: 14 }) }) }))] }, idx))) }));
54
55
  const tableEl = (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("div", { className: "overflow-x-auto rounded-lg border border-border/60 bg-card/20 shadow-2xs", children: _jsxs("table", { className: "w-full border-collapse text-sm", children: [header, body] }) }), rowTools && _jsx(AddBtn, { onClick: addRow, children: t('form.addRow') })] }));
55
56
  if (mode !== 'view')
56
57
  return tableEl;
package/dist/types.d.ts CHANGED
@@ -48,6 +48,7 @@ export interface FieldValueProps {
48
48
  }
49
49
  export type PickerSize = 'small' | 'large' | 'modal';
50
50
  export type EditorMode = 'popover' | 'modal' | 'inplace' | 'custom';
51
+ export type ActivateMode = 'edit' | 'value';
51
52
  export interface FieldPickerProps {
52
53
  field: FieldMeta;
53
54
  draft: unknown;
@@ -80,5 +81,6 @@ export interface FieldRenderer {
80
81
  pickerSize?: PickerSize | ((field: FieldMeta) => PickerSize);
81
82
  Picker?: FC<FieldPickerProps>;
82
83
  editor?: EditorMode;
84
+ activate?: ActivateMode;
83
85
  keys?: (value: unknown, field: FieldMeta, ctx: FieldKeyCtx) => FieldKey[];
84
86
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffer-org/web-ui",
3
- "version": "4.0.0",
3
+ "version": "6.0.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"
@@ -25,7 +25,7 @@
25
25
  "postpack": "node ../../scripts/swap-exports.mjs src"
26
26
  },
27
27
  "dependencies": {
28
- "@coffer-org/sdk": "^4.0.0",
28
+ "@coffer-org/sdk": "^6.0.0",
29
29
  "@ark-ui/react": "^5.37.2",
30
30
  "@base-ui/react": "^1.5.0",
31
31
  "@icons-pack/react-simple-icons": "^13.13.0",