@platforma-sdk/ui-vue 1.57.3 → 1.58.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/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +2 -2
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +28 -0
- package/dist/defineApp.d.ts +5 -5
- package/dist/defineApp.d.ts.map +1 -1
- package/dist/defineApp.js.map +1 -1
- package/dist/index.js +8 -8
- package/dist/internal/createAppV3.d.ts +6 -10
- package/dist/internal/createAppV3.d.ts.map +1 -1
- package/dist/internal/createAppV3.js +140 -105
- package/dist/internal/createAppV3.js.map +1 -1
- package/dist/internal/createAppV3.test.d.ts +2 -0
- package/dist/internal/createAppV3.test.d.ts.map +1 -0
- package/dist/lib.d.ts +3 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/usePlugin.d.ts +44 -0
- package/dist/usePlugin.d.ts.map +1 -0
- package/dist/usePlugin.js +14 -0
- package/dist/usePlugin.js.map +1 -0
- package/package.json +6 -6
- package/src/defineApp.ts +21 -11
- package/src/internal/createAppV2.test.ts +3 -0
- package/src/internal/createAppV3.test.ts +540 -0
- package/src/internal/createAppV3.ts +109 -41
- package/src/lib.ts +9 -1
- package/src/usePlugin.ts +65 -0
- package/dist/usePluginData.d.ts +0 -30
- package/dist/usePluginData.d.ts.map +0 -1
- package/dist/usePluginData.js +0 -22
- package/dist/usePluginData.js.map +0 -1
- package/src/usePluginData.ts +0 -63
|
@@ -8,12 +8,19 @@ import type {
|
|
|
8
8
|
ValueWithUTag,
|
|
9
9
|
AuthorMarker,
|
|
10
10
|
PlatformaExtended,
|
|
11
|
+
InferPluginHandles,
|
|
12
|
+
PluginHandle,
|
|
13
|
+
InferFactoryData,
|
|
14
|
+
InferFactoryOutputs,
|
|
15
|
+
PluginFactoryLike,
|
|
11
16
|
} from "@platforma-sdk/model";
|
|
12
17
|
import {
|
|
13
18
|
hasAbortError,
|
|
14
19
|
unwrapResult,
|
|
15
20
|
deriveDataFromStorage,
|
|
16
21
|
getPluginData,
|
|
22
|
+
isPluginOutputKey,
|
|
23
|
+
pluginOutputPrefix,
|
|
17
24
|
} from "@platforma-sdk/model";
|
|
18
25
|
import type { Ref } from "vue";
|
|
19
26
|
import { reactive, computed, ref } from "vue";
|
|
@@ -23,14 +30,16 @@ import { ensureOutputHasStableFlag, MultiError } from "../utils";
|
|
|
23
30
|
import { applyPatch } from "fast-json-patch";
|
|
24
31
|
import { UpdateSerializer } from "./UpdateSerializer";
|
|
25
32
|
import { watchIgnorable } from "@vueuse/core";
|
|
33
|
+
import type { PluginState, PluginAccess } from "../usePlugin";
|
|
26
34
|
|
|
27
35
|
export const patchPoolingDelay = 150;
|
|
28
36
|
|
|
29
|
-
/** Internal
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
/** Internal per-plugin state with reconciliation support. */
|
|
38
|
+
interface InternalPluginState<Data = unknown, Outputs = unknown> extends PluginState<
|
|
39
|
+
Data,
|
|
40
|
+
Outputs
|
|
41
|
+
> {
|
|
42
|
+
readonly ignoreUpdates: (fn: () => void) => void;
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
export const createNextAuthorMarker = (marker: AuthorMarker | undefined): AuthorMarker => ({
|
|
@@ -65,9 +74,10 @@ export function createAppV3<
|
|
|
65
74
|
Args = unknown,
|
|
66
75
|
Outputs extends BlockOutputsBase = BlockOutputsBase,
|
|
67
76
|
Href extends `/${string}` = `/${string}`,
|
|
77
|
+
Plugins extends Record<string, unknown> = Record<string, unknown>,
|
|
68
78
|
>(
|
|
69
79
|
state: ValueWithUTag<BlockStateV3<Data, Outputs, Href>>,
|
|
70
|
-
platforma: PlatformaExtended<PlatformaV3<Data, Args, Outputs, Href>>,
|
|
80
|
+
platforma: PlatformaExtended<PlatformaV3<Data, Args, Outputs, Href, Plugins>>,
|
|
71
81
|
settings: AppSettings,
|
|
72
82
|
) {
|
|
73
83
|
const debug = (msg: string, ...rest: unknown[]) => {
|
|
@@ -111,19 +121,19 @@ export function createAppV3<
|
|
|
111
121
|
const debounceSpan = settings.debounceSpan ?? 200;
|
|
112
122
|
|
|
113
123
|
const setDataQueue = new UpdateSerializer({ debounceSpan });
|
|
114
|
-
const pluginDataQueues = new Map<
|
|
115
|
-
const getPluginDataQueue = (
|
|
116
|
-
let queue = pluginDataQueues.get(
|
|
124
|
+
const pluginDataQueues = new Map<PluginHandle, UpdateSerializer>();
|
|
125
|
+
const getPluginDataQueue = (handle: PluginHandle): UpdateSerializer => {
|
|
126
|
+
let queue = pluginDataQueues.get(handle);
|
|
117
127
|
if (!queue) {
|
|
118
128
|
queue = new UpdateSerializer({ debounceSpan });
|
|
119
|
-
pluginDataQueues.set(
|
|
129
|
+
pluginDataQueues.set(handle, queue);
|
|
120
130
|
}
|
|
121
131
|
return queue;
|
|
122
132
|
};
|
|
123
133
|
const setNavigationStateQueue = new UpdateSerializer({ debounceSpan });
|
|
124
134
|
|
|
125
|
-
/**
|
|
126
|
-
const
|
|
135
|
+
/** Lazily-created per-plugin reactive states. */
|
|
136
|
+
const pluginStates = new Map<PluginHandle, InternalPluginState>();
|
|
127
137
|
/**
|
|
128
138
|
* Reactive snapshot of the application state, including args, outputs, UI state, and navigation state.
|
|
129
139
|
*/
|
|
@@ -141,25 +151,21 @@ export function createAppV3<
|
|
|
141
151
|
return platforma.mutateStorage({ operation: "update-block-data", value }, nextAuthorMarker());
|
|
142
152
|
};
|
|
143
153
|
|
|
144
|
-
const updatePluginData = async (
|
|
154
|
+
const updatePluginData = async (handle: PluginHandle, value: unknown) => {
|
|
145
155
|
return platforma.mutateStorage(
|
|
146
|
-
{ operation: "update-plugin-data", pluginId, value },
|
|
156
|
+
{ operation: "update-plugin-data", pluginId: handle, value },
|
|
147
157
|
nextAuthorMarker(),
|
|
148
158
|
);
|
|
149
159
|
};
|
|
150
160
|
|
|
151
|
-
/** Derives plugin data for a given pluginId from the current snapshot. */
|
|
152
|
-
const derivePluginDataFromSnapshot = (pluginId: string): unknown => {
|
|
153
|
-
return getPluginData(snapshot.value.blockStorage, pluginId);
|
|
154
|
-
};
|
|
155
|
-
|
|
156
161
|
const setNavigationState = async (state: NavigationState<Href>) => {
|
|
157
162
|
return platforma.setNavigationState(state);
|
|
158
163
|
};
|
|
159
164
|
|
|
160
165
|
const outputs = computed<OutputValues<Outputs>>(() => {
|
|
161
|
-
const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)
|
|
162
|
-
([k
|
|
166
|
+
const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)
|
|
167
|
+
.filter(([k]) => !isPluginOutputKey(k))
|
|
168
|
+
.map(([k, outputWithStatus]) =>
|
|
163
169
|
platforma.blockModelInfo.outputs[k]?.withStatus
|
|
164
170
|
? [k, ensureOutputHasStableFlag(outputWithStatus)]
|
|
165
171
|
: [
|
|
@@ -168,17 +174,17 @@ export function createAppV3<
|
|
|
168
174
|
? outputWithStatus.value
|
|
169
175
|
: undefined,
|
|
170
176
|
],
|
|
171
|
-
|
|
177
|
+
);
|
|
172
178
|
return Object.fromEntries(entries);
|
|
173
179
|
});
|
|
174
180
|
|
|
175
181
|
const outputErrors = computed<OutputErrors<Outputs>>(() => {
|
|
176
|
-
const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)
|
|
177
|
-
([k
|
|
182
|
+
const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)
|
|
183
|
+
.filter(([k]) => !isPluginOutputKey(k))
|
|
184
|
+
.map(([k, vOrErr]) => [
|
|
178
185
|
k,
|
|
179
186
|
vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined,
|
|
180
|
-
]
|
|
181
|
-
);
|
|
187
|
+
]);
|
|
182
188
|
return Object.fromEntries(entries);
|
|
183
189
|
});
|
|
184
190
|
|
|
@@ -251,8 +257,12 @@ export function createAppV3<
|
|
|
251
257
|
snapshot.value = applyPatch(snapshot.value, patches.value, false, false).newDocument;
|
|
252
258
|
updateAppModel({ data: deriveDataFromStorage<Data>(snapshot.value.blockStorage) });
|
|
253
259
|
// Reconcile plugin data from external source
|
|
254
|
-
for (const
|
|
255
|
-
|
|
260
|
+
for (const [handle, pluginState] of pluginStates) {
|
|
261
|
+
pluginState.ignoreUpdates(() => {
|
|
262
|
+
pluginState.model.data = deepClone(
|
|
263
|
+
getPluginData(snapshot.value.blockStorage, handle),
|
|
264
|
+
);
|
|
265
|
+
});
|
|
256
266
|
}
|
|
257
267
|
data.isExternalSnapshot = isAuthorChanged;
|
|
258
268
|
});
|
|
@@ -318,26 +328,83 @@ export function createAppV3<
|
|
|
318
328
|
},
|
|
319
329
|
};
|
|
320
330
|
|
|
331
|
+
/** Creates a lazily-cached per-plugin reactive state. */
|
|
332
|
+
const createPluginState = <F extends PluginFactoryLike>(
|
|
333
|
+
handle: PluginHandle<F>,
|
|
334
|
+
): InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>> => {
|
|
335
|
+
const prefix = pluginOutputPrefix(handle);
|
|
336
|
+
|
|
337
|
+
const pluginOutputs = computed(() => {
|
|
338
|
+
const result: Record<string, unknown> = {};
|
|
339
|
+
for (const [key, outputWithStatus] of Object.entries(
|
|
340
|
+
snapshot.value.outputs as Partial<Readonly<Outputs>>,
|
|
341
|
+
)) {
|
|
342
|
+
if (!key.startsWith(prefix)) continue;
|
|
343
|
+
result[key.slice(prefix.length)] =
|
|
344
|
+
outputWithStatus.ok && outputWithStatus.value !== undefined
|
|
345
|
+
? outputWithStatus.value
|
|
346
|
+
: undefined;
|
|
347
|
+
}
|
|
348
|
+
return result;
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const pluginOutputErrors = computed(() => {
|
|
352
|
+
const result: Record<string, Error | undefined> = {};
|
|
353
|
+
for (const [key, vOrErr] of Object.entries(
|
|
354
|
+
snapshot.value.outputs as Partial<Readonly<Outputs>>,
|
|
355
|
+
)) {
|
|
356
|
+
if (!key.startsWith(prefix)) continue;
|
|
357
|
+
result[key.slice(prefix.length)] =
|
|
358
|
+
vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined;
|
|
359
|
+
}
|
|
360
|
+
return result;
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const pluginModel = reactive({
|
|
364
|
+
data: deepClone(getPluginData(snapshot.value.blockStorage, handle)),
|
|
365
|
+
outputs: pluginOutputs,
|
|
366
|
+
outputErrors: pluginOutputErrors,
|
|
367
|
+
}) as InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>>["model"];
|
|
368
|
+
|
|
369
|
+
const { ignoreUpdates } = watchIgnorable(
|
|
370
|
+
() => pluginModel.data,
|
|
371
|
+
(newData) => {
|
|
372
|
+
if (newData === undefined) return;
|
|
373
|
+
debug("plugin setData", handle, newData);
|
|
374
|
+
getPluginDataQueue(handle).run(() =>
|
|
375
|
+
updatePluginData(handle, deepClone(newData)).then(unwrapResult),
|
|
376
|
+
);
|
|
377
|
+
},
|
|
378
|
+
{ deep: true },
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
model: pluginModel,
|
|
383
|
+
ignoreUpdates,
|
|
384
|
+
};
|
|
385
|
+
};
|
|
386
|
+
|
|
321
387
|
/** Plugin internals — provided via separate injection key, not exposed on useApp(). */
|
|
322
|
-
const pluginAccess:
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return getPluginDataQueue(pluginId).run(() =>
|
|
328
|
-
updatePluginData(pluginId, value).then(unwrapResult),
|
|
329
|
-
);
|
|
330
|
-
},
|
|
331
|
-
initPluginDataSlot(pluginId: string): void {
|
|
332
|
-
if (!(pluginId in pluginDataMap)) {
|
|
333
|
-
pluginDataMap[pluginId] = derivePluginDataFromSnapshot(pluginId);
|
|
388
|
+
const pluginAccess: PluginAccess = {
|
|
389
|
+
getOrCreatePluginState<F extends PluginFactoryLike>(handle: PluginHandle<F>) {
|
|
390
|
+
const existing = pluginStates.get(handle);
|
|
391
|
+
if (existing) {
|
|
392
|
+
return existing as unknown as PluginState<InferFactoryData<F>, InferFactoryOutputs<F>>;
|
|
334
393
|
}
|
|
394
|
+
const state = createPluginState(handle);
|
|
395
|
+
pluginStates.set(handle, state);
|
|
396
|
+
return state;
|
|
335
397
|
},
|
|
336
398
|
};
|
|
337
399
|
|
|
400
|
+
const plugins = Object.fromEntries(
|
|
401
|
+
platforma.blockModelInfo.pluginIds.map((id) => [id, id]),
|
|
402
|
+
) as InferPluginHandles<Plugins>;
|
|
403
|
+
|
|
338
404
|
const getters = {
|
|
339
405
|
closedRef,
|
|
340
406
|
snapshot,
|
|
407
|
+
plugins,
|
|
341
408
|
queryParams: computed(() => parseQuery<Href>(snapshot.value.navigationState.href as Href)),
|
|
342
409
|
href: computed(() => snapshot.value.navigationState.href),
|
|
343
410
|
hasErrors: computed(() =>
|
|
@@ -360,4 +427,5 @@ export type BaseAppV3<
|
|
|
360
427
|
Args = unknown,
|
|
361
428
|
Outputs extends BlockOutputsBase = BlockOutputsBase,
|
|
362
429
|
Href extends `/${string}` = `/${string}`,
|
|
363
|
-
|
|
430
|
+
Plugins extends Record<string, unknown> = Record<string, unknown>,
|
|
431
|
+
> = ReturnType<typeof createAppV3<Data, Args, Outputs, Href, Plugins>>["app"];
|
package/src/lib.ts
CHANGED
|
@@ -35,7 +35,15 @@ export * from "./components/PlAdvancedFilter";
|
|
|
35
35
|
|
|
36
36
|
export * from "./defineApp";
|
|
37
37
|
|
|
38
|
-
export {
|
|
38
|
+
export { usePlugin } from "./usePlugin";
|
|
39
|
+
export type { PluginState } from "./usePlugin";
|
|
40
|
+
export type {
|
|
41
|
+
PluginHandle,
|
|
42
|
+
PluginFactoryLike,
|
|
43
|
+
InferPluginHandle,
|
|
44
|
+
InferFactoryData,
|
|
45
|
+
InferFactoryOutputs,
|
|
46
|
+
} from "@platforma-sdk/model";
|
|
39
47
|
|
|
40
48
|
export * from "./createModel";
|
|
41
49
|
|
package/src/usePlugin.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { inject, type Reactive } from "vue";
|
|
2
|
+
import { pluginDataKey } from "./defineApp";
|
|
3
|
+
import type {
|
|
4
|
+
PluginHandle,
|
|
5
|
+
InferFactoryData,
|
|
6
|
+
InferFactoryOutputs,
|
|
7
|
+
PluginFactoryLike,
|
|
8
|
+
} from "@platforma-sdk/model";
|
|
9
|
+
|
|
10
|
+
/** Per-plugin reactive model exposed to consumers via usePlugin(). */
|
|
11
|
+
export interface PluginState<Data = unknown, Outputs = unknown> {
|
|
12
|
+
readonly model: Reactive<{
|
|
13
|
+
data: Data;
|
|
14
|
+
outputs: Outputs extends Record<string, unknown>
|
|
15
|
+
? { [K in keyof Outputs]: Outputs[K] | undefined }
|
|
16
|
+
: Record<string, unknown>;
|
|
17
|
+
outputErrors: Outputs extends Record<string, unknown>
|
|
18
|
+
? { [K in keyof Outputs]?: Error }
|
|
19
|
+
: Record<string, Error | undefined>;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Internal interface for plugin access — provided via Vue injection to usePlugin(). */
|
|
24
|
+
export interface PluginAccess {
|
|
25
|
+
getOrCreatePluginState<F extends PluginFactoryLike>(
|
|
26
|
+
handle: PluginHandle<F>,
|
|
27
|
+
): PluginState<InferFactoryData<F>, InferFactoryOutputs<F>>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Composable for accessing a plugin's reactive model: data, outputs, and outputErrors.
|
|
32
|
+
*
|
|
33
|
+
* Mirrors the `app.model` access pattern — `plugin.model.data` is reactive and deep-watched,
|
|
34
|
+
* mutations are automatically queued and sent to storage.
|
|
35
|
+
*
|
|
36
|
+
* @param handle - Opaque plugin handle obtained from `app.plugins`.
|
|
37
|
+
* @typeParam F - The plugin factory type (inferred from the handle)
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```vue
|
|
41
|
+
* <script setup lang="ts">
|
|
42
|
+
* import { usePlugin, type InferPluginHandle } from '@platforma-sdk/ui-vue';
|
|
43
|
+
* import type { CounterPlugin } from './plugins/counter';
|
|
44
|
+
*
|
|
45
|
+
* const props = defineProps<{ instance: InferPluginHandle<CounterPlugin> }>();
|
|
46
|
+
* const plugin = usePlugin(props.instance);
|
|
47
|
+
*
|
|
48
|
+
* plugin.model.data.count += 1; // reactive, triggers storage update
|
|
49
|
+
* plugin.model.outputs.displayText // computed, plugin's own outputs only
|
|
50
|
+
* plugin.model.outputErrors.displayText // Error | undefined
|
|
51
|
+
* </script>
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export function usePlugin<F extends PluginFactoryLike>(handle: PluginHandle<F>) {
|
|
55
|
+
const access = inject<PluginAccess>(pluginDataKey);
|
|
56
|
+
|
|
57
|
+
if (!access) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
"usePlugin requires a V3 block (BlockModelV3). " +
|
|
60
|
+
"Make sure the block uses apiVersion 3 and the plugin is installed.",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return access.getOrCreatePluginState<F>(handle);
|
|
65
|
+
}
|
package/dist/usePluginData.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composable for accessing and updating plugin-specific data.
|
|
3
|
-
*
|
|
4
|
-
* Plugin components are self-contained: they use this composable to read/write
|
|
5
|
-
* their own data slice from BlockStorage without knowing about the parent block's data.
|
|
6
|
-
*
|
|
7
|
-
* Requires a V3 block (BlockModelV3). Throws if used in a V1/V2 block.
|
|
8
|
-
*
|
|
9
|
-
* @param pluginId - The plugin instance ID (must match the ID used in BlockModelV3.plugin()).
|
|
10
|
-
* Must be a static value; changing it after mount will not re-bind the composable.
|
|
11
|
-
* @returns `{ data, updateData }` where `data` is a reactive ref to the plugin's data,
|
|
12
|
-
* and `updateData` returns a promise resolving to `true` if the mutation was sent,
|
|
13
|
-
* or `false` if data is not yet available.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```vue
|
|
17
|
-
* <script setup lang="ts">
|
|
18
|
-
* const { data, updateData } = usePluginData<CounterData>('counter');
|
|
19
|
-
*
|
|
20
|
-
* function increment() {
|
|
21
|
-
* updateData((d) => ({ ...d, count: d.count + 1 }));
|
|
22
|
-
* }
|
|
23
|
-
* </script>
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export declare function usePluginData<Data>(pluginId: string): {
|
|
27
|
-
data: import('vue').ComputedRef<Data | undefined>;
|
|
28
|
-
updateData: (cb: (current: Data) => Data) => Promise<boolean>;
|
|
29
|
-
};
|
|
30
|
-
//# sourceMappingURL=usePluginData.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"usePluginData.d.ts","sourceRoot":"","sources":["../src/usePluginData.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM;;qBAwB1B,CAAC,OAAO,EAAE,IAAI,KAAK,IAAI,KAAG,OAAO,CAAC,OAAO,CAAC;EAQnE"}
|
package/dist/usePluginData.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { inject as i, computed as u } from "vue";
|
|
2
|
-
import { deepClone as s } from "./lib/util/helpers/dist/objects.js";
|
|
3
|
-
import { pluginDataKey as l } from "./defineApp.js";
|
|
4
|
-
function d(t) {
|
|
5
|
-
const e = i(l);
|
|
6
|
-
if (!e)
|
|
7
|
-
throw new Error(
|
|
8
|
-
"usePluginData requires a V3 block (BlockModelV3). Make sure the block uses apiVersion 3 and the plugin is installed."
|
|
9
|
-
);
|
|
10
|
-
e.initPluginDataSlot(t);
|
|
11
|
-
const a = u(() => e.pluginDataMap[t]);
|
|
12
|
-
return { data: a, updateData: (o) => {
|
|
13
|
-
const r = a.value;
|
|
14
|
-
if (r === void 0) return Promise.resolve(!1);
|
|
15
|
-
const n = o(s(r));
|
|
16
|
-
return e.setPluginData(t, n);
|
|
17
|
-
} };
|
|
18
|
-
}
|
|
19
|
-
export {
|
|
20
|
-
d as usePluginData
|
|
21
|
-
};
|
|
22
|
-
//# sourceMappingURL=usePluginData.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"usePluginData.js","sources":["../src/usePluginData.ts"],"sourcesContent":["import { computed, inject } from \"vue\";\nimport { deepClone } from \"@milaboratories/helpers\";\nimport { pluginDataKey } from \"./defineApp\";\nimport type { PluginDataAccess } from \"./internal/createAppV3\";\n\n/**\n * Composable for accessing and updating plugin-specific data.\n *\n * Plugin components are self-contained: they use this composable to read/write\n * their own data slice from BlockStorage without knowing about the parent block's data.\n *\n * Requires a V3 block (BlockModelV3). Throws if used in a V1/V2 block.\n *\n * @param pluginId - The plugin instance ID (must match the ID used in BlockModelV3.plugin()).\n * Must be a static value; changing it after mount will not re-bind the composable.\n * @returns `{ data, updateData }` where `data` is a reactive ref to the plugin's data,\n * and `updateData` returns a promise resolving to `true` if the mutation was sent,\n * or `false` if data is not yet available.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * const { data, updateData } = usePluginData<CounterData>('counter');\n *\n * function increment() {\n * updateData((d) => ({ ...d, count: d.count + 1 }));\n * }\n * </script>\n * ```\n */\nexport function usePluginData<Data>(pluginId: string) {\n const access = inject<PluginDataAccess>(pluginDataKey);\n\n if (!access) {\n throw new Error(\n \"usePluginData requires a V3 block (BlockModelV3). \" +\n \"Make sure the block uses apiVersion 3 and the plugin is installed.\",\n );\n }\n\n // Initialize the plugin data slot from snapshot if not already done\n access.initPluginDataSlot(pluginId);\n\n // Reactive reference to the plugin's data in the shared optimistic map\n const data = computed<Data | undefined>(() => {\n return access.pluginDataMap[pluginId] as Data | undefined;\n });\n\n /**\n * Update plugin data with optimistic feedback.\n *\n * @param cb - Callback that receives a deep clone of current data and returns new data.\n * @returns Promise that resolves to true when the mutation is sent\n */\n const updateData = (cb: (current: Data) => Data): Promise<boolean> => {\n const current = data.value;\n if (current === undefined) return Promise.resolve(false);\n const newValue = cb(deepClone(current));\n return access.setPluginData(pluginId, newValue);\n };\n\n return { data, updateData };\n}\n"],"names":["usePluginData","pluginId","access","inject","pluginDataKey","data","computed","cb","current","newValue","deepClone"],"mappings":";;;AA8BO,SAASA,EAAoBC,GAAkB;AACpD,QAAMC,IAASC,EAAyBC,CAAa;AAErD,MAAI,CAACF;AACH,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAMJ,EAAAA,EAAO,mBAAmBD,CAAQ;AAGlC,QAAMI,IAAOC,EAA2B,MAC/BJ,EAAO,cAAcD,CAAQ,CACrC;AAeD,SAAO,EAAE,MAAAI,GAAM,YAPI,CAACE,MAAkD;AACpE,UAAMC,IAAUH,EAAK;AACrB,QAAIG,MAAY,OAAW,QAAO,QAAQ,QAAQ,EAAK;AACvD,UAAMC,IAAWF,EAAGG,EAAUF,CAAO,CAAC;AACtC,WAAON,EAAO,cAAcD,GAAUQ,CAAQ;AAAA,EAChD,EAEe;AACjB;"}
|
package/src/usePluginData.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { computed, inject } from "vue";
|
|
2
|
-
import { deepClone } from "@milaboratories/helpers";
|
|
3
|
-
import { pluginDataKey } from "./defineApp";
|
|
4
|
-
import type { PluginDataAccess } from "./internal/createAppV3";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Composable for accessing and updating plugin-specific data.
|
|
8
|
-
*
|
|
9
|
-
* Plugin components are self-contained: they use this composable to read/write
|
|
10
|
-
* their own data slice from BlockStorage without knowing about the parent block's data.
|
|
11
|
-
*
|
|
12
|
-
* Requires a V3 block (BlockModelV3). Throws if used in a V1/V2 block.
|
|
13
|
-
*
|
|
14
|
-
* @param pluginId - The plugin instance ID (must match the ID used in BlockModelV3.plugin()).
|
|
15
|
-
* Must be a static value; changing it after mount will not re-bind the composable.
|
|
16
|
-
* @returns `{ data, updateData }` where `data` is a reactive ref to the plugin's data,
|
|
17
|
-
* and `updateData` returns a promise resolving to `true` if the mutation was sent,
|
|
18
|
-
* or `false` if data is not yet available.
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```vue
|
|
22
|
-
* <script setup lang="ts">
|
|
23
|
-
* const { data, updateData } = usePluginData<CounterData>('counter');
|
|
24
|
-
*
|
|
25
|
-
* function increment() {
|
|
26
|
-
* updateData((d) => ({ ...d, count: d.count + 1 }));
|
|
27
|
-
* }
|
|
28
|
-
* </script>
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export function usePluginData<Data>(pluginId: string) {
|
|
32
|
-
const access = inject<PluginDataAccess>(pluginDataKey);
|
|
33
|
-
|
|
34
|
-
if (!access) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
"usePluginData requires a V3 block (BlockModelV3). " +
|
|
37
|
-
"Make sure the block uses apiVersion 3 and the plugin is installed.",
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Initialize the plugin data slot from snapshot if not already done
|
|
42
|
-
access.initPluginDataSlot(pluginId);
|
|
43
|
-
|
|
44
|
-
// Reactive reference to the plugin's data in the shared optimistic map
|
|
45
|
-
const data = computed<Data | undefined>(() => {
|
|
46
|
-
return access.pluginDataMap[pluginId] as Data | undefined;
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Update plugin data with optimistic feedback.
|
|
51
|
-
*
|
|
52
|
-
* @param cb - Callback that receives a deep clone of current data and returns new data.
|
|
53
|
-
* @returns Promise that resolves to true when the mutation is sent
|
|
54
|
-
*/
|
|
55
|
-
const updateData = (cb: (current: Data) => Data): Promise<boolean> => {
|
|
56
|
-
const current = data.value;
|
|
57
|
-
if (current === undefined) return Promise.resolve(false);
|
|
58
|
-
const newValue = cb(deepClone(current));
|
|
59
|
-
return access.setPluginData(pluginId, newValue);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return { data, updateData };
|
|
63
|
-
}
|