@byline/admin 3.12.1 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fields/field-services-types.d.ts +50 -0
- package/dist/forms/form-context.js +30 -60
- package/dist/forms/form-modals.d.ts +30 -0
- package/dist/forms/form-modals.js +189 -0
- package/dist/forms/form-renderer.d.ts +8 -1
- package/dist/forms/form-renderer.js +31 -365
- package/dist/forms/form-status-display.d.ts +21 -0
- package/dist/forms/form-status-display.js +94 -0
- package/dist/forms/status-transitions.d.ts +23 -0
- package/dist/forms/status-transitions.js +37 -0
- package/dist/forms/status-transitions.test.node.d.ts +8 -0
- package/dist/forms/tree-placement-widget.d.ts +23 -0
- package/dist/forms/tree-placement-widget.js +176 -0
- package/dist/forms/tree-placement-widget.module.js +15 -0
- package/dist/forms/tree-placement-widget_module.css +69 -0
- package/dist/forms/use-form-layout.d.ts +35 -0
- package/dist/forms/use-form-layout.js +77 -0
- package/dist/forms/use-form-layout.test.node.d.ts +8 -0
- package/dist/forms/use-tracked-slot.d.ts +45 -0
- package/dist/forms/use-tracked-slot.js +46 -0
- package/dist/react.d.ts +1 -1
- package/package.json +5 -5
- package/src/fields/field-services-types.ts +50 -0
- package/src/forms/form-context.tsx +36 -92
- package/src/forms/form-modals.tsx +186 -0
- package/src/forms/form-renderer.tsx +42 -387
- package/src/forms/form-status-display.tsx +108 -0
- package/src/forms/status-transitions.test.node.ts +87 -0
- package/src/forms/status-transitions.ts +86 -0
- package/src/forms/tree-placement-widget.module.css +87 -0
- package/src/forms/tree-placement-widget.tsx +202 -0
- package/src/forms/use-form-layout.test.node.ts +82 -0
- package/src/forms/use-form-layout.ts +134 -0
- package/src/forms/use-tracked-slot.ts +101 -0
- package/src/react.ts +6 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) Infonomic Company Limited
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { type RefObject, useCallback, useRef } from 'react'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A dirty-tracked, ref-backed form slot with its own listener set — the shared
|
|
15
|
+
* machinery behind the document-grain system fields (`path`, advertised
|
|
16
|
+
* `availableLocales`, …). Each slot holds the current value, the value it was
|
|
17
|
+
* loaded with, and a set of subscribers; a `set` that moves the value away from
|
|
18
|
+
* its loaded baseline registers the slot's `dirtyKey` in the form's shared
|
|
19
|
+
* dirty set (and clears it again when the value returns to baseline), so the
|
|
20
|
+
* single Save button can branch on which buckets changed.
|
|
21
|
+
*
|
|
22
|
+
* Adding a new system slot is then a one-liner at the call site rather than a
|
|
23
|
+
* copy of ref + initial-ref + listener-set + get/set/subscribe.
|
|
24
|
+
*/
|
|
25
|
+
export interface TrackedSlot<T> {
|
|
26
|
+
/** Current value (live ref read — not React state). */
|
|
27
|
+
get: () => T
|
|
28
|
+
/** Write a value; toggles `dirtyKey` against the loaded baseline. */
|
|
29
|
+
set: (value: T) => void
|
|
30
|
+
/** Subscribe to value changes; returns an unsubscribe fn. */
|
|
31
|
+
subscribe: (listener: (value: T) => void) => () => void
|
|
32
|
+
/** Re-baseline: adopt the current value as the new "clean" baseline (called on save). */
|
|
33
|
+
commitInitial: () => void
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface UseTrackedSlotConfig<T> {
|
|
37
|
+
/** Initial / loaded value. */
|
|
38
|
+
initial: T
|
|
39
|
+
/** Key registered in the shared dirty set while this slot diverges from baseline. */
|
|
40
|
+
dirtyKey: string
|
|
41
|
+
/** The form's shared dirty-key set. */
|
|
42
|
+
dirtyFields: RefObject<Set<string>>
|
|
43
|
+
/** Notify the form's meta listeners (drives hasChanges → Save button). */
|
|
44
|
+
notifyMeta: () => void
|
|
45
|
+
/** Equality against the baseline. Defaults to `===` (identity). */
|
|
46
|
+
isEqual?: (a: T, b: T) => boolean
|
|
47
|
+
/** Defensive copy on read-in / write. Defaults to identity (fine for immutables). */
|
|
48
|
+
clone?: (value: T) => T
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function useTrackedSlot<T>(config: UseTrackedSlotConfig<T>): TrackedSlot<T> {
|
|
52
|
+
// Snapshot the config on every render into a ref so the returned callbacks
|
|
53
|
+
// can stay referentially stable (empty deps) while still reading the latest
|
|
54
|
+
// isEqual / clone / notifyMeta — matching the stable identities the previous
|
|
55
|
+
// inline implementation relied on.
|
|
56
|
+
const cfgRef = useRef(config)
|
|
57
|
+
cfgRef.current = config
|
|
58
|
+
|
|
59
|
+
const clone = useCallback((value: T): T => {
|
|
60
|
+
const fn = cfgRef.current.clone
|
|
61
|
+
return fn ? fn(value) : value
|
|
62
|
+
}, [])
|
|
63
|
+
|
|
64
|
+
const valueRef = useRef<T>(clone(config.initial))
|
|
65
|
+
const initialRef = useRef<T>(clone(config.initial))
|
|
66
|
+
const listeners = useRef<Set<(value: T) => void>>(new Set())
|
|
67
|
+
|
|
68
|
+
const get = useCallback(() => valueRef.current, [])
|
|
69
|
+
|
|
70
|
+
const set = useCallback(
|
|
71
|
+
(value: T) => {
|
|
72
|
+
const { dirtyKey, dirtyFields, notifyMeta, isEqual } = cfgRef.current
|
|
73
|
+
const next = clone(value)
|
|
74
|
+
valueRef.current = next
|
|
75
|
+
const equal = isEqual ? isEqual(next, initialRef.current) : next === initialRef.current
|
|
76
|
+
if (equal) {
|
|
77
|
+
dirtyFields.current.delete(dirtyKey)
|
|
78
|
+
} else {
|
|
79
|
+
dirtyFields.current.add(dirtyKey)
|
|
80
|
+
}
|
|
81
|
+
listeners.current.forEach((listener) => {
|
|
82
|
+
listener(next)
|
|
83
|
+
})
|
|
84
|
+
notifyMeta()
|
|
85
|
+
},
|
|
86
|
+
[clone]
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const subscribe = useCallback((listener: (value: T) => void) => {
|
|
90
|
+
listeners.current.add(listener)
|
|
91
|
+
return () => {
|
|
92
|
+
listeners.current.delete(listener)
|
|
93
|
+
}
|
|
94
|
+
}, [])
|
|
95
|
+
|
|
96
|
+
const commitInitial = useCallback(() => {
|
|
97
|
+
initialRef.current = clone(valueRef.current)
|
|
98
|
+
}, [clone])
|
|
99
|
+
|
|
100
|
+
return { get, set, subscribe, commitInitial }
|
|
101
|
+
}
|
package/src/react.ts
CHANGED
|
@@ -80,6 +80,12 @@ export type {
|
|
|
80
80
|
CollectionListParams,
|
|
81
81
|
CollectionListResponse,
|
|
82
82
|
GetCollectionDocumentsFn,
|
|
83
|
+
GetTreeAncestorsFn,
|
|
84
|
+
GetTreeParentFn,
|
|
85
|
+
PlaceTreeNodeFn,
|
|
86
|
+
PlaceTreeNodeInput,
|
|
87
|
+
RemoveFromTreeFn,
|
|
88
|
+
TreeAncestor,
|
|
83
89
|
UploadedFileResult,
|
|
84
90
|
UploadFieldFn,
|
|
85
91
|
} from './fields/field-services-types.js'
|