playhtml 2.1.12-beta.0 → 2.2.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/README.md CHANGED
@@ -181,6 +181,59 @@ The only required properties are `defaultData`, `updateElement` and some kind of
181
181
 
182
182
  If you make something fun, please show me! This is designed as an open library for anyone to add on new interactions and capabilities, so we [welcome contributions](https://github.com/spencerc99/playhtml/blob/main/CONTRIBUTING.md) for new built-in capabilities.
183
183
 
184
+ #### Data updates: mutator vs replacement
185
+
186
+ playhtml supports two ways to update an element's `data` via `setData`, and they have different semantics:
187
+
188
+ - **Mutator form**: pass a function that receives a draft and mutate it in place. This is merge-friendly (supports adding to a list without conflicts) and is the recommended way to update nested arrays/objects.
189
+ - **Replacement form**: pass a full value. This replaces the entire snapshot and is useful for canonical state.
190
+
191
+ Examples
192
+
193
+ 1. **Mutator (merge-friendly): append to a list**
194
+
195
+ ```tsx
196
+ // data: { messages: string[] }
197
+ setData((draft) => {
198
+ draft.messages.push("hello");
199
+ });
200
+ ```
201
+
202
+ Note: when working with the mutator forms, there are some limitations on how you can mutate the array properly.
203
+ **✅ Supported Array Operations:**
204
+
205
+ ```tsx
206
+ setData((draft) => {
207
+ // ✅ Adding elements
208
+ draft.items.push(newItem);
209
+
210
+ // ✅ Removing/inserting at specific positions
211
+ draft.items.splice(0, 1); // Remove first element
212
+ draft.items.splice(2, 0, newItem); // replace element at index 2
213
+
214
+ // ✅ Modifying existing objects in the array
215
+ draft.items[0].name = "updated";
216
+ });
217
+ ```
218
+
219
+ **❌ Unsupported Array Operations:**
220
+
221
+ ```tsx
222
+ setData((draft) => {
223
+ // ❌ These will throw "array assignment is not implemented / supported"
224
+ draft.items.shift(); // Use splice(0, 1) instead
225
+ draft.items.pop(); // Use splice(-1, 1) instead
226
+ draft.items[index] = newItem; // Use splice(index, 1, newItem) instead
227
+ });
228
+ ```
229
+
230
+ 2. **Replacement (overwrite snapshot): toggle boolean**
231
+
232
+ ```tsx
233
+ // data: { on: boolean; ... }
234
+ setData({ ...data, on: !data.on });
235
+ ```
236
+
184
237
  ### Advanced
185
238
 
186
239
  IDs are recommended on all elements to uniquely identify them. If you are applying the same capability to several elements, you can also use the `selector-id` attribute to specify a selector to the elements that distinguishes them. The ID will be the index of the element in that selector query.
@@ -189,6 +242,12 @@ IDs are recommended on all elements to uniquely identify them. If you are applyi
189
242
 
190
243
  These capabilities are common ones that have been designed and created by the community. You should expect that they are relatively well-tested, and they simply build on top of the same API and constructs that `can-play` uses.
191
244
 
245
+ ### `can-mirror`
246
+
247
+ **EXPERIMENTAL: USE WITH CAUTION**
248
+
249
+ Automatically syncs all styles and children of an element. This is a really powerful and expressive way to code as you normally do but have it be automatically collaborative. Still in testing and may have some bugs. NOTE that anyone can change the styles using their dev console and have it also sync across. Restricting values to certain ranges or values will soon be supported.
250
+
192
251
  ### `can-move`
193
252
 
194
253
  https://github.com/spencerc99/playhtml/assets/14796580/215c7631-d71f-40e6-bdda-bd8146a88006
@@ -238,3 +297,7 @@ See [CONTRIBUTING.md](https://github.com/spencerc99/playhtml/blob/main/CONTRIBUT
238
297
  ## Support & Maintenance
239
298
 
240
299
  Thank you for considering reading this little README and browing this project! I'd love to see you share the library and what you've made with it to me and with your friends. And if you enjoy using this, please consider [sponsoring the project or sending a small donation](https://github.com/sponsors/spencerc99). This helps ensure that the library is maintained and improved over time and funds the hosting costs for the syncing and persistence services.
300
+
301
+ ```
302
+
303
+ ```
package/dist/main.d.ts CHANGED
@@ -1,17 +1,16 @@
1
- /// <reference lib="dom" />
2
-
3
- import { ElementAwarenessEventHandlerData } from '@playhtml/common';
4
- import { ElementData } from '@playhtml/common';
5
- import { ElementEventHandlerData } from '@playhtml/common';
6
- import { ElementInitializer } from '@playhtml/common';
7
- import { ElementSetupData } from '@playhtml/common';
8
- import { EventMessage } from '@playhtml/common';
9
- import { ModifierKey } from '@playhtml/common';
10
- import { PlayEvent } from '@playhtml/common';
11
- import { RegisteredPlayEvent } from '@playhtml/common';
12
- import { TagType } from '@playhtml/common';
1
+ import { default as default_2 } from 'y-partykit/provider';
2
+ import { ElementAwarenessEventHandlerData } from '../../common/src';
3
+ import { ElementData } from '../../common/src';
4
+ import { ElementEventHandlerData } from '../../common/src';
5
+ import { ElementInitializer } from '../../common/src';
6
+ import { ElementSetupData } from '../../common/src';
7
+ import { EventMessage } from '../../common/src';
8
+ import { MappedTypeDescription } from '@syncedstore/core/types/doc';
9
+ import { ModifierKey } from '../../common/src';
10
+ import { PlayEvent } from '../../common/src';
11
+ import { RegisteredPlayEvent } from '../../common/src';
12
+ import { TagType } from '../../common/src';
13
13
  import * as Y from 'yjs';
14
- import YPartyKitProvider from 'y-partykit/provider';
15
14
 
16
15
  declare function dispatchPlayEvent(message: EventMessage): void;
17
16
 
@@ -49,9 +48,29 @@ declare class ElementHandler<T = any, U = any, V = any> {
49
48
  getAwarenessEventHandlerData(): ElementAwarenessEventHandlerData<T, U, V>;
50
49
  getSetupData(): ElementSetupData<T, U>;
51
50
  /**
52
- * Public-use setter for data that makes the change to all clients.
51
+ * Public setter for element data.
52
+ *
53
+ * Semantics:
54
+ * - Mutator form: setData((draft) => { ... })
55
+ * When data is backed by SyncedStore/Yjs (dataMode = "syncedstore"),
56
+ * the draft is a live CRDT proxy. You can mutate nested arrays/objects
57
+ * and the change will be merged across clients without conflicts.
58
+ * Example:
59
+ * setData(d => { d.list.push(item); });
60
+ *
61
+ * - Value form: setData(value)
62
+ * Replaces the entire data snapshot. Use this when you need canonical
63
+ * replacement semantics (e.g., snapshot from a mirror) or when running
64
+ * in legacy plain mode. Example:
65
+ * setData({ on: true });
66
+ *
67
+ * Notes:
68
+ * - In plain mode, only the value form results in a sync; mutating draft
69
+ * is a no-op. Prefer the mutator form for merge-friendly edits.
70
+ * - Directly mutating eventData.data may work in SyncedStore mode, but the
71
+ * recommended portable pattern is setData(draft => { ... }).
53
72
  */
54
- setData(data: T): void;
73
+ setData(data: T | ((draft: T) => void)): void;
55
74
  setMyAwareness(data: V): void;
56
75
  setDataDebounced(data: T): void;
57
76
  /**
@@ -60,6 +79,8 @@ declare class ElementHandler<T = any, U = any, V = any> {
60
79
  reset(): void;
61
80
  }
62
81
 
82
+ declare let globalData: Y.Map<any>;
83
+
63
84
  export declare interface InitOptions<T = any> {
64
85
  /**
65
86
  * The room to connect users to (this should be a string that matches the other users
@@ -98,9 +119,13 @@ export declare interface InitOptions<T = any> {
98
119
  * Runs if playhtml fails to connect. Useful to show error messages and debugging.
99
120
  */
100
121
  onError?: () => void;
122
+ /**
123
+ * If true, will render some helpful development UI.
124
+ */
125
+ developmentMode?: boolean;
101
126
  }
102
127
 
103
- declare function initPlayHTML({ host, extraCapabilities, events, defaultRoomOptions, room: inputRoom, onError, }?: InitOptions): Promise<YPartyKitProvider | undefined>;
128
+ declare function initPlayHTML({ host, extraCapabilities, events, defaultRoomOptions, room: inputRoom, onError, developmentMode, }?: InitOptions): Promise<default_2 | undefined>;
104
129
 
105
130
  export declare const playhtml: PlayHTMLComponents;
106
131
 
@@ -110,7 +135,8 @@ declare interface PlayHTMLComponents {
110
135
  setupPlayElement: typeof setupPlayElement;
111
136
  removePlayElement: typeof removePlayElement;
112
137
  setupPlayElementForTag: typeof setupPlayElementForTag;
113
- globalData: Y.Map<any> | undefined;
138
+ syncedStore: (typeof store)["play"];
139
+ globalData: typeof globalData;
114
140
  elementHandlers: Map<string, Map<string, ElementHandler>> | undefined;
115
141
  eventHandlers: Map<string, Array<RegisteredPlayEvent>> | undefined;
116
142
  dispatchPlayEvent: typeof dispatchPlayEvent;
@@ -148,4 +174,10 @@ declare function setupPlayElement(element: Element, { ignoreIfAlreadySetup }?: {
148
174
  */
149
175
  declare function setupPlayElementForTag<T extends TagType | string>(element: HTMLElement, tag: T): Promise<void>;
150
176
 
177
+ declare const store: MappedTypeDescription<StoreShape>;
178
+
179
+ declare type StoreShape = {
180
+ play: Record<string, Record<string, any>>;
181
+ };
182
+
151
183
  export { }