@scarlett-player/embed 1.2.0 → 1.4.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.
@@ -148,6 +148,7 @@ class StateManager {
148
148
  constructor(initialState) {
149
149
  this.signals = /* @__PURE__ */ new Map();
150
150
  this.changeSubscribers = /* @__PURE__ */ new Set();
151
+ this.definedDefaults = /* @__PURE__ */ new Map();
151
152
  this.initializeSignals(initialState);
152
153
  }
153
154
  /**
@@ -157,13 +158,51 @@ class StateManager {
157
158
  initializeSignals(overrides) {
158
159
  const initialState = { ...DEFAULT_STATE, ...overrides };
159
160
  for (const [key, value] of Object.entries(initialState)) {
160
- const stateKey = key;
161
- const stateSignal = signal(value);
162
- stateSignal.subscribe(() => {
163
- this.notifyChangeSubscribers(stateKey);
164
- });
165
- this.signals.set(stateKey, stateSignal);
161
+ this.createSignal(key, value);
162
+ }
163
+ }
164
+ /**
165
+ * Create and register a signal, wired to the global change subscribers.
166
+ *
167
+ * Shared by initializeSignals() and define() so a plugin-defined key behaves
168
+ * exactly like a built-in one and the two paths cannot drift apart.
169
+ *
170
+ * @private
171
+ */
172
+ createSignal(key, value) {
173
+ const stateSignal = signal(value);
174
+ stateSignal.subscribe(() => {
175
+ this.notifyChangeSubscribers(key);
176
+ });
177
+ this.signals.set(key, stateSignal);
178
+ }
179
+ /**
180
+ * Register a state key at runtime, for state a plugin owns.
181
+ *
182
+ * Core cannot know every plugin's keys, and {@link get} deliberately throws
183
+ * for unregistered ones — that throw is a useful typo-catcher and is worth
184
+ * keeping — so a plugin declares its keys before first use.
185
+ *
186
+ * Idempotent by design: re-defining an existing key leaves the current value
187
+ * untouched. Plugins commonly re-run setup after a source change, and that
188
+ * must not reset state that is already live.
189
+ *
190
+ * Namespace plugin keys with the plugin's own name to avoid collisions.
191
+ *
192
+ * @param key - State property key
193
+ * @param initialValue - Value used only when the key is new
194
+ *
195
+ * @example
196
+ * ```ts
197
+ * state.define('highlightSelection', null);
198
+ * ```
199
+ */
200
+ define(key, initialValue) {
201
+ if (this.signals.has(key)) {
202
+ return;
166
203
  }
204
+ this.definedDefaults.set(key, initialValue);
205
+ this.createSignal(key, initialValue);
167
206
  }
168
207
  /**
169
208
  * Get the signal for a state property.
@@ -307,7 +346,10 @@ class StateManager {
307
346
  * ```
308
347
  */
309
348
  reset() {
310
- this.update(DEFAULT_STATE);
349
+ this.update({
350
+ ...DEFAULT_STATE,
351
+ ...Object.fromEntries(this.definedDefaults)
352
+ });
311
353
  }
312
354
  /**
313
355
  * Reset a specific state property to its default value.
@@ -320,7 +362,7 @@ class StateManager {
320
362
  * ```
321
363
  */
322
364
  resetKey(key) {
323
- const defaultValue = DEFAULT_STATE[key];
365
+ const defaultValue = key in DEFAULT_STATE ? DEFAULT_STATE[key] : this.definedDefaults.get(key);
324
366
  this.set(key, defaultValue);
325
367
  }
326
368
  /**
@@ -1214,6 +1256,18 @@ class PluginAPI {
1214
1256
  setState(key, value) {
1215
1257
  this.stateManager.set(key, value);
1216
1258
  }
1259
+ /**
1260
+ * Register a state key this plugin owns, before first use.
1261
+ *
1262
+ * Idempotent — re-defining an existing key keeps its current value.
1263
+ * See {@link IPluginAPI.defineState}.
1264
+ *
1265
+ * @param key - State property key
1266
+ * @param initialValue - Value used only when the key is new
1267
+ */
1268
+ defineState(key, initialValue) {
1269
+ this.stateManager.define(key, initialValue);
1270
+ }
1217
1271
  /**
1218
1272
  * Subscribe to an event.
1219
1273
  *