@panneau/forms 4.1.1 → 5.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -0
- package/dist/ConflictDialog.css +55 -0
- package/dist/ConflictDialog.d.ts +23 -0
- package/dist/ConflictDialog.d.ts.map +1 -0
- package/dist/ConflictDialog.js +122 -0
- package/dist/ConflictDialog.js.map +1 -0
- package/dist/ConflictDialog.module.js +24 -0
- package/dist/ConflictDialog.module.js.map +1 -0
- package/dist/ErrorSummary.d.ts +18 -0
- package/dist/ErrorSummary.d.ts.map +1 -0
- package/dist/ErrorSummary.js +122 -0
- package/dist/ErrorSummary.js.map +1 -0
- package/dist/FieldErrorBoundary.d.ts +19 -0
- package/dist/FieldErrorBoundary.d.ts.map +1 -0
- package/dist/FieldErrorBoundary.js +20 -0
- package/dist/FieldErrorBoundary.js.map +1 -0
- package/dist/Form.css +151 -0
- package/dist/Form.d.ts +20 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/Form.js +41 -0
- package/dist/Form.js.map +1 -0
- package/dist/Form.module.js +44 -0
- package/dist/Form.module.js.map +1 -0
- package/dist/FormBinding.d.ts +8 -0
- package/dist/FormBinding.d.ts.map +1 -0
- package/dist/FormBinding.js +122 -0
- package/dist/FormBinding.js.map +1 -0
- package/dist/FormView.d.ts +48 -0
- package/dist/FormView.d.ts.map +1 -0
- package/dist/FormView.js +203 -0
- package/dist/FormView.js.map +1 -0
- package/dist/context.d.ts +15 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +32 -0
- package/dist/context.js.map +1 -0
- package/dist/cx.d.ts +3 -0
- package/dist/cx.d.ts.map +1 -0
- package/dist/cx.js +9 -0
- package/dist/cx.js.map +1 -0
- package/dist/describe.d.ts +7 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +17 -0
- package/dist/describe.js.map +1 -0
- package/dist/formatError.d.ts +8 -0
- package/dist/formatError.d.ts.map +1 -0
- package/dist/formatError.js +46 -0
- package/dist/formatError.js.map +1 -0
- package/dist/index.d.ts +10 -12
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -90
- package/dist/layout/Layout.d.ts +9 -0
- package/dist/layout/Layout.d.ts.map +1 -0
- package/dist/layout/Layout.js +442 -0
- package/dist/layout/Layout.js.map +1 -0
- package/dist/locales/index.d.ts +15 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/index.js +21 -0
- package/dist/locales/index.js.map +1 -0
- package/dist/messages.d.ts +2 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +1 -0
- package/dist/paths.d.ts +15 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +34 -0
- package/dist/paths.js.map +1 -0
- package/dist/unsaved.d.ts +22 -0
- package/dist/unsaved.d.ts.map +1 -0
- package/dist/unsaved.js +169 -0
- package/dist/unsaved.js.map +1 -0
- package/package.json +30 -60
package/dist/Form.css
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
.panneau-form-SbGXMC {
|
|
2
|
+
container: panneau-form / inline-size;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: var(--panneau-space-6);
|
|
6
|
+
min-width: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.panneau-layout-ZLMO4i {
|
|
10
|
+
display: grid;
|
|
11
|
+
gap: var(--panneau-space-6);
|
|
12
|
+
min-width: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@container panneau-form (min-width: 56rem) {
|
|
16
|
+
.panneau-withSidebar-EZX3tW {
|
|
17
|
+
grid-template-columns: minmax(0, 1fr) minmax(16rem, 20rem);
|
|
18
|
+
align-items: start;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.panneau-stack-PjhKm6 {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
gap: var(--panneau-space-5);
|
|
26
|
+
min-width: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.panneau-row-Yi7-zn {
|
|
30
|
+
display: grid;
|
|
31
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
32
|
+
gap: var(--panneau-space-5) var(--panneau-space-4);
|
|
33
|
+
min-width: 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.panneau-cell--1VhEt {
|
|
37
|
+
grid-column: span var(--panneau-span, 12);
|
|
38
|
+
min-width: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Narrow containers (phones, side panels): every cell takes the full width. */
|
|
42
|
+
@container panneau-form (max-width: 36rem) {
|
|
43
|
+
.panneau-cell--1VhEt {
|
|
44
|
+
grid-column: 1 / -1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.panneau-section-TsDtP1 {
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
gap: var(--panneau-space-4);
|
|
52
|
+
min-width: 0;
|
|
53
|
+
padding: var(--panneau-space-4) var(--panneau-space-5);
|
|
54
|
+
background-color: var(--panneau-color-surface);
|
|
55
|
+
border: var(--panneau-border-width) solid var(--panneau-color-border);
|
|
56
|
+
border-radius: var(--panneau-radius-lg);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@container panneau-form (max-width: 36rem) {
|
|
60
|
+
.panneau-section-TsDtP1 {
|
|
61
|
+
padding: var(--panneau-space-3);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.panneau-sectionHeader-ewRbEd {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
gap: var(--panneau-space-1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.panneau-sectionTitle-13j1RU {
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: var(--panneau-space-2);
|
|
75
|
+
font-size: var(--panneau-font-size-lg);
|
|
76
|
+
font-weight: var(--panneau-font-weight-bold);
|
|
77
|
+
line-height: var(--panneau-line-height-tight);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.panneau-sectionDescription-wMAdQR,
|
|
81
|
+
.panneau-text-8QehWk {
|
|
82
|
+
font-size: var(--panneau-font-size-md);
|
|
83
|
+
color: var(--panneau-color-text-muted);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.panneau-sidebar-sKhl3G {
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: column;
|
|
89
|
+
gap: var(--panneau-space-5);
|
|
90
|
+
min-width: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.panneau-field-4Wbt9T {
|
|
94
|
+
min-width: 0;
|
|
95
|
+
scroll-margin: var(--panneau-space-10);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.panneau-footer-PD5XO8 {
|
|
99
|
+
position: sticky;
|
|
100
|
+
bottom: 0;
|
|
101
|
+
z-index: 1;
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-wrap: wrap;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: flex-end;
|
|
106
|
+
gap: var(--panneau-space-2) var(--panneau-space-3);
|
|
107
|
+
padding: var(--panneau-space-3) 0;
|
|
108
|
+
background-color: var(--panneau-color-bg);
|
|
109
|
+
border-top: var(--panneau-border-width) solid var(--panneau-color-border);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.panneau-dirty-pKx-lf {
|
|
113
|
+
margin-inline-end: auto;
|
|
114
|
+
font-size: var(--panneau-font-size-sm);
|
|
115
|
+
color: var(--panneau-color-text-muted);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.panneau-summary-mM2QXV:focus {
|
|
119
|
+
outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
|
|
120
|
+
outline-offset: 2px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.panneau-summaryList-BPalHL {
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
gap: var(--panneau-space-1);
|
|
127
|
+
margin: 0;
|
|
128
|
+
padding-inline-start: var(--panneau-space-5);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.panneau-summaryLink-wCCmoV {
|
|
132
|
+
padding: 0;
|
|
133
|
+
font: inherit;
|
|
134
|
+
color: inherit;
|
|
135
|
+
text-align: start;
|
|
136
|
+
text-decoration: underline;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
background: none;
|
|
139
|
+
border: 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.panneau-summaryLink-wCCmoV:focus-visible {
|
|
143
|
+
outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
|
|
144
|
+
outline-offset: 2px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@container panneau-form (max-width: 36rem) {
|
|
148
|
+
.panneau-footer-PD5XO8 > :not(.panneau-dirty-pKx-lf) {
|
|
149
|
+
flex: 1 1 auto;
|
|
150
|
+
}
|
|
151
|
+
}
|
package/dist/Form.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type FormOptions } from '@panneau/core';
|
|
2
|
+
import type { Field, LayoutNode } from '@panneau/protocol';
|
|
3
|
+
import { type FormViewProps } from './FormView';
|
|
4
|
+
export interface FormProps extends Omit<FormViewProps, 'form' | 'fields' | 'layout'>, Pick<FormOptions, 'values' | 'version' | 'mode' | 'store' | 'formatError' | 'onSubmit'> {
|
|
5
|
+
/** The fields of the form. Without a layout, they are rendered in order. */
|
|
6
|
+
fields: readonly Field[];
|
|
7
|
+
/** The layout tree. Fields that no node references are added at the end. */
|
|
8
|
+
layout?: readonly LayoutNode[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A form from a list of fields and an `onSubmit`, with or without a definition. It creates its
|
|
12
|
+
* state with `useForm()` of `@panneau/core`: values, validation with the portable rules, server
|
|
13
|
+
* errors (`422`) and version conflicts (`412`) from what `onSubmit` throws. Rule messages are
|
|
14
|
+
* translated with react-intl.
|
|
15
|
+
*
|
|
16
|
+
* Initial values and the version are read once: give the form a new `key` to start from another
|
|
17
|
+
* item, or use `useForm()` and `FormView`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function Form({ fields, layout, values, version, mode, store, formatError, onSubmit, locales, ...props }: FormProps): import("react").JSX.Element;
|
|
20
|
+
//# sourceMappingURL=Form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../src/Form.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAsC,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1D,MAAM,WAAW,SACb,SACI,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC,EACjD,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,UAAU,CAAC;IAC3F,4EAA4E;IAC5E,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CAClC;AAED;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,EACjB,MAAM,EACN,MAAW,EACX,MAAM,EACN,OAAO,EACP,IAAI,EACJ,KAAK,EACL,WAAW,EACX,QAAQ,EACR,OAAO,EACP,GAAG,KAAK,EACX,EAAE,SAAS,+BAwBX"}
|
package/dist/Form.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { FormView } from "./FormView.js";
|
|
2
|
+
import { useFormatRuleFailure } from "./formatError.js";
|
|
3
|
+
import { resolveFields, useForm, usePanneau } from "@panneau/core";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/Form.tsx
|
|
6
|
+
/**
|
|
7
|
+
* A form from a list of fields and an `onSubmit`, with or without a definition. It creates its
|
|
8
|
+
* state with `useForm()` of `@panneau/core`: values, validation with the portable rules, server
|
|
9
|
+
* errors (`422`) and version conflicts (`412`) from what `onSubmit` throws. Rule messages are
|
|
10
|
+
* translated with react-intl.
|
|
11
|
+
*
|
|
12
|
+
* Initial values and the version are read once: give the form a new `key` to start from another
|
|
13
|
+
* item, or use `useForm()` and `FormView`.
|
|
14
|
+
*/
|
|
15
|
+
function Form({ fields, layout = [], values, version, mode, store, formatError, onSubmit, locales, ...props }) {
|
|
16
|
+
const { definition } = usePanneau();
|
|
17
|
+
const resolved = resolveFields(fields, layout, mode !== void 0 ? { mode } : {});
|
|
18
|
+
const formatRuleFailure = useFormatRuleFailure(resolved.fields);
|
|
19
|
+
const formLocales = locales ?? definition?.locales ?? [];
|
|
20
|
+
const { form } = useForm({
|
|
21
|
+
fields: resolved.fields,
|
|
22
|
+
locales: [...formLocales],
|
|
23
|
+
formatError: formatError ?? formatRuleFailure,
|
|
24
|
+
...values !== void 0 ? { values } : {},
|
|
25
|
+
...version !== void 0 ? { version } : {},
|
|
26
|
+
...mode !== void 0 ? { mode } : {},
|
|
27
|
+
...store !== void 0 ? { store } : {},
|
|
28
|
+
...onSubmit !== void 0 ? { onSubmit } : {}
|
|
29
|
+
});
|
|
30
|
+
return /* @__PURE__ */ jsx(FormView, {
|
|
31
|
+
...props,
|
|
32
|
+
form,
|
|
33
|
+
fields: resolved.fields,
|
|
34
|
+
layout: resolved.layout,
|
|
35
|
+
locales: formLocales
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { Form };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=Form.js.map
|
package/dist/Form.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Form.js","names":[],"sources":["../src/Form.tsx"],"sourcesContent":["import { type FormOptions, resolveFields, useForm, usePanneau } from '@panneau/core';\nimport type { Field, LayoutNode } from '@panneau/protocol';\n\nimport { FormView, type FormViewProps } from './FormView';\nimport { useFormatRuleFailure } from './formatError';\n\nexport interface FormProps\n extends\n Omit<FormViewProps, 'form' | 'fields' | 'layout'>,\n Pick<FormOptions, 'values' | 'version' | 'mode' | 'store' | 'formatError' | 'onSubmit'> {\n /** The fields of the form. Without a layout, they are rendered in order. */\n fields: readonly Field[];\n /** The layout tree. Fields that no node references are added at the end. */\n layout?: readonly LayoutNode[];\n}\n\n/**\n * A form from a list of fields and an `onSubmit`, with or without a definition. It creates its\n * state with `useForm()` of `@panneau/core`: values, validation with the portable rules, server\n * errors (`422`) and version conflicts (`412`) from what `onSubmit` throws. Rule messages are\n * translated with react-intl.\n *\n * Initial values and the version are read once: give the form a new `key` to start from another\n * item, or use `useForm()` and `FormView`.\n */\nexport function Form({\n fields,\n layout = [],\n values,\n version,\n mode,\n store,\n formatError,\n onSubmit,\n locales,\n ...props\n}: FormProps) {\n const { definition } = usePanneau();\n const resolved = resolveFields(fields, layout, mode !== undefined ? { mode } : {});\n const formatRuleFailure = useFormatRuleFailure(resolved.fields);\n const formLocales = locales ?? definition?.locales ?? [];\n const { form } = useForm({\n fields: resolved.fields,\n locales: [...formLocales],\n formatError: formatError ?? formatRuleFailure,\n ...(values !== undefined ? { values } : {}),\n ...(version !== undefined ? { version } : {}),\n ...(mode !== undefined ? { mode } : {}),\n ...(store !== undefined ? { store } : {}),\n ...(onSubmit !== undefined ? { onSubmit } : {}),\n });\n return (\n <FormView\n {...props}\n form={form}\n fields={resolved.fields}\n layout={resolved.layout}\n locales={formLocales}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAyBA,SAAgB,KAAK,EACjB,QACA,SAAS,CAAA,GACT,QACA,SACA,MACA,OACA,aACA,UACA,SACA,GAAG,SACO;CACV,MAAM,EAAE,eAAe,WAAW;CAClC,MAAM,WAAW,cAAc,QAAQ,QAAQ,SAAS,KAAA,IAAY,EAAE,KAAK,IAAI,CAAC,CAAC;CACjF,MAAM,oBAAoB,qBAAqB,SAAS,MAAM;CAC9D,MAAM,cAAc,WAAW,YAAY,WAAW,CAAA;CACtD,MAAM,EAAE,SAAS,QAAQ;EACrB,QAAQ,SAAS;EACjB,SAAS,CAAC,GAAG,WAAW;EACxB,aAAa,eAAe;EAC5B,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;EACzC,GAAI,YAAY,KAAA,IAAY,EAAE,QAAQ,IAAI,CAAC;EAC3C,GAAI,SAAS,KAAA,IAAY,EAAE,KAAK,IAAI,CAAC;EACrC,GAAI,UAAU,KAAA,IAAY,EAAE,MAAM,IAAI,CAAC;EACvC,GAAI,aAAa,KAAA,IAAY,EAAE,SAAS,IAAI,CAAC;CACjD,CAAC;CACD,OACI,oBAAC,UAAD;EACI,GAAI;EACE;EACN,QAAQ,SAAS;EACjB,QAAQ,SAAS;EACjB,SAAS;CAAY,CAAA;AAGjC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import "./Form.css";
|
|
2
|
+
//#region src/Form.module.css
|
|
3
|
+
var form = "panneau-form-SbGXMC";
|
|
4
|
+
var layout = "panneau-layout-ZLMO4i";
|
|
5
|
+
var withSidebar = "panneau-withSidebar-EZX3tW";
|
|
6
|
+
var stack = "panneau-stack-PjhKm6";
|
|
7
|
+
var row = "panneau-row-Yi7-zn";
|
|
8
|
+
var cell = "panneau-cell--1VhEt";
|
|
9
|
+
var section = "panneau-section-TsDtP1";
|
|
10
|
+
var sectionHeader = "panneau-sectionHeader-ewRbEd";
|
|
11
|
+
var sectionTitle = "panneau-sectionTitle-13j1RU";
|
|
12
|
+
var sectionDescription = "panneau-sectionDescription-wMAdQR";
|
|
13
|
+
var text = "panneau-text-8QehWk";
|
|
14
|
+
var sidebar = "panneau-sidebar-sKhl3G";
|
|
15
|
+
var field = "panneau-field-4Wbt9T";
|
|
16
|
+
var footer = "panneau-footer-PD5XO8";
|
|
17
|
+
var dirty = "panneau-dirty-pKx-lf";
|
|
18
|
+
var summary = "panneau-summary-mM2QXV";
|
|
19
|
+
var summaryList = "panneau-summaryList-BPalHL";
|
|
20
|
+
var summaryLink = "panneau-summaryLink-wCCmoV";
|
|
21
|
+
var Form_module_default = {
|
|
22
|
+
form,
|
|
23
|
+
layout,
|
|
24
|
+
withSidebar,
|
|
25
|
+
stack,
|
|
26
|
+
row,
|
|
27
|
+
cell,
|
|
28
|
+
section,
|
|
29
|
+
sectionHeader,
|
|
30
|
+
sectionTitle,
|
|
31
|
+
sectionDescription,
|
|
32
|
+
text,
|
|
33
|
+
sidebar,
|
|
34
|
+
field,
|
|
35
|
+
footer,
|
|
36
|
+
dirty,
|
|
37
|
+
summary,
|
|
38
|
+
summaryList,
|
|
39
|
+
summaryLink
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { cell, Form_module_default as default, dirty, field, footer, form, layout, row, section, sectionDescription, sectionHeader, sectionTitle, sidebar, stack, summary, summaryLink, summaryList, text, withSidebar };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=Form.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Form.module.js","names":[],"sources":["../src/Form.module.css"],"sourcesContent":[".form {\n container: panneau-form / inline-size;\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-6);\n min-width: 0;\n}\n\n.layout {\n display: grid;\n gap: var(--panneau-space-6);\n min-width: 0;\n}\n\n@container panneau-form (min-width: 56rem) {\n .withSidebar {\n grid-template-columns: minmax(0, 1fr) minmax(16rem, 20rem);\n align-items: start;\n }\n}\n\n.stack {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-5);\n min-width: 0;\n}\n\n.row {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n gap: var(--panneau-space-5) var(--panneau-space-4);\n min-width: 0;\n}\n\n.cell {\n grid-column: span var(--panneau-span, 12);\n min-width: 0;\n}\n\n/* Narrow containers (phones, side panels): every cell takes the full width. */\n@container panneau-form (max-width: 36rem) {\n .cell {\n grid-column: 1 / -1;\n }\n}\n\n.section {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-4);\n min-width: 0;\n padding: var(--panneau-space-4) var(--panneau-space-5);\n background-color: var(--panneau-color-surface);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-lg);\n}\n\n@container panneau-form (max-width: 36rem) {\n .section {\n padding: var(--panneau-space-3);\n }\n}\n\n.sectionHeader {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n}\n\n.sectionTitle {\n display: flex;\n align-items: center;\n gap: var(--panneau-space-2);\n font-size: var(--panneau-font-size-lg);\n font-weight: var(--panneau-font-weight-bold);\n line-height: var(--panneau-line-height-tight);\n}\n\n.sectionDescription,\n.text {\n font-size: var(--panneau-font-size-md);\n color: var(--panneau-color-text-muted);\n}\n\n.sidebar {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-5);\n min-width: 0;\n}\n\n.field {\n min-width: 0;\n scroll-margin: var(--panneau-space-10);\n}\n\n.footer {\n position: sticky;\n bottom: 0;\n z-index: 1;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--panneau-space-2) var(--panneau-space-3);\n padding: var(--panneau-space-3) 0;\n background-color: var(--panneau-color-bg);\n border-top: var(--panneau-border-width) solid var(--panneau-color-border);\n}\n\n.dirty {\n margin-inline-end: auto;\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n\n.summary:focus {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.summaryList {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n margin: 0;\n padding-inline-start: var(--panneau-space-5);\n}\n\n.summaryLink {\n padding: 0;\n font: inherit;\n color: inherit;\n text-align: start;\n text-decoration: underline;\n cursor: pointer;\n background: none;\n border: 0;\n}\n\n.summaryLink:focus-visible {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n@container panneau-form (max-width: 36rem) {\n .footer > :not(.dirty) {\n flex: 1 1 auto;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FieldBindingProps } from '@panneau/fields';
|
|
2
|
+
/**
|
|
3
|
+
* Binds a field to the form by path: value, change, blur and errors. It hides fields whose
|
|
4
|
+
* `visibleWhen` is false, marks the field's element with its path for the error summary, and
|
|
5
|
+
* keeps a field that throws from breaking the form.
|
|
6
|
+
*/
|
|
7
|
+
export declare function FormBinding({ field, path, parentPath, render }: FieldBindingProps): import("react").JSX.Element | null;
|
|
8
|
+
//# sourceMappingURL=FormBinding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormBinding.d.ts","sourceRoot":"","sources":["../src/FormBinding.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAazD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,iBAAiB,sCAmCjF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { messages } from "./messages.js";
|
|
2
|
+
import Form_module_default from "./Form.module.js";
|
|
3
|
+
import { FieldErrorBoundary } from "./FieldErrorBoundary.js";
|
|
4
|
+
import { useFormContext, useFormState } from "./context.js";
|
|
5
|
+
import { c } from "react/compiler-runtime";
|
|
6
|
+
import { selectErrors, selectValue, selectVisible } from "@panneau/core";
|
|
7
|
+
import { Alert, Button, usePanneauIntl } from "@panneau/ui";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
//#region src/FormBinding.tsx
|
|
10
|
+
/** Fields that show the errors of their nested fields themselves. */
|
|
11
|
+
function rendersNestedFields(field) {
|
|
12
|
+
return field.localized === true || field.type === "group" || field.type === "repeater";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Binds a field to the form by path: value, change, blur and errors. It hides fields whose
|
|
16
|
+
* `visibleWhen` is false, marks the field's element with its path for the error summary, and
|
|
17
|
+
* keeps a field that throws from breaking the form.
|
|
18
|
+
*/
|
|
19
|
+
function FormBinding(t0) {
|
|
20
|
+
const $ = c(29);
|
|
21
|
+
const { field, path, parentPath, render } = t0;
|
|
22
|
+
const form = useFormContext();
|
|
23
|
+
const intl = usePanneauIntl();
|
|
24
|
+
const state = useFormState(form);
|
|
25
|
+
if (!selectVisible(state, field, parentPath)) return null;
|
|
26
|
+
let T0;
|
|
27
|
+
let t1;
|
|
28
|
+
let t2;
|
|
29
|
+
let t3;
|
|
30
|
+
let t4;
|
|
31
|
+
if ($[0] !== field || $[1] !== form || $[2] !== intl || $[3] !== path || $[4] !== render || $[5] !== state) {
|
|
32
|
+
let t5;
|
|
33
|
+
if ($[11] !== field) {
|
|
34
|
+
t5 = rendersNestedFields(field);
|
|
35
|
+
$[11] = field;
|
|
36
|
+
$[12] = t5;
|
|
37
|
+
} else t5 = $[12];
|
|
38
|
+
const errors = selectErrors(state, path, { nested: !t5 });
|
|
39
|
+
t3 = Form_module_default.field;
|
|
40
|
+
t4 = path;
|
|
41
|
+
T0 = FieldErrorBoundary;
|
|
42
|
+
if ($[13] !== field.label || $[14] !== field.name || $[15] !== intl) {
|
|
43
|
+
t1 = (retry) => /* @__PURE__ */ jsx(Alert, {
|
|
44
|
+
tone: "danger",
|
|
45
|
+
actions: /* @__PURE__ */ jsx(Button, {
|
|
46
|
+
size: "sm",
|
|
47
|
+
onPress: retry,
|
|
48
|
+
children: intl.formatMessage(messages.retry)
|
|
49
|
+
}),
|
|
50
|
+
children: intl.formatMessage(messages.fieldCrashed, { field: field.label ?? field.name })
|
|
51
|
+
});
|
|
52
|
+
$[13] = field.label;
|
|
53
|
+
$[14] = field.name;
|
|
54
|
+
$[15] = intl;
|
|
55
|
+
$[16] = t1;
|
|
56
|
+
} else t1 = $[16];
|
|
57
|
+
let t6;
|
|
58
|
+
let t7;
|
|
59
|
+
if ($[17] !== form || $[18] !== path) {
|
|
60
|
+
t6 = (value) => form.setValue(path, value);
|
|
61
|
+
t7 = () => form.blur(path);
|
|
62
|
+
$[17] = form;
|
|
63
|
+
$[18] = path;
|
|
64
|
+
$[19] = t6;
|
|
65
|
+
$[20] = t7;
|
|
66
|
+
} else {
|
|
67
|
+
t6 = $[19];
|
|
68
|
+
t7 = $[20];
|
|
69
|
+
}
|
|
70
|
+
t2 = render({
|
|
71
|
+
value: selectValue(state, path),
|
|
72
|
+
onChange: t6,
|
|
73
|
+
onBlur: t7,
|
|
74
|
+
errors
|
|
75
|
+
});
|
|
76
|
+
$[0] = field;
|
|
77
|
+
$[1] = form;
|
|
78
|
+
$[2] = intl;
|
|
79
|
+
$[3] = path;
|
|
80
|
+
$[4] = render;
|
|
81
|
+
$[5] = state;
|
|
82
|
+
$[6] = T0;
|
|
83
|
+
$[7] = t1;
|
|
84
|
+
$[8] = t2;
|
|
85
|
+
$[9] = t3;
|
|
86
|
+
$[10] = t4;
|
|
87
|
+
} else {
|
|
88
|
+
T0 = $[6];
|
|
89
|
+
t1 = $[7];
|
|
90
|
+
t2 = $[8];
|
|
91
|
+
t3 = $[9];
|
|
92
|
+
t4 = $[10];
|
|
93
|
+
}
|
|
94
|
+
let t5;
|
|
95
|
+
if ($[21] !== T0 || $[22] !== t1 || $[23] !== t2) {
|
|
96
|
+
t5 = /* @__PURE__ */ jsx(T0, {
|
|
97
|
+
fallback: t1,
|
|
98
|
+
children: t2
|
|
99
|
+
});
|
|
100
|
+
$[21] = T0;
|
|
101
|
+
$[22] = t1;
|
|
102
|
+
$[23] = t2;
|
|
103
|
+
$[24] = t5;
|
|
104
|
+
} else t5 = $[24];
|
|
105
|
+
let t6;
|
|
106
|
+
if ($[25] !== t3 || $[26] !== t4 || $[27] !== t5) {
|
|
107
|
+
t6 = /* @__PURE__ */ jsx("div", {
|
|
108
|
+
className: t3,
|
|
109
|
+
"data-panneau-path": t4,
|
|
110
|
+
children: t5
|
|
111
|
+
});
|
|
112
|
+
$[25] = t3;
|
|
113
|
+
$[26] = t4;
|
|
114
|
+
$[27] = t5;
|
|
115
|
+
$[28] = t6;
|
|
116
|
+
} else t6 = $[28];
|
|
117
|
+
return t6;
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
120
|
+
export { FormBinding };
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=FormBinding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormBinding.js","names":["path","retry","_c","styles"],"sources":["../src/FormBinding.tsx"],"sourcesContent":["import { selectErrors, selectValue, selectVisible } from '@panneau/core';\nimport type { FieldBindingProps } from '@panneau/fields';\nimport { Alert, Button, usePanneauIntl } from '@panneau/ui';\n\nimport { FieldErrorBoundary } from './FieldErrorBoundary';\nimport styles from './Form.module.css';\nimport { useFormContext, useFormState } from './context';\nimport { messages } from './messages';\n\n/** Fields that show the errors of their nested fields themselves. */\nfunction rendersNestedFields(field: FieldBindingProps['field']): boolean {\n return field.localized === true || field.type === 'group' || field.type === 'repeater';\n}\n\n/**\n * Binds a field to the form by path: value, change, blur and errors. It hides fields whose\n * `visibleWhen` is false, marks the field's element with its path for the error summary, and\n * keeps a field that throws from breaking the form.\n */\nexport function FormBinding({ field, path, parentPath, render }: FieldBindingProps) {\n const form = useFormContext();\n const intl = usePanneauIntl();\n const state = useFormState(form);\n if (!selectVisible(state, field, parentPath)) {\n return null;\n }\n const errors = selectErrors(state, path, { nested: !rendersNestedFields(field) });\n return (\n <div className={styles.field} data-panneau-path={path}>\n <FieldErrorBoundary\n fallback={(retry) => (\n <Alert\n tone=\"danger\"\n actions={\n <Button size=\"sm\" onPress={retry}>\n {intl.formatMessage(messages.retry)}\n </Button>\n }\n >\n {intl.formatMessage(messages.fieldCrashed, {\n field: field.label ?? field.name,\n })}\n </Alert>\n )}\n >\n {render({\n value: selectValue(state, path),\n onChange: (value) => form.setValue(path, value),\n onBlur: () => form.blur(path),\n errors,\n })}\n </FieldErrorBoundary>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAS,oBAAoB,OAA4C;CACrE,OAAO,MAAM,cAAc,QAAQ,MAAM,SAAS,WAAW,MAAM,SAAS;AAChF;;;;;;AAOA,SAAO,YAAA,IAAA;CAAA,MAAA,IAAAE,EAAA,EAAA;CAAqB,MAAA,EAAA,OAAA,MAAA,YAAA,WAAA;CACxB,MAAA,OAAa,eAAe;CAC5B,MAAA,OAAa,eAAe;CAC5B,MAAA,QAAc,aAAa,IAAI;CAC/B,IAAI,CAAC,cAAc,OAAO,OAAO,UAAU,GAAC,OACjC;CACV,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,SAAA,EAAA,OAAA,QAAA,EAAA,OAAA,QAAA,EAAA,OAAA,QAAA,EAAA,OAAA,UAAA,EAAA,OAAA,OAAA;EAAA,IAAA;EAAA,IAAA,EAAA,QAAA,OAAA;GACmD,KAAA,oBAAoB,KAAK;GAAC,EAAA,MAAA;GAAA,EAAA,MAAA;EAAA,OAAA,KAAA,EAAA;EAA9E,MAAA,SAAe,aAAa,OAAO,MAAM,EAAA,QAAU,CAAC,GAA2B,CAAC;EAE5D,KAAAC,oBAAM;EAA2BH,KAAA;EAC5C,KAAA;EAAkB,IAAA,EAAA,QAAA,MAAA,SAAA,EAAA,QAAA,MAAA,QAAA,EAAA,QAAA,MAAA;GACL,MAAA,UACN,oBAAC,OAAD;IACS,MAAA;IAED,SAAA,oBAAC,QAAD;KAAa,MAAA;KAAcC,SAAA;KACtB,UAAA,KAAI,cAAe,SAAQ,KAAM;IAD/B,CAAA;IAKV,UAAA,KAAI,cAAe,SAAQ,cAAe,EAAA,OAChC,MAAK,SAAU,MAAK,KAC/B,CAAC;GAVC,CAAA;GAYT,EAAA,MAAA,MAAA;GAAA,EAAA,MAAA,MAAA;GAAA,EAAA,MAAA;GAAA,EAAA,MAAA;EAAA,OAAA,KAAA,EAAA;EAAA,IAAA;EAAA,IAAA;EAAA,IAAA,EAAA,QAAA,QAAA,EAAA,QAAA,MAAA;GAIa,MAAA,UAAW,KAAI,SAAU,MAAM,KAAK;GACtC,WAAM,KAAI,KAAM,IAAI;GAAC,EAAA,MAAA;GAAA,EAAA,MAAA;GAAA,EAAA,MAAA;GAAA,EAAA,MAAA;EAAA,OAAA;GAAA,KAAA,EAAA;GAAA,KAAA,EAAA;EAAA;EAHhC,KAAA,OAAO;GAAA,OACG,YAAY,OAAO,IAAI;GAAC,UACrB;GAAqC,QACvC;GAAqB;EAEjC,CAAC;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,MAAA;CAAA,OAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,MAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EArBN,KAAA,oBAAC,IAAD;GACc,UAAA;GAeT,UAAA;EAhBc,CAAA;EAsBE,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,MAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EAvBzB,KAAA,oBAAA,OAAA;GAAgB,WAAA;GAAiCD,qBAAAA;GAC7C,UAAA;EAuBE,CAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAxBN;AAwBM"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type Form } from '@panneau/core';
|
|
3
|
+
import { type FieldEntry, type RelationSource } from '@panneau/fields';
|
|
4
|
+
import type { Field, LayoutNode } from '@panneau/protocol';
|
|
5
|
+
export interface FormViewProps {
|
|
6
|
+
/** The form state, from `useForm()` or `createForm()` of `@panneau/core`. */
|
|
7
|
+
form: Form;
|
|
8
|
+
/** The fields of the form. */
|
|
9
|
+
fields: readonly Field[];
|
|
10
|
+
/** The layout tree. Fields that no node references are added at the end. */
|
|
11
|
+
layout?: readonly LayoutNode[];
|
|
12
|
+
/** Locales of localized fields. Defaults to the definition's, from `PanneauProvider`. */
|
|
13
|
+
locales?: readonly string[];
|
|
14
|
+
/** Where relation fields search. Defaults to the one of a parent `FieldsProvider`. */
|
|
15
|
+
relationSource?: RelationSource | null;
|
|
16
|
+
/** Field entries by type, over the built-in ones and those of the plugins. */
|
|
17
|
+
components?: Readonly<Record<string, FieldEntry>>;
|
|
18
|
+
/** Label of the submit button. Defaults to "Save". `null` hides the button. */
|
|
19
|
+
submitLabel?: ReactNode;
|
|
20
|
+
/** Other buttons, next to the submit button. */
|
|
21
|
+
actions?: ReactNode;
|
|
22
|
+
/** Called after a successful submit, with what `onSubmit` returned. */
|
|
23
|
+
onSubmitted?: (result: unknown) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Called by "Load the current version" in the conflict dialog when the backend didn't send the
|
|
26
|
+
* current item: fetch it, and `form.reset()` with it.
|
|
27
|
+
*/
|
|
28
|
+
onReload?: () => void;
|
|
29
|
+
/** Asks for confirmation before the page is left with unsaved changes. Defaults to true. */
|
|
30
|
+
guardUnsavedChanges?: boolean;
|
|
31
|
+
/** Shows a toast after a successful submit. Defaults to true. */
|
|
32
|
+
showSavedToast?: boolean;
|
|
33
|
+
id?: string;
|
|
34
|
+
'aria-label'?: string;
|
|
35
|
+
className?: string;
|
|
36
|
+
layoutClassName?: string;
|
|
37
|
+
sidebarClassName?: string;
|
|
38
|
+
footerClassName?: string;
|
|
39
|
+
summaryClassName?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Renders a form: its fields in their layout, bound to the form state of `@panneau/core`, with
|
|
43
|
+
* an error summary, a scroll to the first error, error counts on tabs and sections, a guard for
|
|
44
|
+
* unsaved changes and the dialog of version conflicts. Saving is the job of the form's
|
|
45
|
+
* `onSubmit`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function FormView({ form, fields, layout, locales, relationSource, components, submitLabel, actions, onSubmitted, onReload, guardUnsavedChanges, showSavedToast, id, 'aria-label': ariaLabel, className, layoutClassName, sidebarClassName, footerClassName, summaryClassName, }: FormViewProps): import("react").JSX.Element;
|
|
48
|
+
//# sourceMappingURL=FormView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormView.d.ts","sourceRoot":"","sources":["../src/FormView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,OAAO,CAAC;AAEzD,OAAO,EACH,KAAK,IAAI,EAQZ,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,KAAK,UAAU,EAEf,KAAK,cAAc,EAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAa3D,MAAM,WAAW,aAAa;IAC1B,6EAA6E;IAC7E,IAAI,EAAE,IAAI,CAAC;IACX,8BAA8B;IAC9B,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,yFAAyF;IACzF,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,sFAAsF;IACtF,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAClD,+EAA+E;IAC/E,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,gDAAgD;IAChD,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iEAAiE;IACjE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAqCD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EACrB,IAAI,EACJ,MAAM,EACN,MAAW,EACX,OAAO,EACP,cAAc,EACd,UAAU,EACV,WAAW,EACX,OAAO,EACP,WAAW,EACX,QAAQ,EACR,mBAA0B,EAC1B,cAAqB,EACrB,EAAE,EACF,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACnB,EAAE,aAAa,+BAgMf"}
|