@rozenite/controls-plugin 1.11.0 → 1.12.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.
@@ -1,11 +1,11 @@
1
1
  import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
- import { useEffect, useMemo, useRef } from 'react';
2
+ import { useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
3
3
  import type {
4
4
  ControlsEventMap,
5
5
  ControlsInvokeActionEvent,
6
6
  ControlsUpdateRequestEvent,
7
7
  } from '../shared/messaging';
8
- import type { RozeniteControlsPluginOptions } from '../shared/types';
8
+ import type { RozeniteControlsPluginOptionsInput } from '../shared/types';
9
9
  import {
10
10
  buildActionRegistry,
11
11
  getActionRegistryKey,
@@ -13,23 +13,45 @@ import {
13
13
  validateValue,
14
14
  } from '../shared/serialization';
15
15
  import { useControlsAgentTools } from './useControlsAgentTools';
16
+ import { controlsRegistry } from './controlsRegistry';
16
17
 
17
- export const useRozeniteControlsPlugin = ({
18
- sections,
19
- }: RozeniteControlsPluginOptions) => {
18
+ export const useRozeniteControlsPlugin = (
19
+ optionsInput: RozeniteControlsPluginOptionsInput,
20
+ ) => {
20
21
  const client = useRozeniteDevToolsClient<ControlsEventMap>({
21
22
  pluginId: '@rozenite/controls-plugin',
22
23
  });
24
+ const registrationIdRef = useRef<symbol>(Symbol('rozenite-controls'));
25
+ const registrationId = registrationIdRef.current;
26
+ const registrySnapshot = useSyncExternalStore(
27
+ controlsRegistry.subscribe,
28
+ controlsRegistry.getSnapshot,
29
+ controlsRegistry.getSnapshot,
30
+ );
23
31
 
24
- useControlsAgentTools(sections);
25
-
26
- const snapshot = useMemo(() => serializeSections(sections), [sections]);
27
- const actionRegistry = useMemo(() => buildActionRegistry(sections), [sections]);
28
- const actionRegistryRef = useRef(actionRegistry);
32
+ useEffect(() => {
33
+ return () => {
34
+ controlsRegistry.delete(registrationId);
35
+ };
36
+ }, [registrationId]);
29
37
 
30
38
  useEffect(() => {
31
- actionRegistryRef.current = actionRegistry;
32
- }, [actionRegistry]);
39
+ controlsRegistry.set(registrationId, optionsInput);
40
+ }, [optionsInput, registrationId]);
41
+
42
+ const isRegistryOwner = useMemo(
43
+ () =>
44
+ controlsRegistry.isOwner(registrationId, {
45
+ id: registrationId,
46
+ input: optionsInput,
47
+ }),
48
+ [optionsInput, registrySnapshot, registrationId],
49
+ );
50
+
51
+ useControlsAgentTools(
52
+ () => controlsRegistry.getOptions().sections,
53
+ isRegistryOwner,
54
+ );
33
55
 
34
56
  useEffect(() => {
35
57
  if (!client) {
@@ -38,12 +60,12 @@ export const useRozeniteControlsPlugin = ({
38
60
 
39
61
  client.send('snapshot', {
40
62
  type: 'snapshot',
41
- sections: snapshot,
63
+ sections: serializeSections(controlsRegistry.getOptions().sections),
42
64
  });
43
- }, [client, snapshot]);
65
+ }, [client, optionsInput, registrySnapshot]);
44
66
 
45
67
  useEffect(() => {
46
- if (!client) {
68
+ if (!client || !isRegistryOwner) {
47
69
  return;
48
70
  }
49
71
 
@@ -54,7 +76,9 @@ export const useRozeniteControlsPlugin = ({
54
76
  value,
55
77
  }: ControlsUpdateRequestEvent) => {
56
78
  const key = getActionRegistryKey(sectionId, itemId);
57
- const entry = actionRegistryRef.current.get(key);
79
+ const entry = buildActionRegistry(
80
+ controlsRegistry.getOptions().sections,
81
+ ).get(key);
58
82
 
59
83
  if (!entry || entry.type === 'button') {
60
84
  client.send('update-result', {
@@ -142,7 +166,7 @@ export const useRozeniteControlsPlugin = ({
142
166
  } catch (error) {
143
167
  console.warn(
144
168
  `[Rozenite] Controls Plugin: Update failed for ${sectionId}/${itemId}.`,
145
- error
169
+ error,
146
170
  );
147
171
  client.send('update-result', {
148
172
  type: 'update-result',
@@ -162,17 +186,19 @@ export const useRozeniteControlsPlugin = ({
162
186
  }: ControlsInvokeActionEvent) => {
163
187
  if (action !== 'press') {
164
188
  console.warn(
165
- `[Rozenite] Controls Plugin: Unsupported action "${action}" for ${sectionId}/${itemId}.`
189
+ `[Rozenite] Controls Plugin: Unsupported action "${action}" for ${sectionId}/${itemId}.`,
166
190
  );
167
191
  return;
168
192
  }
169
193
 
170
194
  const key = getActionRegistryKey(sectionId, itemId);
171
- const entry = actionRegistryRef.current.get(key);
195
+ const entry = buildActionRegistry(
196
+ controlsRegistry.getOptions().sections,
197
+ ).get(key);
172
198
 
173
199
  if (!entry) {
174
200
  console.warn(
175
- `[Rozenite] Controls Plugin: Action target not found for ${sectionId}/${itemId}.`
201
+ `[Rozenite] Controls Plugin: Action target not found for ${sectionId}/${itemId}.`,
176
202
  );
177
203
  return;
178
204
  }
@@ -180,7 +206,7 @@ export const useRozeniteControlsPlugin = ({
180
206
  try {
181
207
  if (entry.type !== 'button') {
182
208
  console.warn(
183
- `[Rozenite] Controls Plugin: Invalid press action payload for ${sectionId}/${itemId}.`
209
+ `[Rozenite] Controls Plugin: Invalid press action payload for ${sectionId}/${itemId}.`,
184
210
  );
185
211
  return;
186
212
  }
@@ -189,7 +215,7 @@ export const useRozeniteControlsPlugin = ({
189
215
  } catch (error) {
190
216
  console.warn(
191
217
  `[Rozenite] Controls Plugin: Action failed for ${sectionId}/${itemId}.`,
192
- error
218
+ error,
193
219
  );
194
220
  }
195
221
  };
@@ -198,12 +224,15 @@ export const useRozeniteControlsPlugin = ({
198
224
  client.onMessage('get-snapshot', () => {
199
225
  client.send('snapshot', {
200
226
  type: 'snapshot',
201
- sections: snapshot,
227
+ sections: serializeSections(controlsRegistry.getOptions().sections),
202
228
  });
203
229
  }),
204
- client.onMessage('update-request', (event: ControlsUpdateRequestEvent) => {
205
- void handleUpdateRequest(event);
206
- }),
230
+ client.onMessage(
231
+ 'update-request',
232
+ (event: ControlsUpdateRequestEvent) => {
233
+ void handleUpdateRequest(event);
234
+ },
235
+ ),
207
236
  client.onMessage('invoke-action', (event: ControlsInvokeActionEvent) => {
208
237
  void handleInvokeAction(event);
209
238
  }),
@@ -212,7 +241,7 @@ export const useRozeniteControlsPlugin = ({
212
241
  return () => {
213
242
  subscriptions.forEach((subscription) => subscription.remove());
214
243
  };
215
- }, [client, snapshot]);
244
+ }, [client, isRegistryOwner]);
216
245
 
217
246
  return client;
218
247
  };
@@ -98,6 +98,14 @@ export type RozeniteControlsPluginOptions = {
98
98
  sections: ControlsSection[];
99
99
  };
100
100
 
101
+ export type RozeniteControlsPluginOptionsUpdater = (
102
+ previousOptions: RozeniteControlsPluginOptions,
103
+ ) => RozeniteControlsPluginOptions;
104
+
105
+ export type RozeniteControlsPluginOptionsInput =
106
+ | RozeniteControlsPluginOptions
107
+ | RozeniteControlsPluginOptionsUpdater;
108
+
101
109
  export const createSection = <TSection extends ControlsSection>(
102
- section: TSection
110
+ section: TSection,
103
111
  ): TSection => section;