@10x-media/form-builder 0.1.0-beta.3 → 0.1.0-beta.4
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 +42 -0
- package/README.md +2 -2
- package/dist/actions/body/serializeBody.d.ts +19 -4
- package/dist/actions/body/serializeBody.js +3 -1
- package/dist/actions/body/serializeBody.js.map +1 -1
- package/dist/actions/builtin/confirmation.js +13 -4
- package/dist/actions/builtin/confirmation.js.map +1 -1
- package/dist/actions/builtin/emailTeam.js +13 -4
- package/dist/actions/builtin/emailTeam.js.map +1 -1
- package/dist/actions/builtin/index.d.ts +13 -1
- package/dist/actions/builtin/index.js +18 -7
- package/dist/actions/builtin/index.js.map +1 -1
- package/dist/actions/builtin/signedWebhook.js +2 -16
- package/dist/actions/builtin/signedWebhook.js.map +1 -1
- package/dist/actions/runActions.js +2 -0
- package/dist/actions/runActions.js.map +1 -1
- package/dist/aggregation/resolveResultsRequest.d.ts +22 -6
- package/dist/aggregation/resolveResultsRequest.js +18 -7
- package/dist/aggregation/resolveResultsRequest.js.map +1 -1
- package/dist/client/FlowBuilder.js +98 -53
- package/dist/client/FlowBuilder.js.map +1 -1
- package/dist/client/admin.css +47 -5
- package/dist/client/flowAuthoring.js +35 -0
- package/dist/client/flowAuthoring.js.map +1 -0
- package/dist/client/synthesizeClientField.js +6 -2
- package/dist/client/synthesizeClientField.js.map +1 -1
- package/dist/collections/formSubmissions.js +47 -9
- package/dist/collections/formSubmissions.js.map +1 -1
- package/dist/collections/forms.js +180 -34
- package/dist/collections/forms.js.map +1 -1
- package/dist/conditions/conditionType.js +9 -2
- package/dist/conditions/conditionType.js.map +1 -1
- package/dist/conditions/normalizeConditions.js +2 -1
- package/dist/conditions/normalizeConditions.js.map +1 -1
- package/dist/consent/builtin/index.d.ts +11 -1
- package/dist/consent/builtin/index.js +15 -5
- package/dist/consent/builtin/index.js.map +1 -1
- package/dist/consent/builtin/static.js +7 -3
- package/dist/consent/builtin/static.js.map +1 -1
- package/dist/exports/react.d.ts +10 -6
- package/dist/exports/react.js +6 -2
- package/dist/exports/rsc.d.ts +6 -1
- package/dist/exports/rsc.js +6 -1
- package/dist/exports/types.d.ts +4 -4
- package/dist/fields/buildFieldBlocks.js +17 -8
- package/dist/fields/buildFieldBlocks.js.map +1 -1
- package/dist/fields/builtin/consent.js +8 -4
- package/dist/fields/builtin/consent.js.map +1 -1
- package/dist/fields/builtin/file.js +8 -4
- package/dist/fields/builtin/file.js.map +1 -1
- package/dist/fields/builtin/index.d.ts +11 -1
- package/dist/fields/builtin/index.js +21 -9
- package/dist/fields/builtin/index.js.map +1 -1
- package/dist/fields/builtin/message.js +26 -0
- package/dist/fields/builtin/message.js.map +1 -0
- package/dist/fields/builtin/repeater.js +7 -3
- package/dist/fields/builtin/repeater.js.map +1 -1
- package/dist/fields/builtin/select.js +7 -3
- package/dist/fields/builtin/select.js.map +1 -1
- package/dist/fields/localizedIf.d.ts +13 -0
- package/dist/fields/localizedIf.js +12 -0
- package/dist/fields/localizedIf.js.map +1 -0
- package/dist/fields/sharedConfig.js +64 -51
- package/dist/fields/sharedConfig.js.map +1 -1
- package/dist/fields/types.d.ts +7 -2
- package/dist/flow/normalizeFlow.js +7 -1
- package/dist/flow/normalizeFlow.js.map +1 -1
- package/dist/flow/stepLabel.js +15 -0
- package/dist/flow/stepLabel.js.map +1 -0
- package/dist/form/pollState.d.ts +22 -0
- package/dist/form/pollState.js +17 -0
- package/dist/form/pollState.js.map +1 -0
- package/dist/form/toFormDocument.d.ts +60 -0
- package/dist/form/toFormDocument.js +39 -0
- package/dist/form/toFormDocument.js.map +1 -0
- package/dist/form/types.d.ts +48 -0
- package/dist/index.d.ts +69 -18
- package/dist/index.js +24 -13
- package/dist/index.js.map +1 -1
- package/dist/plugin/registerCollections.js +15 -36
- package/dist/plugin/registerCollections.js.map +1 -1
- package/dist/plugin/uploadsCollection.d.ts +11 -0
- package/dist/plugin/uploadsCollection.js +44 -0
- package/dist/plugin/uploadsCollection.js.map +1 -0
- package/dist/poll/applyPollOptions.js +17 -0
- package/dist/poll/applyPollOptions.js.map +1 -0
- package/dist/poll/buildPollOptionSourceFields.js +53 -0
- package/dist/poll/buildPollOptionSourceFields.js.map +1 -0
- package/dist/poll/definePollOptionSource.d.ts +35 -0
- package/dist/poll/definePollOptionSource.js +6 -0
- package/dist/poll/definePollOptionSource.js.map +1 -0
- package/dist/poll/registry.d.ts +16 -0
- package/dist/poll/registry.js +16 -0
- package/dist/poll/registry.js.map +1 -0
- package/dist/poll/resolvePollOptions.d.ts +28 -0
- package/dist/poll/resolvePollOptions.js +64 -0
- package/dist/poll/resolvePollOptions.js.map +1 -0
- package/dist/poll/resolvePollOutcome.d.ts +21 -0
- package/dist/poll/resolvePollOutcome.js +36 -0
- package/dist/poll/resolvePollOutcome.js.map +1 -0
- package/dist/prefill/valuesFromSearchParams.js +1 -1
- package/dist/prefill/valuesFromSearchParams.js.map +1 -1
- package/dist/presentations/types.d.ts +3 -2
- package/dist/react/Form.d.ts +13 -31
- package/dist/react/Form.js +96 -83
- package/dist/react/Form.js.map +1 -1
- package/dist/react/FormContext.d.ts +35 -1
- package/dist/react/FormContext.js.map +1 -1
- package/dist/react/FormControls.d.ts +55 -0
- package/dist/react/FormControls.js +56 -0
- package/dist/react/FormControls.js.map +1 -0
- package/dist/react/FormResults.d.ts +6 -3
- package/dist/react/FormResults.js +37 -29
- package/dist/react/FormResults.js.map +1 -1
- package/dist/react/FormSteps.d.ts +17 -0
- package/dist/react/FormSteps.js +35 -0
- package/dist/react/FormSteps.js.map +1 -0
- package/dist/react/Poll.d.ts +17 -6
- package/dist/react/Poll.js +66 -18
- package/dist/react/Poll.js.map +1 -1
- package/dist/react/fetchResults.d.ts +1 -1
- package/dist/react/fetchResults.js +1 -1
- package/dist/react/fetchResults.js.map +1 -1
- package/dist/react/renderers/file.js +5 -1
- package/dist/react/renderers/file.js.map +1 -1
- package/dist/react/renderers/index.js +2 -0
- package/dist/react/renderers/index.js.map +1 -1
- package/dist/react/renderers/message.js +35 -0
- package/dist/react/renderers/message.js.map +1 -0
- package/dist/react/state.d.ts +25 -1
- package/dist/react/state.js +14 -1
- package/dist/react/state.js.map +1 -1
- package/dist/react/uploadFile.d.ts +2 -2
- package/dist/react/uploadFile.js +1 -1
- package/dist/react/uploadFile.js.map +1 -1
- package/dist/submissions/runSubmission.js +70 -33
- package/dist/submissions/runSubmission.js.map +1 -1
- package/dist/submissions/validateSubmission.js +41 -7
- package/dist/submissions/validateSubmission.js.map +1 -1
- package/dist/submissions/votedCookie.d.ts +13 -0
- package/dist/submissions/votedCookie.js +27 -0
- package/dist/submissions/votedCookie.js.map +1 -0
- package/dist/translations/de.js +219 -0
- package/dist/translations/de.js.map +1 -0
- package/dist/translations/en.js +45 -6
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/index.d.ts +2 -1
- package/dist/translations/index.js +6 -2
- package/dist/translations/index.js.map +1 -1
- package/dist/translations/keys.d.ts +43 -4
- package/dist/translations/keys.js +44 -5
- package/dist/translations/keys.js.map +1 -1
- package/dist/uploads/types.d.ts +1 -2
- package/dist/validation/validateUrl.js +22 -0
- package/dist/validation/validateUrl.js.map +1 -0
- package/package.json +2 -1
- package/styles/form-builder.css +10 -0
- package/dist/collections/uploads.d.ts +0 -30
- package/dist/collections/uploads.js +0 -55
- package/dist/collections/uploads.js.map +0 -1
- package/dist/presentations/registry.d.ts +0 -15
- package/dist/presentations/registry.js +0 -15
- package/dist/presentations/registry.js.map +0 -1
- package/dist/react/toFormDocument.d.ts +0 -24
- package/dist/react/toFormDocument.js +0 -22
- package/dist/react/toFormDocument.js.map +0 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Field, Payload, PayloadRequest } from "payload";
|
|
2
|
+
|
|
3
|
+
//#region src/poll/definePollOptionSource.d.ts
|
|
4
|
+
/** One selectable poll choice. `value` is the host's stable identifier contract: it is stored in submissions and later matched against `outcome.winningValue`, so it must never change once votes exist. */
|
|
5
|
+
type PollOption = {
|
|
6
|
+
label: string;
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
type PollOptionResolveArgs<TConfig extends Record<string, unknown> = Record<string, unknown>> = {
|
|
10
|
+
config: TConfig;
|
|
11
|
+
form: {
|
|
12
|
+
id: number | string;
|
|
13
|
+
title?: string;
|
|
14
|
+
};
|
|
15
|
+
payload: Payload;
|
|
16
|
+
req?: PayloadRequest;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* A poll option source type, authored once by the host: `config` is the admin `Field[]` an author
|
|
20
|
+
* fills per form (e.g. an event id); `resolve` maps that config to the current options from host
|
|
21
|
+
* domain data. Called at render time (via `resolvePollOptions`) and again at submission time, where
|
|
22
|
+
* the resolved values are the only accepted answers (fail closed).
|
|
23
|
+
*/
|
|
24
|
+
type PollOptionSource<TConfig extends Record<string, unknown> = Record<string, unknown>> = {
|
|
25
|
+
type: string;
|
|
26
|
+
label: string;
|
|
27
|
+
config?: Field[];
|
|
28
|
+
resolve: (args: PollOptionResolveArgs<TConfig>) => Promise<PollOption[]> | PollOption[];
|
|
29
|
+
};
|
|
30
|
+
/** Erased shape stored in the registry; config re-narrows per matched type at resolution. */
|
|
31
|
+
type AnyPollOptionSource = PollOptionSource<Record<string, unknown>>;
|
|
32
|
+
declare const definePollOptionSource: <TConfig extends Record<string, unknown> = Record<string, unknown>>(source: PollOptionSource<TConfig>) => PollOptionSource<TConfig>;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { AnyPollOptionSource, PollOption, PollOptionResolveArgs, PollOptionSource, definePollOptionSource };
|
|
35
|
+
//# sourceMappingURL=definePollOptionSource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definePollOptionSource.js","names":[],"sources":["../../src/poll/definePollOptionSource.ts"],"sourcesContent":["import type { Field, Payload, PayloadRequest } from 'payload'\n\n/** One selectable poll choice. `value` is the host's stable identifier contract: it is stored in submissions and later matched against `outcome.winningValue`, so it must never change once votes exist. */\nexport type PollOption = { label: string; value: string }\n\nexport type PollOptionResolveArgs<\n\tTConfig extends Record<string, unknown> = Record<string, unknown>,\n> = {\n\tconfig: TConfig\n\tform: { id: number | string; title?: string }\n\tpayload: Payload\n\treq?: PayloadRequest\n}\n\n/**\n * A poll option source type, authored once by the host: `config` is the admin `Field[]` an author\n * fills per form (e.g. an event id); `resolve` maps that config to the current options from host\n * domain data. Called at render time (via `resolvePollOptions`) and again at submission time, where\n * the resolved values are the only accepted answers (fail closed).\n */\nexport type PollOptionSource<TConfig extends Record<string, unknown> = Record<string, unknown>> = {\n\ttype: string\n\tlabel: string\n\tconfig?: Field[]\n\tresolve: (args: PollOptionResolveArgs<TConfig>) => Promise<PollOption[]> | PollOption[]\n}\n\n/** Erased shape stored in the registry; config re-narrows per matched type at resolution. */\nexport type AnyPollOptionSource = PollOptionSource<Record<string, unknown>>\n\nexport const definePollOptionSource = <\n\tTConfig extends Record<string, unknown> = Record<string, unknown>,\n>(\n\tsource: PollOptionSource<TConfig>\n): PollOptionSource<TConfig> => source\n"],"mappings":";AA8BA,MAAa,0BAGZ,WAC+B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AnyPollOptionSource } from "./definePollOptionSource.js";
|
|
2
|
+
|
|
3
|
+
//#region src/poll/registry.d.ts
|
|
4
|
+
type PollOptionSourceRegistry = Map<string, AnyPollOptionSource>;
|
|
5
|
+
/** `false` removes a source, `true` keeps it (no-op: there are no built-ins), a definition adds or replaces one. */
|
|
6
|
+
type PollOptionSourceOption = boolean | AnyPollOptionSource;
|
|
7
|
+
type PollOptionSourcesConfig = Record<string, PollOptionSourceOption>;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the active poll option-source registry from a consumer map. Unlike the consent and
|
|
10
|
+
* action registries there are no built-in defaults: the registry starts empty and only host
|
|
11
|
+
* definitions populate it, so `true`/`false` entries are accepted but change nothing.
|
|
12
|
+
*/
|
|
13
|
+
declare const resolvePollOptionSources: (config?: PollOptionSourcesConfig) => PollOptionSourceRegistry;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { PollOptionSourceOption, PollOptionSourceRegistry, PollOptionSourcesConfig, resolvePollOptionSources };
|
|
16
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/poll/registry.ts
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the active poll option-source registry from a consumer map. Unlike the consent and
|
|
4
|
+
* action registries there are no built-in defaults: the registry starts empty and only host
|
|
5
|
+
* definitions populate it, so `true`/`false` entries are accepted but change nothing.
|
|
6
|
+
*/
|
|
7
|
+
const resolvePollOptionSources = (config = {}) => {
|
|
8
|
+
const registry = /* @__PURE__ */ new Map();
|
|
9
|
+
for (const [type, option] of Object.entries(config)) if (option === false) registry.delete(type);
|
|
10
|
+
else if (option === true) {} else registry.set(type, option);
|
|
11
|
+
return registry;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { resolvePollOptionSources };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../src/poll/registry.ts"],"sourcesContent":["import type { AnyPollOptionSource } from './definePollOptionSource'\n\nexport type PollOptionSourceRegistry = Map<string, AnyPollOptionSource>\n\n/** `false` removes a source, `true` keeps it (no-op: there are no built-ins), a definition adds or replaces one. */\nexport type PollOptionSourceOption = boolean | AnyPollOptionSource\n\nexport type PollOptionSourcesConfig = Record<string, PollOptionSourceOption>\n\n/**\n * Resolve the active poll option-source registry from a consumer map. Unlike the consent and\n * action registries there are no built-in defaults: the registry starts empty and only host\n * definitions populate it, so `true`/`false` entries are accepted but change nothing.\n */\nexport const resolvePollOptionSources = (\n\tconfig: PollOptionSourcesConfig = {}\n): PollOptionSourceRegistry => {\n\tconst registry: PollOptionSourceRegistry = new Map()\n\tfor (const [type, option] of Object.entries(config)) {\n\t\tif (option === false) {\n\t\t\tregistry.delete(type)\n\t\t} else if (option === true) {\n\t\t\t// keep the default; no-op because no built-in poll option sources exist\n\t\t} else {\n\t\t\tregistry.set(type, option)\n\t\t}\n\t}\n\treturn registry\n}\n"],"mappings":";;;;;;AAcA,MAAa,4BACZ,SAAkC,CAAC,MACL;CAC9B,MAAM,2BAAqC,IAAI,IAAI;CACnD,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,MAAM,GACjD,IAAI,WAAW,OACd,SAAS,OAAO,IAAI;MACd,IAAI,WAAW,MAAM,CAE5B,OACC,SAAS,IAAI,MAAM,MAAM;CAG3B,OAAO;AACR"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PollOption } from "./definePollOptionSource.js";
|
|
2
|
+
import { PollOptionSourceRegistry } from "./registry.js";
|
|
3
|
+
import { Payload, PayloadRequest } from "payload";
|
|
4
|
+
|
|
5
|
+
//#region src/poll/resolvePollOptions.d.ts
|
|
6
|
+
type ResolvePollOptionsArgs = {
|
|
7
|
+
payload: Payload;
|
|
8
|
+
req?: PayloadRequest; /** A loaded forms document (its `poll` group drives resolution). */
|
|
9
|
+
form: {
|
|
10
|
+
id: number | string;
|
|
11
|
+
title?: string | null;
|
|
12
|
+
poll?: unknown;
|
|
13
|
+
}; /** Registry override for plugin-internal callers; defaults to the registry the plugin stashed on the config. */
|
|
14
|
+
sources?: PollOptionSourceRegistry;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a poll-enabled form's choice options from its configured option source (plugin option
|
|
18
|
+
* `poll.sources`). Returns `undefined` when the form is not poll-enabled or has no `optionSource`
|
|
19
|
+
* set, so hand-authored options render unchanged. Hosts call this server-side and hand the result
|
|
20
|
+
* to `toFormDocument(doc, { pollOptions })`; submission validation calls it too, making the
|
|
21
|
+
* resolved values the only accepted answers. Throws when the configured source type is not
|
|
22
|
+
* registered or its `resolve` fails; results are cached per request (keyed by form id) when a
|
|
23
|
+
* `req` is provided.
|
|
24
|
+
*/
|
|
25
|
+
declare const resolvePollOptions: (args: ResolvePollOptionsArgs) => Promise<PollOption[] | undefined>;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { ResolvePollOptionsArgs, resolvePollOptions };
|
|
28
|
+
//# sourceMappingURL=resolvePollOptions.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { pollConfigOf } from "../form/pollState.js";
|
|
2
|
+
//#region src/poll/resolvePollOptions.ts
|
|
3
|
+
/** Root key under `config.custom` where the plugin stashes runtime state for root-level helpers. */
|
|
4
|
+
const CUSTOM_KEY = "@10x-media/form-builder";
|
|
5
|
+
/** Store the resolved registry on the config so `resolvePollOptions` can find it via `payload.config`. */
|
|
6
|
+
const stashPollOptionSources = (custom, registry) => {
|
|
7
|
+
const existing = custom?.[CUSTOM_KEY] != null && typeof custom[CUSTOM_KEY] === "object" ? custom[CUSTOM_KEY] : {};
|
|
8
|
+
return {
|
|
9
|
+
...custom ?? {},
|
|
10
|
+
[CUSTOM_KEY]: {
|
|
11
|
+
...existing,
|
|
12
|
+
pollOptionSources: registry
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
const pollOptionSourcesOf = (payload) => {
|
|
17
|
+
return (payload.config.custom?.[CUSTOM_KEY])?.pollOptionSources ?? /* @__PURE__ */ new Map();
|
|
18
|
+
};
|
|
19
|
+
const CACHE_KEY = "formBuilderPollOptionsCache";
|
|
20
|
+
const cacheOf = (req) => {
|
|
21
|
+
if (!req?.context) return;
|
|
22
|
+
const existing = req.context[CACHE_KEY];
|
|
23
|
+
if (existing instanceof Map) return existing;
|
|
24
|
+
const created = /* @__PURE__ */ new Map();
|
|
25
|
+
req.context[CACHE_KEY] = created;
|
|
26
|
+
return created;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a poll-enabled form's choice options from its configured option source (plugin option
|
|
30
|
+
* `poll.sources`). Returns `undefined` when the form is not poll-enabled or has no `optionSource`
|
|
31
|
+
* set, so hand-authored options render unchanged. Hosts call this server-side and hand the result
|
|
32
|
+
* to `toFormDocument(doc, { pollOptions })`; submission validation calls it too, making the
|
|
33
|
+
* resolved values the only accepted answers. Throws when the configured source type is not
|
|
34
|
+
* registered or its `resolve` fails; results are cached per request (keyed by form id) when a
|
|
35
|
+
* `req` is provided.
|
|
36
|
+
*/
|
|
37
|
+
const resolvePollOptions = async (args) => {
|
|
38
|
+
const { payload, req, form, sources } = args;
|
|
39
|
+
const poll = pollConfigOf(form.poll);
|
|
40
|
+
const optionSource = typeof poll?.optionSource === "string" ? poll.optionSource : void 0;
|
|
41
|
+
if (poll?.enabled !== true || !optionSource) return;
|
|
42
|
+
const source = (sources ?? pollOptionSourcesOf(payload)).get(optionSource);
|
|
43
|
+
if (!source) throw new Error(`Poll option source "${optionSource}" is not registered. Register it via the plugin's poll.sources option.`);
|
|
44
|
+
const cache = cacheOf(req);
|
|
45
|
+
const cacheKey = String(form.id);
|
|
46
|
+
const cached = cache?.get(cacheKey);
|
|
47
|
+
if (cached) return cached;
|
|
48
|
+
const config = poll.sourceConfig != null && typeof poll.sourceConfig === "object" ? poll.sourceConfig : {};
|
|
49
|
+
const options = await source.resolve({
|
|
50
|
+
config,
|
|
51
|
+
form: {
|
|
52
|
+
id: form.id,
|
|
53
|
+
title: typeof form.title === "string" ? form.title : void 0
|
|
54
|
+
},
|
|
55
|
+
payload,
|
|
56
|
+
req
|
|
57
|
+
});
|
|
58
|
+
cache?.set(cacheKey, options);
|
|
59
|
+
return options;
|
|
60
|
+
};
|
|
61
|
+
//#endregion
|
|
62
|
+
export { resolvePollOptions, stashPollOptionSources };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=resolvePollOptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePollOptions.js","names":[],"sources":["../../src/poll/resolvePollOptions.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { pollConfigOf } from '../form/pollState'\nimport type { PollOption } from './definePollOptionSource'\nimport type { PollOptionSourceRegistry } from './registry'\n\n/** Root key under `config.custom` where the plugin stashes runtime state for root-level helpers. */\nconst CUSTOM_KEY = '@10x-media/form-builder'\n\n/** Store the resolved registry on the config so `resolvePollOptions` can find it via `payload.config`. */\nexport const stashPollOptionSources = (\n\tcustom: Record<string, unknown> | undefined,\n\tregistry: PollOptionSourceRegistry\n): Record<string, unknown> => {\n\tconst existing =\n\t\tcustom?.[CUSTOM_KEY] != null && typeof custom[CUSTOM_KEY] === 'object'\n\t\t\t? (custom[CUSTOM_KEY] as Record<string, unknown>)\n\t\t\t: {}\n\treturn { ...(custom ?? {}), [CUSTOM_KEY]: { ...existing, pollOptionSources: registry } }\n}\n\nexport const pollOptionSourcesOf = (payload: Payload): PollOptionSourceRegistry => {\n\tconst custom = payload.config.custom?.[CUSTOM_KEY] as\n\t\t| { pollOptionSources?: PollOptionSourceRegistry }\n\t\t| undefined\n\treturn custom?.pollOptionSources ?? new Map()\n}\n\nconst CACHE_KEY = 'formBuilderPollOptionsCache'\n\ntype OptionsCache = Map<string, PollOption[]>\n\nconst cacheOf = (req: PayloadRequest | undefined): OptionsCache | undefined => {\n\tif (!req?.context) {\n\t\treturn undefined\n\t}\n\tconst existing = req.context[CACHE_KEY]\n\tif (existing instanceof Map) {\n\t\treturn existing as OptionsCache\n\t}\n\tconst created: OptionsCache = new Map()\n\treq.context[CACHE_KEY] = created\n\treturn created\n}\n\nexport type ResolvePollOptionsArgs = {\n\tpayload: Payload\n\treq?: PayloadRequest\n\t/** A loaded forms document (its `poll` group drives resolution). */\n\tform: { id: number | string; title?: string | null; poll?: unknown }\n\t/** Registry override for plugin-internal callers; defaults to the registry the plugin stashed on the config. */\n\tsources?: PollOptionSourceRegistry\n}\n\n/**\n * Resolve a poll-enabled form's choice options from its configured option source (plugin option\n * `poll.sources`). Returns `undefined` when the form is not poll-enabled or has no `optionSource`\n * set, so hand-authored options render unchanged. Hosts call this server-side and hand the result\n * to `toFormDocument(doc, { pollOptions })`; submission validation calls it too, making the\n * resolved values the only accepted answers. Throws when the configured source type is not\n * registered or its `resolve` fails; results are cached per request (keyed by form id) when a\n * `req` is provided.\n */\nexport const resolvePollOptions = async (\n\targs: ResolvePollOptionsArgs\n): Promise<PollOption[] | undefined> => {\n\tconst { payload, req, form, sources } = args\n\tconst poll = pollConfigOf(form.poll)\n\tconst optionSource = typeof poll?.optionSource === 'string' ? poll.optionSource : undefined\n\tif (poll?.enabled !== true || !optionSource) {\n\t\treturn undefined\n\t}\n\tconst source = (sources ?? pollOptionSourcesOf(payload)).get(optionSource)\n\tif (!source) {\n\t\tthrow new Error(\n\t\t\t`Poll option source \"${optionSource}\" is not registered. Register it via the plugin's poll.sources option.`\n\t\t)\n\t}\n\tconst cache = cacheOf(req)\n\tconst cacheKey = String(form.id)\n\tconst cached = cache?.get(cacheKey)\n\tif (cached) {\n\t\treturn cached\n\t}\n\tconst config =\n\t\tpoll.sourceConfig != null && typeof poll.sourceConfig === 'object'\n\t\t\t? (poll.sourceConfig as Record<string, unknown>)\n\t\t\t: {}\n\tconst options = await source.resolve({\n\t\tconfig,\n\t\tform: { id: form.id, title: typeof form.title === 'string' ? form.title : undefined },\n\t\tpayload,\n\t\treq,\n\t})\n\tcache?.set(cacheKey, options)\n\treturn options\n}\n"],"mappings":";;;AAMA,MAAM,aAAa;;AAGnB,MAAa,0BACZ,QACA,aAC6B;CAC7B,MAAM,WACL,SAAS,eAAe,QAAQ,OAAO,OAAO,gBAAgB,WAC1D,OAAO,cACR,CAAC;CACL,OAAO;EAAE,GAAI,UAAU,CAAC;GAAK,aAAa;GAAE,GAAG;GAAU,mBAAmB;EAAS;CAAE;AACxF;AAEA,MAAa,uBAAuB,YAA+C;CAIlF,QAHe,QAAQ,OAAO,SAAS,cAGxB,qCAAqB,IAAI,IAAI;AAC7C;AAEA,MAAM,YAAY;AAIlB,MAAM,WAAW,QAA8D;CAC9E,IAAI,CAAC,KAAK,SACT;CAED,MAAM,WAAW,IAAI,QAAQ;CAC7B,IAAI,oBAAoB,KACvB,OAAO;CAER,MAAM,0BAAwB,IAAI,IAAI;CACtC,IAAI,QAAQ,aAAa;CACzB,OAAO;AACR;;;;;;;;;;AAoBA,MAAa,qBAAqB,OACjC,SACuC;CACvC,MAAM,EAAE,SAAS,KAAK,MAAM,YAAY;CACxC,MAAM,OAAO,aAAa,KAAK,IAAI;CACnC,MAAM,eAAe,OAAO,MAAM,iBAAiB,WAAW,KAAK,eAAe,KAAA;CAClF,IAAI,MAAM,YAAY,QAAQ,CAAC,cAC9B;CAED,MAAM,UAAU,WAAW,oBAAoB,OAAO,GAAG,IAAI,YAAY;CACzE,IAAI,CAAC,QACJ,MAAM,IAAI,MACT,uBAAuB,aAAa,uEACrC;CAED,MAAM,QAAQ,QAAQ,GAAG;CACzB,MAAM,WAAW,OAAO,KAAK,EAAE;CAC/B,MAAM,SAAS,OAAO,IAAI,QAAQ;CAClC,IAAI,QACH,OAAO;CAER,MAAM,SACL,KAAK,gBAAgB,QAAQ,OAAO,KAAK,iBAAiB,WACtD,KAAK,eACN,CAAC;CACL,MAAM,UAAU,MAAM,OAAO,QAAQ;EACpC;EACA,MAAM;GAAE,IAAI,KAAK;GAAI,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAA;EAAU;EACpF;EACA;CACD,CAAC;CACD,OAAO,IAAI,UAAU,OAAO;CAC5B,OAAO;AACR"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Payload, PayloadRequest } from "payload";
|
|
2
|
+
|
|
3
|
+
//#region src/poll/resolvePollOutcome.d.ts
|
|
4
|
+
type ResolvePollOutcomeArgs = {
|
|
5
|
+
payload: Payload;
|
|
6
|
+
formId: number | string; /** A stable option value, matching one of the poll's choice values (the host's contract with `PollOption.value`). */
|
|
7
|
+
winningValue: string;
|
|
8
|
+
req?: PayloadRequest;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Record a poll's final outcome from host domain logic (e.g. after the race is decided): writes
|
|
12
|
+
* `poll.outcome.winningValue` and stamps `resolvedAt` with the current time. The outcome fields are
|
|
13
|
+
* admin read-only with field-level `update: () => false`, so this server-side call (with
|
|
14
|
+
* `overrideAccess`) is the only write path. Throws when the form does not exist or is not
|
|
15
|
+
* poll-enabled. `<Poll>` treats a present `winningValue` as the final state and highlights the
|
|
16
|
+
* matching result bucket.
|
|
17
|
+
*/
|
|
18
|
+
declare const resolvePollOutcome: (args: ResolvePollOutcomeArgs) => Promise<void>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ResolvePollOutcomeArgs, resolvePollOutcome };
|
|
21
|
+
//# sourceMappingURL=resolvePollOutcome.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { pollConfigOf } from "../form/pollState.js";
|
|
2
|
+
import { FORMS_SLUG } from "../collections/forms.js";
|
|
3
|
+
//#region src/poll/resolvePollOutcome.ts
|
|
4
|
+
/**
|
|
5
|
+
* Record a poll's final outcome from host domain logic (e.g. after the race is decided): writes
|
|
6
|
+
* `poll.outcome.winningValue` and stamps `resolvedAt` with the current time. The outcome fields are
|
|
7
|
+
* admin read-only with field-level `update: () => false`, so this server-side call (with
|
|
8
|
+
* `overrideAccess`) is the only write path. Throws when the form does not exist or is not
|
|
9
|
+
* poll-enabled. `<Poll>` treats a present `winningValue` as the final state and highlights the
|
|
10
|
+
* matching result bucket.
|
|
11
|
+
*/
|
|
12
|
+
const resolvePollOutcome = async (args) => {
|
|
13
|
+
const { payload, formId, winningValue, req } = args;
|
|
14
|
+
if (pollConfigOf((await payload.findByID({
|
|
15
|
+
collection: "forms",
|
|
16
|
+
id: formId,
|
|
17
|
+
depth: 0,
|
|
18
|
+
overrideAccess: true,
|
|
19
|
+
req
|
|
20
|
+
})).poll)?.enabled !== true) throw new Error(`Form ${String(formId)} is not poll-enabled; cannot record an outcome.`);
|
|
21
|
+
await payload.update({
|
|
22
|
+
collection: FORMS_SLUG,
|
|
23
|
+
id: formId,
|
|
24
|
+
data: { poll: { outcome: {
|
|
25
|
+
winningValue,
|
|
26
|
+
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
27
|
+
} } },
|
|
28
|
+
depth: 0,
|
|
29
|
+
overrideAccess: true,
|
|
30
|
+
req
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { resolvePollOutcome };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=resolvePollOutcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePollOutcome.js","names":[],"sources":["../../src/poll/resolvePollOutcome.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { FORMS_SLUG } from '../collections/forms'\nimport { pollConfigOf } from '../form/pollState'\n\nexport type ResolvePollOutcomeArgs = {\n\tpayload: Payload\n\tformId: number | string\n\t/** A stable option value, matching one of the poll's choice values (the host's contract with `PollOption.value`). */\n\twinningValue: string\n\treq?: PayloadRequest\n}\n\n/**\n * Record a poll's final outcome from host domain logic (e.g. after the race is decided): writes\n * `poll.outcome.winningValue` and stamps `resolvedAt` with the current time. The outcome fields are\n * admin read-only with field-level `update: () => false`, so this server-side call (with\n * `overrideAccess`) is the only write path. Throws when the form does not exist or is not\n * poll-enabled. `<Poll>` treats a present `winningValue` as the final state and highlights the\n * matching result bucket.\n */\nexport const resolvePollOutcome = async (args: ResolvePollOutcomeArgs): Promise<void> => {\n\tconst { payload, formId, winningValue, req } = args\n\tconst form = await payload.findByID({\n\t\tcollection: FORMS_SLUG,\n\t\tid: formId,\n\t\tdepth: 0,\n\t\toverrideAccess: true,\n\t\treq,\n\t})\n\tconst poll = pollConfigOf(form.poll)\n\tif (poll?.enabled !== true) {\n\t\tthrow new Error(`Form ${String(formId)} is not poll-enabled; cannot record an outcome.`)\n\t}\n\tawait payload.update({\n\t\tcollection: FORMS_SLUG,\n\t\tid: formId,\n\t\tdata: { poll: { outcome: { winningValue, resolvedAt: new Date().toISOString() } } },\n\t\tdepth: 0,\n\t\toverrideAccess: true,\n\t\treq,\n\t})\n}\n"],"mappings":";;;;;;;;;;;AAoBA,MAAa,qBAAqB,OAAO,SAAgD;CACxF,MAAM,EAAE,SAAS,QAAQ,cAAc,QAAQ;CAS/C,IADa,cAAa,MAPP,QAAQ,SAAS;EACnC,YAAA;EACA,IAAI;EACJ,OAAO;EACP,gBAAgB;EAChB;CACD,CAAC,GAC8B,IACxB,GAAG,YAAY,MACrB,MAAM,IAAI,MAAM,QAAQ,OAAO,MAAM,EAAE,gDAAgD;CAExF,MAAM,QAAQ,OAAO;EACpB,YAAY;EACZ,IAAI;EACJ,MAAM,EAAE,MAAM,EAAE,SAAS;GAAE;GAAc,6BAAY,IAAI,KAAK,GAAE,YAAY;EAAE,EAAE,EAAE;EAClF,OAAO;EACP,gBAAgB;EAChB;CACD,CAAC;AACF"}
|
|
@@ -32,7 +32,7 @@ const valuesFromSearchParams = (params, fields, registry, options = {}) => {
|
|
|
32
32
|
if (options.deny?.includes(fieldName)) continue;
|
|
33
33
|
const field = byName.get(fieldName);
|
|
34
34
|
const definition = field && registry.get(field.blockType);
|
|
35
|
-
if (!field || !definition) continue;
|
|
35
|
+
if (!field || !definition || definition.value === "none") continue;
|
|
36
36
|
const all = isSearch ? params.getAll(param) : [params[param]];
|
|
37
37
|
const value = coerce(definition.value, all[0] ?? "", all);
|
|
38
38
|
if (value !== void 0) result[fieldName] = value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"valuesFromSearchParams.js","names":[],"sources":["../../src/prefill/valuesFromSearchParams.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { FormFieldValueKind } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type PrefillOptions = {\n\t/** Map a query-param name to a field name. Unmapped params use their own name. */\n\tmap?: Record<string, string>\n\t/** If set, only these field names may be prefilled. */\n\tallow?: string[]\n\t/** These field names may never be prefilled. */\n\tdeny?: string[]\n}\n\nconst TRUTHY = new Set(['true', '1', 'on', 'yes'])\n\nconst coerce = (kind: FormFieldValueKind, raw: string, all: string[]): unknown => {\n\tswitch (kind) {\n\t\tcase 'number': {\n\t\t\tconst n = Number(raw)\n\t\t\treturn Number.isNaN(n) ? undefined : n\n\t\t}\n\t\tcase 'boolean':\n\t\t\treturn TRUTHY.has(raw.toLowerCase())\n\t\tcase 'text[]':\n\t\t\treturn all\n\t\tdefault:\n\t\t\treturn raw\n\t}\n}\n\n/**\n * Map URL/query params to typed initial values for KNOWN fields only, coerced by each field's value\n * kind. Unknown, denied, or un-allowed params are ignored; invalid numbers are dropped. Prefilled\n * values are never trusted -- they still validate on submit. Pass the result to `<Form initialValues>`.\n */\n// biome-ignore lint/complexity/useMaxParams: four positional args are the minimal surface (params, fields, registry, options)\nexport const valuesFromSearchParams = (\n\tparams: URLSearchParams | Record<string, string>,\n\tfields: FormFieldInstance[],\n\tregistry: FieldTypeRegistry,\n\toptions: PrefillOptions = {}\n): Record<string, unknown> => {\n\tconst isSearch = params instanceof URLSearchParams\n\tconst paramKeys = isSearch ? [...new Set(params.keys())] : Object.keys(params)\n\tconst byName = new Map(fields.map((field) => [field.name, field]))\n\tconst result: Record<string, unknown> = {}\n\n\tfor (const param of paramKeys) {\n\t\tconst fieldName = options.map?.[param] ?? param\n\n\t\tif (options.allow && !options.allow.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\t\tif (options.deny?.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst field = byName.get(fieldName)\n\t\tconst definition = field && registry.get(field.blockType)\n\t\tif (!field || !definition) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst all = isSearch ? params.getAll(param) : [params[param] as string]\n\t\tconst value = coerce(definition.value, all[0] ?? '', all)\n\t\tif (value !== undefined) {\n\t\t\tresult[fieldName] = value\n\t\t}\n\t}\n\n\treturn result\n}\n"],"mappings":";AAaA,MAAM,SAAS,IAAI,IAAI;CAAC;CAAQ;CAAK;CAAM;AAAK,CAAC;AAEjD,MAAM,UAAU,MAA0B,KAAa,QAA2B;CACjF,QAAQ,MAAR;EACC,KAAK,UAAU;GACd,MAAM,IAAI,OAAO,GAAG;GACpB,OAAO,OAAO,MAAM,CAAC,IAAI,KAAA,IAAY;EACtC;EACA,KAAK,WACJ,OAAO,OAAO,IAAI,IAAI,YAAY,CAAC;EACpC,KAAK,UACJ,OAAO;EACR,SACC,OAAO;CACT;AACD;;;;;;AAQA,MAAa,0BACZ,QACA,QACA,UACA,UAA0B,CAAC,MACE;CAC7B,MAAM,WAAW,kBAAkB;CACnC,MAAM,YAAY,WAAW,CAAC,GAAG,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,MAAM;CAC7E,MAAM,SAAS,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;CACjE,MAAM,SAAkC,CAAC;CAEzC,KAAK,MAAM,SAAS,WAAW;EAC9B,MAAM,YAAY,QAAQ,MAAM,UAAU;EAE1C,IAAI,QAAQ,SAAS,CAAC,QAAQ,MAAM,SAAS,SAAS,GACrD;EAED,IAAI,QAAQ,MAAM,SAAS,SAAS,GACnC;EAGD,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,MAAM,aAAa,SAAS,SAAS,IAAI,MAAM,SAAS;
|
|
1
|
+
{"version":3,"file":"valuesFromSearchParams.js","names":[],"sources":["../../src/prefill/valuesFromSearchParams.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { FormFieldValueKind } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type PrefillOptions = {\n\t/** Map a query-param name to a field name. Unmapped params use their own name. */\n\tmap?: Record<string, string>\n\t/** If set, only these field names may be prefilled. */\n\tallow?: string[]\n\t/** These field names may never be prefilled. */\n\tdeny?: string[]\n}\n\nconst TRUTHY = new Set(['true', '1', 'on', 'yes'])\n\nconst coerce = (kind: FormFieldValueKind, raw: string, all: string[]): unknown => {\n\tswitch (kind) {\n\t\tcase 'number': {\n\t\t\tconst n = Number(raw)\n\t\t\treturn Number.isNaN(n) ? undefined : n\n\t\t}\n\t\tcase 'boolean':\n\t\t\treturn TRUTHY.has(raw.toLowerCase())\n\t\tcase 'text[]':\n\t\t\treturn all\n\t\tdefault:\n\t\t\treturn raw\n\t}\n}\n\n/**\n * Map URL/query params to typed initial values for KNOWN fields only, coerced by each field's value\n * kind. Unknown, denied, or un-allowed params are ignored; invalid numbers are dropped. Prefilled\n * values are never trusted -- they still validate on submit. Pass the result to `<Form initialValues>`.\n */\n// biome-ignore lint/complexity/useMaxParams: four positional args are the minimal surface (params, fields, registry, options)\nexport const valuesFromSearchParams = (\n\tparams: URLSearchParams | Record<string, string>,\n\tfields: FormFieldInstance[],\n\tregistry: FieldTypeRegistry,\n\toptions: PrefillOptions = {}\n): Record<string, unknown> => {\n\tconst isSearch = params instanceof URLSearchParams\n\tconst paramKeys = isSearch ? [...new Set(params.keys())] : Object.keys(params)\n\tconst byName = new Map(fields.map((field) => [field.name, field]))\n\tconst result: Record<string, unknown> = {}\n\n\tfor (const param of paramKeys) {\n\t\tconst fieldName = options.map?.[param] ?? param\n\n\t\tif (options.allow && !options.allow.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\t\tif (options.deny?.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst field = byName.get(fieldName)\n\t\tconst definition = field && registry.get(field.blockType)\n\t\t// 'none'-kind (display-only) fields carry no value, so a param under their name is ignored.\n\t\tif (!field || !definition || definition.value === 'none') {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst all = isSearch ? params.getAll(param) : [params[param] as string]\n\t\tconst value = coerce(definition.value, all[0] ?? '', all)\n\t\tif (value !== undefined) {\n\t\t\tresult[fieldName] = value\n\t\t}\n\t}\n\n\treturn result\n}\n"],"mappings":";AAaA,MAAM,SAAS,IAAI,IAAI;CAAC;CAAQ;CAAK;CAAM;AAAK,CAAC;AAEjD,MAAM,UAAU,MAA0B,KAAa,QAA2B;CACjF,QAAQ,MAAR;EACC,KAAK,UAAU;GACd,MAAM,IAAI,OAAO,GAAG;GACpB,OAAO,OAAO,MAAM,CAAC,IAAI,KAAA,IAAY;EACtC;EACA,KAAK,WACJ,OAAO,OAAO,IAAI,IAAI,YAAY,CAAC;EACpC,KAAK,UACJ,OAAO;EACR,SACC,OAAO;CACT;AACD;;;;;;AAQA,MAAa,0BACZ,QACA,QACA,UACA,UAA0B,CAAC,MACE;CAC7B,MAAM,WAAW,kBAAkB;CACnC,MAAM,YAAY,WAAW,CAAC,GAAG,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,MAAM;CAC7E,MAAM,SAAS,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;CACjE,MAAM,SAAkC,CAAC;CAEzC,KAAK,MAAM,SAAS,WAAW;EAC9B,MAAM,YAAY,QAAQ,MAAM,UAAU;EAE1C,IAAI,QAAQ,SAAS,CAAC,QAAQ,MAAM,SAAS,SAAS,GACrD;EAED,IAAI,QAAQ,MAAM,SAAS,SAAS,GACnC;EAGD,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,MAAM,aAAa,SAAS,SAAS,IAAI,MAAM,SAAS;EAExD,IAAI,CAAC,SAAS,CAAC,cAAc,WAAW,UAAU,QACjD;EAGD,MAAM,MAAM,WAAW,OAAO,OAAO,KAAK,IAAI,CAAC,OAAO,MAAgB;EACtE,MAAM,QAAQ,OAAO,WAAW,OAAO,IAAI,MAAM,IAAI,GAAG;EACxD,IAAI,UAAU,KAAA,GACb,OAAO,aAAa;CAEtB;CAEA,OAAO;AACR"}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
type PresentationSurface = 'inline' | 'page' | 'overlay';
|
|
4
4
|
type PresentationDensity = 'comfortable' | 'compact';
|
|
5
5
|
/**
|
|
6
|
-
* Serializable, framework-agnostic description of a presentation.
|
|
7
|
-
*
|
|
6
|
+
* Serializable, framework-agnostic description of a presentation. `presentations/defaults.ts`
|
|
7
|
+
* ships the built-ins the React presentation registry wraps with a `Wrapper` (see `./react`). No
|
|
8
|
+
* React here.
|
|
8
9
|
*/
|
|
9
10
|
type PresentationDescriptor = {
|
|
10
11
|
name: string; /** i18n key or literal shown in the admin select. */
|
package/dist/react/Form.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AnyFormFieldDefinition } from "../fields/types.js";
|
|
2
|
-
import {
|
|
3
|
-
import { FormFlow } from "../flow/types.js";
|
|
2
|
+
import { FormDisplaySettings, FormDocument, FormPollSettings, FormResponseSettings } from "../form/types.js";
|
|
4
3
|
import { RendererTranslate } from "./contract.js";
|
|
5
4
|
import { FormEventSink } from "../events/types.js";
|
|
6
5
|
import { AnyValidationRuleDefinition } from "../validation/types.js";
|
|
6
|
+
import { BackButtonRenderProps, NextButtonRenderProps, SubmitButtonRenderProps } from "./FormControls.js";
|
|
7
7
|
import { FormPresentation } from "./presentation/types.js";
|
|
8
8
|
import { PresentationsConfig } from "./presentation/registry.js";
|
|
9
9
|
import { RenderersConfig } from "./registry.js";
|
|
@@ -11,29 +11,6 @@ import { SubmitHandler } from "./submitForm.js";
|
|
|
11
11
|
import { ReactNode } from "react";
|
|
12
12
|
|
|
13
13
|
//#region src/react/Form.d.ts
|
|
14
|
-
type FormDocument = {
|
|
15
|
-
id: number | string;
|
|
16
|
-
fields: FormFieldInstance[];
|
|
17
|
-
flow?: FormFlow; /** Stored presentation name; overridden by the `presentation` prop. */
|
|
18
|
-
defaultPresentation?: string;
|
|
19
|
-
};
|
|
20
|
-
/** Props passed to `renderSubmit`. */
|
|
21
|
-
type SubmitButtonRenderProps = {
|
|
22
|
-
label: string;
|
|
23
|
-
submitting: boolean;
|
|
24
|
-
};
|
|
25
|
-
/** Props passed to `renderNext`. */
|
|
26
|
-
type NextButtonRenderProps = {
|
|
27
|
-
label: string;
|
|
28
|
-
submitting: boolean;
|
|
29
|
-
onClick: () => void;
|
|
30
|
-
};
|
|
31
|
-
/** Props passed to `renderBack`. */
|
|
32
|
-
type BackButtonRenderProps = {
|
|
33
|
-
label: string;
|
|
34
|
-
submitting: boolean;
|
|
35
|
-
onClick: () => void;
|
|
36
|
-
};
|
|
37
14
|
type FormProps = {
|
|
38
15
|
form: FormDocument;
|
|
39
16
|
fieldTypes?: AnyFormFieldDefinition[];
|
|
@@ -46,15 +23,20 @@ type FormProps = {
|
|
|
46
23
|
events?: FormEventSink;
|
|
47
24
|
t?: RendererTranslate;
|
|
48
25
|
locale?: string;
|
|
49
|
-
layout?: boolean;
|
|
50
|
-
submitLabel?: string;
|
|
51
|
-
nextLabel?: string;
|
|
26
|
+
layout?: boolean; /** Submit button label. Precedence: this prop, then the form's `response.submitLabel`, then the translated default. */
|
|
27
|
+
submitLabel?: string; /** "Next" button label for multi-step forms. Defaults to the translated `'Next'`. */
|
|
28
|
+
nextLabel?: string; /** "Back" button label for multi-step forms. Defaults to the translated `'Back'`. */
|
|
52
29
|
backLabel?: string; /** Label for the overlay close control (modal/drawer). */
|
|
53
30
|
closeLabel?: string;
|
|
54
|
-
successMessage?: string; /** Active presentation: a name into the registry or an inline presentation.
|
|
31
|
+
successMessage?: string; /** Active presentation: a name into the registry or an inline presentation. Defaults to `'page'` when omitted. */
|
|
55
32
|
presentation?: string | FormPresentation; /** Per-render presentation overrides merged onto the defaults (add, replace, or `false` to remove). */
|
|
56
33
|
presentations?: PresentationsConfig; /** Invoked when an overlay presentation dismisses (close button, Escape, outside click, or `dismissOnSuccess`). */
|
|
57
|
-
onClose?: () => void;
|
|
34
|
+
onClose?: () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Accessible name for an overlay surface (modal/drawer). Hosts choosing between a trigger
|
|
37
|
+
* label and the form's own display title should prefer `form.display?.title` when
|
|
38
|
+
* `form.display?.showTitle` is set, falling back to their own label otherwise.
|
|
39
|
+
*/
|
|
58
40
|
title?: string; /** Seed initial field values (e.g. from `valuesFromSearchParams`). Still validated on submit. */
|
|
59
41
|
initialValues?: Record<string, unknown>; /** Honeypot decoy (on by default). `false` removes it; `{ name }` matches a customized server `spam.honeypot.fieldName`. */
|
|
60
42
|
honeypot?: false | {
|
|
@@ -106,5 +88,5 @@ declare const Form: ({
|
|
|
106
88
|
backButtonClassName
|
|
107
89
|
}: FormProps) => import("react/jsx-runtime").JSX.Element;
|
|
108
90
|
//#endregion
|
|
109
|
-
export {
|
|
91
|
+
export { Form, FormProps };
|
|
110
92
|
//# sourceMappingURL=Form.d.ts.map
|