@pumped-fn/lite-react-json-render 0.0.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/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ # @pumped-fn/lite-react-json-render
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License Copyright (c) 2025 Duke
2
+
3
+ Permission is hereby granted, free of
4
+ charge, to any person obtaining a copy of this software and associated
5
+ documentation files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use, copy, modify, merge,
7
+ publish, distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice
12
+ (including the next paragraph) shall be included in all copies or substantial
13
+ portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
16
+ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
18
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # @pumped-fn/lite-react-json-render
2
+
3
+ json-render state and action adapters for `@pumped-fn/lite-react`.
4
+
5
+ Use this package when a json-render spec should bind to Lite-owned frontend state and emit actions into
6
+ Lite-owned flows. `@pumped-fn/lite-react` still owns the scope, execution context, scoped value, resources,
7
+ tags, presets, and tests; json-render reads, writes, and emits through its normal provider contracts.
8
+
9
+ ## When to Use
10
+
11
+ Use these adapters when json-render is already the right UI boundary: generated specs, server-authored
12
+ forms, schema-driven editors, or embedded surfaces that need json-render's `$state`, `$bindState`, `on`,
13
+ or `watch` contracts. The timing is the integration edge, after the draft/form/editor state and action
14
+ flows have clear Lite owners.
15
+
16
+ Do not use it to make ordinary React components more indirect. If the UI is hand-authored React, render forms
17
+ and drafts from `useScopedValue` and mutate through scoped actions. Use `useResource` when an integration
18
+ boundary needs the resolved access object. If json-render should own isolated state that never needs Lite
19
+ flows, resources, resets, or tests, use json-render's own store and handlers instead.
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npm install @pumped-fn/lite @pumped-fn/lite-react @pumped-fn/lite-react-json-render
25
+ npm install @json-render/core @json-render/react zod
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ```tsx
31
+ import { JSONUIProvider, type ComponentRegistry } from "@json-render/react"
32
+ import { flow, tag } from "@pumped-fn/lite"
33
+ import { scopedValue, type ScopedValueAccess, useResource } from "@pumped-fn/lite-react"
34
+ import { flowAction, scopedValueStateStore, useFlowHandlers } from "@pumped-fn/lite-react-json-render"
35
+ import { useMemo } from "react"
36
+ import { z } from "zod"
37
+
38
+ interface OrderState {
39
+ order: {
40
+ item: string
41
+ quantity: number
42
+ }
43
+ submission: {
44
+ message: string
45
+ } | null
46
+ }
47
+
48
+ const submitOrderInput = z.object({
49
+ item: z.string(),
50
+ quantity: z.number(),
51
+ })
52
+
53
+ const currentOrderDraft = tag<ScopedValueAccess<OrderState>>({
54
+ label: "current.order-draft",
55
+ })
56
+
57
+ const orderDraft = scopedValue({
58
+ name: "order-draft",
59
+ initial: (): OrderState => ({
60
+ order: { item: "Coffee", quantity: 1 },
61
+ submission: null,
62
+ }),
63
+ })
64
+
65
+ const submitOrder = flow({
66
+ name: "submit-order",
67
+ parse: submitOrderInput.parse,
68
+ factory: (ctx) => {
69
+ const draft = ctx.data.getTag(currentOrderDraft)!
70
+ const message = `Submitted ${ctx.input.item} x ${ctx.input.quantity}`
71
+ draft.patch({ submission: { message } })
72
+ return message
73
+ },
74
+ })
75
+
76
+ function GeneratedOrder(
77
+ { registry, children }: { registry: ComponentRegistry; children: React.ReactNode }
78
+ ) {
79
+ const draft = useResource(orderDraft)
80
+
81
+ return (
82
+ <OrderBridge registry={registry} draft={draft}>
83
+ {children}
84
+ </OrderBridge>
85
+ )
86
+ }
87
+
88
+ function OrderBridge(
89
+ { registry, draft, children }: {
90
+ registry: ComponentRegistry
91
+ draft: ScopedValueAccess<OrderState>
92
+ children: React.ReactNode
93
+ }
94
+ ) {
95
+ const store = useMemo(() => scopedValueStateStore({ value: draft }), [draft])
96
+ const actions = useMemo(() => ({
97
+ submitOrder: flowAction({
98
+ flow: submitOrder,
99
+ tags: [currentOrderDraft(draft)],
100
+ }),
101
+ }), [draft])
102
+ const handlers = useFlowHandlers(actions)
103
+
104
+ return (
105
+ <JSONUIProvider registry={registry} store={store} handlers={handlers}>
106
+ {children}
107
+ </JSONUIProvider>
108
+ )
109
+ }
110
+ ```
111
+
112
+ The adapter exposes json-render's `StateStore` shape: JSON Pointer `get`, `set`, batched `update`,
113
+ `getSnapshot`, server snapshot, and `subscribe`.
114
+
115
+ `flowHandlers` returns json-render `ActionHandler` functions. Bare flows receive resolved
116
+ json-render params as `rawInput`, so a flow parser can validate generated params. Use `flowAction` when
117
+ the boundary needs to map input, set an execution name, or pass tags.
118
+
119
+ `useFlowHandlers` returns stable proxy handlers that read the latest Lite context and action
120
+ configuration. That matches json-render's action provider, which registers the handler map at provider mount.
121
+
122
+ ## Behavior Surface
123
+
124
+ Pass the returned `handlers` to `JSONUIProvider` for json-render `on` and `watch` bindings. json-render
125
+ continues to own event binding, action param resolution, confirmation, `onSuccess`, `onError`, and loading
126
+ state; Lite owns the executed flows and their resources/tags/extensions.
127
+
128
+ json-render also accepts `navigate`, `validationFunctions`, `functions`, and `directives`. Keep those as
129
+ native `JSONUIProvider` props. Validation and computed functions are synchronous json-render contracts, so
130
+ do not hide async Lite flows behind them. If they need Lite-owned data, adapt already-resolved graph values
131
+ into sync functions at the integration boundary, or have action flows write derived results back into the
132
+ scoped value.
133
+
134
+ ## Nested Slices
135
+
136
+ For a nested state model, pass a selector and updater:
137
+
138
+ ```ts
139
+ const store = scopedValueStateStore({
140
+ value: appDraft,
141
+ selector: (state) => state.ui,
142
+ updater: (next, value) => value.set({ ...value.getSnapshot(), ui: next as { count: number } }),
143
+ })
144
+ ```
145
+
146
+ The updater is required for selected slices so unrelated graph-owned state is not replaced by the
147
+ json-render slice.
148
+
149
+ ## Testing
150
+
151
+ Logic tests can resolve the scoped value through `createScope`, adapt it, call action handlers, and assert
152
+ `StateStore` plus flow behavior without React. Browser observer tests should render the real json-render
153
+ provider under `ScopeProvider` and `ExecutionContextProvider`.
154
+
155
+ ## License
156
+
157
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,85 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _json_render_core_store_utils = require("@json-render/core/store-utils");
3
+ let _pumped_fn_lite_react = require("@pumped-fn/lite-react");
4
+ let react = require("react");
5
+ //#region src/index.ts
6
+ function scopedValueStateStore(options) {
7
+ const source = options.value;
8
+ const selector = "selector" in options ? options.selector : (state) => state;
9
+ const updater = "updater" in options ? options.updater : (next, value) => value.set(next);
10
+ return (0, _json_render_core_store_utils.createStoreAdapter)({
11
+ getSnapshot: () => selector(source.getSnapshot()),
12
+ setSnapshot: (next) => updater(next, source),
13
+ subscribe(listener) {
14
+ let prev = selector(source.getSnapshot());
15
+ return source.subscribe(() => {
16
+ const current = selector(source.getSnapshot());
17
+ if (current !== prev) {
18
+ prev = current;
19
+ listener();
20
+ prev = selector(source.getSnapshot());
21
+ }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ function flowAction(options) {
27
+ return options;
28
+ }
29
+ function flowHandlers(options) {
30
+ return Object.fromEntries(Object.entries(options.actions).map(([name, target]) => [name, flowActionHandler(options.ctx, target)]));
31
+ }
32
+ function useFlowHandlers(actions) {
33
+ const ctx = (0, _pumped_fn_lite_react.useExecutionContext)();
34
+ const ref = (0, react.useRef)(null);
35
+ if (!ref.current) ref.current = {
36
+ handlers: {},
37
+ cells: /* @__PURE__ */ new Map()
38
+ };
39
+ const { handlers, cells } = ref.current;
40
+ const actionNames = new Set(Object.keys(actions));
41
+ for (const name of Object.keys(handlers)) if (!actionNames.has(name)) {
42
+ delete handlers[name];
43
+ cells.delete(name);
44
+ }
45
+ for (const [name, target] of Object.entries(actions)) {
46
+ let cell = cells.get(name);
47
+ if (!cell) {
48
+ const nextCell = {
49
+ ctx,
50
+ target
51
+ };
52
+ cell = nextCell;
53
+ cells.set(name, nextCell);
54
+ handlers[name] = (params) => flowActionHandler(nextCell.ctx, nextCell.target)(params);
55
+ }
56
+ cell.ctx = ctx;
57
+ cell.target = target;
58
+ }
59
+ return handlers;
60
+ }
61
+ function flowActionHandler(ctx, target) {
62
+ if ("flow" in target) return (params) => {
63
+ if (target.input) return ctx.exec({
64
+ flow: target.flow,
65
+ input: target.input(params),
66
+ name: target.name,
67
+ tags: target.tags
68
+ });
69
+ return ctx.exec({
70
+ flow: target.flow,
71
+ rawInput: target.rawInput ? target.rawInput(params) : params,
72
+ name: target.name,
73
+ tags: target.tags
74
+ });
75
+ };
76
+ return (params) => ctx.exec({
77
+ flow: target,
78
+ rawInput: params
79
+ });
80
+ }
81
+ //#endregion
82
+ exports.flowAction = flowAction;
83
+ exports.flowHandlers = flowHandlers;
84
+ exports.scopedValueStateStore = scopedValueStateStore;
85
+ exports.useFlowHandlers = useFlowHandlers;
@@ -0,0 +1,44 @@
1
+ import { ActionHandler, StateModel, StateStore } from "@json-render/core";
2
+ import { Lite, ScopedValueAccess } from "@pumped-fn/lite-react";
3
+
4
+ //#region src/index.d.ts
5
+ type ScopedValueStateSource<State extends object> = Pick<ScopedValueAccess<State>, 'getSnapshot' | 'set' | 'subscribe'>;
6
+ type JsonRenderActionParams = Record<string, unknown>;
7
+ type FlowActionHandlerResult<Target> = Target extends Lite.Flow<infer Output, any> ? Output : Target extends FlowActionOptions<infer Flow> ? Lite.Utils.FlowOutput<Flow> : never;
8
+ type FlowHandlers<Actions extends FlowActionTargets> = { [Name in keyof Actions]: ActionHandler<JsonRenderActionParams, FlowActionHandlerResult<Actions[Name]>> };
9
+ type FlowActionTargets = Record<string, FlowActionTarget<Lite.Flow<any, any>>>;
10
+ type FlowActionTarget<Flow extends Lite.Flow<any, any>> = Flow | FlowActionOptions<Flow>;
11
+ interface ScopedValueStateStoreOptions<State extends object = StateModel> {
12
+ value: ScopedValueStateSource<State>;
13
+ }
14
+ interface ScopedValueStateStoreSliceOptions<State extends object> {
15
+ value: ScopedValueStateSource<State>;
16
+ selector(state: State): StateModel;
17
+ updater(nextState: StateModel, value: ScopedValueStateSource<State>): void;
18
+ }
19
+ interface FlowActionBaseOptions<Flow extends Lite.Flow<any, any>> {
20
+ flow: Flow;
21
+ name?: string;
22
+ tags?: Lite.Tagged<any>[];
23
+ }
24
+ interface FlowActionInputOptions<Flow extends Lite.Flow<any, any>> extends FlowActionBaseOptions<Flow> {
25
+ input(params: JsonRenderActionParams): Lite.Utils.FlowInput<Flow>;
26
+ rawInput?: never;
27
+ }
28
+ interface FlowActionRawInputOptions<Flow extends Lite.Flow<any, any>> extends FlowActionBaseOptions<Flow> {
29
+ rawInput?(params: JsonRenderActionParams): unknown;
30
+ input?: never;
31
+ }
32
+ type FlowActionOptions<Flow extends Lite.Flow<any, any>> = FlowActionInputOptions<Flow> | FlowActionRawInputOptions<Flow>;
33
+ interface FlowHandlersOptions<Actions extends FlowActionTargets> {
34
+ ctx: Lite.ExecutionContext;
35
+ actions: Actions;
36
+ }
37
+ declare function scopedValueStateStore<State extends object>(options: ScopedValueStateStoreOptions<State>): StateStore;
38
+ declare function scopedValueStateStore<State extends object>(options: ScopedValueStateStoreSliceOptions<State>): StateStore;
39
+ declare function flowAction<Flow extends Lite.Flow<any, any>>(options: FlowActionOptions<Flow>): FlowActionOptions<Flow>;
40
+ declare function flowHandlers<const Actions extends FlowActionTargets>(options: FlowHandlersOptions<Actions>): FlowHandlers<Actions>;
41
+ declare function useFlowHandlers<const Actions extends FlowActionTargets>(actions: Actions): FlowHandlers<Actions>;
42
+ //#endregion
43
+ export { type FlowActionInputOptions, type FlowActionOptions, type FlowActionRawInputOptions, type FlowActionTarget, type FlowActionTargets, type FlowHandlers, type FlowHandlersOptions, type JsonRenderActionParams, type ScopedValueStateSource, type ScopedValueStateStoreOptions, type ScopedValueStateStoreSliceOptions, flowAction, flowHandlers, scopedValueStateStore, useFlowHandlers };
44
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;KAMK,sBAAA,yBAA+C,IAAA,CAAK,iBAAA,CAAkB,KAAA;AAAA,KACtE,sBAAA,GAAyB,MAAM;AAAA,KAC/B,uBAAA,WACH,MAAA,SAAe,IAAA,CAAK,IAAA,sBAChB,MAAA,GACA,MAAA,SAAe,iBAAA,eACb,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,IAAA;AAAA,KAEzB,YAAA,iBAA6B,iBAAA,qBACjB,OAAA,GAAU,aAAA,CAAc,sBAAA,EAAwB,uBAAA,CAAwB,OAAA,CAAQ,IAAA;AAAA,KAE5F,iBAAA,GAAoB,MAAA,SAAe,gBAAA,CAAiB,IAAA,CAAK,IAAA;AAAA,KACzD,gBAAA,cAA8B,IAAA,CAAK,IAAA,cAAkB,IAAA,GAAO,iBAAA,CAAkB,IAAA;AAAA,UAEzE,4BAAA,wBAAoD,UAAA;EAC5D,KAAA,EAAO,sBAAA,CAAuB,KAAA;AAAA;AAAA,UAGtB,iCAAA;EACR,KAAA,EAAO,sBAAA,CAAuB,KAAA;EAC9B,QAAA,CAAS,KAAA,EAAO,KAAA,GAAQ,UAAA;EACxB,OAAA,CAAQ,SAAA,EAAW,UAAA,EAAY,KAAA,EAAO,sBAAA,CAAuB,KAAA;AAAA;AAAA,UAGrD,qBAAA,cAAmC,IAAA,CAAK,IAAA;EAChD,IAAA,EAAM,IAAA;EACN,IAAA;EACA,IAAA,GAAO,IAAA,CAAK,MAAA;AAAA;AAAA,UAGJ,sBAAA,cAAoC,IAAA,CAAK,IAAA,oBAAwB,qBAAA,CAAsB,IAAA;EAC/F,KAAA,CAAM,MAAA,EAAQ,sBAAA,GAAyB,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,IAAA;EAC5D,QAAA;AAAA;AAAA,UAGQ,yBAAA,cAAuC,IAAA,CAAK,IAAA,oBAAwB,qBAAA,CAAsB,IAAA;EAClG,QAAA,EAAU,MAAA,EAAQ,sBAAA;EAClB,KAAA;AAAA;AAAA,KAGG,iBAAA,cAA+B,IAAA,CAAK,IAAA,cACrC,sBAAA,CAAuB,IAAA,IACvB,yBAAA,CAA0B,IAAA;AAAA,UAEpB,mBAAA,iBAAoC,iBAAA;EAC5C,GAAA,EAAK,IAAA,CAAK,gBAAA;EACV,OAAA,EAAS,OAAA;AAAA;AAAA,iBAaF,qBAAA,sBAAA,CACP,OAAA,EAAS,4BAAA,CAA6B,KAAA,IACrC,UAAA;AAAA,iBACM,qBAAA,sBAAA,CACP,OAAA,EAAS,iCAAA,CAAkC,KAAA,IAC1C,UAAA;AAAA,iBA6BM,UAAA,cAAwB,IAAA,CAAK,IAAA,WAAA,CAAgB,OAAA,EAAS,iBAAA,CAAkB,IAAA,IAAQ,iBAAA,CAAkB,IAAA;AAAA,iBAIlG,YAAA,uBAAmC,iBAAA,CAAA,CAC1C,OAAA,EAAS,mBAAA,CAAoB,OAAA,IAC5B,YAAA,CAAa,OAAA;AAAA,iBASP,eAAA,uBAAsC,iBAAA,CAAA,CAC7C,OAAA,EAAS,OAAA,GACR,YAAA,CAAa,OAAA"}
@@ -0,0 +1,44 @@
1
+ import { Lite, ScopedValueAccess } from "@pumped-fn/lite-react";
2
+ import { ActionHandler, StateModel, StateStore } from "@json-render/core";
3
+
4
+ //#region src/index.d.ts
5
+ type ScopedValueStateSource<State extends object> = Pick<ScopedValueAccess<State>, 'getSnapshot' | 'set' | 'subscribe'>;
6
+ type JsonRenderActionParams = Record<string, unknown>;
7
+ type FlowActionHandlerResult<Target> = Target extends Lite.Flow<infer Output, any> ? Output : Target extends FlowActionOptions<infer Flow> ? Lite.Utils.FlowOutput<Flow> : never;
8
+ type FlowHandlers<Actions extends FlowActionTargets> = { [Name in keyof Actions]: ActionHandler<JsonRenderActionParams, FlowActionHandlerResult<Actions[Name]>> };
9
+ type FlowActionTargets = Record<string, FlowActionTarget<Lite.Flow<any, any>>>;
10
+ type FlowActionTarget<Flow extends Lite.Flow<any, any>> = Flow | FlowActionOptions<Flow>;
11
+ interface ScopedValueStateStoreOptions<State extends object = StateModel> {
12
+ value: ScopedValueStateSource<State>;
13
+ }
14
+ interface ScopedValueStateStoreSliceOptions<State extends object> {
15
+ value: ScopedValueStateSource<State>;
16
+ selector(state: State): StateModel;
17
+ updater(nextState: StateModel, value: ScopedValueStateSource<State>): void;
18
+ }
19
+ interface FlowActionBaseOptions<Flow extends Lite.Flow<any, any>> {
20
+ flow: Flow;
21
+ name?: string;
22
+ tags?: Lite.Tagged<any>[];
23
+ }
24
+ interface FlowActionInputOptions<Flow extends Lite.Flow<any, any>> extends FlowActionBaseOptions<Flow> {
25
+ input(params: JsonRenderActionParams): Lite.Utils.FlowInput<Flow>;
26
+ rawInput?: never;
27
+ }
28
+ interface FlowActionRawInputOptions<Flow extends Lite.Flow<any, any>> extends FlowActionBaseOptions<Flow> {
29
+ rawInput?(params: JsonRenderActionParams): unknown;
30
+ input?: never;
31
+ }
32
+ type FlowActionOptions<Flow extends Lite.Flow<any, any>> = FlowActionInputOptions<Flow> | FlowActionRawInputOptions<Flow>;
33
+ interface FlowHandlersOptions<Actions extends FlowActionTargets> {
34
+ ctx: Lite.ExecutionContext;
35
+ actions: Actions;
36
+ }
37
+ declare function scopedValueStateStore<State extends object>(options: ScopedValueStateStoreOptions<State>): StateStore;
38
+ declare function scopedValueStateStore<State extends object>(options: ScopedValueStateStoreSliceOptions<State>): StateStore;
39
+ declare function flowAction<Flow extends Lite.Flow<any, any>>(options: FlowActionOptions<Flow>): FlowActionOptions<Flow>;
40
+ declare function flowHandlers<const Actions extends FlowActionTargets>(options: FlowHandlersOptions<Actions>): FlowHandlers<Actions>;
41
+ declare function useFlowHandlers<const Actions extends FlowActionTargets>(actions: Actions): FlowHandlers<Actions>;
42
+ //#endregion
43
+ export { type FlowActionInputOptions, type FlowActionOptions, type FlowActionRawInputOptions, type FlowActionTarget, type FlowActionTargets, type FlowHandlers, type FlowHandlersOptions, type JsonRenderActionParams, type ScopedValueStateSource, type ScopedValueStateStoreOptions, type ScopedValueStateStoreSliceOptions, flowAction, flowHandlers, scopedValueStateStore, useFlowHandlers };
44
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;KAMK,sBAAA,yBAA+C,IAAA,CAAK,iBAAA,CAAkB,KAAA;AAAA,KACtE,sBAAA,GAAyB,MAAM;AAAA,KAC/B,uBAAA,WACH,MAAA,SAAe,IAAA,CAAK,IAAA,sBAChB,MAAA,GACA,MAAA,SAAe,iBAAA,eACb,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,IAAA;AAAA,KAEzB,YAAA,iBAA6B,iBAAA,qBACjB,OAAA,GAAU,aAAA,CAAc,sBAAA,EAAwB,uBAAA,CAAwB,OAAA,CAAQ,IAAA;AAAA,KAE5F,iBAAA,GAAoB,MAAA,SAAe,gBAAA,CAAiB,IAAA,CAAK,IAAA;AAAA,KACzD,gBAAA,cAA8B,IAAA,CAAK,IAAA,cAAkB,IAAA,GAAO,iBAAA,CAAkB,IAAA;AAAA,UAEzE,4BAAA,wBAAoD,UAAA;EAC5D,KAAA,EAAO,sBAAA,CAAuB,KAAA;AAAA;AAAA,UAGtB,iCAAA;EACR,KAAA,EAAO,sBAAA,CAAuB,KAAA;EAC9B,QAAA,CAAS,KAAA,EAAO,KAAA,GAAQ,UAAA;EACxB,OAAA,CAAQ,SAAA,EAAW,UAAA,EAAY,KAAA,EAAO,sBAAA,CAAuB,KAAA;AAAA;AAAA,UAGrD,qBAAA,cAAmC,IAAA,CAAK,IAAA;EAChD,IAAA,EAAM,IAAA;EACN,IAAA;EACA,IAAA,GAAO,IAAA,CAAK,MAAA;AAAA;AAAA,UAGJ,sBAAA,cAAoC,IAAA,CAAK,IAAA,oBAAwB,qBAAA,CAAsB,IAAA;EAC/F,KAAA,CAAM,MAAA,EAAQ,sBAAA,GAAyB,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,IAAA;EAC5D,QAAA;AAAA;AAAA,UAGQ,yBAAA,cAAuC,IAAA,CAAK,IAAA,oBAAwB,qBAAA,CAAsB,IAAA;EAClG,QAAA,EAAU,MAAA,EAAQ,sBAAA;EAClB,KAAA;AAAA;AAAA,KAGG,iBAAA,cAA+B,IAAA,CAAK,IAAA,cACrC,sBAAA,CAAuB,IAAA,IACvB,yBAAA,CAA0B,IAAA;AAAA,UAEpB,mBAAA,iBAAoC,iBAAA;EAC5C,GAAA,EAAK,IAAA,CAAK,gBAAA;EACV,OAAA,EAAS,OAAA;AAAA;AAAA,iBAaF,qBAAA,sBAAA,CACP,OAAA,EAAS,4BAAA,CAA6B,KAAA,IACrC,UAAA;AAAA,iBACM,qBAAA,sBAAA,CACP,OAAA,EAAS,iCAAA,CAAkC,KAAA,IAC1C,UAAA;AAAA,iBA6BM,UAAA,cAAwB,IAAA,CAAK,IAAA,WAAA,CAAgB,OAAA,EAAS,iBAAA,CAAkB,IAAA,IAAQ,iBAAA,CAAkB,IAAA;AAAA,iBAIlG,YAAA,uBAAmC,iBAAA,CAAA,CAC1C,OAAA,EAAS,mBAAA,CAAoB,OAAA,IAC5B,YAAA,CAAa,OAAA;AAAA,iBASP,eAAA,uBAAsC,iBAAA,CAAA,CAC7C,OAAA,EAAS,OAAA,GACR,YAAA,CAAa,OAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,83 @@
1
+ import { createStoreAdapter } from "@json-render/core/store-utils";
2
+ import { useExecutionContext } from "@pumped-fn/lite-react";
3
+ import { useRef } from "react";
4
+ //#region src/index.ts
5
+ function scopedValueStateStore(options) {
6
+ const source = options.value;
7
+ const selector = "selector" in options ? options.selector : (state) => state;
8
+ const updater = "updater" in options ? options.updater : (next, value) => value.set(next);
9
+ return createStoreAdapter({
10
+ getSnapshot: () => selector(source.getSnapshot()),
11
+ setSnapshot: (next) => updater(next, source),
12
+ subscribe(listener) {
13
+ let prev = selector(source.getSnapshot());
14
+ return source.subscribe(() => {
15
+ const current = selector(source.getSnapshot());
16
+ if (current !== prev) {
17
+ prev = current;
18
+ listener();
19
+ prev = selector(source.getSnapshot());
20
+ }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ function flowAction(options) {
26
+ return options;
27
+ }
28
+ function flowHandlers(options) {
29
+ return Object.fromEntries(Object.entries(options.actions).map(([name, target]) => [name, flowActionHandler(options.ctx, target)]));
30
+ }
31
+ function useFlowHandlers(actions) {
32
+ const ctx = useExecutionContext();
33
+ const ref = useRef(null);
34
+ if (!ref.current) ref.current = {
35
+ handlers: {},
36
+ cells: /* @__PURE__ */ new Map()
37
+ };
38
+ const { handlers, cells } = ref.current;
39
+ const actionNames = new Set(Object.keys(actions));
40
+ for (const name of Object.keys(handlers)) if (!actionNames.has(name)) {
41
+ delete handlers[name];
42
+ cells.delete(name);
43
+ }
44
+ for (const [name, target] of Object.entries(actions)) {
45
+ let cell = cells.get(name);
46
+ if (!cell) {
47
+ const nextCell = {
48
+ ctx,
49
+ target
50
+ };
51
+ cell = nextCell;
52
+ cells.set(name, nextCell);
53
+ handlers[name] = (params) => flowActionHandler(nextCell.ctx, nextCell.target)(params);
54
+ }
55
+ cell.ctx = ctx;
56
+ cell.target = target;
57
+ }
58
+ return handlers;
59
+ }
60
+ function flowActionHandler(ctx, target) {
61
+ if ("flow" in target) return (params) => {
62
+ if (target.input) return ctx.exec({
63
+ flow: target.flow,
64
+ input: target.input(params),
65
+ name: target.name,
66
+ tags: target.tags
67
+ });
68
+ return ctx.exec({
69
+ flow: target.flow,
70
+ rawInput: target.rawInput ? target.rawInput(params) : params,
71
+ name: target.name,
72
+ tags: target.tags
73
+ });
74
+ };
75
+ return (params) => ctx.exec({
76
+ flow: target,
77
+ rawInput: params
78
+ });
79
+ }
80
+ //#endregion
81
+ export { flowAction, flowHandlers, scopedValueStateStore, useFlowHandlers };
82
+
83
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { createStoreAdapter } from '@json-render/core/store-utils'\nimport type { ActionHandler, StateModel, StateStore } from '@json-render/core'\nimport { useExecutionContext } from '@pumped-fn/lite-react'\nimport type { Lite, ScopedValueAccess } from '@pumped-fn/lite-react'\nimport { useRef } from 'react'\n\ntype ScopedValueStateSource<State extends object> = Pick<ScopedValueAccess<State>, 'getSnapshot' | 'set' | 'subscribe'>\ntype JsonRenderActionParams = Record<string, unknown>\ntype FlowActionHandlerResult<Target> =\n Target extends Lite.Flow<infer Output, any>\n ? Output\n : Target extends FlowActionOptions<infer Flow>\n ? Lite.Utils.FlowOutput<Flow>\n : never\ntype FlowHandlers<Actions extends FlowActionTargets> = {\n [Name in keyof Actions]: ActionHandler<JsonRenderActionParams, FlowActionHandlerResult<Actions[Name]>>\n}\ntype FlowActionTargets = Record<string, FlowActionTarget<Lite.Flow<any, any>>>\ntype FlowActionTarget<Flow extends Lite.Flow<any, any>> = Flow | FlowActionOptions<Flow>\n\ninterface ScopedValueStateStoreOptions<State extends object = StateModel> {\n value: ScopedValueStateSource<State>\n}\n\ninterface ScopedValueStateStoreSliceOptions<State extends object> {\n value: ScopedValueStateSource<State>\n selector(state: State): StateModel\n updater(nextState: StateModel, value: ScopedValueStateSource<State>): void\n}\n\ninterface FlowActionBaseOptions<Flow extends Lite.Flow<any, any>> {\n flow: Flow\n name?: string\n tags?: Lite.Tagged<any>[]\n}\n\ninterface FlowActionInputOptions<Flow extends Lite.Flow<any, any>> extends FlowActionBaseOptions<Flow> {\n input(params: JsonRenderActionParams): Lite.Utils.FlowInput<Flow>\n rawInput?: never\n}\n\ninterface FlowActionRawInputOptions<Flow extends Lite.Flow<any, any>> extends FlowActionBaseOptions<Flow> {\n rawInput?(params: JsonRenderActionParams): unknown\n input?: never\n}\n\ntype FlowActionOptions<Flow extends Lite.Flow<any, any>> =\n | FlowActionInputOptions<Flow>\n | FlowActionRawInputOptions<Flow>\n\ninterface FlowHandlersOptions<Actions extends FlowActionTargets> {\n ctx: Lite.ExecutionContext\n actions: Actions\n}\n\ninterface FlowActionHandlerCell {\n ctx: Lite.ExecutionContext\n target: FlowActionTarget<Lite.Flow<any, any>>\n}\n\ninterface FlowHandlersRef {\n handlers: Record<string, ActionHandler<JsonRenderActionParams, unknown>>\n cells: Map<string, FlowActionHandlerCell>\n}\n\nfunction scopedValueStateStore<State extends object>(\n options: ScopedValueStateStoreOptions<State>\n): StateStore\nfunction scopedValueStateStore<State extends object>(\n options: ScopedValueStateStoreSliceOptions<State>\n): StateStore\nfunction scopedValueStateStore<State extends object>(\n options: ScopedValueStateStoreOptions<State> | ScopedValueStateStoreSliceOptions<State>\n): StateStore {\n const source = options.value\n const selector: (state: State) => StateModel = 'selector' in options\n ? options.selector\n : (state) => state as unknown as StateModel\n const updater: (next: StateModel, value: ScopedValueStateSource<State>) => void = 'updater' in options\n ? options.updater\n : (next, value) => value.set(next as unknown as State)\n\n return createStoreAdapter({\n getSnapshot: () => selector(source.getSnapshot()),\n setSnapshot: (next) => updater(next, source),\n subscribe(listener) {\n let prev = selector(source.getSnapshot())\n return source.subscribe(() => {\n const current = selector(source.getSnapshot())\n if (current !== prev) {\n prev = current\n listener()\n prev = selector(source.getSnapshot())\n }\n })\n },\n })\n}\n\nfunction flowAction<Flow extends Lite.Flow<any, any>>(options: FlowActionOptions<Flow>): FlowActionOptions<Flow> {\n return options\n}\n\nfunction flowHandlers<const Actions extends FlowActionTargets>(\n options: FlowHandlersOptions<Actions>\n): FlowHandlers<Actions> {\n return Object.fromEntries(\n Object.entries(options.actions).map(([name, target]) => [\n name,\n flowActionHandler(options.ctx, target),\n ])\n ) as FlowHandlers<Actions>\n}\n\nfunction useFlowHandlers<const Actions extends FlowActionTargets>(\n actions: Actions\n): FlowHandlers<Actions> {\n const ctx = useExecutionContext()\n const ref = useRef<FlowHandlersRef | null>(null)\n if (!ref.current) {\n ref.current = {\n handlers: {},\n cells: new Map(),\n }\n }\n\n const { handlers, cells } = ref.current\n const actionNames = new Set(Object.keys(actions))\n\n for (const name of Object.keys(handlers)) {\n if (!actionNames.has(name)) {\n delete handlers[name]\n cells.delete(name)\n }\n }\n\n for (const [name, target] of Object.entries(actions)) {\n let cell = cells.get(name)\n if (!cell) {\n const nextCell = { ctx, target }\n cell = nextCell\n cells.set(name, nextCell)\n handlers[name] = (params) => flowActionHandler(nextCell.ctx, nextCell.target)(params)\n }\n cell.ctx = ctx\n cell.target = target\n }\n\n return handlers as FlowHandlers<Actions>\n}\n\nfunction flowActionHandler<Flow extends Lite.Flow<any, any>>(\n ctx: Lite.ExecutionContext,\n target: FlowActionTarget<Flow>\n): ActionHandler<JsonRenderActionParams, Lite.Utils.FlowOutput<Flow>> {\n if ('flow' in target) {\n return (params) => {\n if (target.input) {\n return ctx.exec<Lite.Utils.FlowOutput<Flow>, Lite.Utils.FlowInput<Flow>>({\n flow: target.flow,\n input: target.input(params),\n name: target.name,\n tags: target.tags,\n })\n }\n\n return ctx.exec<Lite.Utils.FlowOutput<Flow>, Lite.Utils.FlowInput<Flow>>({\n flow: target.flow,\n rawInput: target.rawInput ? target.rawInput(params) : params,\n name: target.name,\n tags: target.tags,\n })\n }\n }\n\n return (params) => ctx.exec<Lite.Utils.FlowOutput<Flow>, Lite.Utils.FlowInput<Flow>>({\n flow: target,\n rawInput: params,\n })\n}\n\nexport { flowAction, flowHandlers, scopedValueStateStore, useFlowHandlers }\nexport type {\n FlowHandlers,\n FlowHandlersOptions,\n FlowActionInputOptions,\n FlowActionOptions,\n FlowActionRawInputOptions,\n FlowActionTarget,\n FlowActionTargets,\n JsonRenderActionParams,\n ScopedValueStateSource,\n ScopedValueStateStoreOptions,\n ScopedValueStateStoreSliceOptions,\n}\n"],"mappings":";;;;AAuEA,SAAS,sBACP,SACY;CACZ,MAAM,SAAS,QAAQ;CACvB,MAAM,WAAyC,cAAc,UACzD,QAAQ,YACP,UAAU;CACf,MAAM,UAA4E,aAAa,UAC3F,QAAQ,WACP,MAAM,UAAU,MAAM,IAAI,IAAwB;CAEvD,OAAO,mBAAmB;EACxB,mBAAmB,SAAS,OAAO,YAAY,CAAC;EAChD,cAAc,SAAS,QAAQ,MAAM,MAAM;EAC3C,UAAU,UAAU;GAClB,IAAI,OAAO,SAAS,OAAO,YAAY,CAAC;GACxC,OAAO,OAAO,gBAAgB;IAC5B,MAAM,UAAU,SAAS,OAAO,YAAY,CAAC;IAC7C,IAAI,YAAY,MAAM;KACpB,OAAO;KACP,SAAS;KACT,OAAO,SAAS,OAAO,YAAY,CAAC;IACtC;GACF,CAAC;EACH;CACF,CAAC;AACH;AAEA,SAAS,WAA6C,SAA2D;CAC/G,OAAO;AACT;AAEA,SAAS,aACP,SACuB;CACvB,OAAO,OAAO,YACZ,OAAO,QAAQ,QAAQ,OAAO,EAAE,KAAK,CAAC,MAAM,YAAY,CACtD,MACA,kBAAkB,QAAQ,KAAK,MAAM,CACvC,CAAC,CACH;AACF;AAEA,SAAS,gBACP,SACuB;CACvB,MAAM,MAAM,oBAAoB;CAChC,MAAM,MAAM,OAA+B,IAAI;CAC/C,IAAI,CAAC,IAAI,SACP,IAAI,UAAU;EACZ,UAAU,CAAC;EACX,uBAAO,IAAI,IAAI;CACjB;CAGF,MAAM,EAAE,UAAU,UAAU,IAAI;CAChC,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,OAAO,CAAC;CAEhD,KAAK,MAAM,QAAQ,OAAO,KAAK,QAAQ,GACrC,IAAI,CAAC,YAAY,IAAI,IAAI,GAAG;EAC1B,OAAO,SAAS;EAChB,MAAM,OAAO,IAAI;CACnB;CAGF,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,OAAO,GAAG;EACpD,IAAI,OAAO,MAAM,IAAI,IAAI;EACzB,IAAI,CAAC,MAAM;GACT,MAAM,WAAW;IAAE;IAAK;GAAO;GAC/B,OAAO;GACP,MAAM,IAAI,MAAM,QAAQ;GACxB,SAAS,SAAS,WAAW,kBAAkB,SAAS,KAAK,SAAS,MAAM,EAAE,MAAM;EACtF;EACA,KAAK,MAAM;EACX,KAAK,SAAS;CAChB;CAEA,OAAO;AACT;AAEA,SAAS,kBACP,KACA,QACoE;CACpE,IAAI,UAAU,QACZ,QAAQ,WAAW;EACjB,IAAI,OAAO,OACT,OAAO,IAAI,KAA8D;GACvE,MAAM,OAAO;GACb,OAAO,OAAO,MAAM,MAAM;GAC1B,MAAM,OAAO;GACb,MAAM,OAAO;EACf,CAAC;EAGH,OAAO,IAAI,KAA8D;GACvE,MAAM,OAAO;GACb,UAAU,OAAO,WAAW,OAAO,SAAS,MAAM,IAAI;GACtD,MAAM,OAAO;GACb,MAAM,OAAO;EACf,CAAC;CACH;CAGF,QAAQ,WAAW,IAAI,KAA8D;EACnF,MAAM;EACN,UAAU;CACZ,CAAC;AACH"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@pumped-fn/lite-react-json-render",
3
+ "version": "0.0.0",
4
+ "description": "json-render state and action adapters for @pumped-fn/lite-react",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.cts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.mts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE",
25
+ "CHANGELOG.md"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsdown --config-loader tsx",
29
+ "typecheck": "tsc --noEmit",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest"
32
+ },
33
+ "dependencies": {
34
+ "@json-render/core": "catalog:"
35
+ },
36
+ "peerDependencies": {
37
+ "@pumped-fn/lite-react": "^2.3.0",
38
+ "react": "^18.0.0 || ^19.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@pumped-fn/lite": "workspace:*",
42
+ "@pumped-fn/lite-react": "workspace:*",
43
+ "@types/react": "catalog:",
44
+ "react": "catalog:",
45
+ "tsdown": "catalog:",
46
+ "typescript": "catalog:",
47
+ "vite": "catalog:",
48
+ "vitest": "catalog:"
49
+ },
50
+ "engines": {
51
+ "node": ">=18"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "repository": {
57
+ "type": "git",
58
+ "directory": "packages/lite-react-json-render",
59
+ "url": "git+https://github.com/pumped-fn/pumped-fn.git"
60
+ },
61
+ "keywords": [
62
+ "json-render",
63
+ "state-store",
64
+ "pumped-fn",
65
+ "lite-react",
66
+ "react",
67
+ "scoped-value"
68
+ ],
69
+ "license": "MIT"
70
+ }