Skip to content

Commit 9e8e5b8

Browse files
committed
Fix #111 - Add experimental compute widget
1 parent abdd5a8 commit 9e8e5b8

File tree

5 files changed

+112
-2
lines changed

5 files changed

+112
-2
lines changed

src/lib/components/contents/details/editor/field-editor.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
$: validity = validities[locale][keyPath];
9090
9191
$: fieldLabel = label || fieldName;
92-
$: readonly = i18n === 'duplicate' && locale !== defaultLocale;
92+
$: readonly = (i18n === 'duplicate' && locale !== defaultLocale) || widgetName === 'compute';
9393
$: invalid = validity?.valid === false;
9494
</script>
9595
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<!--
2+
@component
3+
Implement the editor for the experimental Compute widget.
4+
-->
5+
<script>
6+
import { TextInput } from '@sveltia/ui';
7+
import { entryDraft } from '$lib/services/contents/editor';
8+
import { getFieldDisplayValue } from '$lib/services/contents/entry';
9+
import { getCanonicalLocale } from '$lib/services/contents/i18n';
10+
11+
/**
12+
* @type {LocaleCode}
13+
*/
14+
export let locale;
15+
/**
16+
* @type {string}
17+
*/
18+
// svelte-ignore unused-export-let
19+
export let keyPath;
20+
/**
21+
* @type {string}
22+
*/
23+
export let fieldId;
24+
/**
25+
* @type {string}
26+
*/
27+
// svelte-ignore unused-export-let
28+
export let fieldLabel;
29+
/**
30+
* @type {ComputeField}
31+
*/
32+
export let fieldConfig;
33+
/**
34+
* @type {string}
35+
*/
36+
export let currentValue;
37+
/**
38+
* @type {boolean}
39+
*/
40+
export let readonly = false;
41+
/**
42+
* @type {boolean}
43+
*/
44+
export let required = false;
45+
/**
46+
* @type {boolean}
47+
*/
48+
export let invalid = false;
49+
50+
$: ({
51+
// Widget-specific options
52+
value: valueTemplate = '',
53+
} = fieldConfig);
54+
55+
$: ({ collectionName, fileName, currentValues } = $entryDraft ?? /** @type {EntryDraft} */ ({}));
56+
$: valueMap = currentValues[locale];
57+
$: canonicalLocale = getCanonicalLocale(locale);
58+
$: listFormatter = new Intl.ListFormat(canonicalLocale, { style: 'narrow', type: 'conjunction' });
59+
60+
/**
61+
* Update {@link currentValue} based on the current values.
62+
*/
63+
const updateCurrentValue = () => {
64+
const newValue = valueTemplate.replaceAll(/{{fields\.(.+?)}}/g, (_match, _fieldName) => {
65+
const value = getFieldDisplayValue({
66+
collectionName,
67+
fileName,
68+
valueMap,
69+
keyPath: _fieldName,
70+
locale,
71+
});
72+
73+
return Array.isArray(value) ? listFormatter.format(value) : String(value);
74+
});
75+
76+
// Make sure to avoid infinite loops
77+
if (currentValue !== newValue) {
78+
currentValue = newValue;
79+
}
80+
};
81+
82+
$: {
83+
void valueMap;
84+
updateCurrentValue();
85+
}
86+
</script>
87+
88+
<TextInput
89+
value={currentValue}
90+
flex
91+
{readonly}
92+
{required}
93+
{invalid}
94+
aria-labelledby="{fieldId}-label"
95+
aria-errormessage="{fieldId}-error"
96+
/>

src/lib/components/contents/details/widgets/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import BooleanEditor from '$lib/components/contents/details/widgets/boolean/bool
22
import BooleanPreview from '$lib/components/contents/details/widgets/boolean/boolean-preview.svelte';
33
import ColorEditor from '$lib/components/contents/details/widgets/color/color-editor.svelte';
44
import ColorPreview from '$lib/components/contents/details/widgets/color/color-preview.svelte';
5+
import ComputeEditor from '$lib/components/contents/details/widgets/compute/compute-editor.svelte';
56
import DateTimeEditor from '$lib/components/contents/details/widgets/date-time/date-time-editor.svelte';
67
import DateTimePreview from '$lib/components/contents/details/widgets/date-time/date-time-preview.svelte';
78
import FileEditor from '$lib/components/contents/details/widgets/file/file-editor.svelte';
@@ -31,6 +32,7 @@ import UuidPreview from '$lib/components/contents/details/widgets/uuid/uuid-prev
3132
export const editors = {
3233
boolean: BooleanEditor,
3334
color: ColorEditor,
35+
compute: ComputeEditor,
3436
datetime: DateTimeEditor,
3537
file: FileEditor,
3638
image: FileEditor, // alias
@@ -51,6 +53,7 @@ export const editors = {
5153
export const previews = {
5254
boolean: BooleanPreview,
5355
color: ColorPreview,
56+
compute: StringPreview, // alias
5457
datetime: DateTimePreview,
5558
file: FilePreview,
5659
image: FilePreview, // alias

src/lib/services/contents/editor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ const validateEntry = () => {
770770
}
771771
}
772772

773-
if (!['object', 'list', 'hidden'].includes(widgetName)) {
773+
if (!['object', 'list', 'hidden', 'compute'].includes(widgetName)) {
774774
if (_required && (value === undefined || value === '' || (multiple && !value.length))) {
775775
valueMissing = true;
776776
}

src/lib/typedefs.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,17 @@
409409
* @typedef {CommonFieldProps & ColorFieldProps} ColorField
410410
*/
411411

412+
/**
413+
* Compute field properties.
414+
* @typedef {object} ComputeFieldProps
415+
* @property {string} value Value template, like `posts-{{fields.slug}}`.
416+
*/
417+
418+
/**
419+
* Compute field definition.
420+
* @typedef {CommonFieldProps & ComputeFieldProps} ComputeField
421+
*/
422+
412423
/**
413424
* DateTime field properties.
414425
* @typedef {object} DateTimeFieldProps

0 commit comments

Comments
 (0)