@ai-matrx/records-ui 0.103.0 → 0.103.3
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/CHANGELOG.md +18 -0
- package/dist/index.cjs +162 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +162 -46
- package/dist/index.js.map +1 -1
- package/dist/pickers.cjs +10 -2
- package/dist/pickers.cjs.map +1 -1
- package/dist/pickers.js +10 -2
- package/dist/pickers.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -2993,6 +2993,12 @@ interface ConditionGroupProps {
|
|
|
2993
2993
|
* person builds them — the depth the store compiles.
|
|
2994
2994
|
*/
|
|
2995
2995
|
allowNesting?: boolean;
|
|
2996
|
+
/**
|
|
2997
|
+
* How many levels of groups a person may make below the whole condition (Notion's advanced
|
|
2998
|
+
* filter: 2 — a group, and a group inside it). Left out, no limit. A deeper saved question still
|
|
2999
|
+
* draws; only "Add a group" stops at the limit.
|
|
3000
|
+
*/
|
|
3001
|
+
maxDepth?: number | undefined;
|
|
2996
3002
|
/** How deep this group sits (0 = the whole condition). Set by the builder itself. */
|
|
2997
3003
|
depth?: number;
|
|
2998
3004
|
/** A nested group can take itself away; the outermost one cannot. */
|
|
@@ -3005,7 +3011,7 @@ interface ConditionGroupProps {
|
|
|
3005
3011
|
* writing one condition never meets a control for a problem they do not have. A nested group
|
|
3006
3012
|
* always shows its joiner: it is a box with its own and / or, and that is the whole point of it.
|
|
3007
3013
|
*/
|
|
3008
|
-
declare function ConditionGroup({ lead, expr, fields, onChange, emptyLabel, allowNesting, depth, onRemove, className, }: ConditionGroupProps): react.JSX.Element;
|
|
3014
|
+
declare function ConditionGroup({ lead, expr, fields, onChange, emptyLabel, allowNesting, maxDepth, depth, onRemove, className, }: ConditionGroupProps): react.JSX.Element;
|
|
3009
3015
|
|
|
3010
3016
|
/** The longest name a table keeps; a longer one is said, never cut. */
|
|
3011
3017
|
declare const TABLE_NAME_MAX = 120;
|
|
@@ -3224,6 +3230,12 @@ interface PickOrAddChip {
|
|
|
3224
3230
|
interface PickOrAddProps {
|
|
3225
3231
|
/** The trigger's accessible name, e.g. "Pick for Category". */
|
|
3226
3232
|
triggerLabel: string;
|
|
3233
|
+
/**
|
|
3234
|
+
* The trigger's height. "field" (the default) is the height of the text box beside it in a form
|
|
3235
|
+
* (WALK3-FIX, 2026-10-07: Pick/Choose sat 4px shorter than the date box in the same grid row);
|
|
3236
|
+
* "compact" keeps the small button a filter row or a chooser draws.
|
|
3237
|
+
*/
|
|
3238
|
+
triggerSize?: "field" | "compact" | undefined;
|
|
3227
3239
|
/** The trigger's visible word, e.g. "Pick", "Change", "Choose". */
|
|
3228
3240
|
triggerText: string;
|
|
3229
3241
|
triggerId?: string | undefined;
|
|
@@ -3276,7 +3288,7 @@ interface PickOrAddProps {
|
|
|
3276
3288
|
*/
|
|
3277
3289
|
multi?: boolean | undefined;
|
|
3278
3290
|
}
|
|
3279
|
-
declare function PickOrAdd({ triggerLabel, triggerText, triggerId, open, onOpenChange, search, onSearch, items, onPick, notice, empty, add, foot, footNote, onEnterWithNoMatch, anchored, children, chips, multi, onEscape, }: PickOrAddProps): react.JSX.Element;
|
|
3291
|
+
declare function PickOrAdd({ triggerSize, triggerLabel, triggerText, triggerId, open, onOpenChange, search, onSearch, items, onPick, notice, empty, add, foot, footNote, onEnterWithNoMatch, anchored, children, chips, multi, onEscape, }: PickOrAddProps): react.JSX.Element;
|
|
3280
3292
|
|
|
3281
3293
|
/** What the panel says while the chosen list is empty. */
|
|
3282
3294
|
declare const ENTITY_REFERENCE_KINDS_MISSING = "Choose at least one kind of thing this column points at.";
|
package/dist/index.d.ts
CHANGED
|
@@ -2993,6 +2993,12 @@ interface ConditionGroupProps {
|
|
|
2993
2993
|
* person builds them — the depth the store compiles.
|
|
2994
2994
|
*/
|
|
2995
2995
|
allowNesting?: boolean;
|
|
2996
|
+
/**
|
|
2997
|
+
* How many levels of groups a person may make below the whole condition (Notion's advanced
|
|
2998
|
+
* filter: 2 — a group, and a group inside it). Left out, no limit. A deeper saved question still
|
|
2999
|
+
* draws; only "Add a group" stops at the limit.
|
|
3000
|
+
*/
|
|
3001
|
+
maxDepth?: number | undefined;
|
|
2996
3002
|
/** How deep this group sits (0 = the whole condition). Set by the builder itself. */
|
|
2997
3003
|
depth?: number;
|
|
2998
3004
|
/** A nested group can take itself away; the outermost one cannot. */
|
|
@@ -3005,7 +3011,7 @@ interface ConditionGroupProps {
|
|
|
3005
3011
|
* writing one condition never meets a control for a problem they do not have. A nested group
|
|
3006
3012
|
* always shows its joiner: it is a box with its own and / or, and that is the whole point of it.
|
|
3007
3013
|
*/
|
|
3008
|
-
declare function ConditionGroup({ lead, expr, fields, onChange, emptyLabel, allowNesting, depth, onRemove, className, }: ConditionGroupProps): react.JSX.Element;
|
|
3014
|
+
declare function ConditionGroup({ lead, expr, fields, onChange, emptyLabel, allowNesting, maxDepth, depth, onRemove, className, }: ConditionGroupProps): react.JSX.Element;
|
|
3009
3015
|
|
|
3010
3016
|
/** The longest name a table keeps; a longer one is said, never cut. */
|
|
3011
3017
|
declare const TABLE_NAME_MAX = 120;
|
|
@@ -3224,6 +3230,12 @@ interface PickOrAddChip {
|
|
|
3224
3230
|
interface PickOrAddProps {
|
|
3225
3231
|
/** The trigger's accessible name, e.g. "Pick for Category". */
|
|
3226
3232
|
triggerLabel: string;
|
|
3233
|
+
/**
|
|
3234
|
+
* The trigger's height. "field" (the default) is the height of the text box beside it in a form
|
|
3235
|
+
* (WALK3-FIX, 2026-10-07: Pick/Choose sat 4px shorter than the date box in the same grid row);
|
|
3236
|
+
* "compact" keeps the small button a filter row or a chooser draws.
|
|
3237
|
+
*/
|
|
3238
|
+
triggerSize?: "field" | "compact" | undefined;
|
|
3227
3239
|
/** The trigger's visible word, e.g. "Pick", "Change", "Choose". */
|
|
3228
3240
|
triggerText: string;
|
|
3229
3241
|
triggerId?: string | undefined;
|
|
@@ -3276,7 +3288,7 @@ interface PickOrAddProps {
|
|
|
3276
3288
|
*/
|
|
3277
3289
|
multi?: boolean | undefined;
|
|
3278
3290
|
}
|
|
3279
|
-
declare function PickOrAdd({ triggerLabel, triggerText, triggerId, open, onOpenChange, search, onSearch, items, onPick, notice, empty, add, foot, footNote, onEnterWithNoMatch, anchored, children, chips, multi, onEscape, }: PickOrAddProps): react.JSX.Element;
|
|
3291
|
+
declare function PickOrAdd({ triggerSize, triggerLabel, triggerText, triggerId, open, onOpenChange, search, onSearch, items, onPick, notice, empty, add, foot, footNote, onEnterWithNoMatch, anchored, children, chips, multi, onEscape, }: PickOrAddProps): react.JSX.Element;
|
|
3280
3292
|
|
|
3281
3293
|
/** What the panel says while the chosen list is empty. */
|
|
3282
3294
|
declare const ENTITY_REFERENCE_KINDS_MISSING = "Choose at least one kind of thing this column points at.";
|
package/dist/index.js
CHANGED
|
@@ -1115,6 +1115,7 @@ function PickChips({ chips }) {
|
|
|
1115
1115
|
) });
|
|
1116
1116
|
}
|
|
1117
1117
|
function PickOrAdd({
|
|
1118
|
+
triggerSize = "field",
|
|
1118
1119
|
triggerLabel,
|
|
1119
1120
|
triggerText,
|
|
1120
1121
|
triggerId,
|
|
@@ -1173,7 +1174,7 @@ function PickOrAdd({
|
|
|
1173
1174
|
}
|
|
1174
1175
|
) : null;
|
|
1175
1176
|
return /* @__PURE__ */ jsxs5(Popover, { open, onOpenChange, children: [
|
|
1176
|
-
anchored ? /* @__PURE__ */ jsx6(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsx6("div", { className: "flex min-h-6 w-full min-w-0 flex-wrap items-center gap-1", "aria-label": triggerLabel, children }) }) : /* @__PURE__ */ jsx6(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(Button2, { id: triggerId, type: "button", size: "sm", variant: "outline", "aria-label": triggerLabel, children: triggerText }) }),
|
|
1177
|
+
anchored ? /* @__PURE__ */ jsx6(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsx6("div", { "data-pick-anchor": "", className: "flex min-h-6 w-full min-w-0 flex-wrap items-center gap-1", "aria-label": triggerLabel, children }) }) : /* @__PURE__ */ jsx6(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(Button2, { id: triggerId, type: "button", size: "sm", variant: "outline", className: triggerSize === "field" ? "h-9" : void 0, "aria-label": triggerLabel, children: triggerText }) }),
|
|
1177
1178
|
/* @__PURE__ */ jsxs5(
|
|
1178
1179
|
PopoverContent,
|
|
1179
1180
|
{
|
|
@@ -3595,6 +3596,7 @@ function PickOne({
|
|
|
3595
3596
|
return /* @__PURE__ */ jsx14("span", { className: cn11("inline-flex min-w-0", className), "data-records-pick-one": "search", "data-pick-value": value, ...attrs ?? {}, children: /* @__PURE__ */ jsx14(
|
|
3596
3597
|
PickOrAdd,
|
|
3597
3598
|
{
|
|
3599
|
+
triggerSize: "compact",
|
|
3598
3600
|
triggerLabel: label,
|
|
3599
3601
|
triggerText: current?.label ?? placeholder ?? "",
|
|
3600
3602
|
triggerId: id,
|
|
@@ -4680,7 +4682,7 @@ function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
|
|
|
4680
4682
|
disabled,
|
|
4681
4683
|
autoComplete: "off",
|
|
4682
4684
|
"aria-invalid": refusal4 ? true : void 0,
|
|
4683
|
-
placeholder: helper
|
|
4685
|
+
placeholder: helper ? typedDatePlaceholder(helper) : void 0,
|
|
4684
4686
|
onChange: (e) => retype(e.target.value),
|
|
4685
4687
|
onBlur: () => {
|
|
4686
4688
|
if (!refusal4) return;
|
|
@@ -4694,6 +4696,12 @@ function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
|
|
|
4694
4696
|
refusal4 ? /* @__PURE__ */ jsx19("span", { "data-records-typed-refusal": "", "data-records-cell-note": "", role: "status", title: why, className: "text-[11px] leading-snug text-amber-700 dark:text-amber-400", children: refusal4 }) : null
|
|
4695
4697
|
] });
|
|
4696
4698
|
}
|
|
4699
|
+
function typedDatePlaceholder(helper) {
|
|
4700
|
+
const time = "h:mm AM";
|
|
4701
|
+
if (helper === "time") return time;
|
|
4702
|
+
const pattern = typedDateText2("2026-11-22").replace("2026", "YYYY").replace("11", "MM").replace("22", "DD");
|
|
4703
|
+
return helper === "datetime" ? `${pattern} ${time}` : pattern;
|
|
4704
|
+
}
|
|
4697
4705
|
function CheckboxControl({ field: field2, value, onChange, disabled, id }) {
|
|
4698
4706
|
const unanswered = value === null || value === void 0;
|
|
4699
4707
|
return /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
|
|
@@ -6347,16 +6355,16 @@ function cellMarkSentence(field2, document2, value) {
|
|
|
6347
6355
|
const kept = keptAsideFor(document2, field2.key);
|
|
6348
6356
|
return kept ? keptAsideReason(field2, kept) : null;
|
|
6349
6357
|
}
|
|
6350
|
-
|
|
6351
|
-
function WorkedOutError({ field: field2, sentence: sentence2 }) {
|
|
6358
|
+
function WorkedOutError({ field: field2, sentence: sentence2, floated = false }) {
|
|
6352
6359
|
return /* @__PURE__ */ jsx26(
|
|
6353
6360
|
"span",
|
|
6354
6361
|
{
|
|
6355
6362
|
"data-records-worked-out-error": field2.key,
|
|
6363
|
+
role: "img",
|
|
6356
6364
|
title: sentence2,
|
|
6357
|
-
"aria-label":
|
|
6358
|
-
className: "cursor-help
|
|
6359
|
-
children:
|
|
6365
|
+
"aria-label": sentence2,
|
|
6366
|
+
className: (floated ? "absolute right-1 top-1/2 z-10 flex -translate-y-1/2 " : "inline-flex align-middle ") + "h-4 w-4 shrink-0 cursor-help items-center justify-center rounded-full bg-destructive text-[10px] font-bold leading-none text-destructive-foreground",
|
|
6367
|
+
children: "!"
|
|
6360
6368
|
}
|
|
6361
6369
|
);
|
|
6362
6370
|
}
|
|
@@ -6585,7 +6593,7 @@ function RecordValue({
|
|
|
6585
6593
|
if (withheld && (value === null || value === void 0)) return /* @__PURE__ */ jsx27(WithheldValue, { field: field2, notice: withheld });
|
|
6586
6594
|
if (value === null || value === void 0) {
|
|
6587
6595
|
const failed = workedOutErrorFor(document2, field2.key);
|
|
6588
|
-
if (failed) return /* @__PURE__ */ jsx27(WorkedOutError, { field: field2, sentence: failed });
|
|
6596
|
+
if (failed) return /* @__PURE__ */ jsx27(WorkedOutError, { field: field2, sentence: failed, floated: Boolean(inCell) });
|
|
6589
6597
|
}
|
|
6590
6598
|
if (inCell) {
|
|
6591
6599
|
const kept = keptAsideFor(document2, field2.key);
|
|
@@ -7208,6 +7216,22 @@ function GridCell({
|
|
|
7208
7216
|
const open = Boolean(
|
|
7209
7217
|
editing && editing.editing?.rowId === row.id && editing.editing.key === field2.key
|
|
7210
7218
|
);
|
|
7219
|
+
const closedControl = useRef15(null);
|
|
7220
|
+
const wasOpen = useRef15(false);
|
|
7221
|
+
useEffect15(() => {
|
|
7222
|
+
if (open) {
|
|
7223
|
+
wasOpen.current = true;
|
|
7224
|
+
return;
|
|
7225
|
+
}
|
|
7226
|
+
if (!wasOpen.current) return;
|
|
7227
|
+
wasOpen.current = false;
|
|
7228
|
+
if (!clickOpens) return;
|
|
7229
|
+
const frame = requestAnimationFrame(() => {
|
|
7230
|
+
const active = document.activeElement;
|
|
7231
|
+
if (!active || active === document.body) closedControl.current?.focus({ preventScroll: true });
|
|
7232
|
+
});
|
|
7233
|
+
return () => cancelAnimationFrame(frame);
|
|
7234
|
+
}, [open, clickOpens]);
|
|
7211
7235
|
const wasActive = useRef15(false);
|
|
7212
7236
|
const singlePress = useRef15(null);
|
|
7213
7237
|
const cancelSinglePress = () => {
|
|
@@ -7351,9 +7375,13 @@ function GridCell({
|
|
|
7351
7375
|
/* @__PURE__ */ jsx28(
|
|
7352
7376
|
"span",
|
|
7353
7377
|
{
|
|
7378
|
+
ref: closedControl,
|
|
7354
7379
|
role: editable ? "button" : void 0,
|
|
7355
7380
|
"aria-label": editable ? `Edit ${fieldName(field2)}` : void 0,
|
|
7356
|
-
title: cellMark ? cellMark : editable ?
|
|
7381
|
+
title: cellMark ? cellMark : editable ? (
|
|
7382
|
+
// The words match the gesture (WALK3-FIX): one click opens a record-page field.
|
|
7383
|
+
clickOpens ? `${fieldName(field2)} \u2014 click to edit` : `${fieldName(field2)} \u2014 double-click or press Enter to edit`
|
|
7384
|
+
) : fieldIsEditable(field2) ? (
|
|
7357
7385
|
// NOT A DEAD CONTROL AND NOT A SILENT ONE: the cell is plain
|
|
7358
7386
|
// text, and hovering it says exactly why, in the level's own
|
|
7359
7387
|
// words. The editor was never offered, so nothing is refused
|
|
@@ -8655,6 +8683,7 @@ function ChoiceValue({ field: field2, value, onChange }) {
|
|
|
8655
8683
|
return /* @__PURE__ */ jsx34("span", { className: "inline-flex min-w-0", "data-records-condition-choice": "", "data-pick-value": value, children: /* @__PURE__ */ jsx34(
|
|
8656
8684
|
PickOrAdd,
|
|
8657
8685
|
{
|
|
8686
|
+
triggerSize: "compact",
|
|
8658
8687
|
triggerLabel: `Choice for ${field2.label || field2.key}`,
|
|
8659
8688
|
triggerText: value || "Choose",
|
|
8660
8689
|
open,
|
|
@@ -8878,6 +8907,7 @@ function ConditionGroup({
|
|
|
8878
8907
|
onChange,
|
|
8879
8908
|
emptyLabel = "always",
|
|
8880
8909
|
allowNesting = true,
|
|
8910
|
+
maxDepth,
|
|
8881
8911
|
depth = 0,
|
|
8882
8912
|
onRemove,
|
|
8883
8913
|
className
|
|
@@ -8948,6 +8978,7 @@ function ConditionGroup({
|
|
|
8948
8978
|
onChange: (next) => replaceAt(index, next),
|
|
8949
8979
|
onRemove: () => replaceAt(index, null),
|
|
8950
8980
|
emptyLabel,
|
|
8981
|
+
maxDepth,
|
|
8951
8982
|
depth: depth + 1
|
|
8952
8983
|
}
|
|
8953
8984
|
) }, key);
|
|
@@ -8991,7 +9022,7 @@ function ConditionGroup({
|
|
|
8991
9022
|
children: "Add another condition"
|
|
8992
9023
|
}
|
|
8993
9024
|
),
|
|
8994
|
-
allowNesting ? /* @__PURE__ */ jsx34(
|
|
9025
|
+
allowNesting && (maxDepth === void 0 || depth < maxDepth) ? /* @__PURE__ */ jsx34(
|
|
8995
9026
|
Button14,
|
|
8996
9027
|
{
|
|
8997
9028
|
size: "sm",
|
|
@@ -10663,6 +10694,7 @@ function FieldEditor(props) {
|
|
|
10663
10694
|
const [formulaWritten, setFormulaWritten] = useState31(() => startingFormulaText.trim() !== "" || Boolean(field2));
|
|
10664
10695
|
const [formulaOk, setFormulaOk] = useState31(null);
|
|
10665
10696
|
const [askingToRemove, setAskingToRemove] = useState31(false);
|
|
10697
|
+
const [attempted, setAttempted] = useState31(false);
|
|
10666
10698
|
const [showsAs, setShowsAs] = useState31(() => field2 ? startingChoice(field2) : { format: null, retype: null });
|
|
10667
10699
|
const [backfillError, setBackfillError] = useState31(null);
|
|
10668
10700
|
const [notLanded, setNotLanded] = useState31(false);
|
|
@@ -10712,6 +10744,8 @@ function FieldEditor(props) {
|
|
|
10712
10744
|
const missing = editing ? formulaMissing ?? (listsChoices ? whatTheChoiceListIsMissing(choiceList) : null) : formulaMissing ?? (listsChoices ? whatTheChoiceListIsMissing(newChoices) : null) ?? (type === "formula" && formulaWritten ? null : whatIsMissing(
|
|
10713
10745
|
type === "count" ? { type: "rollup", label, options, via, pick, agg: "count", of, relations: totalSources, formulaFields, relationTarget, allowedTypes, noun } : { type, label, options, via, pick, agg, of, relations: sourcesFor(type), formulaFields, relationTarget, allowedTypes, noun }
|
|
10714
10746
|
));
|
|
10747
|
+
const missingShown = missing && (attempted || formulaMissing) ? missing : null;
|
|
10748
|
+
const removeConsequence = field2 ? `${archiveConfirmSentence(`the field \u201C${fieldName(field2)}\u201D`)} Its values stay in every record and come back with it.${linkReaders.length > 0 ? ` ${readersSentence(linkReaders.length, farTable.data?.name ?? null)}` : ""}` : "";
|
|
10715
10749
|
const save = async () => {
|
|
10716
10750
|
if (missing) return;
|
|
10717
10751
|
if (editing && field2) {
|
|
@@ -10859,8 +10893,8 @@ function FieldEditor(props) {
|
|
|
10859
10893
|
const remove = async () => {
|
|
10860
10894
|
if (!field2) return;
|
|
10861
10895
|
const gone = await tableMutation.retire({ field_id: field2.id });
|
|
10862
|
-
setAskingToRemove(false);
|
|
10863
10896
|
if (gone) (onRemoved ?? onSaved)?.();
|
|
10897
|
+
else setAskingToRemove(false);
|
|
10864
10898
|
};
|
|
10865
10899
|
return /* @__PURE__ */ jsxs35("div", { className: cn24("flex min-w-0 flex-col gap-3 text-xs", className), "data-records-field-editor": "", children: [
|
|
10866
10900
|
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
|
|
@@ -10877,7 +10911,12 @@ function FieldEditor(props) {
|
|
|
10877
10911
|
autoFocus: true,
|
|
10878
10912
|
"aria-label": "Field name",
|
|
10879
10913
|
placeholder: "Day rate",
|
|
10880
|
-
onChange: (e) => setLabel(e.target.value)
|
|
10914
|
+
onChange: (e) => setLabel(e.target.value),
|
|
10915
|
+
onBlur: (e) => {
|
|
10916
|
+
const to = e.relatedTarget;
|
|
10917
|
+
if (to?.textContent === "Cancel") return;
|
|
10918
|
+
setAttempted(true);
|
|
10919
|
+
}
|
|
10881
10920
|
}
|
|
10882
10921
|
)
|
|
10883
10922
|
] }),
|
|
@@ -11165,7 +11204,6 @@ function FieldEditor(props) {
|
|
|
11165
11204
|
] }),
|
|
11166
11205
|
editing && field2 && !onEntity && rulesChanged(savedRules, editedRules) ? /* @__PURE__ */ jsx40(FieldRulePreview, { field: field2, tableId, rules: editedRules }) : null,
|
|
11167
11206
|
mutation.error ? /* @__PURE__ */ jsx40(RefusalNotice, { error: mutation.error }) : null,
|
|
11168
|
-
missing ? /* @__PURE__ */ jsx40("p", { id: "field-editor-missing", className: "text-[11px] text-muted-foreground", "data-field-editor-missing": "", children: missing }) : null,
|
|
11169
11207
|
notLanded ? /* @__PURE__ */ jsx40(
|
|
11170
11208
|
RefusalNotice,
|
|
11171
11209
|
{
|
|
@@ -11210,27 +11248,61 @@ function FieldEditor(props) {
|
|
|
11210
11248
|
/* @__PURE__ */ jsx40("p", { className: "text-[11px]", children: "The column is made. The records already in the table were not numbered:" }),
|
|
11211
11249
|
/* @__PURE__ */ jsx40(RefusalNotice, { error: backfillError })
|
|
11212
11250
|
] }) : null,
|
|
11213
|
-
/* @__PURE__ */ jsxs35("div", { className: "flex flex-
|
|
11251
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex min-w-0 flex-nowrap items-center gap-2", "data-field-editor-footer": "", children: [
|
|
11214
11252
|
/* @__PURE__ */ jsx40(
|
|
11215
11253
|
Button17,
|
|
11216
11254
|
{
|
|
11217
11255
|
size: "sm",
|
|
11218
|
-
disabled: mutation.saving ||
|
|
11219
|
-
...
|
|
11220
|
-
onClick: () =>
|
|
11256
|
+
disabled: mutation.saving || Boolean(formulaMissing),
|
|
11257
|
+
...missingShown ? { "aria-describedby": "field-editor-missing" } : {},
|
|
11258
|
+
onClick: () => {
|
|
11259
|
+
if (missing) {
|
|
11260
|
+
setAttempted(true);
|
|
11261
|
+
return;
|
|
11262
|
+
}
|
|
11263
|
+
void save();
|
|
11264
|
+
},
|
|
11221
11265
|
children: mutation.saving ? "Saving\u2026" : field2 ? EDIT_FIELD_SAVE_LABEL : onEntity ? ADD_STANDARD_FIELD_SAVE_LABEL : ADD_FIELD_SAVE_LABEL
|
|
11222
11266
|
}
|
|
11223
11267
|
),
|
|
11224
11268
|
onCancel ? /* @__PURE__ */ jsx40(Button17, { size: "sm", variant: "ghost", onClick: onCancel, children: "Cancel" }) : null,
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11269
|
+
/* @__PURE__ */ jsx40(
|
|
11270
|
+
"span",
|
|
11271
|
+
{
|
|
11272
|
+
id: "field-editor-missing",
|
|
11273
|
+
"data-field-editor-missing": missingShown ? "" : void 0,
|
|
11274
|
+
title: missingShown ?? void 0,
|
|
11275
|
+
className: "min-w-0 flex-1 truncate text-[11px] text-muted-foreground",
|
|
11276
|
+
children: missingShown
|
|
11277
|
+
}
|
|
11278
|
+
),
|
|
11279
|
+
field2 ? (
|
|
11280
|
+
/* WALK3-FIX (2026-10-07): the confirm appears IN PLACE. Both states share one grid cell,
|
|
11281
|
+
the idle one drawn invisibly under the asking one and the other way round, so the
|
|
11282
|
+
footer is always as wide and as tall as its larger state: opening the confirm moved
|
|
11283
|
+
the dialog card 0.2278 and closing it 0.1303. The consequence is the tooltip of
|
|
11284
|
+
"Remove it" (interface-text: the slot holds a label, never a paragraph). */
|
|
11285
|
+
/* @__PURE__ */ jsxs35("div", { className: "ml-auto grid shrink-0 items-center", "data-field-editor-remove": askingToRemove ? "asking" : "idle", children: [
|
|
11286
|
+
/* @__PURE__ */ jsx40("div", { className: cn24("col-start-1 row-start-1 flex items-center justify-end gap-2", askingToRemove && "invisible"), "aria-hidden": askingToRemove || void 0, children: /* @__PURE__ */ jsx40(Button17, { size: "sm", variant: "outline", tabIndex: askingToRemove ? -1 : void 0, onClick: () => setAskingToRemove(true), children: "Remove this field" }) }),
|
|
11287
|
+
/* @__PURE__ */ jsxs35("div", { className: cn24("col-start-1 row-start-1 flex items-center justify-end gap-2", !askingToRemove && "invisible"), "aria-hidden": !askingToRemove || void 0, children: [
|
|
11288
|
+
/* @__PURE__ */ jsx40("span", { className: "whitespace-nowrap text-destructive", "data-field-editor-remove-ask": "", children: "Archive this field?" }),
|
|
11289
|
+
/* @__PURE__ */ jsx40(
|
|
11290
|
+
Button17,
|
|
11291
|
+
{
|
|
11292
|
+
size: "sm",
|
|
11293
|
+
variant: "destructive",
|
|
11294
|
+
tabIndex: askingToRemove ? void 0 : -1,
|
|
11295
|
+
disabled: mutation.saving,
|
|
11296
|
+
title: removeConsequence,
|
|
11297
|
+
"aria-description": removeConsequence,
|
|
11298
|
+
onClick: () => void remove(),
|
|
11299
|
+
children: "Remove it"
|
|
11300
|
+
}
|
|
11301
|
+
),
|
|
11302
|
+
/* @__PURE__ */ jsx40(Button17, { size: "sm", variant: "ghost", tabIndex: askingToRemove ? void 0 : -1, onClick: () => setAskingToRemove(false), children: "Keep it" })
|
|
11303
|
+
] })
|
|
11304
|
+
] })
|
|
11305
|
+
) : null
|
|
11234
11306
|
] })
|
|
11235
11307
|
] });
|
|
11236
11308
|
}
|
|
@@ -14137,6 +14209,13 @@ function useMergedGridControls(args) {
|
|
|
14137
14209
|
const tableVersion = useTableVersion(client, tableId, table);
|
|
14138
14210
|
const mutation = useFieldMutation2();
|
|
14139
14211
|
const [dialog, setDialog] = useState42(null);
|
|
14212
|
+
const lastColumnDialog = useRef22(null);
|
|
14213
|
+
const insertEpoch = useRef22(0);
|
|
14214
|
+
if (dialog?.kind === "settings" || dialog?.kind === "insert") {
|
|
14215
|
+
if (dialog !== lastColumnDialog.current) insertEpoch.current += 1;
|
|
14216
|
+
lastColumnDialog.current = dialog;
|
|
14217
|
+
}
|
|
14218
|
+
const columnDialog = dialog?.kind === "settings" || dialog?.kind === "insert" ? dialog : lastColumnDialog.current;
|
|
14140
14219
|
const [renameTo, setRenameTo] = useState42("");
|
|
14141
14220
|
const [deleteBusy, setDeleteBusy] = useState42(false);
|
|
14142
14221
|
const [labelling, setLabelling] = useState42(false);
|
|
@@ -14626,27 +14705,27 @@ function useMergedGridControls(args) {
|
|
|
14626
14705
|
},
|
|
14627
14706
|
children: /* @__PURE__ */ jsxs47(DialogContent8, { className: "max-h-[85vh] overflow-y-auto sm:max-w-2xl", children: [
|
|
14628
14707
|
/* @__PURE__ */ jsxs47(DialogHeader8, { children: [
|
|
14629
|
-
/* @__PURE__ */ jsx52(DialogTitle8, { children:
|
|
14708
|
+
/* @__PURE__ */ jsx52(DialogTitle8, { children: columnDialog?.kind === "settings" ? `Column settings \xB7 ${fieldName(columnDialog.field)}` : columnDialog?.kind === "insert" && columnDialog.anchor ? `Add column ${columnDialog.side === "left" ? "left" : "right"} of ${fieldOf2(columnDialog.anchor) ? fieldName(fieldOf2(columnDialog.anchor)) : columnDialog.anchor}` : ADD_FIELD_OPEN_LABEL }),
|
|
14630
14709
|
/* @__PURE__ */ jsx52(DialogDescription6, { className: "sr-only", children: "Name, type and look" })
|
|
14631
14710
|
] }),
|
|
14632
|
-
|
|
14711
|
+
columnDialog?.kind === "settings" ? /* @__PURE__ */ jsx52(
|
|
14633
14712
|
FieldEditor,
|
|
14634
14713
|
{
|
|
14635
14714
|
tableId,
|
|
14636
|
-
field:
|
|
14715
|
+
field: columnDialog.field,
|
|
14637
14716
|
onSaved: () => {
|
|
14638
|
-
notify?.success(`${fieldName(
|
|
14717
|
+
notify?.success(`${fieldName(columnDialog.field)} is saved.`);
|
|
14639
14718
|
close();
|
|
14640
14719
|
},
|
|
14641
14720
|
onRemoved: () => {
|
|
14642
|
-
if (args.onColumnRetired) args.onColumnRetired(
|
|
14643
|
-
else notify?.success(`${fieldName(
|
|
14721
|
+
if (args.onColumnRetired) args.onColumnRetired(columnDialog.field);
|
|
14722
|
+
else notify?.success(`${fieldName(columnDialog.field)} is gone from the table. It can be brought back from Archived.`);
|
|
14644
14723
|
close();
|
|
14645
14724
|
},
|
|
14646
14725
|
onCancel: close
|
|
14647
14726
|
},
|
|
14648
|
-
|
|
14649
|
-
) :
|
|
14727
|
+
`${columnDialog.field.id}-${insertEpoch.current}`
|
|
14728
|
+
) : columnDialog?.kind === "insert" ? /* @__PURE__ */ jsx52(
|
|
14650
14729
|
FieldEditor,
|
|
14651
14730
|
{
|
|
14652
14731
|
tableId,
|
|
@@ -14655,10 +14734,11 @@ function useMergedGridControls(args) {
|
|
|
14655
14734
|
close();
|
|
14656
14735
|
},
|
|
14657
14736
|
onSaved: () => {
|
|
14658
|
-
pendingInsert.current = { before: new Set(fieldKeys), anchor:
|
|
14737
|
+
pendingInsert.current = { before: new Set(fieldKeys), anchor: columnDialog.anchor, side: columnDialog.side };
|
|
14659
14738
|
close();
|
|
14660
14739
|
}
|
|
14661
|
-
}
|
|
14740
|
+
},
|
|
14741
|
+
`insert-${insertEpoch.current}`
|
|
14662
14742
|
) : null
|
|
14663
14743
|
] })
|
|
14664
14744
|
}
|
|
@@ -20228,7 +20308,7 @@ function UndoRedoPair({ face, onUndo, onRedo }) {
|
|
|
20228
20308
|
)
|
|
20229
20309
|
] });
|
|
20230
20310
|
}
|
|
20231
|
-
function UndoNotice({ undo }) {
|
|
20311
|
+
function UndoNotice({ undo, placement = "frame" }) {
|
|
20232
20312
|
const notice = undo.notice;
|
|
20233
20313
|
const dismiss = undo.dismiss;
|
|
20234
20314
|
useEffect44(() => {
|
|
@@ -20242,7 +20322,8 @@ function UndoNotice({ undo }) {
|
|
|
20242
20322
|
{
|
|
20243
20323
|
role: "status",
|
|
20244
20324
|
"data-records-undo-notice": notice.refusal ? "refused" : "done",
|
|
20245
|
-
|
|
20325
|
+
"data-records-undo-placement": placement,
|
|
20326
|
+
className: `pointer-events-auto ${placement === "viewport" ? "fixed bottom-4 z-50" : "absolute bottom-3 z-30"} left-1/2 flex max-w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-lg`,
|
|
20246
20327
|
children: [
|
|
20247
20328
|
/* @__PURE__ */ jsx66("span", { children: notice.says }),
|
|
20248
20329
|
notice.canUndo && undo.canUndo ? /* @__PURE__ */ jsx66(Button38, { size: "sm", variant: "outline", className: "ml-auto h-6", "data-records-undo-now": "", onClick: () => void undo.undo(), children: "Undo" }) : null,
|
|
@@ -21597,6 +21678,11 @@ function GridBody({
|
|
|
21597
21678
|
page: query.page
|
|
21598
21679
|
});
|
|
21599
21680
|
}, [reportQuery, query.sort, query.columnFilters, query.search, query.page, openingKey]);
|
|
21681
|
+
const liveKeys = useMemo35(() => fields.data ? new Set(fields.data.map((f) => f.key)) : null, [fields.data]);
|
|
21682
|
+
useEffect47(() => {
|
|
21683
|
+
if (!liveKeys) return;
|
|
21684
|
+
setQuery((held) => withoutGoneColumns(held, liveKeys, openingSort));
|
|
21685
|
+
}, [liveKeys]);
|
|
21600
21686
|
const resetEpoch = address?.resetEpoch ?? 0;
|
|
21601
21687
|
const resetSeen = useRef31(resetEpoch);
|
|
21602
21688
|
useEffect47(() => {
|
|
@@ -21650,7 +21736,9 @@ function GridBody({
|
|
|
21650
21736
|
page: classicInCard ? 0 : page,
|
|
21651
21737
|
...readFilter ? { filter: readFilter } : {}
|
|
21652
21738
|
});
|
|
21653
|
-
const
|
|
21739
|
+
const pageAskedFor = useRef31(null);
|
|
21740
|
+
if (fields.data && !table.loading) pageAskedFor.current = tableId;
|
|
21741
|
+
const pageAsked = !storePaged || Boolean(fields.data) && pageAskedFor.current === tableId;
|
|
21654
21742
|
const serverRead = useRecordPage(storePaged && pageAsked ? tableId : null, {
|
|
21655
21743
|
pageSize: query.pageSize,
|
|
21656
21744
|
page: Math.max(0, query.page - 1),
|
|
@@ -23102,7 +23190,7 @@ function GridBody({
|
|
|
23102
23190
|
}, [rowsAnswered, rowMemoryKey, rows.length, embedded, tableId]);
|
|
23103
23191
|
if (table.error) return /* @__PURE__ */ jsx70(RefusalNotice, { error: table.error, className });
|
|
23104
23192
|
if (fields.error) return /* @__PURE__ */ jsx70(RefusalNotice, { error: fields.error, className });
|
|
23105
|
-
const nothingToShowYet = table.loading || fields.loading || !rights.known || records.loading && rows.length === 0 || // The page read has neither answered nor refused: nothing has been said yet, so nothing is empty.
|
|
23193
|
+
const nothingToShowYet = table.loading && !table.data || fields.loading && !fields.data || !rights.known || records.loading && rows.length === 0 || // The page read has neither answered nor refused: nothing has been said yet, so nothing is empty.
|
|
23106
23194
|
!records.data && !records.error || countedButNotReturned || manual && hand.loading && rows.length === 0;
|
|
23107
23195
|
const refreshing = !nothingToShowYet && (records.loading || manual && hand.loading);
|
|
23108
23196
|
const noColumnsYet = !nothingToShowYet && (fields.data ?? []).length === 0;
|
|
@@ -23557,6 +23645,15 @@ function withHeaderMenus(columns, menuFor, filterFor) {
|
|
|
23557
23645
|
return filter ? { ...withMenu, ...filter } : withMenu;
|
|
23558
23646
|
});
|
|
23559
23647
|
}
|
|
23648
|
+
function withoutGoneColumns(query, liveKeys, openingSort) {
|
|
23649
|
+
const sortGone = Boolean(query.sort && !liveKeys.has(query.sort.id));
|
|
23650
|
+
const goneFilters = Object.keys(query.columnFilters ?? {}).filter((key) => !liveKeys.has(key));
|
|
23651
|
+
if (!sortGone && goneFilters.length === 0) return query;
|
|
23652
|
+
const columnFilters = { ...query.columnFilters };
|
|
23653
|
+
for (const key of goneFilters) delete columnFilters[key];
|
|
23654
|
+
const fallback = openingSort && liveKeys.has(openingSort.id) ? openingSort : null;
|
|
23655
|
+
return { ...query, sort: sortGone ? fallback : query.sort, columnFilters, page: 1 };
|
|
23656
|
+
}
|
|
23560
23657
|
|
|
23561
23658
|
// src/RecordsTableCard.tsx
|
|
23562
23659
|
import { MatrxTableCard, MatrxTableCardEmpty, MatrxTableCardShowMore as MatrxTableCardShowMore2, TABLE_CARD_DEFAULT_INITIAL_ROWS } from "@ai-matrx/design-system/data-table";
|
|
@@ -28780,7 +28877,7 @@ function RecordFieldsInPlace({
|
|
|
28780
28877
|
/* @__PURE__ */ jsx94(
|
|
28781
28878
|
"dd",
|
|
28782
28879
|
{
|
|
28783
|
-
className: "min-w-0 rounded hover:bg-muted/50 [&_[data-matrx-cell-editor]_input:not([type=checkbox]):not([type=radio])]:!h-7",
|
|
28880
|
+
className: "min-w-0 rounded hover:bg-muted/50 [&_[data-matrx-cell-editor]_input:not([type=checkbox]):not([type=radio])]:!h-7 [&_[data-pick-anchor]]:!w-fit",
|
|
28784
28881
|
"data-records-in-place-field": field2.key,
|
|
28785
28882
|
children: /* @__PURE__ */ jsx94(
|
|
28786
28883
|
GridCell,
|
|
@@ -28798,7 +28895,7 @@ function RecordFieldsInPlace({
|
|
|
28798
28895
|
)
|
|
28799
28896
|
] }, field2.id);
|
|
28800
28897
|
}) }),
|
|
28801
|
-
/* @__PURE__ */ jsx94(UndoNotice, { undo })
|
|
28898
|
+
/* @__PURE__ */ jsx94(UndoNotice, { undo, placement: "viewport" })
|
|
28802
28899
|
]
|
|
28803
28900
|
}
|
|
28804
28901
|
);
|
|
@@ -29024,6 +29121,7 @@ function Peek({ tableId, recordId, onClose, className, onPage = false }) {
|
|
|
29024
29121
|
if (record.error) return /* @__PURE__ */ jsx97(RefusalNotice, { error: record.error, className });
|
|
29025
29122
|
if (fields.error) return /* @__PURE__ */ jsx97(RefusalNotice, { error: fields.error, className });
|
|
29026
29123
|
const document2 = record.data?.document;
|
|
29124
|
+
const computedShown = computedLinesWorthShowing(record.data?.computed, document2);
|
|
29027
29125
|
const title = document2 ? recordNameIn(table.data, document2) : "";
|
|
29028
29126
|
const bodyKey = onPage ? bodyFieldOf(fields.data ?? [])?.key : void 0;
|
|
29029
29127
|
const shownFields = (fields.data ?? []).filter((field2) => !onPage || !drawnBelowOnPage(field2, bodyKey));
|
|
@@ -29123,15 +29221,20 @@ function Peek({ tableId, recordId, onClose, className, onPage = false }) {
|
|
|
29123
29221
|
/* @__PURE__ */ jsx97(Separator9, {}),
|
|
29124
29222
|
/* @__PURE__ */ jsx97("p", { className: "text-muted-foreground", children: "Nothing here can say which columns the system worked out for itself: that part of the record is not readable from your seat. Everything above is the record as it stands." })
|
|
29125
29223
|
] }) : null,
|
|
29126
|
-
|
|
29224
|
+
computedShown.length ? /* @__PURE__ */ jsxs88(Fragment36, { children: [
|
|
29127
29225
|
/* @__PURE__ */ jsx97(Separator9, {}),
|
|
29128
29226
|
/* @__PURE__ */ jsxs88("div", { className: "flex flex-col gap-1", children: [
|
|
29129
29227
|
/* @__PURE__ */ jsx97("span", { className: "font-medium", children: "Worked out by the system" }),
|
|
29130
|
-
|
|
29228
|
+
computedShown.map((row, i) => /* @__PURE__ */ jsx97("p", { className: "text-muted-foreground", children: computedInPlainWords(row, (fields.data ?? []).find((f) => f.key === row.field_key)) }, i))
|
|
29131
29229
|
] })
|
|
29132
29230
|
] }) : null
|
|
29133
29231
|
] });
|
|
29134
29232
|
}
|
|
29233
|
+
function computedLinesWorthShowing(rows, document2) {
|
|
29234
|
+
return (rows ?? []).filter(
|
|
29235
|
+
(row) => !((row.value === null || row.value === void 0 || row.value === "") && workedOutErrorFor(document2, row.field_key))
|
|
29236
|
+
);
|
|
29237
|
+
}
|
|
29135
29238
|
function computedInPlainWords(row, field2) {
|
|
29136
29239
|
const name = field2 ? fieldName(field2) : humanizeIdentifier12(row.field_key);
|
|
29137
29240
|
const shown4 = row.value === null || row.value === void 0 || row.value === "" ? "nothing" : field2 ? scalarText(field2, row.value) : String(row.value);
|
|
@@ -36279,7 +36382,8 @@ function HistoryPanel({ tableId, recordId, onAskAboutField, className }) {
|
|
|
36279
36382
|
ref: listRef,
|
|
36280
36383
|
role: "listbox",
|
|
36281
36384
|
"aria-label": "Versions of this record, newest first",
|
|
36282
|
-
|
|
36385
|
+
"data-records-history-list": "",
|
|
36386
|
+
className: "flex max-h-[9.25rem] min-h-0 flex-col divide-y overflow-y-auto rounded border",
|
|
36283
36387
|
onKeyDown: (event) => {
|
|
36284
36388
|
const at = entries.findIndex((e) => e.version === open);
|
|
36285
36389
|
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
@@ -40622,6 +40726,18 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
|
|
|
40622
40726
|
onChange: (e) => patchQuestion(index, { help: e.target.value || null })
|
|
40623
40727
|
}
|
|
40624
40728
|
),
|
|
40729
|
+
/* @__PURE__ */ jsxs119("label", { className: "col-span-2 flex items-center gap-2 text-xs", children: [
|
|
40730
|
+
/* @__PURE__ */ jsx129(
|
|
40731
|
+
Checkbox15,
|
|
40732
|
+
{
|
|
40733
|
+
checked: field2.required ? true : question.required === true,
|
|
40734
|
+
disabled: field2.required === true,
|
|
40735
|
+
"aria-label": `${fieldName(field2)} is required`,
|
|
40736
|
+
onCheckedChange: (checked) => patchQuestion(index, { required: checked === true ? true : null })
|
|
40737
|
+
}
|
|
40738
|
+
),
|
|
40739
|
+
"Required"
|
|
40740
|
+
] }),
|
|
40625
40741
|
/* @__PURE__ */ jsx129(
|
|
40626
40742
|
Condition,
|
|
40627
40743
|
{
|
|
@@ -47712,7 +47828,7 @@ function TablePage({
|
|
|
47712
47828
|
if (hostFromLink || opened.layout || layoutChosen) return;
|
|
47713
47829
|
setHostLayout(face.hostLayout);
|
|
47714
47830
|
}, [face.kind, face.kind === "designated" ? face.hostLayout : null, layoutChosen]);
|
|
47715
|
-
const faceUnknown = !hostFromLink && !opened.layout && (views === void 0 || Array.isArray(views) && views.length > 0 &&
|
|
47831
|
+
const faceUnknown = !hostFromLink && !opened.layout && (views === void 0 || looks === void 0 || Array.isArray(views) && views.length > 0 && view === null);
|
|
47716
47832
|
const shownLayout = layoutFromLink ?? shown4?.layout ?? "grid";
|
|
47717
47833
|
const shownFilter = filter ?? (shown4?.where ? shown4.where : null) ?? (shown4?.filters && Object.keys(shown4.filters).length > 0 ? shown4.filters : null);
|
|
47718
47834
|
const press = (pressed) => {
|