@panneau/fields 5.0.0-alpha.17 → 5.0.0-alpha.19
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 +23 -0
- package/dist/address/AddressField.js +3 -3
- package/dist/compound/Compound.css +26 -0
- package/dist/compound/Compound.module.js +16 -0
- package/dist/compound/Compound.module.js.map +1 -0
- package/dist/compound/compound.d.ts +56 -0
- package/dist/compound/compound.d.ts.map +1 -0
- package/dist/compound/compound.js +186 -0
- package/dist/compound/compound.js.map +1 -0
- package/dist/country/CountryField.js +1 -1
- package/dist/credits/CreditsField.d.ts +15 -0
- package/dist/credits/CreditsField.d.ts.map +1 -0
- package/dist/credits/CreditsField.js +58 -0
- package/dist/credits/CreditsField.js.map +1 -0
- package/dist/credits/credits.d.ts +18 -0
- package/dist/credits/credits.d.ts.map +1 -0
- package/dist/credits/credits.js +33 -0
- package/dist/credits/credits.js.map +1 -0
- package/dist/credits/index.d.ts +5 -0
- package/dist/credits/index.d.ts.map +1 -0
- package/dist/credits/index.js +3 -0
- package/dist/embed/EmbedField.js +2 -2
- package/dist/file/FileField.js +3 -3
- package/dist/group/GroupField.d.ts +7 -1
- package/dist/group/GroupField.d.ts.map +1 -1
- package/dist/group/GroupField.js +60 -68
- package/dist/group/GroupField.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/json/JsonField.js +1 -1
- package/dist/link/LinkField.js +3 -3
- package/dist/localized/LocalizedField.js +3 -3
- package/dist/location/LocationField.js +3 -3
- package/dist/location/LocationMap.js +1 -1
- package/dist/money/MoneyField.js +1 -1
- package/dist/relation/RelationField.js +3 -3
- package/dist/repeater/RepeaterField.d.ts +12 -1
- package/dist/repeater/RepeaterField.d.ts.map +1 -1
- package/dist/repeater/RepeaterField.js +53 -49
- package/dist/repeater/RepeaterField.js.map +1 -1
- package/dist/sessions/SessionsField.d.ts +15 -0
- package/dist/sessions/SessionsField.d.ts.map +1 -0
- package/dist/sessions/SessionsField.js +49 -0
- package/dist/sessions/SessionsField.js.map +1 -0
- package/dist/sessions/index.d.ts +4 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +1 -0
- package/dist/shared/CodeComboBox.js +1 -1
- package/dist/shared/DefinitionField.d.ts +3 -2
- package/dist/shared/DefinitionField.d.ts.map +1 -1
- package/dist/shared/DefinitionField.js +8 -4
- package/dist/shared/DefinitionField.js.map +1 -1
- package/dist/shared/builtIn.js +2 -2
- package/dist/shared/context.js +1 -1
- package/dist/slug/SlugField.js +3 -3
- package/dist/tel/TelField.js +1 -1
- package/dist/text/TextField.js +2 -2
- package/dist/upload/FilePicker.js +1 -1
- package/dist/upload/UploadList.js +1 -1
- package/dist/url/UrlField.js +1 -1
- package/package.json +14 -4
package/README.md
CHANGED
|
@@ -84,6 +84,29 @@ import {
|
|
|
84
84
|
- **Files** upload through the `uploadSource` of the provider (below). Without one, the value holds the files themselves.
|
|
85
85
|
- **Plugin slot:** a type without an entry, such as `richtext` and `media` without their plugins (`@panneau/editor`, `@panneau/media`), renders a placeholder that names it. A plugin that provides the type replaces it.
|
|
86
86
|
|
|
87
|
+
### Compound fields
|
|
88
|
+
|
|
89
|
+
A compound field (decision 0065) is a type of a plugin that carries its sub-fields in `fields`: an object of them, or a list with `multiple`. Without its plugin, it renders as a group, or as a repeater. `defineCompoundField()` makes the entry of such a type: `layout` places the rendered sub-fields of one value by name, and `summarize` gives one value as text, for the title of an item and for lists and details.
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import { defineCompoundField, restParts } from '@panneau/fields';
|
|
93
|
+
|
|
94
|
+
export const TeamFieldEntry = defineCompoundField({
|
|
95
|
+
layout: ({ parts }) => (
|
|
96
|
+
<div className={styles.row}>
|
|
97
|
+
{parts.person}
|
|
98
|
+
{parts.role}
|
|
99
|
+
{restParts(parts, ['person', 'role'])}
|
|
100
|
+
</div>
|
|
101
|
+
),
|
|
102
|
+
summarize: (member) => (typeof member.role === 'string' ? member.role : null),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const teamPlugin = { id: 'team', fields: { team: TeamFieldEntry } };
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Two are ready to load: `creditsPlugin` (`@panneau/fields/credits`: `person`, `name`, `roles`, `featured`) and `sessionsPlugin` (`@panneau/fields/sessions`: `dates`, `venue`). The definition gives the sub-fields: those a site adds come after.
|
|
109
|
+
|
|
87
110
|
## Files and uploads
|
|
88
111
|
|
|
89
112
|
`FileField` (the `file` type) holds files that belong to an item, outside the media library: an attachment, a PDF, a CSV ([decision 0025](../../docs/decisions/0025-presigned-uploads.md)). Its value is a file, or a list of them with `multiple`:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { useFieldsContext } from "../shared/context.js";
|
|
2
1
|
import { cx } from "../shared/cx.js";
|
|
3
2
|
import { getFieldProps, getSetting, isBoolean, isString } from "../shared/entry.js";
|
|
3
|
+
import { useFieldsContext } from "../shared/context.js";
|
|
4
4
|
import { messages } from "../shared/messages.js";
|
|
5
5
|
import { CountryField } from "../country/CountryField.js";
|
|
6
6
|
import { LocationMap } from "../location/LocationMap.js";
|
|
@@ -13,10 +13,10 @@ import AddressField_module_default from "./AddressField.module.js";
|
|
|
13
13
|
import { cleanAddress, endsWithRegion, isAddress } from "./address.js";
|
|
14
14
|
import { c } from "react/compiler-runtime";
|
|
15
15
|
import { DEFAULT_ADDRESS_REQUIRED_PARTS, getAddressRequiredParts, normalizePostalCode } from "@panneau/protocol/runtime";
|
|
16
|
-
import { X } from "lucide-react";
|
|
17
|
-
import { useRef, useState } from "react";
|
|
18
16
|
import { ComboBox, Fieldset, IconButton, usePanneauIntl } from "@panneau/ui";
|
|
19
17
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { X } from "lucide-react";
|
|
19
|
+
import { useRef, useState } from "react";
|
|
20
20
|
//#region src/address/AddressField.tsx
|
|
21
21
|
var WORLD = {
|
|
22
22
|
lat: 20,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* The layout of compound fields (decision 0065): their parts side by side, the wide ones on a row
|
|
2
|
+
of their own. */
|
|
3
|
+
.panneau-compound-row {
|
|
4
|
+
display: grid;
|
|
5
|
+
grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr));
|
|
6
|
+
gap: var(--panneau-space-3) var(--panneau-space-4);
|
|
7
|
+
align-items: start;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.panneau-compound-part {
|
|
11
|
+
min-width: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* A part hidden by its condition renders nothing: its cell takes no column. */
|
|
15
|
+
.panneau-compound-part:empty {
|
|
16
|
+
display: none;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.panneau-compound-wide {
|
|
20
|
+
grid-column: 1 / -1;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.panneau-compound-stack {
|
|
24
|
+
display: grid;
|
|
25
|
+
gap: var(--panneau-space-3);
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import "./Compound.css";
|
|
2
|
+
//#region src/compound/Compound.module.css
|
|
3
|
+
var row = "panneau-compound-row";
|
|
4
|
+
var part = "panneau-compound-part";
|
|
5
|
+
var wide = "panneau-compound-wide";
|
|
6
|
+
var stack = "panneau-compound-stack";
|
|
7
|
+
var Compound_module_default = {
|
|
8
|
+
row,
|
|
9
|
+
part,
|
|
10
|
+
wide,
|
|
11
|
+
stack
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { Compound_module_default as default, part, row, stack, wide };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=Compound.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Compound.module.js","names":[],"sources":["../../src/compound/Compound.module.css"],"sourcesContent":["/* The layout of compound fields (decision 0065): their parts side by side, the wide ones on a row\n of their own. */\n.row {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr));\n gap: var(--panneau-space-3) var(--panneau-space-4);\n align-items: start;\n}\n\n.part {\n min-width: 0;\n}\n\n/* A part hidden by its condition renders nothing: its cell takes no column. */\n.part:empty {\n display: none;\n}\n\n.wide {\n grid-column: 1 / -1;\n}\n\n.stack {\n display: grid;\n gap: var(--panneau-space-3);\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Field } from '@panneau/protocol';
|
|
3
|
+
import type { FieldEntry } from '../shared/types.js';
|
|
4
|
+
/** What a compound field's summary is given. */
|
|
5
|
+
export interface CompoundSummaryContext {
|
|
6
|
+
/** The compound field, as the definition describes it. */
|
|
7
|
+
field: Field;
|
|
8
|
+
/** The locale of the interface. */
|
|
9
|
+
locale: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A short text for one value of a compound field: its object, or an item of its list. `null` when
|
|
13
|
+
* there is nothing to say.
|
|
14
|
+
*/
|
|
15
|
+
export type CompoundSummary = (value: Readonly<Record<string, unknown>>, context: CompoundSummaryContext) => string | null;
|
|
16
|
+
/** What lays out the sub-fields of one value of a compound field. */
|
|
17
|
+
export interface CompoundLayoutProps {
|
|
18
|
+
/** The rendered sub-fields, by name. Those the definition doesn't have are missing. */
|
|
19
|
+
parts: Readonly<Record<string, ReactNode>>;
|
|
20
|
+
/** The value: the object, or the item of the list. */
|
|
21
|
+
value: Readonly<Record<string, unknown>>;
|
|
22
|
+
/** The compound field. */
|
|
23
|
+
field: Field;
|
|
24
|
+
}
|
|
25
|
+
export interface CompoundFieldOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Lays out the sub-fields of one value. Without it, they flow as in a group. Sub-fields that
|
|
28
|
+
* the layout doesn't place aren't shown: `restParts()` gives them.
|
|
29
|
+
*/
|
|
30
|
+
layout?: (props: CompoundLayoutProps) => ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* Summarizes one value: the title of an item in the form, and the value in lists and details,
|
|
33
|
+
* where the items of a list are joined.
|
|
34
|
+
*/
|
|
35
|
+
summarize?: CompoundSummary;
|
|
36
|
+
}
|
|
37
|
+
/** The entry of a compound field type, with its summary for lists and details. */
|
|
38
|
+
export type CompoundFieldEntry = FieldEntry & {
|
|
39
|
+
summarize?: CompoundSummary;
|
|
40
|
+
};
|
|
41
|
+
/** The rendered sub-fields that aren't in `names`, in the order of the definition. */
|
|
42
|
+
export declare function restParts(parts: Readonly<Record<string, ReactNode>>, names: readonly string[]): ReactNode[];
|
|
43
|
+
/**
|
|
44
|
+
* Summarizes the value of a compound field with its entry's `summarize`: one text, or the texts of
|
|
45
|
+
* its items joined by commas. `null` without a summary, or when there is nothing to say.
|
|
46
|
+
*/
|
|
47
|
+
export declare function summarizeCompound(entry: unknown, value: unknown, context: CompoundSummaryContext): string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Makes the entry of a compound field type (decision 0065): a type of a plugin that carries its
|
|
50
|
+
* sub-fields in `fields`. Its value is an object of them, or a list of objects with `multiple`,
|
|
51
|
+
* rendered as a `group` or a `repeater` with the layout and the summary given. The definition
|
|
52
|
+
* decides the sub-fields: the layout places those it knows by name. The README of
|
|
53
|
+
* `@panneau/fields` has an example.
|
|
54
|
+
*/
|
|
55
|
+
export declare function defineCompoundField(options?: CompoundFieldOptions): CompoundFieldEntry;
|
|
56
|
+
//# sourceMappingURL=compound.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compound.d.ts","sourceRoot":"","sources":["../../src/compound/compound.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO/C,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,iBAAiB,CAAC;AAEnE,gDAAgD;AAChD,MAAM,WAAW,sBAAsB;IACnC,0DAA0D;IAC1D,KAAK,EAAE,KAAK,CAAC;IACb,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,CAC1B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,OAAO,EAAE,sBAAsB,KAC9B,MAAM,GAAG,IAAI,CAAC;AAEnB,qEAAqE;AACrE,MAAM,WAAW,mBAAmB;IAChC,uFAAuF;IACvF,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAC3C,sDAAsD;IACtD,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,0BAA0B;IAC1B,KAAK,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,SAAS,CAAC;IACnD;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,kFAAkF;AAClF,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG;IAAE,SAAS,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC;AAE9E,sFAAsF;AACtF,wBAAgB,SAAS,CACrB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAC1C,KAAK,EAAE,SAAS,MAAM,EAAE,GACzB,SAAS,EAAE,CAIb;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,sBAAsB,GAChC,MAAM,GAAG,IAAI,CAcf;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,kBAAkB,CA6C1F"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { getFieldProps, getRuleNumber } from "../shared/entry.js";
|
|
2
|
+
import { GroupField } from "../group/GroupField.js";
|
|
3
|
+
import { RepeaterField } from "../repeater/RepeaterField.js";
|
|
4
|
+
import { c } from "react/compiler-runtime";
|
|
5
|
+
import { getNestedShape } from "@panneau/protocol/runtime";
|
|
6
|
+
import { usePanneauIntl } from "@panneau/ui";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
//#region src/compound/compound.tsx
|
|
9
|
+
/** The rendered sub-fields that aren't in `names`, in the order of the definition. */
|
|
10
|
+
function restParts(parts, names) {
|
|
11
|
+
return Object.entries(parts).filter(([name]) => !names.includes(name)).map(([, part]) => part);
|
|
12
|
+
}
|
|
13
|
+
function isObject(value) {
|
|
14
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Summarizes the value of a compound field with its entry's `summarize`: one text, or the texts of
|
|
18
|
+
* its items joined by commas. `null` without a summary, or when there is nothing to say.
|
|
19
|
+
*/
|
|
20
|
+
function summarizeCompound(entry, value, context) {
|
|
21
|
+
const summarize = typeof entry === "function" && "summarize" in entry ? entry.summarize : void 0;
|
|
22
|
+
if (summarize === void 0) return null;
|
|
23
|
+
const texts = (Array.isArray(value) ? value.filter(isObject) : isObject(value) ? [value] : []).flatMap((item) => {
|
|
24
|
+
const text = summarize(item, context);
|
|
25
|
+
return text !== null && text !== "" ? [text] : [];
|
|
26
|
+
});
|
|
27
|
+
return texts.length > 0 ? texts.join(", ") : null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Makes the entry of a compound field type (decision 0065): a type of a plugin that carries its
|
|
31
|
+
* sub-fields in `fields`. Its value is an object of them, or a list of objects with `multiple`,
|
|
32
|
+
* rendered as a `group` or a `repeater` with the layout and the summary given. The definition
|
|
33
|
+
* decides the sub-fields: the layout places those it knows by name. The README of
|
|
34
|
+
* `@panneau/fields` has an example.
|
|
35
|
+
*/
|
|
36
|
+
function defineCompoundField(options = {}) {
|
|
37
|
+
const { layout, summarize } = options;
|
|
38
|
+
function CompoundField(props) {
|
|
39
|
+
const $ = c(44);
|
|
40
|
+
const intl = usePanneauIntl();
|
|
41
|
+
const { field, value } = props;
|
|
42
|
+
let t0;
|
|
43
|
+
if ($[0] !== field.fields) {
|
|
44
|
+
t0 = field.fields ?? [];
|
|
45
|
+
$[0] = field.fields;
|
|
46
|
+
$[1] = t0;
|
|
47
|
+
} else t0 = $[1];
|
|
48
|
+
const fields = t0;
|
|
49
|
+
let t1;
|
|
50
|
+
if ($[2] !== field || $[3] !== intl.locale) {
|
|
51
|
+
t1 = {
|
|
52
|
+
field,
|
|
53
|
+
locale: intl.locale
|
|
54
|
+
};
|
|
55
|
+
$[2] = field;
|
|
56
|
+
$[3] = intl.locale;
|
|
57
|
+
$[4] = t1;
|
|
58
|
+
} else t1 = $[4];
|
|
59
|
+
const context = t1;
|
|
60
|
+
let t2;
|
|
61
|
+
if ($[5] !== field) {
|
|
62
|
+
t2 = layout !== void 0 ? (parts, item) => layout({
|
|
63
|
+
parts,
|
|
64
|
+
value: item,
|
|
65
|
+
field
|
|
66
|
+
}) : void 0;
|
|
67
|
+
$[5] = field;
|
|
68
|
+
$[6] = t2;
|
|
69
|
+
} else t2 = $[6];
|
|
70
|
+
const renderFields = t2;
|
|
71
|
+
if (getNestedShape(field) === "repeater") {
|
|
72
|
+
let t3;
|
|
73
|
+
if ($[7] !== field) {
|
|
74
|
+
t3 = getRuleNumber(field, "min");
|
|
75
|
+
$[7] = field;
|
|
76
|
+
$[8] = t3;
|
|
77
|
+
} else t3 = $[8];
|
|
78
|
+
const min = t3;
|
|
79
|
+
let t4;
|
|
80
|
+
if ($[9] !== field) {
|
|
81
|
+
t4 = getRuleNumber(field, "max");
|
|
82
|
+
$[9] = field;
|
|
83
|
+
$[10] = t4;
|
|
84
|
+
} else t4 = $[10];
|
|
85
|
+
const max = t4;
|
|
86
|
+
let t5;
|
|
87
|
+
if ($[11] !== props) {
|
|
88
|
+
t5 = getFieldProps(props);
|
|
89
|
+
$[11] = props;
|
|
90
|
+
$[12] = t5;
|
|
91
|
+
} else t5 = $[12];
|
|
92
|
+
let t6;
|
|
93
|
+
if ($[13] !== value) {
|
|
94
|
+
t6 = Array.isArray(value) ? value.filter(isObject) : null;
|
|
95
|
+
$[13] = value;
|
|
96
|
+
$[14] = t6;
|
|
97
|
+
} else t6 = $[14];
|
|
98
|
+
let t7;
|
|
99
|
+
if ($[15] !== renderFields) {
|
|
100
|
+
t7 = renderFields !== void 0 ? { renderFields } : {};
|
|
101
|
+
$[15] = renderFields;
|
|
102
|
+
$[16] = t7;
|
|
103
|
+
} else t7 = $[16];
|
|
104
|
+
let t8;
|
|
105
|
+
if ($[17] !== context) {
|
|
106
|
+
t8 = summarize !== void 0 ? { itemTitle: (item_0) => summarize(item_0, context) } : {};
|
|
107
|
+
$[17] = context;
|
|
108
|
+
$[18] = t8;
|
|
109
|
+
} else t8 = $[18];
|
|
110
|
+
let t9;
|
|
111
|
+
if ($[19] !== min) {
|
|
112
|
+
t9 = min !== void 0 ? { min } : {};
|
|
113
|
+
$[19] = min;
|
|
114
|
+
$[20] = t9;
|
|
115
|
+
} else t9 = $[20];
|
|
116
|
+
let t10;
|
|
117
|
+
if ($[21] !== max) {
|
|
118
|
+
t10 = max !== void 0 ? { max } : {};
|
|
119
|
+
$[21] = max;
|
|
120
|
+
$[22] = t10;
|
|
121
|
+
} else t10 = $[22];
|
|
122
|
+
let t11;
|
|
123
|
+
if ($[23] !== fields || $[24] !== props.onChange || $[25] !== props.path || $[26] !== t10 || $[27] !== t5 || $[28] !== t6 || $[29] !== t7 || $[30] !== t8 || $[31] !== t9) {
|
|
124
|
+
t11 = /* @__PURE__ */ jsx(RepeaterField, {
|
|
125
|
+
...t5,
|
|
126
|
+
path: props.path,
|
|
127
|
+
fields,
|
|
128
|
+
value: t6,
|
|
129
|
+
onChange: props.onChange,
|
|
130
|
+
...t7,
|
|
131
|
+
...t8,
|
|
132
|
+
...t9,
|
|
133
|
+
...t10
|
|
134
|
+
});
|
|
135
|
+
$[23] = fields;
|
|
136
|
+
$[24] = props.onChange;
|
|
137
|
+
$[25] = props.path;
|
|
138
|
+
$[26] = t10;
|
|
139
|
+
$[27] = t5;
|
|
140
|
+
$[28] = t6;
|
|
141
|
+
$[29] = t7;
|
|
142
|
+
$[30] = t8;
|
|
143
|
+
$[31] = t9;
|
|
144
|
+
$[32] = t11;
|
|
145
|
+
} else t11 = $[32];
|
|
146
|
+
return t11;
|
|
147
|
+
}
|
|
148
|
+
let t3;
|
|
149
|
+
if ($[33] !== props) {
|
|
150
|
+
t3 = getFieldProps(props);
|
|
151
|
+
$[33] = props;
|
|
152
|
+
$[34] = t3;
|
|
153
|
+
} else t3 = $[34];
|
|
154
|
+
const t4 = isObject(value) ? value : null;
|
|
155
|
+
let t5;
|
|
156
|
+
if ($[35] !== renderFields) {
|
|
157
|
+
t5 = renderFields !== void 0 ? { renderFields } : {};
|
|
158
|
+
$[35] = renderFields;
|
|
159
|
+
$[36] = t5;
|
|
160
|
+
} else t5 = $[36];
|
|
161
|
+
let t6;
|
|
162
|
+
if ($[37] !== fields || $[38] !== props.onChange || $[39] !== props.path || $[40] !== t3 || $[41] !== t4 || $[42] !== t5) {
|
|
163
|
+
t6 = /* @__PURE__ */ jsx(GroupField, {
|
|
164
|
+
...t3,
|
|
165
|
+
fields,
|
|
166
|
+
path: props.path,
|
|
167
|
+
value: t4,
|
|
168
|
+
onChange: props.onChange,
|
|
169
|
+
...t5
|
|
170
|
+
});
|
|
171
|
+
$[37] = fields;
|
|
172
|
+
$[38] = props.onChange;
|
|
173
|
+
$[39] = props.path;
|
|
174
|
+
$[40] = t3;
|
|
175
|
+
$[41] = t4;
|
|
176
|
+
$[42] = t5;
|
|
177
|
+
$[43] = t6;
|
|
178
|
+
} else t6 = $[43];
|
|
179
|
+
return t6;
|
|
180
|
+
}
|
|
181
|
+
return Object.assign(CompoundField, summarize !== void 0 ? { summarize } : {});
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
export { defineCompoundField, restParts, summarizeCompound };
|
|
185
|
+
|
|
186
|
+
//# sourceMappingURL=compound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compound.js","names":["ReactNode","Field","getNestedShape","usePanneauIntl","GroupField","GroupValue","RepeaterField","RepeaterItem","getFieldProps","getRuleNumber","FieldEntry","FieldEntryProps","CompoundSummaryContext","field","locale","CompoundSummary","value","Readonly","Record","context","CompoundLayoutProps","parts","CompoundFieldOptions","layout","props","summarize","CompoundFieldEntry","restParts","names","Object","entries","filter","name","includes","map","part","isObject","Array","isArray","summarizeCompound","entry","undefined","values","texts","flatMap","item","text","length","join","defineCompoundField","options","CompoundField","$","_c","intl","t0","fields","t1","t2","renderFields","t3","min","t4","max","t5","t6","t7","t8","itemTitle","item_0","t9","t10","t11","onChange","path","assign","_c"],"sources":["../../src/compound/compound.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport type { Field } from '@panneau/protocol';\nimport { getNestedShape } from '@panneau/protocol/runtime';\nimport { usePanneauIntl } from '@panneau/ui';\n\nimport { GroupField, type GroupValue } from '../group/GroupField';\nimport { RepeaterField, type RepeaterItem } from '../repeater/RepeaterField';\nimport { getFieldProps, getRuleNumber } from '../shared/entry';\nimport type { FieldEntry, FieldEntryProps } from '../shared/types';\n\n/** What a compound field's summary is given. */\nexport interface CompoundSummaryContext {\n /** The compound field, as the definition describes it. */\n field: Field;\n /** The locale of the interface. */\n locale: string;\n}\n\n/**\n * A short text for one value of a compound field: its object, or an item of its list. `null` when\n * there is nothing to say.\n */\nexport type CompoundSummary = (\n value: Readonly<Record<string, unknown>>,\n context: CompoundSummaryContext,\n) => string | null;\n\n/** What lays out the sub-fields of one value of a compound field. */\nexport interface CompoundLayoutProps {\n /** The rendered sub-fields, by name. Those the definition doesn't have are missing. */\n parts: Readonly<Record<string, ReactNode>>;\n /** The value: the object, or the item of the list. */\n value: Readonly<Record<string, unknown>>;\n /** The compound field. */\n field: Field;\n}\n\nexport interface CompoundFieldOptions {\n /**\n * Lays out the sub-fields of one value. Without it, they flow as in a group. Sub-fields that\n * the layout doesn't place aren't shown: `restParts()` gives them.\n */\n layout?: (props: CompoundLayoutProps) => ReactNode;\n /**\n * Summarizes one value: the title of an item in the form, and the value in lists and details,\n * where the items of a list are joined.\n */\n summarize?: CompoundSummary;\n}\n\n/** The entry of a compound field type, with its summary for lists and details. */\nexport type CompoundFieldEntry = FieldEntry & { summarize?: CompoundSummary };\n\n/** The rendered sub-fields that aren't in `names`, in the order of the definition. */\nexport function restParts(\n parts: Readonly<Record<string, ReactNode>>,\n names: readonly string[],\n): ReactNode[] {\n return Object.entries(parts)\n .filter(([name]) => !names.includes(name))\n .map(([, part]) => part);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Summarizes the value of a compound field with its entry's `summarize`: one text, or the texts of\n * its items joined by commas. `null` without a summary, or when there is nothing to say.\n */\nexport function summarizeCompound(\n entry: unknown,\n value: unknown,\n context: CompoundSummaryContext,\n): string | null {\n const summarize =\n typeof entry === 'function' && 'summarize' in entry\n ? (entry.summarize as CompoundSummary | undefined)\n : undefined;\n if (summarize === undefined) {\n return null;\n }\n const values = Array.isArray(value) ? value.filter(isObject) : isObject(value) ? [value] : [];\n const texts = values.flatMap((item) => {\n const text = summarize(item, context);\n return text !== null && text !== '' ? [text] : [];\n });\n return texts.length > 0 ? texts.join(', ') : null;\n}\n\n/**\n * Makes the entry of a compound field type (decision 0065): a type of a plugin that carries its\n * sub-fields in `fields`. Its value is an object of them, or a list of objects with `multiple`,\n * rendered as a `group` or a `repeater` with the layout and the summary given. The definition\n * decides the sub-fields: the layout places those it knows by name. The README of\n * `@panneau/fields` has an example.\n */\nexport function defineCompoundField(options: CompoundFieldOptions = {}): CompoundFieldEntry {\n const { layout, summarize } = options;\n\n function CompoundField(props: FieldEntryProps) {\n const intl = usePanneauIntl();\n const { field, value } = props;\n const fields = field.fields ?? [];\n const context = { field, locale: intl.locale };\n const renderFields =\n layout !== undefined\n ? (parts: Readonly<Record<string, ReactNode>>, item: Record<string, unknown>) =>\n layout({ parts, value: item, field })\n : undefined;\n if (getNestedShape(field) === 'repeater') {\n const min = getRuleNumber(field, 'min');\n const max = getRuleNumber(field, 'max');\n return (\n <RepeaterField\n {...getFieldProps(props)}\n path={props.path}\n fields={fields}\n value={Array.isArray(value) ? value.filter(isObject) : null}\n onChange={props.onChange}\n {...(renderFields !== undefined ? { renderFields } : {})}\n {...(summarize !== undefined\n ? { itemTitle: (item: RepeaterItem) => summarize(item, context) }\n : {})}\n {...(min !== undefined ? { min } : {})}\n {...(max !== undefined ? { max } : {})}\n />\n );\n }\n return (\n <GroupField\n {...getFieldProps(props)}\n fields={fields}\n path={props.path}\n value={isObject(value) ? (value as GroupValue) : null}\n onChange={props.onChange}\n {...(renderFields !== undefined ? { renderFields } : {})}\n />\n );\n }\n\n return Object.assign(CompoundField, summarize !== undefined ? { summarize } : {});\n}\n"],"mappings":"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"}
|
|
@@ -4,9 +4,9 @@ import { CodeComboBox } from "../shared/CodeComboBox.js";
|
|
|
4
4
|
import CountryField_module_default from "./CountryField.module.js";
|
|
5
5
|
import { getCountryChoices, getCountryFlag, getCountryName, isCountryCode } from "./countries.js";
|
|
6
6
|
import { c } from "react/compiler-runtime";
|
|
7
|
-
import { X } from "lucide-react";
|
|
8
7
|
import { Fieldset, IconButton, usePanneauIntl } from "@panneau/ui";
|
|
9
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { X } from "lucide-react";
|
|
10
10
|
//#region src/country/CountryField.tsx
|
|
11
11
|
/**
|
|
12
12
|
* A country, as its ISO 3166-1 alpha-2 code (`CA`): a combo box of the countries with their flags
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type CompoundFieldEntry } from '../compound/compound.js';
|
|
2
|
+
/**
|
|
3
|
+
* The `credits` type (decision 0065): a compound field whose items are a person (`person`, a
|
|
4
|
+
* relation) or a free name (`name`), their `roles`, and whether the credit is `featured`. The
|
|
5
|
+
* definition gives the sub-fields: those of a site come after these.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CreditsFieldEntry: CompoundFieldEntry;
|
|
8
|
+
/** The `credits` type, as a `@panneau/core` plugin. */
|
|
9
|
+
export declare const creditsPlugin: {
|
|
10
|
+
id: string;
|
|
11
|
+
fields: {
|
|
12
|
+
credits: CompoundFieldEntry;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=CreditsField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreditsField.d.ts","sourceRoot":"","sources":["../../src/credits/CreditsField.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,kBAAkB,EAAkC,MAAM,sBAAsB,CAAC;AAK/F;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,kBAmB9B,CAAC;AAEH,uDAAuD;AACvD,eAAO,MAAM,aAAa;;;;;CAGzB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineCompoundField, restParts } from "../compound/compound.js";
|
|
2
|
+
import Compound_module_default from "../compound/Compound.module.js";
|
|
3
|
+
import { formatCredit } from "./credits.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/credits/CreditsField.tsx
|
|
6
|
+
var PLACED = [
|
|
7
|
+
"person",
|
|
8
|
+
"name",
|
|
9
|
+
"roles",
|
|
10
|
+
"featured"
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* The `credits` type (decision 0065): a compound field whose items are a person (`person`, a
|
|
14
|
+
* relation) or a free name (`name`), their `roles`, and whether the credit is `featured`. The
|
|
15
|
+
* definition gives the sub-fields: those of a site come after these.
|
|
16
|
+
*/
|
|
17
|
+
var CreditsFieldEntry = defineCompoundField({
|
|
18
|
+
layout: ({ parts }) => /* @__PURE__ */ jsxs("div", {
|
|
19
|
+
className: Compound_module_default.stack,
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ jsxs("div", {
|
|
22
|
+
className: Compound_module_default.row,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsx("div", {
|
|
25
|
+
className: Compound_module_default.part,
|
|
26
|
+
children: parts.person
|
|
27
|
+
}),
|
|
28
|
+
/* @__PURE__ */ jsx("div", {
|
|
29
|
+
className: Compound_module_default.part,
|
|
30
|
+
children: parts.name
|
|
31
|
+
}),
|
|
32
|
+
/* @__PURE__ */ jsx("div", {
|
|
33
|
+
className: Compound_module_default.part,
|
|
34
|
+
children: parts.roles
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
}),
|
|
38
|
+
parts.featured !== void 0 ? /* @__PURE__ */ jsx("div", {
|
|
39
|
+
className: Compound_module_default.part,
|
|
40
|
+
children: parts.featured
|
|
41
|
+
}) : null,
|
|
42
|
+
restParts(parts, PLACED).map((part, index) => /* @__PURE__ */ jsx("div", {
|
|
43
|
+
className: Compound_module_default.part,
|
|
44
|
+
children: part
|
|
45
|
+
}, index))
|
|
46
|
+
]
|
|
47
|
+
}),
|
|
48
|
+
summarize: (credit, { locale }) => formatCredit(credit, locale)
|
|
49
|
+
});
|
|
50
|
+
/** The `credits` type, as a `@panneau/core` plugin. */
|
|
51
|
+
var creditsPlugin = {
|
|
52
|
+
id: "panneau.credits",
|
|
53
|
+
fields: { credits: CreditsFieldEntry }
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
export { CreditsFieldEntry, creditsPlugin };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=CreditsField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreditsField.js","names":["styles","CompoundFieldEntry","defineCompoundField","restParts","formatCredit","PLACED","CreditsFieldEntry","layout","parts","stack","row","part","person","name","roles","featured","undefined","map","index","summarize","credit","locale","creditsPlugin","id","fields","credits","styles"],"sources":["../../src/credits/CreditsField.tsx"],"sourcesContent":["import styles from '../compound/Compound.module.css';\nimport { type CompoundFieldEntry, defineCompoundField, restParts } from '../compound/compound';\nimport { formatCredit } from './credits';\n\nconst PLACED = ['person', 'name', 'roles', 'featured'];\n\n/**\n * The `credits` type (decision 0065): a compound field whose items are a person (`person`, a\n * relation) or a free name (`name`), their `roles`, and whether the credit is `featured`. The\n * definition gives the sub-fields: those of a site come after these.\n */\nexport const CreditsFieldEntry: CompoundFieldEntry = defineCompoundField({\n layout: ({ parts }) => (\n <div className={styles.stack}>\n <div className={styles.row}>\n <div className={styles.part}>{parts.person}</div>\n <div className={styles.part}>{parts.name}</div>\n <div className={styles.part}>{parts.roles}</div>\n </div>\n {parts.featured !== undefined ? (\n <div className={styles.part}>{parts.featured}</div>\n ) : null}\n {restParts(parts, PLACED).map((part, index) => (\n <div key={index} className={styles.part}>\n {part}\n </div>\n ))}\n </div>\n ),\n summarize: (credit, { locale }) => formatCredit(credit, locale),\n});\n\n/** The `credits` type, as a `@panneau/core` plugin. */\nexport const creditsPlugin = {\n id: 'panneau.credits',\n fields: { credits: CreditsFieldEntry },\n};\n"],"mappings":";;;;;AAIA,IAAMK,SAAS;CAAC;CAAU;CAAQ;CAAS;AAAU;;;;;;AAOrD,IAAaC,oBAAwCJ,oBAAoB;CACrEK,SAAS,EAAEC,YACP,qBAAC,OAAD;EAAK,WAAWR,wBAAOS;EAAvB,UAAA;GACI,qBAAC,OAAD;IAAK,WAAWT,wBAAOU;IAAvB,UAAA;KACI,oBAAC,OAAD;MAAK,WAAWV,wBAAOW;MAAOH,UAAAA,MAAMI;KAAY,CAAA;KAChD,oBAAC,OAAD;MAAK,WAAWZ,wBAAOW;MAAOH,UAAAA,MAAMK;KAAU,CAAA;KAC9C,oBAAC,OAAD;MAAK,WAAWb,wBAAOW;MAAOH,UAAAA,MAAMM;KAAW,CAAA;IAC9C;;GACJN,MAAMO,aAAaC,KAAAA,IAChB,oBAAC,OAAD;IAAK,WAAWhB,wBAAOW;IAAOH,UAAAA,MAAMO;GAAc,CAAA,IAClD;GACHZ,UAAUK,OAAOH,MAAM,CAAC,CAACY,KAAKN,MAAMO,UACjC,oBAAC,OAAD;IAAiB,WAAWlB,wBAAOW;IAC9BA,UAAAA;GACA,GAFKO,KAEL,CACR;EACA;;CAETC,YAAYC,QAAQ,EAAEC,aAAajB,aAAagB,QAAQC,MAAM;AAClE,CAAC;;AAGD,IAAaC,gBAAgB;CACzBC,IAAI;CACJC,QAAQ,EAAEC,SAASnB,kBAAkB;AACzC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** A credit, as the sub-fields of a `credits` field give it. */
|
|
2
|
+
export interface Credit {
|
|
3
|
+
/** A reference to a person, `{ id, label }`, or `null`. */
|
|
4
|
+
person?: unknown;
|
|
5
|
+
/** The name of a person who isn't in the database. */
|
|
6
|
+
name?: unknown;
|
|
7
|
+
/** References to roles, or a role as text, localized or not. */
|
|
8
|
+
roles?: unknown;
|
|
9
|
+
/** Whether the credit is featured, `true` or left out. */
|
|
10
|
+
featured?: unknown;
|
|
11
|
+
}
|
|
12
|
+
/** The name of the credited person: the label of the person, or the free name. */
|
|
13
|
+
export declare function getCreditName(credit: Credit, locale: string): string | null;
|
|
14
|
+
/** The roles of a credit: the labels of its references, or its text in the locale. */
|
|
15
|
+
export declare function getCreditRoles(credit: Credit, locale: string): string[];
|
|
16
|
+
/** A credit as text: `Ada Lovelace (Director, Writer)`, or `null` without a name nor a role. */
|
|
17
|
+
export declare function formatCredit(credit: Credit, locale: string): string | null;
|
|
18
|
+
//# sourceMappingURL=credits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../src/credits/credits.ts"],"names":[],"mappings":"AAGA,gEAAgE;AAChE,MAAM,WAAW,MAAM;IACnB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAeD,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE3E;AAED,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAOvE;AAED,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO1E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { toReferences } from "../shared/relation.js";
|
|
2
|
+
//#region src/credits/credits.ts
|
|
3
|
+
function localizedText(value, locale) {
|
|
4
|
+
if (typeof value === "string") return value.trim() !== "" ? value.trim() : null;
|
|
5
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
6
|
+
const texts = value;
|
|
7
|
+
const text = texts[locale] ?? Object.values(texts).find((entry) => typeof entry === "string");
|
|
8
|
+
return typeof text === "string" && text.trim() !== "" ? text.trim() : null;
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
/** The name of the credited person: the label of the person, or the free name. */
|
|
13
|
+
function getCreditName(credit, locale) {
|
|
14
|
+
return toReferences(credit.person)[0]?.label ?? localizedText(credit.name, locale);
|
|
15
|
+
}
|
|
16
|
+
/** The roles of a credit: the labels of its references, or its text in the locale. */
|
|
17
|
+
function getCreditRoles(credit, locale) {
|
|
18
|
+
const { roles } = credit;
|
|
19
|
+
if (Array.isArray(roles) || roles !== null && typeof roles === "object" && "id" in roles) return toReferences(roles).map((reference) => reference.label);
|
|
20
|
+
const text = localizedText(roles, locale);
|
|
21
|
+
return text !== null ? [text] : [];
|
|
22
|
+
}
|
|
23
|
+
/** A credit as text: `Ada Lovelace (Director, Writer)`, or `null` without a name nor a role. */
|
|
24
|
+
function formatCredit(credit, locale) {
|
|
25
|
+
const name = getCreditName(credit, locale);
|
|
26
|
+
const roles = getCreditRoles(credit, locale);
|
|
27
|
+
if (name === null) return roles.length > 0 ? roles.join(", ") : null;
|
|
28
|
+
return roles.length > 0 ? `${name} (${roles.join(", ")})` : name;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { formatCredit, getCreditName, getCreditRoles };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=credits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credits.js","names":["toReferences","Credit","person","name","roles","featured","localizedText","value","locale","trim","Array","isArray","texts","Record","text","Object","values","find","entry","getCreditName","credit","label","getCreditRoles","map","reference","formatCredit","length","join"],"sources":["../../src/credits/credits.ts"],"sourcesContent":["// The `credits` compound field (decision 0065): people, or free names, and their roles.\nimport { toReferences } from '../shared/relation';\n\n/** A credit, as the sub-fields of a `credits` field give it. */\nexport interface Credit {\n /** A reference to a person, `{ id, label }`, or `null`. */\n person?: unknown;\n /** The name of a person who isn't in the database. */\n name?: unknown;\n /** References to roles, or a role as text, localized or not. */\n roles?: unknown;\n /** Whether the credit is featured, `true` or left out. */\n featured?: unknown;\n}\n\nfunction localizedText(value: unknown, locale: string): string | null {\n if (typeof value === 'string') {\n return value.trim() !== '' ? value.trim() : null;\n }\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n const texts = value as Record<string, unknown>;\n const text =\n texts[locale] ?? Object.values(texts).find((entry) => typeof entry === 'string');\n return typeof text === 'string' && text.trim() !== '' ? text.trim() : null;\n }\n return null;\n}\n\n/** The name of the credited person: the label of the person, or the free name. */\nexport function getCreditName(credit: Credit, locale: string): string | null {\n return toReferences(credit.person)[0]?.label ?? localizedText(credit.name, locale);\n}\n\n/** The roles of a credit: the labels of its references, or its text in the locale. */\nexport function getCreditRoles(credit: Credit, locale: string): string[] {\n const { roles } = credit;\n if (Array.isArray(roles) || (roles !== null && typeof roles === 'object' && 'id' in roles)) {\n return toReferences(roles).map((reference) => reference.label);\n }\n const text = localizedText(roles, locale);\n return text !== null ? [text] : [];\n}\n\n/** A credit as text: `Ada Lovelace (Director, Writer)`, or `null` without a name nor a role. */\nexport function formatCredit(credit: Credit, locale: string): string | null {\n const name = getCreditName(credit, locale);\n const roles = getCreditRoles(credit, locale);\n if (name === null) {\n return roles.length > 0 ? roles.join(', ') : null;\n }\n return roles.length > 0 ? `${name} (${roles.join(', ')})` : name;\n}\n"],"mappings":";;AAeA,SAASM,cAAcC,OAAgBC,QAA+B;CAClE,IAAI,OAAOD,UAAU,UACjB,OAAOA,MAAME,KAAK,MAAM,KAAKF,MAAME,KAAK,IAAI;CAEhD,IAAIF,UAAU,QAAQ,OAAOA,UAAU,YAAY,CAACG,MAAMC,QAAQJ,KAAK,GAAG;EACtE,MAAMK,QAAQL;EACd,MAAMO,OACFF,MAAMJ,WAAWO,OAAOC,OAAOJ,KAAK,CAAC,CAACK,MAAMC,UAAU,OAAOA,UAAU,QAAQ;EACnF,OAAO,OAAOJ,SAAS,YAAYA,KAAKL,KAAK,MAAM,KAAKK,KAAKL,KAAK,IAAI;CAC1E;CACA,OAAO;AACX;;AAGA,SAAgBU,cAAcC,QAAgBZ,QAA+B;CACzE,OAAOR,aAAaoB,OAAOlB,MAAM,CAAC,CAAC,EAAE,EAAEmB,SAASf,cAAcc,OAAOjB,MAAMK,MAAM;AACrF;;AAGA,SAAgBc,eAAeF,QAAgBZ,QAA0B;CACrE,MAAM,EAAEJ,UAAUgB;CAClB,IAAIV,MAAMC,QAAQP,KAAK,KAAMA,UAAU,QAAQ,OAAOA,UAAU,YAAY,QAAQA,OAChF,OAAOJ,aAAaI,KAAK,CAAC,CAACmB,KAAKC,cAAcA,UAAUH,KAAK;CAEjE,MAAMP,OAAOR,cAAcF,OAAOI,MAAM;CACxC,OAAOM,SAAS,OAAO,CAACA,IAAI,IAAI,CAAA;AACpC;;AAGA,SAAgBW,aAAaL,QAAgBZ,QAA+B;CACxE,MAAML,OAAOgB,cAAcC,QAAQZ,MAAM;CACzC,MAAMJ,QAAQkB,eAAeF,QAAQZ,MAAM;CAC3C,IAAIL,SAAS,MACT,OAAOC,MAAMsB,SAAS,IAAItB,MAAMuB,KAAK,IAAI,IAAI;CAEjD,OAAOvB,MAAMsB,SAAS,IAAI,GAAGvB,KAAI,IAAKC,MAAMuB,KAAK,IAAI,EAAC,KAAMxB;AAChE"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CreditsFieldEntry, creditsPlugin } from './CreditsField.js';
|
|
2
|
+
export { type Credit, formatCredit, getCreditName, getCreditRoles } from './credits.js';
|
|
3
|
+
export type { CompoundFieldEntry, CompoundSummary, CompoundSummaryContext, } from '../compound/compound.js';
|
|
4
|
+
export type { FieldEntry, FieldEntryProps } from '../shared/types.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/credits/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,KAAK,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACrF,YAAY,EACR,kBAAkB,EAClB,eAAe,EACf,sBAAsB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/embed/EmbedField.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { useFieldsContext } from "../shared/context.js";
|
|
2
1
|
import { findRule, getFieldProps, isString } from "../shared/entry.js";
|
|
2
|
+
import { useFieldsContext } from "../shared/context.js";
|
|
3
3
|
import { messages } from "../shared/messages.js";
|
|
4
4
|
import EmbedField_module_default from "./EmbedField.module.js";
|
|
5
5
|
import { c } from "react/compiler-runtime";
|
|
6
|
-
import { useEffect, useEffectEvent, useState } from "react";
|
|
7
6
|
import { Spinner, TextInput, usePanneauIntl } from "@panneau/ui";
|
|
8
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { useEffect, useEffectEvent, useState } from "react";
|
|
9
9
|
import { formsMessages } from "@panneau/intl";
|
|
10
10
|
//#region src/embed/EmbedField.tsx
|
|
11
11
|
var RESOLVE_DELAY = 500;
|
package/dist/file/FileField.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useFieldsContext } from "../shared/context.js";
|
|
2
1
|
import { getAccept, getFieldProps, getMaxSize } from "../shared/entry.js";
|
|
2
|
+
import { useFieldsContext } from "../shared/context.js";
|
|
3
3
|
import { messages } from "../shared/messages.js";
|
|
4
4
|
import { FilePicker } from "../upload/FilePicker.js";
|
|
5
5
|
import { formatSize } from "../upload/files.js";
|
|
@@ -8,10 +8,10 @@ import { useRejectionMessage } from "../upload/useRejectionMessage.js";
|
|
|
8
8
|
import { useUploads } from "../upload/useUploads.js";
|
|
9
9
|
import FileField_module_default from "./FileField.module.js";
|
|
10
10
|
import { c } from "react/compiler-runtime";
|
|
11
|
-
import { FileText, X } from "lucide-react";
|
|
12
|
-
import { useEffect, useRef, useState } from "react";
|
|
13
11
|
import { Fieldset, IconButton, usePanneauIntl } from "@panneau/ui";
|
|
14
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { FileText, X } from "lucide-react";
|
|
14
|
+
import { useEffect, useRef, useState } from "react";
|
|
15
15
|
//#region src/file/FileField.tsx
|
|
16
16
|
function fileSize(file) {
|
|
17
17
|
return typeof file.size === "number" ? file.size : null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import type { Field } from '@panneau/protocol';
|
|
2
3
|
import type { FieldEntryProps, FieldProps } from '../shared/types.js';
|
|
3
4
|
export type GroupValue = Record<string, unknown>;
|
|
@@ -6,6 +7,11 @@ export interface GroupFieldProps extends FieldProps<GroupValue> {
|
|
|
6
7
|
fields: readonly Field[];
|
|
7
8
|
/** Dot path of the group's value, the prefix of its fields' paths. Defaults to `name`. */
|
|
8
9
|
path?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Lays out the rendered fields, by name, instead of the flow of short fields side by side:
|
|
12
|
+
* the layout of a compound field (decision 0065).
|
|
13
|
+
*/
|
|
14
|
+
renderFields?: (parts: Readonly<Record<string, ReactNode>>, value: GroupValue) => ReactNode;
|
|
9
15
|
fieldsClassName?: string;
|
|
10
16
|
}
|
|
11
17
|
/**
|
|
@@ -13,7 +19,7 @@ export interface GroupFieldProps extends FieldProps<GroupValue> {
|
|
|
13
19
|
* field renders with the entry of its type, at the path `<group>.<field>`. Without a binding in the fields context, the group sets the whole
|
|
14
20
|
* object through `onChange`.
|
|
15
21
|
*/
|
|
16
|
-
export declare function GroupField({ fields, path, name, value, onChange, onBlur, label, description, errors, disabled, readOnly, required, className, labelClassName, descriptionClassName, errorsClassName, fieldsClassName, }: GroupFieldProps): import("react").JSX.Element;
|
|
22
|
+
export declare function GroupField({ fields, path, name, value, onChange, onBlur, label, description, errors, disabled, readOnly, required, className, labelClassName, descriptionClassName, errorsClassName, renderFields, fieldsClassName, }: GroupFieldProps): import("react").JSX.Element;
|
|
17
23
|
/** The `group` type: its `fields`, as a nested object. */
|
|
18
24
|
export declare function GroupFieldEntry(props: FieldEntryProps): import("react").JSX.Element;
|
|
19
25
|
//# sourceMappingURL=GroupField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupField.d.ts","sourceRoot":"","sources":["../../src/group/GroupField.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO/C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGnE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,WAAW,eAAgB,SAAQ,UAAU,CAAC,UAAU,CAAC;IAC3D,0EAA0E;IAC1E,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACvB,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,WAAW,EACX,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,eAAe,GAClB,EAAE,eAAe,+
|
|
1
|
+
{"version":3,"file":"GroupField.d.ts","sourceRoot":"","sources":["../../src/group/GroupField.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO/C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGnE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,WAAW,eAAgB,SAAQ,UAAU,CAAC,UAAU,CAAC;IAC3D,0EAA0E;IAC1E,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,KAAK,SAAS,CAAC;IAC5F,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACvB,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,WAAW,EACX,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,eAAe,GAClB,EAAE,eAAe,+BA+CjB;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,+BAerD"}
|