@panneau/fields 5.0.0-alpha.0 → 5.0.0-alpha.2
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 +2 -0
- package/dist/color/ColorField.css +5 -5
- package/dist/color/ColorField.module.js +3 -3
- package/dist/group/GroupField.css +2 -2
- package/dist/group/GroupField.module.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/localized/LocalizedField.css +2 -2
- package/dist/localized/LocalizedField.module.js +2 -2
- package/dist/missing/MissingField.css +4 -3
- package/dist/missing/MissingField.module.js +3 -3
- package/dist/missing/MissingField.module.js.map +1 -1
- package/dist/relation/RelationField.css +7 -7
- package/dist/relation/RelationField.d.ts +10 -2
- package/dist/relation/RelationField.d.ts.map +1 -1
- package/dist/relation/RelationField.js +59 -24
- package/dist/relation/RelationField.js.map +1 -1
- package/dist/relation/RelationField.module.js +6 -6
- package/dist/relation/index.d.ts +1 -1
- package/dist/relation/index.d.ts.map +1 -1
- package/dist/relation/index.js +2 -2
- package/dist/repeater/RepeaterField.css +12 -11
- package/dist/repeater/RepeaterField.module.js +9 -9
- package/dist/repeater/RepeaterField.module.js.map +1 -1
- package/dist/select/SelectField.css +1 -1
- package/dist/select/SelectField.module.js +1 -1
- package/dist/shared/DefinitionField.d.ts +1 -1
- package/dist/shared/DefinitionField.d.ts.map +1 -1
- package/dist/shared/DefinitionField.js +1 -1
- package/dist/shared/DefinitionField.js.map +1 -1
- package/dist/shared/relation.d.ts +41 -5
- package/dist/shared/relation.d.ts.map +1 -1
- package/dist/shared/relation.js +119 -12
- package/dist/shared/relation.js.map +1 -1
- package/dist/url/UrlField.css +2 -2
- package/dist/url/UrlField.module.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -63,6 +63,8 @@ import {
|
|
|
63
63
|
- **Localized fields** (`localized: true`) render the field of their type for each locale of the provider, at `title.fr`, `title.en`.
|
|
64
64
|
- **Groups and repeaters** render their nested fields with `NestedField`, at paths like `blocks.2.body`. A `binding` in `FieldsProvider` can bind every nested field to a store by path: `@panneau/forms` binds them to its form state. Without one, the group or repeater sets its whole value.
|
|
65
65
|
- **Relations** search a `RelationSource`. `createRelationSource()` makes one from any adapter with a `list()` method, such as the `DataAdapter` of `@panneau/data`. Labels come from the resource's `itemTitle`. Without a source, a relation field shows its references, read-only.
|
|
66
|
+
- **Plain ids.** Values can be ids (`"12"`, `["12", "13"]`), as a product's own API gives them. The field shows their labels once the source's optional `resolve(resource, ids)` gives them (`createRelationSource()` implements it with the adapter's `get()`), and their ids until then. Fields that show the same ids share one request. `useRelationReferences()` does the same for other components.
|
|
67
|
+
- **Creating from the picker.** When the source has `create(resource, text)`, the picker offers "Create “…”" for a text that matches no item, and adds the new item. `createRelationSource(adapter, { create: true })` creates it with the adapter's `create()`, with the text as its `itemTitle` (in every locale when it is localized), on the resources that allow `create`; a function gives other values. A field's `onCreate` prop replaces the source's, and can open a dialog with a full form: it resolves with the new reference, or `null`. `onCreate={null}` turns creating off.
|
|
66
68
|
- **Plugin slot:** a type without an entry, such as `richtext` and `media` until Phase 2, renders a placeholder that names it. A plugin that provides the type replaces it.
|
|
67
69
|
|
|
68
70
|
## Messages
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.panneau-swatch
|
|
1
|
+
.panneau-color-field-swatch {
|
|
2
2
|
position: relative;
|
|
3
3
|
display: inline-flex;
|
|
4
4
|
width: 1.5rem;
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
border-radius: var(--panneau-radius-sm);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
.panneau-swatch
|
|
11
|
+
.panneau-color-field-swatch:focus-within {
|
|
12
12
|
outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
|
|
13
13
|
outline-offset: 2px;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
.panneau-picker
|
|
16
|
+
.panneau-color-field-picker {
|
|
17
17
|
position: absolute;
|
|
18
18
|
inset: -0.5rem;
|
|
19
19
|
width: calc(100% + 1rem);
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
border: 0;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
.panneau-picker
|
|
27
|
+
.panneau-color-field-picker:disabled {
|
|
28
28
|
cursor: not-allowed;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
.panneau-input
|
|
31
|
+
.panneau-color-field-input {
|
|
32
32
|
font-family: var(--panneau-font-family-mono);
|
|
33
33
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./ColorField.css";
|
|
2
2
|
//#region src/color/ColorField.module.css
|
|
3
|
-
var swatch = "panneau-swatch
|
|
4
|
-
var picker = "panneau-picker
|
|
5
|
-
var input = "panneau-input
|
|
3
|
+
var swatch = "panneau-color-field-swatch";
|
|
4
|
+
var picker = "panneau-color-field-picker";
|
|
5
|
+
var input = "panneau-color-field-input";
|
|
6
6
|
var ColorField_module_default = {
|
|
7
7
|
swatch,
|
|
8
8
|
picker,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.panneau-fields
|
|
1
|
+
.panneau-group-field-fields {
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
gap: var(--panneau-space-4);
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
@media (max-width: 30rem) {
|
|
11
|
-
.panneau-fields
|
|
11
|
+
.panneau-group-field-fields {
|
|
12
12
|
padding: var(--panneau-space-3);
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./GroupField.css";
|
|
2
2
|
//#region src/group/GroupField.module.css
|
|
3
|
-
var fields = "panneau-fields
|
|
3
|
+
var fields = "panneau-group-field-fields";
|
|
4
4
|
var GroupField_module_default = { fields };
|
|
5
5
|
//#endregion
|
|
6
6
|
export { GroupField_module_default as default, fields };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { DefinitionField, NestedField, type NestedFieldProps } from './shared/De
|
|
|
2
2
|
export { builtInFields, fieldsPlugin } from './shared/builtIn';
|
|
3
3
|
export { type BoundFieldProps, type FieldBinding, type FieldBindingProps, FieldsProvider, type FieldsContextValue, type FieldsProviderProps, getParentPath, useFieldsContext, } from './shared/context';
|
|
4
4
|
export { findRule, getFieldProps, getRuleNumber, isRequired } from './shared/entry';
|
|
5
|
-
export { type RelationListAdapter, type RelationReference, type RelationSource, type RelationSourceOptions, createRelationSource, toReferences, } from './shared/relation';
|
|
5
|
+
export { type RelationListAdapter, type RelationReference, type RelationSource, type RelationSourceOptions, createRelationSource, toReferences, useRelationReferences, } from './shared/relation';
|
|
6
6
|
export type { FieldEntry, FieldEntryProps, FieldProps } from './shared/types';
|
|
7
7
|
export { MissingFieldEntry } from './missing/MissingField';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,aAAa,EACb,gBAAgB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,EACH,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,oBAAoB,EACpB,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,aAAa,EACb,gBAAgB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,EACH,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FieldsProvider, getParentPath, useFieldsContext } from "./shared/context.js";
|
|
2
2
|
import { findRule, getFieldProps, getRuleNumber, isRequired } from "./shared/entry.js";
|
|
3
3
|
import { MissingFieldEntry } from "./missing/MissingField.js";
|
|
4
|
-
import { createRelationSource, toReferences } from "./shared/relation.js";
|
|
4
|
+
import { createRelationSource, toReferences, useRelationReferences } from "./shared/relation.js";
|
|
5
5
|
import { builtInFields, fieldsPlugin } from "./shared/builtIn.js";
|
|
6
6
|
import { DefinitionField, NestedField } from "./shared/DefinitionField.js";
|
|
7
|
-
export { DefinitionField, FieldsProvider, MissingFieldEntry, NestedField, builtInFields, createRelationSource, fieldsPlugin, findRule, getFieldProps, getParentPath, getRuleNumber, isRequired, toReferences, useFieldsContext };
|
|
7
|
+
export { DefinitionField, FieldsProvider, MissingFieldEntry, NestedField, builtInFields, createRelationSource, fieldsPlugin, findRule, getFieldProps, getParentPath, getRuleNumber, isRequired, toReferences, useFieldsContext, useRelationReferences };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./LocalizedField.css";
|
|
2
2
|
//#region src/localized/LocalizedField.module.css
|
|
3
|
-
var locales = "panneau-
|
|
4
|
-
var locale = "panneau-locale
|
|
3
|
+
var locales = "panneau-localized-field-locales";
|
|
4
|
+
var locale = "panneau-localized-field-locale";
|
|
5
5
|
var LocalizedField_module_default = {
|
|
6
6
|
locales,
|
|
7
7
|
locale
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
.panneau-missing-
|
|
1
|
+
.panneau-missing-field-missing {
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
gap: var(--panneau-space-1);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.panneau-notice
|
|
7
|
+
.panneau-missing-field-notice {
|
|
8
8
|
padding: var(--panneau-space-2) var(--panneau-space-3);
|
|
9
9
|
font-size: var(--panneau-font-size-sm);
|
|
10
10
|
color: var(--panneau-color-text-muted);
|
|
11
11
|
background-color: var(--panneau-color-surface-sunken);
|
|
12
12
|
border: var(--panneau-border-width) dashed var(--panneau-color-border-control);
|
|
13
13
|
border-radius: var(--panneau-radius-md);
|
|
14
|
+
margin: 0;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
.panneau-label
|
|
17
|
+
.panneau-missing-field-label {
|
|
17
18
|
font-weight: var(--panneau-font-weight-medium);
|
|
18
19
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./MissingField.css";
|
|
2
2
|
//#region src/missing/MissingField.module.css
|
|
3
|
-
var missing = "panneau-missing-
|
|
4
|
-
var notice = "panneau-notice
|
|
5
|
-
var label = "panneau-label
|
|
3
|
+
var missing = "panneau-missing-field-missing";
|
|
4
|
+
var notice = "panneau-missing-field-notice";
|
|
5
|
+
var label = "panneau-missing-field-label";
|
|
6
6
|
var MissingField_module_default = {
|
|
7
7
|
missing,
|
|
8
8
|
notice,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MissingField.module.js","names":[],"sources":["../../src/missing/MissingField.module.css"],"sourcesContent":[".missing {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n}\n\n.notice {\n padding: var(--panneau-space-2) var(--panneau-space-3);\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) dashed var(--panneau-color-border-control);\n border-radius: var(--panneau-radius-md);\n}\n\n.label {\n font-weight: var(--panneau-font-weight-medium);\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"MissingField.module.js","names":[],"sources":["../../src/missing/MissingField.module.css"],"sourcesContent":[".missing {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n}\n\n.notice {\n padding: var(--panneau-space-2) var(--panneau-space-3);\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) dashed var(--panneau-color-border-control);\n border-radius: var(--panneau-radius-md);\n margin: 0;\n}\n\n.label {\n font-weight: var(--panneau-font-weight-medium);\n}\n"],"mappings":""}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
.panneau-
|
|
1
|
+
.panneau-relation-field-multiple {
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
gap: var(--panneau-space-2);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.panneau-selected
|
|
7
|
+
.panneau-relation-field-selected {
|
|
8
8
|
display: flex;
|
|
9
9
|
flex-wrap: wrap;
|
|
10
10
|
gap: var(--panneau-space-1) var(--panneau-space-2);
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
list-style: none;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
.panneau-reference
|
|
16
|
+
.panneau-relation-field-reference {
|
|
17
17
|
display: inline-flex;
|
|
18
18
|
align-items: center;
|
|
19
19
|
gap: var(--panneau-space-1);
|
|
@@ -26,18 +26,18 @@
|
|
|
26
26
|
border-radius: var(--panneau-radius-full);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
.panneau-reference
|
|
30
|
-
.panneau-
|
|
29
|
+
.panneau-relation-field-reference:only-child,
|
|
30
|
+
.panneau-relation-field-read-only .panneau-relation-field-reference {
|
|
31
31
|
padding-inline-end: var(--panneau-space-3);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
.panneau-
|
|
34
|
+
.panneau-relation-field-reference-label {
|
|
35
35
|
overflow: hidden;
|
|
36
36
|
text-overflow: ellipsis;
|
|
37
37
|
white-space: nowrap;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
.panneau-none
|
|
40
|
+
.panneau-relation-field-none {
|
|
41
41
|
font-size: var(--panneau-font-size-md);
|
|
42
42
|
color: var(--panneau-color-text-muted);
|
|
43
43
|
}
|
|
@@ -14,6 +14,12 @@ export interface RelationFieldBaseProps extends Omit<FieldProps<never>, 'value'
|
|
|
14
14
|
resource: string;
|
|
15
15
|
/** Where to search. Defaults to the fields context's. Without one, the field is read-only. */
|
|
16
16
|
source?: RelationSource | null;
|
|
17
|
+
/**
|
|
18
|
+
* Creates an item from the typed text, offered as "Create “…”" in the picker: it can open a
|
|
19
|
+
* dialog, and resolves with the new reference, or `null` when nothing was created. Defaults to
|
|
20
|
+
* the source's `create()`. `null` turns creating off.
|
|
21
|
+
*/
|
|
22
|
+
onCreate?: ((text: string) => Promise<RelationReference | null>) | null;
|
|
17
23
|
placeholder?: string;
|
|
18
24
|
controlClassName?: string;
|
|
19
25
|
}
|
|
@@ -31,8 +37,10 @@ export interface MultipleRelationFieldProps extends RelationFieldBaseProps {
|
|
|
31
37
|
export type RelationFieldProps = SingleRelationFieldProps | MultipleRelationFieldProps;
|
|
32
38
|
/**
|
|
33
39
|
* A reference to an item of another resource, or several with `multiple`, picked by searching a
|
|
34
|
-
* `RelationSource`. Values are references (`{ id, label }`), as items carry them
|
|
35
|
-
*
|
|
40
|
+
* `RelationSource`. Values are references (`{ id, label }`), as items carry them; plain ids get
|
|
41
|
+
* their labels from the source's `resolve()`. When the source can `create()` (or with `onCreate`),
|
|
42
|
+
* the picker offers to create an item from the typed text. Without a source, the field shows its
|
|
43
|
+
* references and can't change them.
|
|
36
44
|
*/
|
|
37
45
|
export declare function RelationField(props: RelationFieldProps): import("react").JSX.Element;
|
|
38
46
|
/** The `relation` type: `resource` and `multiple`. Items search the fields context's source. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RelationField.d.ts","sourceRoot":"","sources":["../../src/relation/RelationField.tsx"],"names":[],"mappings":"AASA,OAAO,
|
|
1
|
+
{"version":3,"file":"RelationField.d.ts","sourceRoot":"","sources":["../../src/relation/RelationField.tsx"],"names":[],"mappings":"AASA,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAGtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMnE,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,cAAc,GAAG,IAAI,EAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,EAAE,OAAc,EAAE,KAAW,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5E;IAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAmCpD;AAED,yDAAyD;AACzD,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACzF,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,wBAAyB,SAAQ,sBAAsB;IACpE,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,KAAK,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,0BAA2B,SAAQ,sBAAsB;IACtE,QAAQ,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,iBAAiB,EAAE,GAAG,IAAI,CAAC;IAC5C,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,GAAG,0BAA0B,CAAC;AA+BvF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,+BAyNtD;AAED,gGAAgG;AAChG,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,+BAQxD"}
|
|
@@ -2,7 +2,7 @@ import { useFieldsContext } from "../shared/context.js";
|
|
|
2
2
|
import { cx } from "../shared/cx.js";
|
|
3
3
|
import { getFieldProps } from "../shared/entry.js";
|
|
4
4
|
import { messages } from "../shared/messages.js";
|
|
5
|
-
import { toReferences } from "../shared/relation.js";
|
|
5
|
+
import { toReferences, useRelationReferences } from "../shared/relation.js";
|
|
6
6
|
import RelationField_module_default from "./RelationField.module.js";
|
|
7
7
|
import { c } from "react/compiler-runtime";
|
|
8
8
|
import { ComboBox, Fieldset, IconButton, usePanneauIntl } from "@panneau/ui";
|
|
@@ -10,6 +10,8 @@ import { useEffect, useState } from "react";
|
|
|
10
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
import { X } from "lucide-react";
|
|
12
12
|
//#region src/relation/RelationField.tsx
|
|
13
|
+
/** The id of the "Create “…”" option of the picker. */
|
|
14
|
+
var CREATE_ID = "\0create";
|
|
13
15
|
/** Results of a search in a relation source, as it types. */
|
|
14
16
|
function useRelationSearch(source, resource, query, { enabled = true, delay = 250 } = {}) {
|
|
15
17
|
const [state, setState] = useState({
|
|
@@ -109,22 +111,47 @@ function References(t0) {
|
|
|
109
111
|
}
|
|
110
112
|
/**
|
|
111
113
|
* A reference to an item of another resource, or several with `multiple`, picked by searching a
|
|
112
|
-
* `RelationSource`. Values are references (`{ id, label }`), as items carry them
|
|
113
|
-
*
|
|
114
|
+
* `RelationSource`. Values are references (`{ id, label }`), as items carry them; plain ids get
|
|
115
|
+
* their labels from the source's `resolve()`. When the source can `create()` (or with `onCreate`),
|
|
116
|
+
* the picker offers to create an item from the typed text. Without a source, the field shows its
|
|
117
|
+
* references and can't change them.
|
|
114
118
|
*/
|
|
115
119
|
function RelationField(props) {
|
|
116
120
|
const intl = usePanneauIntl();
|
|
117
121
|
const context = useFieldsContext();
|
|
118
122
|
const source = props.source === void 0 ? context.relationSource : props.source;
|
|
119
123
|
const { resource, label, description, errors, disabled, readOnly, required, placeholder = intl.formatMessage(messages.search), onBlur, name, id, className, labelClassName, descriptionClassName, errorsClassName, controlClassName } = props;
|
|
120
|
-
const selected = toReferences(props.value);
|
|
124
|
+
const selected = useRelationReferences(source, resource, toReferences(props.value));
|
|
121
125
|
const [query, setQuery] = useState(null);
|
|
126
|
+
const [creating, setCreating] = useState(false);
|
|
127
|
+
const [createError, setCreateError] = useState(null);
|
|
122
128
|
const editable = source !== null && disabled !== true && readOnly !== true;
|
|
123
|
-
const { items, isLoading } = useRelationSearch(source, resource, query ?? "", { enabled: editable });
|
|
124
|
-
const
|
|
129
|
+
const { items: found, isLoading: searching } = useRelationSearch(source, resource, query ?? "", { enabled: editable });
|
|
130
|
+
const sourceCreate = source?.create;
|
|
131
|
+
const create = props.onCreate !== void 0 ? props.onCreate : sourceCreate !== void 0 && source?.canCreate?.(resource) !== false ? (text) => sourceCreate.call(source, resource, text) : null;
|
|
132
|
+
const text_0 = (query ?? "").trim();
|
|
133
|
+
const items = create !== null && text_0 !== "" && !searching && ![...found, ...selected].some((item) => item.label.toLocaleLowerCase(intl.locale) === text_0.toLocaleLowerCase(intl.locale)) ? [...found, {
|
|
134
|
+
id: CREATE_ID,
|
|
135
|
+
label: intl.formatMessage(messages.createRelation, { text: text_0 })
|
|
136
|
+
}] : found;
|
|
137
|
+
const isLoading = searching || creating;
|
|
138
|
+
const allErrors = createError !== null ? [...errors ?? [], createError] : errors;
|
|
139
|
+
/** Creates an item from the text, then adds its reference with `add`. */
|
|
140
|
+
const createFrom = (add) => {
|
|
141
|
+
if (create === null) return;
|
|
142
|
+
setCreating(true);
|
|
143
|
+
setCreateError(null);
|
|
144
|
+
create(text_0).then((reference) => {
|
|
145
|
+
if (reference !== null) {
|
|
146
|
+
add(reference);
|
|
147
|
+
setQuery(null);
|
|
148
|
+
}
|
|
149
|
+
}).catch(() => setCreateError(intl.formatMessage(messages.createRelationFailed, { text: text_0 }))).finally(() => setCreating(false));
|
|
150
|
+
};
|
|
151
|
+
const removeLabel = (reference_0) => `${intl.formatMessage(messages.remove)} ${reference_0.label}`;
|
|
125
152
|
const chrome = {
|
|
126
153
|
legend: label,
|
|
127
|
-
errors,
|
|
154
|
+
errors: allErrors,
|
|
128
155
|
isRequired: required,
|
|
129
156
|
className,
|
|
130
157
|
legendClassName: labelClassName,
|
|
@@ -158,20 +185,24 @@ function RelationField(props) {
|
|
|
158
185
|
children: [selected.length > 0 ? /* @__PURE__ */ jsx(References, {
|
|
159
186
|
references: selected,
|
|
160
187
|
removeLabel,
|
|
161
|
-
onRemove: (
|
|
188
|
+
onRemove: (reference_1) => set(selected.filter((entry) => entry.id !== reference_1.id))
|
|
162
189
|
}) : null, /* @__PURE__ */ jsx(ComboBox, {
|
|
163
190
|
"aria-label": comboLabel,
|
|
164
|
-
items: items.filter((
|
|
165
|
-
id:
|
|
166
|
-
label:
|
|
191
|
+
items: items.filter((item_0) => !selected.some((entry_0) => entry_0.id === item_0.id)).map((item_1) => ({
|
|
192
|
+
id: item_1.id,
|
|
193
|
+
label: item_1.label
|
|
167
194
|
})),
|
|
168
195
|
value: null,
|
|
169
196
|
inputValue: query ?? "",
|
|
170
197
|
onInputChange: setQuery,
|
|
171
198
|
onChange: (itemId) => {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
199
|
+
if (itemId === CREATE_ID) {
|
|
200
|
+
createFrom((reference_2) => set([...selected, reference_2]));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const reference_3 = found.find((item_2) => item_2.id === itemId);
|
|
204
|
+
if (reference_3 !== void 0) {
|
|
205
|
+
set([...selected, reference_3]);
|
|
175
206
|
setQuery(null);
|
|
176
207
|
}
|
|
177
208
|
},
|
|
@@ -188,11 +219,11 @@ function RelationField(props) {
|
|
|
188
219
|
}
|
|
189
220
|
const { onChange: onChange_0 } = props;
|
|
190
221
|
const current = selected[0] ?? null;
|
|
191
|
-
const shown = current !== null && !items.some((
|
|
222
|
+
const shown = current !== null && !items.some((item_3) => item_3.id === current.id) ? [current, ...items] : items;
|
|
192
223
|
return /* @__PURE__ */ jsx(ComboBox, {
|
|
193
224
|
label,
|
|
194
225
|
description,
|
|
195
|
-
errors,
|
|
226
|
+
errors: allErrors,
|
|
196
227
|
isRequired: required,
|
|
197
228
|
className,
|
|
198
229
|
labelClassName,
|
|
@@ -200,21 +231,25 @@ function RelationField(props) {
|
|
|
200
231
|
errorsClassName,
|
|
201
232
|
...controlClassName !== void 0 ? { controlClassName } : {},
|
|
202
233
|
...props["aria-label"] !== void 0 ? { "aria-label": props["aria-label"] } : {},
|
|
203
|
-
items: shown.map((
|
|
204
|
-
id:
|
|
205
|
-
label:
|
|
234
|
+
items: shown.map((item_4) => ({
|
|
235
|
+
id: item_4.id,
|
|
236
|
+
label: item_4.label
|
|
206
237
|
})),
|
|
207
238
|
value: current?.id ?? null,
|
|
208
239
|
inputValue: query ?? current?.label ?? "",
|
|
209
|
-
onInputChange: (
|
|
210
|
-
setQuery(
|
|
211
|
-
if (
|
|
240
|
+
onInputChange: (text_1) => {
|
|
241
|
+
setQuery(text_1);
|
|
242
|
+
if (text_1 === "" && current !== null) onChange_0?.(null);
|
|
212
243
|
},
|
|
213
244
|
onChange: (itemId_0) => {
|
|
245
|
+
if (itemId_0 === CREATE_ID) {
|
|
246
|
+
createFrom((reference_4) => onChange_0?.(reference_4));
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
214
249
|
setQuery(null);
|
|
215
250
|
if (itemId_0 === null) return;
|
|
216
|
-
const
|
|
217
|
-
if (
|
|
251
|
+
const reference_5 = shown.find((item_5) => item_5.id === itemId_0) ?? null;
|
|
252
|
+
if (reference_5?.id !== current?.id) onChange_0?.(reference_5);
|
|
218
253
|
},
|
|
219
254
|
isLoading,
|
|
220
255
|
placeholder,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RelationField.js","names":["X","reference","entry","item","onChange","itemId","references","_c","styles","_Fragment"],"sources":["../../src/relation/RelationField.tsx"],"sourcesContent":["import { X } from 'lucide-react';\nimport { useEffect, useState } from 'react';\n\nimport { ComboBox, Fieldset, IconButton, usePanneauIntl } from '@panneau/ui';\n\nimport { useFieldsContext } from '../shared/context';\nimport { cx } from '../shared/cx';\nimport { getFieldProps } from '../shared/entry';\nimport { messages } from '../shared/messages';\nimport { type RelationReference, type RelationSource, toReferences } from '../shared/relation';\nimport type { FieldEntryProps, FieldProps } from '../shared/types';\nimport styles from './RelationField.module.css';\n\n/** Results of a search in a relation source, as it types. */\nexport function useRelationSearch(\n source: RelationSource | null,\n resource: string,\n query: string,\n { enabled = true, delay = 250 }: { enabled?: boolean; delay?: number } = {},\n): { items: RelationReference[]; isLoading: boolean } {\n const [state, setState] = useState<{\n key: string;\n items: RelationReference[];\n isLoading: boolean;\n }>({ key: '', items: [], isLoading: false });\n const key = `${resource}\\u0000${query}`;\n\n useEffect(() => {\n if (source === null || !enabled) {\n return undefined;\n }\n const controller = new AbortController();\n const timer = setTimeout(() => {\n setState((current) => ({ ...current, key, isLoading: true }));\n source\n .search(resource, query, { signal: controller.signal })\n .then((items) => {\n if (!controller.signal.aborted) {\n setState({ key, items, isLoading: false });\n }\n })\n .catch(() => {\n if (!controller.signal.aborted) {\n setState({ key, items: [], isLoading: false });\n }\n });\n }, delay);\n return () => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [source, resource, query, key, enabled, delay]);\n\n return { items: state.items, isLoading: state.isLoading || state.key !== key };\n}\n\n/** Props of both single and multiple relation fields. */\nexport interface RelationFieldBaseProps extends Omit<FieldProps<never>, 'value' | 'onChange'> {\n /** Id of the related resource, passed to the source. */\n resource: string;\n /** Where to search. Defaults to the fields context's. Without one, the field is read-only. */\n source?: RelationSource | null;\n placeholder?: string;\n controlClassName?: string;\n}\n\nexport interface SingleRelationFieldProps extends RelationFieldBaseProps {\n multiple?: false;\n value?: RelationReference | null;\n onChange?: (value: RelationReference | null) => void;\n}\n\nexport interface MultipleRelationFieldProps extends RelationFieldBaseProps {\n multiple: true;\n value?: readonly RelationReference[] | null;\n /** Called with the references. An empty list is `null`. */\n onChange?: (value: RelationReference[] | null) => void;\n}\n\nexport type RelationFieldProps = SingleRelationFieldProps | MultipleRelationFieldProps;\n\nfunction References({\n references,\n onRemove,\n removeLabel,\n}: {\n references: readonly RelationReference[];\n onRemove?: (reference: RelationReference) => void;\n removeLabel: (reference: RelationReference) => string;\n}) {\n return (\n <ul className={cx(styles.selected, onRemove === undefined && styles.readOnly)}>\n {references.map((reference) => (\n <li key={reference.id} className={styles.reference}>\n <span className={styles.referenceLabel}>{reference.label}</span>\n {onRemove !== undefined ? (\n <IconButton\n icon={X}\n size=\"sm\"\n label={removeLabel(reference)}\n showTooltip={false}\n onPress={() => onRemove(reference)}\n />\n ) : null}\n </li>\n ))}\n </ul>\n );\n}\n\n/**\n * A reference to an item of another resource, or several with `multiple`, picked by searching a\n * `RelationSource`. Values are references (`{ id, label }`), as items carry them. Without a\n * source, the field shows its references and can't change them.\n */\nexport function RelationField(props: RelationFieldProps) {\n const intl = usePanneauIntl();\n const context = useFieldsContext();\n const source = props.source === undefined ? context.relationSource : props.source;\n const {\n resource,\n label,\n description,\n errors,\n disabled,\n readOnly,\n required,\n placeholder = intl.formatMessage(messages.search),\n onBlur,\n name,\n id,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n controlClassName,\n } = props;\n const selected = toReferences(props.value);\n const [query, setQuery] = useState<string | null>(null);\n const editable = source !== null && disabled !== true && readOnly !== true;\n const { items, isLoading } = useRelationSearch(source, resource, query ?? '', {\n enabled: editable,\n });\n const removeLabel = (reference: RelationReference) =>\n `${intl.formatMessage(messages.remove)} ${reference.label}`;\n const chrome = {\n legend: label,\n errors,\n isRequired: required,\n className,\n legendClassName: labelClassName,\n descriptionClassName,\n errorsClassName,\n };\n\n if (!editable) {\n return (\n <Fieldset\n {...chrome}\n description={\n source === null && disabled !== true && readOnly !== true ? (\n <>\n {description} {intl.formatMessage(messages.relationUnavailable)}\n </>\n ) : (\n description\n )\n }\n >\n {selected.length > 0 ? (\n <References references={selected} removeLabel={removeLabel} />\n ) : (\n <span className={styles.none}>{intl.formatMessage(messages.noRelation)}</span>\n )}\n </Fieldset>\n );\n }\n\n const comboLabel = typeof label === 'string' ? label : props['aria-label'];\n\n if (props.multiple === true) {\n const { onChange } = props;\n const set = (next: RelationReference[]) => onChange?.(next.length > 0 ? next : null);\n return (\n <Fieldset {...chrome} description={description}>\n <div className={styles.multiple}>\n {selected.length > 0 ? (\n <References\n references={selected}\n removeLabel={removeLabel}\n onRemove={(reference) =>\n set(selected.filter((entry) => entry.id !== reference.id))\n }\n />\n ) : null}\n <ComboBox\n aria-label={comboLabel}\n items={items\n .filter((item) => !selected.some((entry) => entry.id === item.id))\n .map((item) => ({ id: item.id, label: item.label }))}\n value={null}\n inputValue={query ?? ''}\n onInputChange={setQuery}\n onChange={(itemId) => {\n const reference = items.find((item) => item.id === itemId);\n if (reference !== undefined) {\n set([...selected, reference]);\n setQuery(null);\n }\n }}\n isLoading={isLoading}\n placeholder={placeholder}\n emptyMessage={intl.formatMessage(messages.noResults)}\n {...(onBlur !== undefined ? { onBlur: () => onBlur() } : {})}\n {...(name !== undefined ? { name } : {})}\n {...(id !== undefined ? { id } : {})}\n {...(controlClassName !== undefined ? { controlClassName } : {})}\n />\n </div>\n </Fieldset>\n );\n }\n\n const { onChange } = props;\n const current = selected[0] ?? null;\n // The selected reference is among the items, so that the combo box knows its label.\n const shown =\n current !== null && !items.some((item) => item.id === current.id)\n ? [current, ...items]\n : items;\n return (\n <ComboBox\n label={label}\n description={description}\n errors={errors}\n isRequired={required}\n className={className}\n labelClassName={labelClassName}\n descriptionClassName={descriptionClassName}\n errorsClassName={errorsClassName}\n {...(controlClassName !== undefined ? { controlClassName } : {})}\n {...(props['aria-label'] !== undefined ? { 'aria-label': props['aria-label'] } : {})}\n items={shown.map((item) => ({ id: item.id, label: item.label }))}\n value={current?.id ?? null}\n inputValue={query ?? current?.label ?? ''}\n onInputChange={(text) => {\n setQuery(text);\n if (text === '' && current !== null) {\n onChange?.(null);\n }\n }}\n onChange={(itemId) => {\n setQuery(null);\n if (itemId === null) {\n return;\n }\n const reference = shown.find((item) => item.id === itemId) ?? null;\n if (reference?.id !== current?.id) {\n onChange?.(reference);\n }\n }}\n isLoading={isLoading}\n placeholder={placeholder}\n emptyMessage={intl.formatMessage(messages.noResults)}\n {...(onBlur !== undefined\n ? {\n onBlur: () => {\n setQuery(null);\n onBlur();\n },\n }\n : { onBlur: () => setQuery(null) })}\n {...(name !== undefined ? { name } : {})}\n {...(id !== undefined ? { id } : {})}\n />\n );\n}\n\n/** The `relation` type: `resource` and `multiple`. Items search the fields context's source. */\nexport function RelationFieldEntry(props: FieldEntryProps) {\n const { field } = props;\n const references = toReferences(props.value);\n const shared = { ...getFieldProps(props), resource: field.resource ?? '' };\n if (field.multiple === true) {\n return <RelationField {...shared} multiple value={references} onChange={props.onChange} />;\n }\n return <RelationField {...shared} value={references[0] ?? null} onChange={props.onChange} />;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RelationField.js","names":["X","text","reference","item","entry","onChange","itemId","references","_c","styles","_Fragment"],"sources":["../../src/relation/RelationField.tsx"],"sourcesContent":["import { X } from 'lucide-react';\nimport { useEffect, useState } from 'react';\n\nimport { ComboBox, Fieldset, IconButton, usePanneauIntl } from '@panneau/ui';\n\nimport { useFieldsContext } from '../shared/context';\nimport { cx } from '../shared/cx';\nimport { getFieldProps } from '../shared/entry';\nimport { messages } from '../shared/messages';\nimport {\n type RelationReference,\n type RelationSource,\n toReferences,\n useRelationReferences,\n} from '../shared/relation';\nimport type { FieldEntryProps, FieldProps } from '../shared/types';\nimport styles from './RelationField.module.css';\n\n/** The id of the \"Create “…”\" option of the picker. */\nconst CREATE_ID = '\\u0000create';\n\n/** Results of a search in a relation source, as it types. */\nexport function useRelationSearch(\n source: RelationSource | null,\n resource: string,\n query: string,\n { enabled = true, delay = 250 }: { enabled?: boolean; delay?: number } = {},\n): { items: RelationReference[]; isLoading: boolean } {\n const [state, setState] = useState<{\n key: string;\n items: RelationReference[];\n isLoading: boolean;\n }>({ key: '', items: [], isLoading: false });\n const key = `${resource}\\u0000${query}`;\n\n useEffect(() => {\n if (source === null || !enabled) {\n return undefined;\n }\n const controller = new AbortController();\n const timer = setTimeout(() => {\n setState((current) => ({ ...current, key, isLoading: true }));\n source\n .search(resource, query, { signal: controller.signal })\n .then((items) => {\n if (!controller.signal.aborted) {\n setState({ key, items, isLoading: false });\n }\n })\n .catch(() => {\n if (!controller.signal.aborted) {\n setState({ key, items: [], isLoading: false });\n }\n });\n }, delay);\n return () => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [source, resource, query, key, enabled, delay]);\n\n return { items: state.items, isLoading: state.isLoading || state.key !== key };\n}\n\n/** Props of both single and multiple relation fields. */\nexport interface RelationFieldBaseProps extends Omit<FieldProps<never>, 'value' | 'onChange'> {\n /** Id of the related resource, passed to the source. */\n resource: string;\n /** Where to search. Defaults to the fields context's. Without one, the field is read-only. */\n source?: RelationSource | null;\n /**\n * Creates an item from the typed text, offered as \"Create “…”\" in the picker: it can open a\n * dialog, and resolves with the new reference, or `null` when nothing was created. Defaults to\n * the source's `create()`. `null` turns creating off.\n */\n onCreate?: ((text: string) => Promise<RelationReference | null>) | null;\n placeholder?: string;\n controlClassName?: string;\n}\n\nexport interface SingleRelationFieldProps extends RelationFieldBaseProps {\n multiple?: false;\n value?: RelationReference | null;\n onChange?: (value: RelationReference | null) => void;\n}\n\nexport interface MultipleRelationFieldProps extends RelationFieldBaseProps {\n multiple: true;\n value?: readonly RelationReference[] | null;\n /** Called with the references. An empty list is `null`. */\n onChange?: (value: RelationReference[] | null) => void;\n}\n\nexport type RelationFieldProps = SingleRelationFieldProps | MultipleRelationFieldProps;\n\nfunction References({\n references,\n onRemove,\n removeLabel,\n}: {\n references: readonly RelationReference[];\n onRemove?: (reference: RelationReference) => void;\n removeLabel: (reference: RelationReference) => string;\n}) {\n return (\n <ul className={cx(styles.selected, onRemove === undefined && styles.readOnly)}>\n {references.map((reference) => (\n <li key={reference.id} className={styles.reference}>\n <span className={styles.referenceLabel}>{reference.label}</span>\n {onRemove !== undefined ? (\n <IconButton\n icon={X}\n size=\"sm\"\n label={removeLabel(reference)}\n showTooltip={false}\n onPress={() => onRemove(reference)}\n />\n ) : null}\n </li>\n ))}\n </ul>\n );\n}\n\n/**\n * A reference to an item of another resource, or several with `multiple`, picked by searching a\n * `RelationSource`. Values are references (`{ id, label }`), as items carry them; plain ids get\n * their labels from the source's `resolve()`. When the source can `create()` (or with `onCreate`),\n * the picker offers to create an item from the typed text. Without a source, the field shows its\n * references and can't change them.\n */\nexport function RelationField(props: RelationFieldProps) {\n const intl = usePanneauIntl();\n const context = useFieldsContext();\n const source = props.source === undefined ? context.relationSource : props.source;\n const {\n resource,\n label,\n description,\n errors,\n disabled,\n readOnly,\n required,\n placeholder = intl.formatMessage(messages.search),\n onBlur,\n name,\n id,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n controlClassName,\n } = props;\n const selected = useRelationReferences(source, resource, toReferences(props.value));\n const [query, setQuery] = useState<string | null>(null);\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n const editable = source !== null && disabled !== true && readOnly !== true;\n const { items: found, isLoading: searching } = useRelationSearch(\n source,\n resource,\n query ?? '',\n { enabled: editable },\n );\n const sourceCreate = source?.create;\n const create =\n props.onCreate !== undefined\n ? props.onCreate\n : sourceCreate !== undefined && source?.canCreate?.(resource) !== false\n ? (text: string) => sourceCreate.call(source, resource, text)\n : null;\n const text = (query ?? '').trim();\n const offersCreate =\n create !== null &&\n text !== '' &&\n !searching &&\n ![...found, ...selected].some(\n (item) =>\n item.label.toLocaleLowerCase(intl.locale) === text.toLocaleLowerCase(intl.locale),\n );\n const items = offersCreate\n ? [\n ...found,\n { id: CREATE_ID, label: intl.formatMessage(messages.createRelation, { text }) },\n ]\n : found;\n const isLoading = searching || creating;\n const allErrors = createError !== null ? [...(errors ?? []), createError] : errors;\n /** Creates an item from the text, then adds its reference with `add`. */\n const createFrom = (add: (reference: RelationReference) => void) => {\n if (create === null) {\n return;\n }\n setCreating(true);\n setCreateError(null);\n create(text)\n .then((reference) => {\n if (reference !== null) {\n add(reference);\n setQuery(null);\n }\n })\n .catch(() =>\n setCreateError(intl.formatMessage(messages.createRelationFailed, { text })),\n )\n .finally(() => setCreating(false));\n };\n const removeLabel = (reference: RelationReference) =>\n `${intl.formatMessage(messages.remove)} ${reference.label}`;\n const chrome = {\n legend: label,\n errors: allErrors,\n isRequired: required,\n className,\n legendClassName: labelClassName,\n descriptionClassName,\n errorsClassName,\n };\n\n if (!editable) {\n return (\n <Fieldset\n {...chrome}\n description={\n source === null && disabled !== true && readOnly !== true ? (\n <>\n {description} {intl.formatMessage(messages.relationUnavailable)}\n </>\n ) : (\n description\n )\n }\n >\n {selected.length > 0 ? (\n <References references={selected} removeLabel={removeLabel} />\n ) : (\n <span className={styles.none}>{intl.formatMessage(messages.noRelation)}</span>\n )}\n </Fieldset>\n );\n }\n\n const comboLabel = typeof label === 'string' ? label : props['aria-label'];\n\n if (props.multiple === true) {\n const { onChange } = props;\n const set = (next: RelationReference[]) => onChange?.(next.length > 0 ? next : null);\n return (\n <Fieldset {...chrome} description={description}>\n <div className={styles.multiple}>\n {selected.length > 0 ? (\n <References\n references={selected}\n removeLabel={removeLabel}\n onRemove={(reference) =>\n set(selected.filter((entry) => entry.id !== reference.id))\n }\n />\n ) : null}\n <ComboBox\n aria-label={comboLabel}\n items={items\n .filter((item) => !selected.some((entry) => entry.id === item.id))\n .map((item) => ({ id: item.id, label: item.label }))}\n value={null}\n inputValue={query ?? ''}\n onInputChange={setQuery}\n onChange={(itemId) => {\n if (itemId === CREATE_ID) {\n createFrom((reference) => set([...selected, reference]));\n return;\n }\n const reference = found.find((item) => item.id === itemId);\n if (reference !== undefined) {\n set([...selected, reference]);\n setQuery(null);\n }\n }}\n isLoading={isLoading}\n placeholder={placeholder}\n emptyMessage={intl.formatMessage(messages.noResults)}\n {...(onBlur !== undefined ? { onBlur: () => onBlur() } : {})}\n {...(name !== undefined ? { name } : {})}\n {...(id !== undefined ? { id } : {})}\n {...(controlClassName !== undefined ? { controlClassName } : {})}\n />\n </div>\n </Fieldset>\n );\n }\n\n const { onChange } = props;\n const current = selected[0] ?? null;\n // The selected reference is among the items, so that the combo box knows its label.\n const shown =\n current !== null && !items.some((item) => item.id === current.id)\n ? [current, ...items]\n : items;\n return (\n <ComboBox\n label={label}\n description={description}\n errors={allErrors}\n isRequired={required}\n className={className}\n labelClassName={labelClassName}\n descriptionClassName={descriptionClassName}\n errorsClassName={errorsClassName}\n {...(controlClassName !== undefined ? { controlClassName } : {})}\n {...(props['aria-label'] !== undefined ? { 'aria-label': props['aria-label'] } : {})}\n items={shown.map((item) => ({ id: item.id, label: item.label }))}\n value={current?.id ?? null}\n inputValue={query ?? current?.label ?? ''}\n onInputChange={(text) => {\n setQuery(text);\n if (text === '' && current !== null) {\n onChange?.(null);\n }\n }}\n onChange={(itemId) => {\n if (itemId === CREATE_ID) {\n createFrom((reference) => onChange?.(reference));\n return;\n }\n setQuery(null);\n if (itemId === null) {\n return;\n }\n const reference = shown.find((item) => item.id === itemId) ?? null;\n if (reference?.id !== current?.id) {\n onChange?.(reference);\n }\n }}\n isLoading={isLoading}\n placeholder={placeholder}\n emptyMessage={intl.formatMessage(messages.noResults)}\n {...(onBlur !== undefined\n ? {\n onBlur: () => {\n setQuery(null);\n onBlur();\n },\n }\n : { onBlur: () => setQuery(null) })}\n {...(name !== undefined ? { name } : {})}\n {...(id !== undefined ? { id } : {})}\n />\n );\n}\n\n/** The `relation` type: `resource` and `multiple`. Items search the fields context's source. */\nexport function RelationFieldEntry(props: FieldEntryProps) {\n const { field } = props;\n const references = toReferences(props.value);\n const shared = { ...getFieldProps(props), resource: field.resource ?? '' };\n if (field.multiple === true) {\n return <RelationField {...shared} multiple value={references} onChange={props.onChange} />;\n }\n return <RelationField {...shared} value={references[0] ?? null} onChange={props.onChange} />;\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import "./RelationField.css";
|
|
2
2
|
//#region src/relation/RelationField.module.css
|
|
3
|
-
var multiple = "panneau-
|
|
4
|
-
var selected = "panneau-selected
|
|
5
|
-
var reference = "panneau-reference
|
|
6
|
-
var readOnly = "panneau-
|
|
7
|
-
var referenceLabel = "panneau-
|
|
8
|
-
var none = "panneau-none
|
|
3
|
+
var multiple = "panneau-relation-field-multiple";
|
|
4
|
+
var selected = "panneau-relation-field-selected";
|
|
5
|
+
var reference = "panneau-relation-field-reference";
|
|
6
|
+
var readOnly = "panneau-relation-field-read-only";
|
|
7
|
+
var referenceLabel = "panneau-relation-field-reference-label";
|
|
8
|
+
var none = "panneau-relation-field-none";
|
|
9
9
|
var RelationField_module_default = {
|
|
10
10
|
multiple,
|
|
11
11
|
selected,
|
package/dist/relation/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { type MultipleRelationFieldProps, type RelationFieldBaseProps, RelationField, RelationFieldEntry, type RelationFieldProps, type SingleRelationFieldProps, useRelationSearch, } from './RelationField';
|
|
2
|
-
export { type RelationListAdapter, type RelationReference, type RelationSource, type RelationSourceOptions, createRelationSource, } from '../shared/relation';
|
|
2
|
+
export { type RelationListAdapter, type RelationReference, type RelationSource, type RelationSourceOptions, createRelationSource, useRelationReferences, } from '../shared/relation';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,aAAa,EACb,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,iBAAiB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACH,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,aAAa,EACb,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,iBAAiB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACH,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,oBAAoB,EACpB,qBAAqB,GACxB,MAAM,oBAAoB,CAAC"}
|
package/dist/relation/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { createRelationSource } from "../shared/relation.js";
|
|
1
|
+
import { createRelationSource, useRelationReferences } from "../shared/relation.js";
|
|
2
2
|
import { RelationField, RelationFieldEntry, useRelationSearch } from "./RelationField.js";
|
|
3
|
-
export { RelationField, RelationFieldEntry, createRelationSource, useRelationSearch };
|
|
3
|
+
export { RelationField, RelationFieldEntry, createRelationSource, useRelationReferences, useRelationSearch };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.panneau-items
|
|
1
|
+
.panneau-repeater-field-items {
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
gap: var(--panneau-space-3);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
list-style: none;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
.panneau-item
|
|
10
|
+
.panneau-repeater-field-item {
|
|
11
11
|
display: flex;
|
|
12
12
|
flex-direction: column;
|
|
13
13
|
min-width: 0;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
border-radius: var(--panneau-radius-md);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
.panneau-header
|
|
19
|
+
.panneau-repeater-field-header {
|
|
20
20
|
display: flex;
|
|
21
21
|
align-items: center;
|
|
22
22
|
gap: var(--panneau-space-2);
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
border-start-end-radius: inherit;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
.panneau-title
|
|
32
|
+
.panneau-repeater-field-title {
|
|
33
33
|
flex: 1 1 auto;
|
|
34
34
|
min-width: 0;
|
|
35
35
|
overflow: hidden;
|
|
@@ -39,42 +39,43 @@
|
|
|
39
39
|
white-space: nowrap;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
.panneau-index
|
|
42
|
+
.panneau-repeater-field-index {
|
|
43
43
|
margin-inline-end: var(--panneau-space-2);
|
|
44
|
-
font-variant-numeric:
|
|
44
|
+
font-variant-numeric: var(--panneau-font-numeric);
|
|
45
45
|
color: var(--panneau-color-text-muted);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
.panneau-tools
|
|
48
|
+
.panneau-repeater-field-tools {
|
|
49
49
|
display: flex;
|
|
50
50
|
flex: 0 0 auto;
|
|
51
51
|
gap: var(--panneau-space-1);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
.panneau-body
|
|
54
|
+
.panneau-repeater-field-body {
|
|
55
55
|
display: flex;
|
|
56
56
|
flex-direction: column;
|
|
57
57
|
gap: var(--panneau-space-4);
|
|
58
58
|
padding: var(--panneau-space-4);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
.panneau-empty
|
|
61
|
+
.panneau-repeater-field-empty {
|
|
62
62
|
padding: var(--panneau-space-3);
|
|
63
63
|
font-size: var(--panneau-font-size-sm);
|
|
64
64
|
color: var(--panneau-color-text-muted);
|
|
65
65
|
text-align: center;
|
|
66
66
|
border: var(--panneau-border-width) dashed var(--panneau-color-border-control);
|
|
67
67
|
border-radius: var(--panneau-radius-md);
|
|
68
|
+
margin: 0;
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
.panneau-footer
|
|
71
|
+
.panneau-repeater-field-footer {
|
|
71
72
|
display: flex;
|
|
72
73
|
flex-wrap: wrap;
|
|
73
74
|
gap: var(--panneau-space-2);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
@media (max-width: 30rem) {
|
|
77
|
-
.panneau-body
|
|
78
|
+
.panneau-repeater-field-body {
|
|
78
79
|
padding: var(--panneau-space-3);
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import "./RepeaterField.css";
|
|
2
2
|
//#region src/repeater/RepeaterField.module.css
|
|
3
|
-
var items = "panneau-items
|
|
4
|
-
var item = "panneau-item
|
|
5
|
-
var header = "panneau-header
|
|
6
|
-
var title = "panneau-title
|
|
7
|
-
var index = "panneau-index
|
|
8
|
-
var tools = "panneau-tools
|
|
9
|
-
var body = "panneau-body
|
|
10
|
-
var empty = "panneau-empty
|
|
11
|
-
var footer = "panneau-footer
|
|
3
|
+
var items = "panneau-repeater-field-items";
|
|
4
|
+
var item = "panneau-repeater-field-item";
|
|
5
|
+
var header = "panneau-repeater-field-header";
|
|
6
|
+
var title = "panneau-repeater-field-title";
|
|
7
|
+
var index = "panneau-repeater-field-index";
|
|
8
|
+
var tools = "panneau-repeater-field-tools";
|
|
9
|
+
var body = "panneau-repeater-field-body";
|
|
10
|
+
var empty = "panneau-repeater-field-empty";
|
|
11
|
+
var footer = "panneau-repeater-field-footer";
|
|
12
12
|
var RepeaterField_module_default = {
|
|
13
13
|
items,
|
|
14
14
|
item,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepeaterField.module.js","names":[],"sources":["../../src/repeater/RepeaterField.module.css"],"sourcesContent":[".items {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-3);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.item {\n display: flex;\n flex-direction: column;\n min-width: 0;\n background-color: var(--panneau-color-surface);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-md);\n}\n\n.header {\n display: flex;\n align-items: center;\n gap: var(--panneau-space-2);\n min-height: var(--panneau-control-height);\n padding: var(--panneau-space-1) var(--panneau-space-1) var(--panneau-space-1)\n var(--panneau-space-3);\n background-color: var(--panneau-color-surface-sunken);\n border-bottom: var(--panneau-border-width) solid var(--panneau-color-border);\n border-start-start-radius: inherit;\n border-start-end-radius: inherit;\n}\n\n.title {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n font-size: var(--panneau-font-size-sm);\n font-weight: var(--panneau-font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.index {\n margin-inline-end: var(--panneau-space-2);\n font-variant-numeric:
|
|
1
|
+
{"version":3,"file":"RepeaterField.module.js","names":[],"sources":["../../src/repeater/RepeaterField.module.css"],"sourcesContent":[".items {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-3);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.item {\n display: flex;\n flex-direction: column;\n min-width: 0;\n background-color: var(--panneau-color-surface);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-md);\n}\n\n.header {\n display: flex;\n align-items: center;\n gap: var(--panneau-space-2);\n min-height: var(--panneau-control-height);\n padding: var(--panneau-space-1) var(--panneau-space-1) var(--panneau-space-1)\n var(--panneau-space-3);\n background-color: var(--panneau-color-surface-sunken);\n border-bottom: var(--panneau-border-width) solid var(--panneau-color-border);\n border-start-start-radius: inherit;\n border-start-end-radius: inherit;\n}\n\n.title {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n font-size: var(--panneau-font-size-sm);\n font-weight: var(--panneau-font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.index {\n margin-inline-end: var(--panneau-space-2);\n font-variant-numeric: var(--panneau-font-numeric);\n color: var(--panneau-color-text-muted);\n}\n\n.tools {\n display: flex;\n flex: 0 0 auto;\n gap: var(--panneau-space-1);\n}\n\n.body {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-4);\n padding: var(--panneau-space-4);\n}\n\n.empty {\n padding: var(--panneau-space-3);\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n text-align: center;\n border: var(--panneau-border-width) dashed var(--panneau-color-border-control);\n border-radius: var(--panneau-radius-md);\n margin: 0;\n}\n\n.footer {\n display: flex;\n flex-wrap: wrap;\n gap: var(--panneau-space-2);\n}\n\n@media (max-width: 30rem) {\n .body {\n padding: var(--panneau-space-3);\n }\n}\n"],"mappings":""}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./SelectField.css";
|
|
2
2
|
//#region src/select/SelectField.module.css
|
|
3
|
-
var checkboxes = "panneau-checkboxes
|
|
3
|
+
var checkboxes = "panneau-select-field-checkboxes";
|
|
4
4
|
var SelectField_module_default = { checkboxes };
|
|
5
5
|
//#endregion
|
|
6
6
|
export { checkboxes, SelectField_module_default as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefinitionField.d.ts","sourceRoot":"","sources":["../../src/shared/DefinitionField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"DefinitionField.d.ts","sourceRoot":"","sources":["../../src/shared/DefinitionField.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAU/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,4EAA4E;IAC5E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,SAAS,GACZ,EAAE,gBAAgB,sCAgClB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,+BAQrD"}
|
|
@@ -3,7 +3,7 @@ import { LocalizedFieldEntry } from "../localized/LocalizedField.js";
|
|
|
3
3
|
import { MissingFieldEntry } from "../missing/MissingField.js";
|
|
4
4
|
import { builtInFields } from "./builtIn.js";
|
|
5
5
|
import { c } from "react/compiler-runtime";
|
|
6
|
-
import { evaluateCondition } from "@panneau/protocol";
|
|
6
|
+
import { evaluateCondition } from "@panneau/protocol/runtime";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
8
|
//#region src/shared/DefinitionField.tsx
|
|
9
9
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefinitionField.js","names":["field","path","value","_c"],"sources":["../../src/shared/DefinitionField.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"DefinitionField.js","names":["field","path","value","_c"],"sources":["../../src/shared/DefinitionField.tsx"],"sourcesContent":["import type { Field } from '@panneau/protocol';\nimport { evaluateCondition } from '@panneau/protocol/runtime';\n\n// Groups, repeaters and localized values render nested fields, which render through\n// `DefinitionField`: the modules import each other, which is fine since they only use each other\n// while rendering.\nimport { LocalizedFieldEntry } from '../localized/LocalizedField';\nimport { MissingFieldEntry } from '../missing/MissingField';\nimport { builtInFields } from './builtIn';\nimport { getParentPath, useFieldsContext } from './context';\nimport type { FieldEntryProps } from './types';\n\nexport interface NestedFieldProps {\n field: Field;\n /** Dot path of the field's value. */\n path: string;\n /** The value, without a binding. */\n value?: unknown;\n /** Sets the value, without a binding. */\n onChange?: (value: unknown) => void;\n onBlur?: () => void;\n errors?: readonly string[];\n /** The object the field belongs to, for conditions and generated values. */\n parentValue?: unknown;\n disabled?: boolean;\n readOnly?: boolean;\n className?: string;\n}\n\n/**\n * A field inside another one (a group, a block, a localized value), or at the top of a form.\n * With a binding in context, the binding gives its value and decides whether it shows. Without\n * one, it uses `value` and `onChange`, and hides itself when its `visibleWhen` condition on the\n * parent value is false.\n */\nexport function NestedField({\n field,\n path,\n value,\n onChange,\n onBlur,\n errors,\n parentValue,\n disabled,\n readOnly,\n className,\n}: NestedFieldProps) {\n const { binding: Binding } = useFieldsContext();\n const shared = {\n field,\n path,\n parentValue,\n ...(disabled !== undefined ? { disabled } : {}),\n ...(readOnly !== undefined ? { readOnly } : {}),\n ...(className !== undefined ? { className } : {}),\n };\n if (Binding !== null) {\n return (\n <Binding\n field={field}\n path={path}\n parentPath={getParentPath(path)}\n render={(bound) => <DefinitionField {...shared} {...bound} />}\n />\n );\n }\n if (field.visibleWhen !== undefined && !evaluateCondition(field.visibleWhen, parentValue)) {\n return null;\n }\n return (\n <DefinitionField\n {...shared}\n value={value}\n onChange={onChange ?? (() => undefined)}\n {...(onBlur !== undefined ? { onBlur } : {})}\n {...(errors !== undefined ? { errors } : {})}\n />\n );\n}\n\n/**\n * Renders a field of the definition with the entry of its type: from the fields context, or a\n * built-in one. A localized field renders an input per locale. A type without an entry renders a\n * placeholder that names the missing plugin.\n */\nexport function DefinitionField(props: FieldEntryProps) {\n const { components } = useFieldsContext();\n const { field } = props;\n if (field.localized === true) {\n return <LocalizedFieldEntry {...props} />;\n }\n const Entry = components[field.type] ?? builtInFields[field.type] ?? MissingFieldEntry;\n return <Entry {...props} />;\n}\n"],"mappings":"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"}
|
|
@@ -10,28 +10,64 @@ export interface RelationSource {
|
|
|
10
10
|
search(resource: string, query: string, options: {
|
|
11
11
|
signal: AbortSignal;
|
|
12
12
|
}): Promise<RelationReference[]>;
|
|
13
|
+
/**
|
|
14
|
+
* The references of items by id, for values that are only ids (`"12"`, `["12", "13"]`), as a
|
|
15
|
+
* product's own API gives them. In any order; ids it doesn't find are left out, and keep their
|
|
16
|
+
* id as label. Without it, fields show the ids.
|
|
17
|
+
*/
|
|
18
|
+
resolve?(resource: string, ids: readonly string[], options: {
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
}): Promise<RelationReference[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Creates an item from the text typed in the picker, which offers "Create “…”" when this
|
|
23
|
+
* method exists. It can open a dialog, and resolves with the reference of the new item, or with
|
|
24
|
+
* `null` when nothing was created.
|
|
25
|
+
*/
|
|
26
|
+
create?(resource: string, text: string): Promise<RelationReference | null>;
|
|
27
|
+
/** Whether `create()` can create items of a resource. Defaults to true. */
|
|
28
|
+
canCreate?(resource: string): boolean;
|
|
13
29
|
}
|
|
14
|
-
/** What `createRelationSource()` needs from an adapter: the `list()` of `@panneau/data`. */
|
|
30
|
+
/** What `createRelationSource()` needs from an adapter: the `list()`, `get()` and `create()` of `@panneau/data`. */
|
|
15
31
|
export interface RelationListAdapter {
|
|
16
32
|
list(resource: string, query?: ListQuery, options?: {
|
|
17
33
|
signal?: AbortSignal;
|
|
18
34
|
}): Promise<{
|
|
19
35
|
data: Item[];
|
|
20
36
|
}>;
|
|
37
|
+
/** One item, for `resolve()`. Without it, the source doesn't resolve ids. */
|
|
38
|
+
get?(resource: string, id: string, options?: {
|
|
39
|
+
signal?: AbortSignal;
|
|
40
|
+
}): Promise<Item>;
|
|
41
|
+
/** Creates an item, for `create()`. */
|
|
42
|
+
create?(resource: string, values: Record<string, unknown>): Promise<Item>;
|
|
21
43
|
}
|
|
22
44
|
export interface RelationSourceOptions {
|
|
23
45
|
/** The definition, for the field that titles the items of each resource (`itemTitle`). */
|
|
24
|
-
definition?: Pick<Definition, 'resources'> | null;
|
|
46
|
+
definition?: (Pick<Definition, 'resources'> & Partial<Pick<Definition, 'locales'>>) | null;
|
|
25
47
|
/** Items per search. Defaults to 20. */
|
|
26
48
|
perPage?: number;
|
|
27
49
|
/** The label of an item, when `itemTitle` isn't enough. */
|
|
28
50
|
getLabel?: (item: Item, resource: string) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Lets the picker create items, with the adapter's `create()`. `true` sets the typed text as the
|
|
53
|
+
* value of the resource's `itemTitle` field (in every locale of the definition when it is
|
|
54
|
+
* localized), on the resources that allow `create`. A function gives the values of the new item
|
|
55
|
+
* instead, or `null` for a resource where items can't be created.
|
|
56
|
+
*/
|
|
57
|
+
create?: boolean | ((text: string, resource: string) => Record<string, unknown> | null);
|
|
29
58
|
}
|
|
30
59
|
/**
|
|
31
|
-
* A relation source over an adapter
|
|
32
|
-
*
|
|
60
|
+
* A relation source over an adapter, such as the `DataAdapter` of `@panneau/data`: a search is a
|
|
61
|
+
* list query with `q`, ids are resolved with `get()`, and, with the `create` option, items are
|
|
62
|
+
* created with `create()`. Labels come from the resource's `itemTitle`.
|
|
33
63
|
*/
|
|
34
|
-
export declare function createRelationSource(adapter: RelationListAdapter, { definition, perPage, getLabel }?: RelationSourceOptions): RelationSource;
|
|
64
|
+
export declare function createRelationSource(adapter: RelationListAdapter, { definition, perPage, getLabel, create }?: RelationSourceOptions): RelationSource;
|
|
35
65
|
/** Reads relation values: references, ids, or lists of them. */
|
|
36
66
|
export declare function toReferences(value: unknown): RelationReference[];
|
|
67
|
+
/**
|
|
68
|
+
* Relation references with the labels of plain ids: references whose label is their id (from
|
|
69
|
+
* `"12"`) are resolved with the source's `resolve()`, once per source, resource and id. They keep
|
|
70
|
+
* their id as label until then, or when the source doesn't find them.
|
|
71
|
+
*/
|
|
72
|
+
export declare function useRelationReferences(source: RelationSource | null, resource: string, references: readonly RelationReference[]): RelationReference[];
|
|
37
73
|
//# sourceMappingURL=relation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/shared/relation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/shared/relation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAErE,qFAAqF;AACrF,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,8CAA8C;AAC9C,MAAM,WAAW,cAAc;IAC3B,6DAA6D;IAC7D,MAAM,CACF,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,MAAM,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAChC;;;;OAIG;IACH,OAAO,CAAC,CACJ,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,SAAS,MAAM,EAAE,EACtB,OAAO,EAAE;QAAE,MAAM,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC3E,2EAA2E;IAC3E,SAAS,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CACzC;AAED,oHAAoH;AACpH,MAAM,WAAW,mBAAmB;IAChC,IAAI,CACA,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,SAAS,EACjB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACnC,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,EAAE,CAAA;KAAE,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtF,uCAAuC;IACvC,MAAM,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,qBAAqB;IAClC,0FAA0F;IAC1F,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC3F,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACpD;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;CAC3F;AAeD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAChC,OAAO,EAAE,mBAAmB,EAC5B,EAAE,UAAiB,EAAE,OAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAE,qBAA0B,GAClF,cAAc,CAgEhB;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,EAAE,CAkBhE;AAiDD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACjC,MAAM,EAAE,cAAc,GAAG,IAAI,EAC7B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,iBAAiB,EAAE,GACzC,iBAAiB,EAAE,CA2CrB"}
|
package/dist/shared/relation.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
1
3
|
//#region src/shared/relation.ts
|
|
2
4
|
function labelOf(value, locale) {
|
|
3
5
|
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
@@ -9,22 +11,48 @@ function labelOf(value, locale) {
|
|
|
9
11
|
return null;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
|
-
* A relation source over an adapter
|
|
13
|
-
*
|
|
14
|
+
* A relation source over an adapter, such as the `DataAdapter` of `@panneau/data`: a search is a
|
|
15
|
+
* list query with `q`, ids are resolved with `get()`, and, with the `create` option, items are
|
|
16
|
+
* created with `create()`. Labels come from the resource's `itemTitle`.
|
|
14
17
|
*/
|
|
15
|
-
function createRelationSource(adapter, { definition = null, perPage = 20, getLabel } = {}) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
function createRelationSource(adapter, { definition = null, perPage = 20, getLabel, create } = {}) {
|
|
19
|
+
const resourceOf = (resource) => definition?.resources.find((candidate) => candidate.id === resource);
|
|
20
|
+
const toReference = (item, resource) => {
|
|
21
|
+
const titleField = resourceOf(resource)?.itemTitle;
|
|
22
|
+
return {
|
|
23
|
+
id: item.id,
|
|
24
|
+
label: getLabel?.(item, resource) ?? (titleField !== void 0 ? labelOf(item[titleField]) : null) ?? item.id
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const valuesOf = (text, resource) => {
|
|
28
|
+
if (typeof create === "function") return create(text, resource);
|
|
29
|
+
const definitionResource = resourceOf(resource);
|
|
30
|
+
const titleField = definitionResource?.itemTitle;
|
|
31
|
+
if (definitionResource === void 0 || titleField === void 0) return null;
|
|
32
|
+
const field = definitionResource.fields.find((candidate) => candidate.name === titleField);
|
|
33
|
+
const locales = definition?.locales ?? [];
|
|
34
|
+
return { [titleField]: field?.localized === true && locales.length > 0 ? Object.fromEntries(locales.map((locale) => [locale, text])) : text };
|
|
35
|
+
};
|
|
36
|
+
const source = { async search(resource, query, { signal }) {
|
|
37
|
+
return (await adapter.list(resource, {
|
|
18
38
|
page: 1,
|
|
19
39
|
perPage,
|
|
20
40
|
...query !== "" ? { q: query } : {}
|
|
21
|
-
}, { signal });
|
|
22
|
-
const titleField = definition?.resources.find((r) => r.id === resource)?.itemTitle;
|
|
23
|
-
return response.data.map((item) => ({
|
|
24
|
-
id: item.id,
|
|
25
|
-
label: getLabel?.(item, resource) ?? (titleField !== void 0 ? labelOf(item[titleField]) : null) ?? item.id
|
|
26
|
-
}));
|
|
41
|
+
}, { signal })).data.map((item) => toReference(item, resource));
|
|
27
42
|
} };
|
|
43
|
+
const { get, create: createItem } = adapter;
|
|
44
|
+
if (get !== void 0) source.resolve = async (resource, ids, { signal }) => {
|
|
45
|
+
return (await Promise.allSettled(ids.map((id) => get.call(adapter, resource, id, { signal })))).flatMap((result) => result.status === "fulfilled" ? [toReference(result.value, resource)] : []);
|
|
46
|
+
};
|
|
47
|
+
if (create !== void 0 && create !== false && createItem !== void 0) {
|
|
48
|
+
source.canCreate = (resource) => resourceOf(resource)?.abilities?.create !== false && valuesOf("", resource) !== null;
|
|
49
|
+
source.create = async (resource, text) => {
|
|
50
|
+
const values = valuesOf(text, resource);
|
|
51
|
+
if (values === null) return null;
|
|
52
|
+
return toReference(await createItem.call(adapter, resource, values), resource);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return source;
|
|
28
56
|
}
|
|
29
57
|
/** Reads relation values: references, ids, or lists of them. */
|
|
30
58
|
function toReferences(value) {
|
|
@@ -43,7 +71,86 @@ function toReferences(value) {
|
|
|
43
71
|
return [];
|
|
44
72
|
});
|
|
45
73
|
}
|
|
74
|
+
var resolved = /* @__PURE__ */ new WeakMap();
|
|
75
|
+
function resolvedOf(source) {
|
|
76
|
+
let entry = resolved.get(source);
|
|
77
|
+
if (entry === void 0) {
|
|
78
|
+
entry = {
|
|
79
|
+
labels: /* @__PURE__ */ new Map(),
|
|
80
|
+
pending: /* @__PURE__ */ new Map()
|
|
81
|
+
};
|
|
82
|
+
resolved.set(source, entry);
|
|
83
|
+
}
|
|
84
|
+
return entry;
|
|
85
|
+
}
|
|
86
|
+
var keyOf = (resource, id) => `${resource}\u0000${id}`;
|
|
87
|
+
/** Resolves the ids that no request has resolved or is resolving yet, and waits for all of them. */
|
|
88
|
+
function resolveIds(source, resource, ids) {
|
|
89
|
+
const { labels, pending } = resolvedOf(source);
|
|
90
|
+
const fresh = ids.filter((id) => !pending.has(keyOf(resource, id)));
|
|
91
|
+
if (fresh.length > 0 && source.resolve !== void 0) {
|
|
92
|
+
const request = source.resolve(resource, fresh, { signal: new AbortController().signal }).then((found) => {
|
|
93
|
+
fresh.forEach((id) => labels.set(keyOf(resource, id), found.find((candidate) => candidate.id === id)?.label ?? null));
|
|
94
|
+
}, () => {
|
|
95
|
+
fresh.forEach((id) => pending.delete(keyOf(resource, id)));
|
|
96
|
+
});
|
|
97
|
+
fresh.forEach((id) => pending.set(keyOf(resource, id), request));
|
|
98
|
+
}
|
|
99
|
+
return Promise.all(ids.map((id) => pending.get(keyOf(resource, id))));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Relation references with the labels of plain ids: references whose label is their id (from
|
|
103
|
+
* `"12"`) are resolved with the source's `resolve()`, once per source, resource and id. They keep
|
|
104
|
+
* their id as label until then, or when the source doesn't find them.
|
|
105
|
+
*/
|
|
106
|
+
function useRelationReferences(source, resource, references) {
|
|
107
|
+
const $ = c(1);
|
|
108
|
+
const cache = source !== null ? resolvedOf(source).labels : null;
|
|
109
|
+
let t0;
|
|
110
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
111
|
+
t0 = {};
|
|
112
|
+
$[0] = t0;
|
|
113
|
+
} else t0 = $[0];
|
|
114
|
+
const [labels, setLabels] = useState(t0);
|
|
115
|
+
const label = (id) => labels[keyOf(resource, id)] ?? cache?.get(keyOf(resource, id)) ?? void 0;
|
|
116
|
+
const missingKey = (source?.resolve !== void 0 && cache !== null ? references.filter(_temp).map(_temp2).filter((id_0) => !cache.has(keyOf(resource, id_0))) : []).join("\0");
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
const ids = missingKey === "" ? [] : missingKey.split("\0");
|
|
119
|
+
if (source === null || cache === null || ids.length === 0) return;
|
|
120
|
+
let active = true;
|
|
121
|
+
resolveIds(source, resource, ids).then(() => {
|
|
122
|
+
if (!active) return;
|
|
123
|
+
const next = {};
|
|
124
|
+
ids.forEach((id_1) => {
|
|
125
|
+
const found = cache.get(keyOf(resource, id_1));
|
|
126
|
+
if (typeof found === "string") next[keyOf(resource, id_1)] = found;
|
|
127
|
+
});
|
|
128
|
+
setLabels((current) => ({
|
|
129
|
+
...current,
|
|
130
|
+
...next
|
|
131
|
+
}));
|
|
132
|
+
});
|
|
133
|
+
return () => {
|
|
134
|
+
active = false;
|
|
135
|
+
};
|
|
136
|
+
}, [
|
|
137
|
+
source,
|
|
138
|
+
cache,
|
|
139
|
+
resource,
|
|
140
|
+
missingKey
|
|
141
|
+
]);
|
|
142
|
+
return references.map((reference_1) => reference_1.label === reference_1.id ? {
|
|
143
|
+
id: reference_1.id,
|
|
144
|
+
label: label(reference_1.id) ?? reference_1.id
|
|
145
|
+
} : reference_1);
|
|
146
|
+
}
|
|
147
|
+
function _temp2(reference_0) {
|
|
148
|
+
return reference_0.id;
|
|
149
|
+
}
|
|
150
|
+
function _temp(reference) {
|
|
151
|
+
return reference.label === reference.id;
|
|
152
|
+
}
|
|
46
153
|
//#endregion
|
|
47
|
-
export { createRelationSource, toReferences };
|
|
154
|
+
export { createRelationSource, toReferences, useRelationReferences };
|
|
48
155
|
|
|
49
156
|
//# sourceMappingURL=relation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation.js","names":[],"sources":["../../src/shared/relation.ts"],"sourcesContent":["import type { Definition, Item, ListQuery } from '@panneau/protocol';\n\n/** A related item: its id, and a label to show it. The value of a relation field. */\nexport interface RelationReference {\n id: string;\n label: string;\n}\n\n/** Where relation fields search for items. */\nexport interface RelationSource {\n /** Items of a resource that match a text, for the picker. */\n search(\n resource: string,\n query: string,\n options: { signal: AbortSignal },\n ): Promise<RelationReference[]>;\n}\n\n/** What `createRelationSource()` needs from an adapter: the `list()` of `@panneau/data`. */\nexport interface RelationListAdapter {\n list(\n resource: string,\n query?: ListQuery,\n options?: { signal?: AbortSignal },\n ): Promise<{ data: Item[] }>;\n}\n\nexport interface RelationSourceOptions {\n /** The definition, for the field that titles the items of each resource (`itemTitle`). */\n definition?: Pick<Definition, 'resources'> | null;\n /** Items per search. Defaults to 20. */\n perPage?: number;\n /** The label of an item, when `itemTitle` isn't enough. */\n getLabel?: (item: Item, resource: string) => string;\n}\n\nfunction labelOf(value: unknown, locale?: string): string | null {\n if (typeof value === 'string' || typeof value === 'number') {\n return String(value);\n }\n if (value !== null && typeof value === 'object') {\n const localized = value as Record<string, unknown>;\n const first =\n (locale !== undefined ? localized[locale] : undefined) ?? Object.values(localized)[0];\n return typeof first === 'string' ? first : null;\n }\n return null;\n}\n\n/**\n * A relation source over an adapter's `list()`, such as the `DataAdapter` of `@panneau/data`: a\n * search is a list query with `q`. Labels come from the resource's `itemTitle`.\n */\nexport function createRelationSource(\n adapter: RelationListAdapter,\n { definition = null, perPage = 20, getLabel }: RelationSourceOptions = {},\n): RelationSource {\n return {\n async search(resource, query, { signal }) {\n const response = await adapter.list(\n resource,\n { page: 1, perPage, ...(query !== '' ? { q: query } : {}) },\n { signal },\n );\n const titleField = definition?.resources.find((r) => r.id === resource)?.itemTitle;\n return response.data.map((item) => ({\n id: item.id,\n label:\n getLabel?.(item, resource) ??\n (titleField !== undefined ? labelOf(item[titleField]) : null) ??\n item.id,\n }));\n },\n };\n}\n\n/** Reads relation values: references, ids, or lists of them. */\nexport function toReferences(value: unknown): RelationReference[] {\n const list = Array.isArray(value)\n ? value\n : value === null || value === undefined\n ? []\n : [value];\n return list.flatMap((entry: unknown) => {\n if (typeof entry === 'string' || typeof entry === 'number') {\n return [{ id: String(entry), label: String(entry) }];\n }\n if (entry !== null && typeof entry === 'object' && 'id' in entry) {\n const { id, label } = entry as { id: unknown; label?: unknown };\n if (typeof id === 'string' || typeof id === 'number') {\n return [{ id: String(id), label: typeof label === 'string' ? label : String(id) }];\n }\n }\n return [];\n });\n}\n"],"mappings":";AAoCA,SAAS,QAAQ,OAAgB,QAAgC;CAC7D,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAC9C,OAAO,OAAO,KAAK;CAEvB,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;EAC7C,MAAM,YAAY;EAClB,MAAM,SACD,WAAW,KAAA,IAAY,UAAU,UAAU,KAAA,MAAc,OAAO,OAAO,SAAS,CAAC,CAAC;EACvF,OAAO,OAAO,UAAU,WAAW,QAAQ;CAC/C;CACA,OAAO;AACX;;;;;AAMA,SAAgB,qBACZ,SACA,EAAE,aAAa,MAAM,UAAU,IAAI,aAAoC,CAAC,GAC1D;CACd,OAAO,EACH,MAAM,OAAO,UAAU,OAAO,EAAE,UAAU;EACtC,MAAM,WAAW,MAAM,QAAQ,KAC3B,UACA;GAAE,MAAM;GAAG;GAAS,GAAI,UAAU,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC;EAAG,GAC1D,EAAE,OAAO,CACb;EACA,MAAM,aAAa,YAAY,UAAU,MAAM,MAAM,EAAE,OAAO,QAAQ,CAAC,EAAE;EACzE,OAAO,SAAS,KAAK,KAAK,UAAU;GAChC,IAAI,KAAK;GACT,OACI,WAAW,MAAM,QAAQ,MACxB,eAAe,KAAA,IAAY,QAAQ,KAAK,WAAW,IAAI,SACxD,KAAK;EACb,EAAE;CACN,EACJ;AACJ;;AAGA,SAAgB,aAAa,OAAqC;CAM9D,QALa,MAAM,QAAQ,KAAK,IAC1B,QACA,UAAU,QAAQ,UAAU,KAAA,IAC1B,CAAA,IACA,CAAC,KAAK,EAAA,CACF,SAAS,UAAmB;EACpC,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAC9C,OAAO,CAAC;GAAE,IAAI,OAAO,KAAK;GAAG,OAAO,OAAO,KAAK;EAAE,CAAC;EAEvD,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,QAAQ,OAAO;GAC9D,MAAM,EAAE,IAAI,UAAU;GACtB,IAAI,OAAO,OAAO,YAAY,OAAO,OAAO,UACxC,OAAO,CAAC;IAAE,IAAI,OAAO,EAAE;IAAG,OAAO,OAAO,UAAU,WAAW,QAAQ,OAAO,EAAE;GAAE,CAAC;EAEzF;EACA,OAAO,CAAA;CACX,CAAC;AACL"}
|
|
1
|
+
{"version":3,"file":"relation.js","names":["id","active","reference","_c"],"sources":["../../src/shared/relation.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nimport type { Definition, Item, ListQuery } from '@panneau/protocol';\n\n/** A related item: its id, and a label to show it. The value of a relation field. */\nexport interface RelationReference {\n id: string;\n label: string;\n}\n\n/** Where relation fields search for items. */\nexport interface RelationSource {\n /** Items of a resource that match a text, for the picker. */\n search(\n resource: string,\n query: string,\n options: { signal: AbortSignal },\n ): Promise<RelationReference[]>;\n /**\n * The references of items by id, for values that are only ids (`\"12\"`, `[\"12\", \"13\"]`), as a\n * product's own API gives them. In any order; ids it doesn't find are left out, and keep their\n * id as label. Without it, fields show the ids.\n */\n resolve?(\n resource: string,\n ids: readonly string[],\n options: { signal: AbortSignal },\n ): Promise<RelationReference[]>;\n /**\n * Creates an item from the text typed in the picker, which offers \"Create “…”\" when this\n * method exists. It can open a dialog, and resolves with the reference of the new item, or with\n * `null` when nothing was created.\n */\n create?(resource: string, text: string): Promise<RelationReference | null>;\n /** Whether `create()` can create items of a resource. Defaults to true. */\n canCreate?(resource: string): boolean;\n}\n\n/** What `createRelationSource()` needs from an adapter: the `list()`, `get()` and `create()` of `@panneau/data`. */\nexport interface RelationListAdapter {\n list(\n resource: string,\n query?: ListQuery,\n options?: { signal?: AbortSignal },\n ): Promise<{ data: Item[] }>;\n /** One item, for `resolve()`. Without it, the source doesn't resolve ids. */\n get?(resource: string, id: string, options?: { signal?: AbortSignal }): Promise<Item>;\n /** Creates an item, for `create()`. */\n create?(resource: string, values: Record<string, unknown>): Promise<Item>;\n}\n\nexport interface RelationSourceOptions {\n /** The definition, for the field that titles the items of each resource (`itemTitle`). */\n definition?: (Pick<Definition, 'resources'> & Partial<Pick<Definition, 'locales'>>) | null;\n /** Items per search. Defaults to 20. */\n perPage?: number;\n /** The label of an item, when `itemTitle` isn't enough. */\n getLabel?: (item: Item, resource: string) => string;\n /**\n * Lets the picker create items, with the adapter's `create()`. `true` sets the typed text as the\n * value of the resource's `itemTitle` field (in every locale of the definition when it is\n * localized), on the resources that allow `create`. A function gives the values of the new item\n * instead, or `null` for a resource where items can't be created.\n */\n create?: boolean | ((text: string, resource: string) => Record<string, unknown> | null);\n}\n\nfunction labelOf(value: unknown, locale?: string): string | null {\n if (typeof value === 'string' || typeof value === 'number') {\n return String(value);\n }\n if (value !== null && typeof value === 'object') {\n const localized = value as Record<string, unknown>;\n const first =\n (locale !== undefined ? localized[locale] : undefined) ?? Object.values(localized)[0];\n return typeof first === 'string' ? first : null;\n }\n return null;\n}\n\n/**\n * A relation source over an adapter, such as the `DataAdapter` of `@panneau/data`: a search is a\n * list query with `q`, ids are resolved with `get()`, and, with the `create` option, items are\n * created with `create()`. Labels come from the resource's `itemTitle`.\n */\nexport function createRelationSource(\n adapter: RelationListAdapter,\n { definition = null, perPage = 20, getLabel, create }: RelationSourceOptions = {},\n): RelationSource {\n const resourceOf = (resource: string) =>\n definition?.resources.find((candidate) => candidate.id === resource);\n const toReference = (item: Item, resource: string): RelationReference => {\n const titleField = resourceOf(resource)?.itemTitle;\n return {\n id: item.id,\n label:\n getLabel?.(item, resource) ??\n (titleField !== undefined ? labelOf(item[titleField]) : null) ??\n item.id,\n };\n };\n const valuesOf = (text: string, resource: string): Record<string, unknown> | null => {\n if (typeof create === 'function') {\n return create(text, resource);\n }\n const definitionResource = resourceOf(resource);\n const titleField = definitionResource?.itemTitle;\n if (definitionResource === undefined || titleField === undefined) {\n return null;\n }\n const field = definitionResource.fields.find((candidate) => candidate.name === titleField);\n const locales = definition?.locales ?? [];\n return {\n [titleField]:\n field?.localized === true && locales.length > 0\n ? Object.fromEntries(locales.map((locale) => [locale, text]))\n : text,\n };\n };\n const source: RelationSource = {\n async search(resource, query, { signal }) {\n const response = await adapter.list(\n resource,\n { page: 1, perPage, ...(query !== '' ? { q: query } : {}) },\n { signal },\n );\n return response.data.map((item) => toReference(item, resource));\n },\n };\n const { get, create: createItem } = adapter;\n if (get !== undefined) {\n source.resolve = async (resource, ids, { signal }) => {\n const results = await Promise.allSettled(\n ids.map((id) => get.call(adapter, resource, id, { signal })),\n );\n return results.flatMap((result) =>\n result.status === 'fulfilled' ? [toReference(result.value, resource)] : [],\n );\n };\n }\n if (create !== undefined && create !== false && createItem !== undefined) {\n source.canCreate = (resource) =>\n resourceOf(resource)?.abilities?.create !== false && valuesOf('', resource) !== null;\n source.create = async (resource, text) => {\n const values = valuesOf(text, resource);\n if (values === null) {\n return null;\n }\n return toReference(await createItem.call(adapter, resource, values), resource);\n };\n }\n return source;\n}\n\n/** Reads relation values: references, ids, or lists of them. */\nexport function toReferences(value: unknown): RelationReference[] {\n const list = Array.isArray(value)\n ? value\n : value === null || value === undefined\n ? []\n : [value];\n return list.flatMap((entry: unknown) => {\n if (typeof entry === 'string' || typeof entry === 'number') {\n return [{ id: String(entry), label: String(entry) }];\n }\n if (entry !== null && typeof entry === 'object' && 'id' in entry) {\n const { id, label } = entry as { id: unknown; label?: unknown };\n if (typeof id === 'string' || typeof id === 'number') {\n return [{ id: String(id), label: typeof label === 'string' ? label : String(id) }];\n }\n }\n return [];\n });\n}\n\ninterface ResolvedLabels {\n /** Labels by resource and id: `null` for ids that the source didn't find. */\n labels: Map<string, string | null>;\n /** Requests in flight, so that fields with the same ids share one. */\n pending: Map<string, Promise<void>>;\n}\n\nconst resolved = new WeakMap<RelationSource, ResolvedLabels>();\n\nfunction resolvedOf(source: RelationSource): ResolvedLabels {\n let entry = resolved.get(source);\n if (entry === undefined) {\n entry = { labels: new Map(), pending: new Map() };\n resolved.set(source, entry);\n }\n return entry;\n}\n\nconst keyOf = (resource: string, id: string) => `${resource}\\u0000${id}`;\n\n/** Resolves the ids that no request has resolved or is resolving yet, and waits for all of them. */\nfunction resolveIds(source: RelationSource, resource: string, ids: readonly string[]) {\n const { labels, pending } = resolvedOf(source);\n const fresh = ids.filter((id) => !pending.has(keyOf(resource, id)));\n if (fresh.length > 0 && source.resolve !== undefined) {\n // Shared by every field that asks for these ids: it isn't aborted when one unmounts.\n const request = source\n .resolve(resource, fresh, { signal: new AbortController().signal })\n .then(\n (found) => {\n fresh.forEach((id) =>\n labels.set(\n keyOf(resource, id),\n found.find((candidate) => candidate.id === id)?.label ?? null,\n ),\n );\n },\n () => {\n // Tried again the next time a field shows these ids.\n fresh.forEach((id) => pending.delete(keyOf(resource, id)));\n },\n );\n fresh.forEach((id) => pending.set(keyOf(resource, id), request));\n }\n return Promise.all(ids.map((id) => pending.get(keyOf(resource, id))));\n}\n\n/**\n * Relation references with the labels of plain ids: references whose label is their id (from\n * `\"12\"`) are resolved with the source's `resolve()`, once per source, resource and id. They keep\n * their id as label until then, or when the source doesn't find them.\n */\nexport function useRelationReferences(\n source: RelationSource | null,\n resource: string,\n references: readonly RelationReference[],\n): RelationReference[] {\n const cache = source !== null ? resolvedOf(source).labels : null;\n const [labels, setLabels] = useState<Readonly<Record<string, string>>>({});\n const label = (id: string): string | undefined =>\n labels[keyOf(resource, id)] ?? cache?.get(keyOf(resource, id)) ?? undefined;\n const missing =\n source?.resolve !== undefined && cache !== null\n ? references\n .filter((reference) => reference.label === reference.id)\n .map((reference) => reference.id)\n .filter((id) => !cache.has(keyOf(resource, id)))\n : [];\n const missingKey = missing.join('\\u0000');\n\n useEffect(() => {\n const ids = missingKey === '' ? [] : missingKey.split('\\u0000');\n if (source === null || cache === null || ids.length === 0) {\n return undefined;\n }\n let active = true;\n void resolveIds(source, resource, ids).then(() => {\n if (!active) {\n return;\n }\n const next: Record<string, string> = {};\n ids.forEach((id) => {\n const found = cache.get(keyOf(resource, id));\n if (typeof found === 'string') {\n next[keyOf(resource, id)] = found;\n }\n });\n setLabels((current) => ({ ...current, ...next }));\n });\n return () => {\n active = false;\n };\n }, [source, cache, resource, missingKey]);\n\n return references.map((reference) =>\n reference.label === reference.id\n ? { id: reference.id, label: label(reference.id) ?? reference.id }\n : reference,\n );\n}\n"],"mappings":"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"}
|
package/dist/url/UrlField.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.panneau-open
|
|
1
|
+
.panneau-url-field-open {
|
|
2
2
|
display: inline-flex;
|
|
3
3
|
align-items: center;
|
|
4
4
|
padding: var(--panneau-space-1);
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
border-radius: var(--panneau-radius-sm);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
.panneau-open
|
|
9
|
+
.panneau-url-field-open:hover {
|
|
10
10
|
color: var(--panneau-color-text);
|
|
11
11
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panneau/fields",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.2",
|
|
4
4
|
"description": "Controlled field components of Panneau for the protocol's built-in field types, one subpath per field.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -122,9 +122,9 @@
|
|
|
122
122
|
},
|
|
123
123
|
"dependencies": {
|
|
124
124
|
"@internationalized/date": "^3.12.4",
|
|
125
|
-
"@panneau/intl": "5.0.0-alpha.
|
|
126
|
-
"@panneau/protocol": "5.0.0-alpha.
|
|
127
|
-
"@panneau/ui": "5.0.0-alpha.
|
|
125
|
+
"@panneau/intl": "5.0.0-alpha.2",
|
|
126
|
+
"@panneau/protocol": "5.0.0-alpha.2",
|
|
127
|
+
"@panneau/ui": "5.0.0-alpha.2",
|
|
128
128
|
"lucide-react": "^1.57.0"
|
|
129
129
|
}
|
|
130
130
|
}
|