@ai-matrx/records-ui 0.107.0 → 0.107.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 +69 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +69 -18
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.107.3
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/records-ui/v0.107.0..npm/records-ui/v0.107.3 -- apps/shared/records-ui`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.107.2
|
|
10
|
+
|
|
11
|
+
A question's jumps may read its own answer again (the live walk showed "Missing question" on a budget jump that conditions on the budget); "Email the respondent" also finds a text question named for an email.
|
|
12
|
+
|
|
13
|
+
**Consumer action:** none.
|
|
14
|
+
|
|
15
|
+
## 0.107.1
|
|
16
|
+
|
|
17
|
+
TYPEFORM-2 resume: "Email the respondent" in Notify on answer — off by default, enabled only when the form has an email question, kept as `presentation.notify.email_respondent` + `respondent_field` and sent by `custom.form_respondent_copy` through the platform notification sender, worded from the ending reached. The builder preview and its two option boxes follow the organization's knobs (`client.formKnobs`, records 0.80.4) under the form's own override.
|
|
18
|
+
|
|
19
|
+
**Consumer action:** none; install records 0.80.4 with it.
|
|
20
|
+
|
|
3
21
|
## 0.107.0
|
|
4
22
|
|
|
5
23
|
TYPEFORM-2, the second pass on forms against Typeform. Runner: Next/Enter refuse an empty required answer ("This field is required") or a bad email / phone / link ("Enter a valid email" …), announced in an `aria-live` alert with the caret kept in the answer, and the old "still needs an answer" line is gone; one large centred question (question ≥ 20 px, answer ≥ 16 px) filling the screen; "press Enter ↵" beside Next; a single choice moves on after a pick (`autoAdvance` prop / `FormSpec.autoAdvance`, default on — knob `forms/choice_auto_advance`); arrow keys move and pick inside the radiogroup and Back lands on the picked choice; focus lands in the first answer after Start; the count is hidden until the store has answered the route once; progress bar `aria-label`; `{{question}}` recall in question words, help and endings (`pipeAnswers`); runner sentences are labels with tooltips. Inputs: email / phone / link carry `inputmode` and `autocomplete`. `FormLookFrame showOwnerHeader` (knob `forms/show_owner_header`, per-form `FormSpec.showOwnerHeader`). Builder: questions listed in respondent order with drag-to-reorder (dnd-kit), unasked fields as "+" chips, the live preview beside the editor (the container query asked itself and never fired), "Notify on answer": Email me (the owner's email subscription, made and handed to the form) and a webhook (a `form_answered` automation, kept as `presentation.notify`); "Show our logo and name" and "Next after a choice" per form; conditions show option labels and badge a missing question. Results: category ticks wrap at words (`wrapTickWords`).
|
package/dist/index.cjs
CHANGED
|
@@ -37957,14 +37957,26 @@ function formPresentation(spec) {
|
|
|
37957
37957
|
theme: themeDocument(spec.theme ?? null),
|
|
37958
37958
|
...typeof spec.showOwnerHeader === "boolean" ? { show_owner_header: spec.showOwnerHeader } : {},
|
|
37959
37959
|
...typeof spec.autoAdvance === "boolean" ? { auto_advance: spec.autoAdvance } : {},
|
|
37960
|
-
...spec.notify && (spec.notify.webhookUrl || spec.notify.webhookAutomationId
|
|
37960
|
+
...spec.notify && (spec.notify.webhookUrl || spec.notify.webhookAutomationId || spec.notify.emailRespondent) ? {
|
|
37961
|
+
notify: strip({
|
|
37962
|
+
webhook_url: text(spec.notify.webhookUrl),
|
|
37963
|
+
webhook_automation_id: text(spec.notify.webhookAutomationId),
|
|
37964
|
+
email_respondent: spec.notify.emailRespondent ? true : null,
|
|
37965
|
+
respondent_field: spec.notify.emailRespondent ? text(spec.notify.respondentField) : null
|
|
37966
|
+
})
|
|
37967
|
+
} : {}
|
|
37961
37968
|
};
|
|
37962
37969
|
}
|
|
37963
37970
|
function notifyFromDocument(raw) {
|
|
37964
37971
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
37965
37972
|
const d = raw;
|
|
37966
|
-
const n = {
|
|
37967
|
-
|
|
37973
|
+
const n = {
|
|
37974
|
+
webhookUrl: text(d["webhook_url"]),
|
|
37975
|
+
webhookAutomationId: text(d["webhook_automation_id"]),
|
|
37976
|
+
emailRespondent: d["email_respondent"] === true ? true : null,
|
|
37977
|
+
respondentField: text(d["respondent_field"])
|
|
37978
|
+
};
|
|
37979
|
+
return n.webhookUrl || n.webhookAutomationId || n.emailRespondent ? n : null;
|
|
37968
37980
|
}
|
|
37969
37981
|
var bool = (v) => typeof v === "boolean" ? v : null;
|
|
37970
37982
|
function answerRefusal(kind, required, value) {
|
|
@@ -42545,6 +42557,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
|
|
|
42545
42557
|
const [shownUrl, setShownUrl] = (0, import_react232.useState)(null);
|
|
42546
42558
|
const [lookOptions, setLookOptions] = (0, import_react232.useState)(null);
|
|
42547
42559
|
const [lookUnread, setLookUnread] = (0, import_react232.useState)(null);
|
|
42560
|
+
const [orgKnobs, setOrgKnobs] = (0, import_react232.useState)(null);
|
|
42548
42561
|
const [restoredAt, setRestoredAt] = (0, import_react232.useState)(null);
|
|
42549
42562
|
const [showResults, setShowResults] = (0, import_react232.useState)(false);
|
|
42550
42563
|
const [adding, setAdding] = (0, import_react232.useState)(false);
|
|
@@ -42581,6 +42594,15 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
|
|
|
42581
42594
|
(0, import_react232.useEffect)(() => {
|
|
42582
42595
|
void load();
|
|
42583
42596
|
}, [load]);
|
|
42597
|
+
(0, import_react232.useEffect)(() => {
|
|
42598
|
+
let cancelled = false;
|
|
42599
|
+
Promise.resolve().then(() => client.formKnobs()).then((r) => {
|
|
42600
|
+
if (!cancelled && r.ok) setOrgKnobs(r.data);
|
|
42601
|
+
}).catch(() => void 0);
|
|
42602
|
+
return () => {
|
|
42603
|
+
cancelled = true;
|
|
42604
|
+
};
|
|
42605
|
+
}, [client]);
|
|
42584
42606
|
(0, import_react232.useEffect)(() => {
|
|
42585
42607
|
if (!forms || forms.length === 0) return;
|
|
42586
42608
|
if (createOnMount && makeOnMount !== "made") return;
|
|
@@ -42881,6 +42903,11 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
|
|
|
42881
42903
|
formName: draft.name,
|
|
42882
42904
|
ruleId: draft.notifyRuleId,
|
|
42883
42905
|
notify: draft.notify ?? null,
|
|
42906
|
+
emailQuestion: (
|
|
42907
|
+
// An email field first; else a question whose field is named for an email (an imported
|
|
42908
|
+
// "Contact email" kept as text). The store's resolver refuses an answer that is not one.
|
|
42909
|
+
(draft.questions.map((q) => byKey.get(q.field)).find((f) => f && String(editorKindFor(f)) === "email") ?? draft.questions.map((q) => byKey.get(q.field)).find((f) => f && /e-?mail/i.test(`${f.key} ${f.label ?? ""}`)))?.key ?? null
|
|
42910
|
+
),
|
|
42884
42911
|
onRule: (ruleId) => void chooseNotify(ruleId),
|
|
42885
42912
|
onNotify: (notify) => void chooseWebhook(notify)
|
|
42886
42913
|
}
|
|
@@ -42890,7 +42917,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
|
|
|
42890
42917
|
/* @__PURE__ */ (0, import_jsx_runtime133.jsx)(
|
|
42891
42918
|
import_design_system118.Checkbox,
|
|
42892
42919
|
{
|
|
42893
|
-
checked: draft.showOwnerHeader ?? true,
|
|
42920
|
+
checked: draft.showOwnerHeader ?? orgKnobs?.show_owner_header ?? true,
|
|
42894
42921
|
onCheckedChange: (checked) => patch({ showOwnerHeader: checked === true }),
|
|
42895
42922
|
"aria-label": "Show our logo and name"
|
|
42896
42923
|
}
|
|
@@ -42901,7 +42928,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
|
|
|
42901
42928
|
/* @__PURE__ */ (0, import_jsx_runtime133.jsx)(
|
|
42902
42929
|
import_design_system118.Checkbox,
|
|
42903
42930
|
{
|
|
42904
|
-
checked: draft.autoAdvance ?? true,
|
|
42931
|
+
checked: draft.autoAdvance ?? orgKnobs?.choice_auto_advance ?? true,
|
|
42905
42932
|
onCheckedChange: (checked) => patch({ autoAdvance: checked === true }),
|
|
42906
42933
|
"aria-label": "Next after a choice"
|
|
42907
42934
|
}
|
|
@@ -43070,7 +43097,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
|
|
|
43070
43097
|
{
|
|
43071
43098
|
className: "w-full shrink-0 overflow-auto rounded border p-2 @3xl:sticky @3xl:top-2 @3xl:max-h-[calc(100dvh-6rem)] @3xl:w-[min(45%,520px)]",
|
|
43072
43099
|
"data-records-form-preview": "",
|
|
43073
|
-
children: showResults && stored ? /* @__PURE__ */ (0, import_jsx_runtime133.jsx)(FormResultsPanel, { form: stored }) : /* @__PURE__ */ (0, import_jsx_runtime133.jsx)(FormLookFrame, { look: lookOptions?.look ?? null, title: draft.name, contained: true, showOwnerHeader: draft.showOwnerHeader ?? true, children: /* @__PURE__ */ (0, import_jsx_runtime133.jsx)(FormRunner, { form: draft, preview: true }) })
|
|
43100
|
+
children: showResults && stored ? /* @__PURE__ */ (0, import_jsx_runtime133.jsx)(FormResultsPanel, { form: stored }) : /* @__PURE__ */ (0, import_jsx_runtime133.jsx)(FormLookFrame, { look: lookOptions?.look ?? null, title: draft.name, contained: true, showOwnerHeader: draft.showOwnerHeader ?? orgKnobs?.show_owner_header ?? true, children: /* @__PURE__ */ (0, import_jsx_runtime133.jsx)(FormRunner, { form: draft, preview: true, autoAdvance: draft.autoAdvance ?? orgKnobs?.choice_auto_advance ?? true }) })
|
|
43074
43101
|
}
|
|
43075
43102
|
)
|
|
43076
43103
|
) : null
|
|
@@ -43190,6 +43217,7 @@ function QuestionList({
|
|
|
43190
43217
|
field: byKey.get(question.field) ?? null,
|
|
43191
43218
|
draft,
|
|
43192
43219
|
conditionFields: asked3.filter((f) => f.key !== question.field),
|
|
43220
|
+
jumpFields: asked3,
|
|
43193
43221
|
label,
|
|
43194
43222
|
onChange: (change) => onQuestion(index, change),
|
|
43195
43223
|
onRemove: () => onQuestions(draft.questions.filter((q) => q.field !== question.field))
|
|
@@ -43229,6 +43257,7 @@ function QuestionRow({
|
|
|
43229
43257
|
field: field2,
|
|
43230
43258
|
draft,
|
|
43231
43259
|
conditionFields,
|
|
43260
|
+
jumpFields,
|
|
43232
43261
|
label,
|
|
43233
43262
|
onChange,
|
|
43234
43263
|
onRemove
|
|
@@ -43307,7 +43336,7 @@ function QuestionRow({
|
|
|
43307
43336
|
questions: draft.questions,
|
|
43308
43337
|
endings: draft.endings ?? [],
|
|
43309
43338
|
field: field2,
|
|
43310
|
-
fieldKeys:
|
|
43339
|
+
fieldKeys: jumpFields,
|
|
43311
43340
|
label,
|
|
43312
43341
|
onChange
|
|
43313
43342
|
}
|
|
@@ -43323,6 +43352,7 @@ function NotifyOnAnswer({
|
|
|
43323
43352
|
formName,
|
|
43324
43353
|
ruleId,
|
|
43325
43354
|
notify,
|
|
43355
|
+
emailQuestion,
|
|
43326
43356
|
onRule,
|
|
43327
43357
|
onNotify
|
|
43328
43358
|
}) {
|
|
@@ -43388,7 +43418,7 @@ function NotifyOnAnswer({
|
|
|
43388
43418
|
try {
|
|
43389
43419
|
if (next === "") {
|
|
43390
43420
|
if (notify?.webhookAutomationId) await client.automationArchive({ automation_id: notify.webhookAutomationId });
|
|
43391
|
-
onNotify(null);
|
|
43421
|
+
onNotify(notify?.emailRespondent ? { ...notify, webhookUrl: null, webhookAutomationId: null } : null);
|
|
43392
43422
|
return;
|
|
43393
43423
|
}
|
|
43394
43424
|
const declared2 = await client.automationDeclare({
|
|
@@ -43401,22 +43431,43 @@ function NotifyOnAnswer({
|
|
|
43401
43431
|
setSaid(Object.values(declared2.data._errors)[0] ?? "Not saved");
|
|
43402
43432
|
return;
|
|
43403
43433
|
}
|
|
43404
|
-
onNotify({ webhookUrl: next, webhookAutomationId: declared2.data.automation_id });
|
|
43434
|
+
onNotify({ ...notify ?? {}, webhookUrl: next, webhookAutomationId: declared2.data.automation_id });
|
|
43405
43435
|
} finally {
|
|
43406
43436
|
setBusy(false);
|
|
43407
43437
|
}
|
|
43408
43438
|
}
|
|
43409
43439
|
return /* @__PURE__ */ (0, import_jsx_runtime133.jsxs)("section", { className: "flex flex-col gap-2 rounded border px-2.5 py-2 text-xs", "aria-label": "Notify on answer", "data-records-form-notify": "", children: [
|
|
43410
43440
|
/* @__PURE__ */ (0, import_jsx_runtime133.jsx)("span", { className: "font-medium", children: "Notify on answer" }),
|
|
43411
|
-
/* @__PURE__ */ (0, import_jsx_runtime133.
|
|
43412
|
-
/* @__PURE__ */ (0, import_jsx_runtime133.
|
|
43413
|
-
|
|
43414
|
-
|
|
43415
|
-
"(",
|
|
43416
|
-
|
|
43417
|
-
|
|
43418
|
-
|
|
43419
|
-
|
|
43441
|
+
/* @__PURE__ */ (0, import_jsx_runtime133.jsxs)("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-1", children: [
|
|
43442
|
+
/* @__PURE__ */ (0, import_jsx_runtime133.jsxs)("label", { className: "flex items-center gap-2", title: "An email to you each time somebody answers.", children: [
|
|
43443
|
+
/* @__PURE__ */ (0, import_jsx_runtime133.jsx)(import_design_system118.Checkbox, { checked: Boolean(ruleId), disabled: busy, onCheckedChange: (c) => void emailMe(c === true), "aria-label": "Email me" }),
|
|
43444
|
+
"Email me",
|
|
43445
|
+
chosen && chosen.channel !== "email" ? /* @__PURE__ */ (0, import_jsx_runtime133.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
43446
|
+
"(",
|
|
43447
|
+
chosen.channel === "sms" ? "text" : "in app",
|
|
43448
|
+
")"
|
|
43449
|
+
] }) : null
|
|
43450
|
+
] }),
|
|
43451
|
+
/* @__PURE__ */ (0, import_jsx_runtime133.jsxs)(
|
|
43452
|
+
"label",
|
|
43453
|
+
{
|
|
43454
|
+
className: (0, import_design_system118.cn)("flex items-center gap-2", !emailQuestion && "text-muted-foreground"),
|
|
43455
|
+
title: emailQuestion ? "An email to the person who answered, in your ending's words." : "Add an email question first.",
|
|
43456
|
+
children: [
|
|
43457
|
+
/* @__PURE__ */ (0, import_jsx_runtime133.jsx)(
|
|
43458
|
+
import_design_system118.Checkbox,
|
|
43459
|
+
{
|
|
43460
|
+
checked: Boolean(notify?.emailRespondent) && Boolean(emailQuestion),
|
|
43461
|
+
disabled: busy || !emailQuestion,
|
|
43462
|
+
onCheckedChange: (c) => onNotify({ ...notify ?? {}, emailRespondent: c === true ? true : null, respondentField: c === true ? emailQuestion : null }),
|
|
43463
|
+
"aria-label": "Email the respondent"
|
|
43464
|
+
}
|
|
43465
|
+
),
|
|
43466
|
+
"Email the respondent"
|
|
43467
|
+
]
|
|
43468
|
+
}
|
|
43469
|
+
)
|
|
43470
|
+
] }),
|
|
43420
43471
|
/* @__PURE__ */ (0, import_jsx_runtime133.jsxs)("label", { className: "flex items-center gap-2", children: [
|
|
43421
43472
|
/* @__PURE__ */ (0, import_jsx_runtime133.jsx)("span", { className: "shrink-0", children: "Webhook" }),
|
|
43422
43473
|
/* @__PURE__ */ (0, import_jsx_runtime133.jsx)(
|