playhtml 2.2.0 → 2.3.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/dist/style.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";.__playhtml-can-move{cursor:grab;transition:transform .15s;will-change:transform}.__playhtml-can-move.cursordown{cursor:grabbing}.__playhtml-can-spin{cursor:grab;transition:transform .25s;will-change:transform}.__playhtml-can-spin.cursordown{cursor:grabbing}.__playhtml-can-grow{cursor:pointer;transition:transform .25s;will-change:transform}.__playhtml-can-toggle,.__playhtml-can-draw{cursor:pointer}.__playhtml-can-draw .__playhtml-draw-container{position:relative;width:100%;height:100%;cursor:none}.__playhtml-can-draw .__playhtml-draw-container canvas{position:absolute;top:0;left:0;cursor:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewport='0 0 100 100' style='overflow: visible; fill:black;font-size:20px;'><text y='-30%' x='-50%' style='transform:rotate(180deg)'>🖍️</text></svg>") 16 0,auto}body .__playhtml-element.editing:nth-child(2n){animation-name:jiggle1;animation-iteration-count:infinite;transform-origin:50% 10%;animation-duration:.25s;animation-delay:var(--jiggle-delay)}body .__playhtml-element.editing:nth-child(2n-1){animation-name:jiggle2;animation-iteration-count:infinite;animation-direction:alternate;transform-origin:30% 5%;animation-duration:.45s;animation-delay:var(--jiggle-delay)}@keyframes jiggle1{0%{transform:rotate(-1deg);animation-timing-function:ease-in}50%{transform:rotate(1.5deg);animation-timing-function:ease-out}}@keyframes jiggle2{0%{transform:rotate(1deg);animation-timing-function:ease-in}50%{transform:rotate(-1.5deg);animation-timing-function:ease-out}}
1
+ [can-move]{cursor:grab;transition:transform .15s;will-change:transform}[can-move].cursordown{cursor:grabbing}[can-spin]{cursor:grab;transition:transform .25s;will-change:transform}[can-spin].cursordown{cursor:grabbing}[can-grow]{cursor:pointer;transition:transform .25s;will-change:transform}[can-toggle]{cursor:pointer}body .__playhtml-element.editing:nth-child(2n){animation-name:jiggle1;animation-iteration-count:infinite;transform-origin:50% 10%;animation-duration:.25s;animation-delay:var(--jiggle-delay)}body .__playhtml-element.editing:nth-child(2n-1){animation-name:jiggle2;animation-iteration-count:infinite;animation-direction:alternate;transform-origin:30% 5%;animation-duration:.45s;animation-delay:var(--jiggle-delay)}@keyframes jiggle1{0%{transform:rotate(-1deg);animation-timing-function:ease-in}50%{transform:rotate(1.5deg);animation-timing-function:ease-out}}@keyframes jiggle2{0%{transform:rotate(1deg);animation-timing-function:ease-in}50%{transform:rotate(-1.5deg);animation-timing-function:ease-out}}.playhtml-loading{pointer-events:none}.playhtml-loading[data-loading-behavior=hidden]{opacity:0;visibility:hidden}.playhtml-loading[data-loading-style=breathing],.playhtml-loading[can-move],.playhtml-loading[can-toggle],.playhtml-loading[can-spin],.playhtml-loading[can-grow],.playhtml-loading[can-duplicate],.playhtml-loading[can-mirror],.playhtml-loading[can-draw],.playhtml-loading [loading-behavior=animate].playhtml-loading{animation:playhtml-breathing 2s infinite ease-in-out}.playhtml-loading[loading-style=fade]{opacity:.4!important;animation:none!important;transform:none!important}.playhtml-loading[loading-style=none],.playhtml-loading[loading-behavior=none]{opacity:1!important;animation:none!important;transform:none!important;visibility:visible!important;pointer-events:auto!important}@keyframes playhtml-breathing{0%,to{opacity:.7;transform:scale(1)}50%{opacity:.4;transform:scale(1.01)}}@keyframes playhtml-pulse{0%,to{opacity:.7;transform:scale(1)}50%{opacity:.3;transform:scale(1)}}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "playhtml",
3
3
  "title": "playhtml",
4
4
  "description": "Create interactive, collaborative html elements with a single attribute",
5
- "version": "2.2.0",
5
+ "version": "2.3.0",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "keywords": [
@@ -49,15 +49,7 @@
49
49
  "scripts": {
50
50
  "build": "tsc && vite build",
51
51
  "test": "vitest run --no-typecheck",
52
- "test:watch": "vitest --no-typecheck",
53
- "version-patch": "bun pm version patch",
54
- "version-minor": "bun pm version minor",
55
- "version-major": "bun pm version major",
56
- "publish": "(bun run build && rm README.md && cp ../../README.md . && bun publish && bun run cleanup) || (bun run cleanup)",
57
- "release-patch": "bun run version-patch && bun run publish",
58
- "release-minor": "bun run version-minor && bun run publish",
59
- "release-major": "bun run version-major && bun run publish",
60
- "cleanup": "rm README.md && ln -s ../../README.md ."
52
+ "test:watch": "vitest --no-typecheck"
61
53
  },
62
54
  "devDependencies": {
63
55
  "sass": "^1.62.1",
@@ -68,7 +60,7 @@
68
60
  "jsdom": "^26.1.0"
69
61
  },
70
62
  "dependencies": {
71
- "@playhtml/common": "0.1.0",
63
+ "@playhtml/common": "0.2.0",
72
64
  "@syncedstore/core": "^0.6.0",
73
65
  "y-indexeddb": "^9.0.11",
74
66
  "y-partykit": "^0.0.31",
package/README.md DELETED
@@ -1,303 +0,0 @@
1
- # <a href="https://playhtml.fun">playhtml</a> 🛝🌐 [![npm release](https://img.shields.io/npm/v/playhtml?color=%23ff980c)](https://www.npmjs.com/package/playhtml) [![Downloads](https://img.shields.io/npm/dm/playhtml)](https://www.npmjs.com/package/playhtml) [![Size](https://img.shields.io/bundlephobia/min/playhtml?color=%23c6e1ea)](https://www.npmjs.com/package/playhtml)
2
-
3
- _interactive, collaborative html elements with a single data attribute_
4
-
5
- playhtml is a fast, small (~300KB), library-agnostic, and expressive library for magically creating collaborative interactive HTML elements that persist their state across sessions.
6
-
7
- The simplest example is creating a shared, movable piece of HTML "furniture":
8
-
9
- ```html
10
- <div id="couch" can-move style="font-size: 80px">🛋</div>
11
- ```
12
-
13
- At a glance, playhtml supports:
14
-
15
- - reactive data scoped at a per-element level
16
- - sync and data persistence behavior customization (locally persisted, real-time synced, or globally persisted)
17
- - custom events for imperative logic
18
- - a range of magical plug-and-play and full customization
19
- - _(coming soon)_ a web component library for "plug-and-play" collaborative elements
20
- - _(coming soon)_ sharing state across domains
21
- - _(coming soon)_ permissioning for behaviors
22
- - _(coming soon)_ triggering behavior on a schedule (think cron)
23
- - _(coming soon)_ custom data sources for long-term persistence
24
-
25
- https://github.com/spencerc99/playhtml/assets/14796580/00e84e15-2c1c-4b4b-8e15-2af22f39db7a
26
-
27
- playhtml is still in beta and active development. Join our [Discord community](https://discord.gg/h7sABTv8) to get help and show off what you've built!
28
-
29
- ## Usage
30
-
31
- Head to the proper section depending on your technology preference:
32
-
33
- - [vanilla html / simple browser usage](#vanilla-html--simple-browser-usage)
34
- - [react / next.js / other frameworks](#react--nextjs--other-frameworks)
35
-
36
- ### vanilla html / simple browser usage
37
-
38
- To use this library, you can import the library from a CDN (in this case we will use [unpkg.com](https://unpkg.com)). Please make sure to do this after all the HTML elements on the page and ensure that the HTML elements you are "magic-ifying" have an `id` set.
39
-
40
- ```html
41
- <body>
42
- <!-- ... html elements here -->
43
- <!-- valid example -->
44
- <img
45
- src="https://media2.giphy.com/media/lL7A3Li0YtFHq/giphy.gif?cid=ecf05e47ah89o71gzz7ke7inrgb1ai1xcbrjnqdf7o890118&ep=v1_stickers_search&rid=giphy.gif"
46
- can-move
47
- id="openSign"
48
- />
49
- <!-- INVALID EXAMPLE <img src="https://media2.giphy.com/media/lL7A3Li0YtFHq/giphy.gif?cid=ecf05e47ah89o71gzz7ke7inrgb1ai1xcbrjnqdf7o890118&ep=v1_stickers_search&rid=giphy.gif" can-move /> -->
50
- <!-- import the script -->
51
-
52
- <!-- Option 1 (simplest, no customization) -->
53
- <script
54
- type="module"
55
- src="https://unpkg.com/playhtml@latest/dist/init.es.js"
56
- ></script>
57
-
58
- <!-- Option 2 (customize options to specify the room everyone connects to (a unique ID) or use your own partykit provider) -->
59
- <script type="module">
60
- import "https://unpkg.com/playhtml@latest";
61
- playhtml.init({
62
- room: "my-room",
63
- host: `${myPartykitUser}.partykit.dev`,
64
- });
65
- </script>
66
- </body>
67
- ```
68
-
69
- If you have dynamic elements that are hydrated after the initial load, you can call `playhtml.setupPlayElement(element)` to imbue the element with playhtml properties.
70
-
71
- ```html
72
- <script type="module">
73
- import { playhtml } from "https://unpkg.com/playhtml@latest";
74
- const newPlayElement = document.createElement("div");
75
- newPlayElement.id = "newPlayElement";
76
- playhtml.setupPlayElement(newPlayElement);
77
- </script>
78
- ```
79
-
80
- #### eventing
81
-
82
- You can set up imperative logic that doesn't depend on a data value changing (like triggering confetti when someone clicks in an area) by registering events with playhtml. You can either pass in a list of events when you call `playhtml.init` or you can call `playhtml.registerPlayEventListener` to register an event at any time.
83
-
84
- https://github.com/spencerc99/playhtml/assets/14796580/bd8ecfaf-73ab-4aa2-9312-8917809f52a2
85
-
86
- ```html
87
- <div
88
- style="width: 400px; height: 400px; border: 1px red solid"
89
- id="confettiZone"
90
- >
91
- <h1>CONFETTI ZONE</h1>
92
- </div>
93
- <!-- Import confetti library -->
94
- <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script>
95
- <script>
96
- confettiZone.addEventListener("click", onClickConfettiZone);
97
- function onClickConfettiZone(e) {
98
- playhtml.dispatchPlayEvent({ type: "confetti" });
99
- }
100
- </script>
101
- <script type="module">
102
- import "https://unpkg.com/playhtml@latest";
103
- playhtml.init({
104
- events: {
105
- confetti: {
106
- type: "confetti",
107
- onEvent: (data) => {
108
- window.confetti({
109
- particleCount: 100,
110
- spread: 70,
111
- origin: { y: 0.6 },
112
- });
113
- },
114
- },
115
- },
116
- });
117
- </script>
118
- ```
119
-
120
- ### react-based frameworks
121
-
122
- **react**
123
- `@playhtml/react` provides components out of the box corresponding to each of the capabilities. It manages all the state syncing for you, so you can reactively render your component based on whatever data is coming in.
124
-
125
- Refer to the [@playhtml/react README](https://github.com/spencerc99/playhtml/tree/main/packages/react) for the getting started guide.
126
-
127
- ---
128
-
129
- To create your own custom element, refer to the [can-play](#can-play) section.
130
-
131
- If you're trying this out and having trouble, please message me ([email](mailto:spencerc99@gmail.com), [twitter](https://twitter.com/spencerc99)) and I'm happy to help out!
132
-
133
- ## Examples
134
-
135
- To get started, you can find examples inside `index.html`, the `website/experiments` folder (these all have corresponding live demos at playhtml.fun/experiments/one/), and React examples under `packages/react/examples`.
136
-
137
- ## Custom Capabilities
138
-
139
- ### `can-play`
140
-
141
- `can-play` is the fully customizable experience of `playhtml`. You can create anything using simple HTML, CSS, and Javascript by simply adding on the functionality needed to the element itself. The library will handle magically syncing and persisting any data that you store.
142
-
143
- Here's the simple example included on the playhtml website:
144
-
145
- https://github.com/spencerc99/playhtml/assets/14796580/fae669b1-b3e2-404e-bd7a-3d36b81c572d
146
-
147
- ```html
148
- <img can-play id="customCandle" src="/candle-gif.gif" />
149
- <!-- IMPORTANT: this data must be set _before_ importing the playhtml library. -->
150
- <script>
151
- let candle = document.getElementById("customCandle");
152
- candle.defaultData = { on: true };
153
- candle.onClick = (_e, { data, setData }) => {
154
- setData({ on: !data.on });
155
- };
156
- candle.updateElement = ({ element, data }) => {
157
- element.src = data.on ? "/candle-gif.gif" : "/candle-off.png";
158
- };
159
- candle.resetShortcut = "shiftKey";
160
-
161
- // If you wanted to trigger this on hover, you could use `onMount`
162
- // which can initialize several different event listeners and custom logic.
163
- // customCandle.onMount = ({ getData, setData }) => {
164
- // customCandle.addEventListener("mouseover", (_e) => {
165
- // const data = getData();
166
- // setData({on: !data.on}});
167
- // });
168
- // };
169
- </script>
170
-
171
- <!-- Import playhtml -->
172
- <script type="module">
173
- import "https://unpkg.com/playhtml@latest";
174
- playhtml.init();
175
- </script>
176
- ```
177
-
178
- See all supported properties in the `ElementInitializer` [object in `common/src/index.ts`](https://github.com/spencerc99/playhtml/blob/main/packages/common/src/index.ts#L7).
179
-
180
- The only required properties are `defaultData`, `updateElement` and some kind of setup to trigger those functions (in this case, `onClick`, but you can add custom event listeners and logic using the `onMount` property). See more examples based on the definitions for the included capabilities in [`elements.ts`](https://github.com/spencerc99/playhtml/blob/packages/playhtml/src/elements.ts).
181
-
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
-
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
-
237
- ### Advanced
238
-
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.
240
-
241
- ## Plug-and-play Capabilities
242
-
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.
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
-
251
- ### `can-move`
252
-
253
- https://github.com/spencerc99/playhtml/assets/14796580/215c7631-d71f-40e6-bdda-bd8146a88006
254
-
255
- Creates a movable element using 2D `translate` on the element. Dragging the element around will move it
256
-
257
- **troubleshooting**
258
-
259
- - This currently doesn't work on `inline` display elements.
260
-
261
- ### `can-toggle`
262
-
263
- https://github.com/spencerc99/playhtml/assets/14796580/7e667c06-c32e-4369-b250-c9ca321de163
264
-
265
- _from https://twitter.com/spencerc99/status/1681048824884895744_
266
-
267
- Creates an element that can be switched on and off. Clicking the element will toggle the `clicked` class on the element.
268
-
269
- ### `can-duplicate`
270
-
271
- https://github.com/spencerc99/playhtml/assets/14796580/6d9f1228-08cf-45a7-987a-8bebfaaefd83
272
-
273
- _used to programmatically and dynamically create new playhtml elements that aren't included in the initial HTML_
274
-
275
- Creates an element that duplicates a target element (specified by the value of the `can-duplicate` attribute, which can be an element's ID or custom CSS selector) when clicked. Optionally can specify where the duplicate element is inserted in the DOM via the `can-duplicate-to` setting (default is as a sibling to the original element).
276
-
277
- ### `can-grow`
278
-
279
- Creates an element that can be resized using a `scale` `transform`. Clicking the element will grow it, clicking with <kbd>ALT</kbd> will shrink it. Currently, the max size is 2x the original size and the min size is 1/2 the original size.
280
-
281
- ### `can-spin`
282
-
283
- Creates a rotatable element using a `rotate` `transform` on the element. Dragging the element to the left or right will rotate it counter-clockwise and clockwise respectively.
284
-
285
- ## Help & Community
286
-
287
- Join our [Discord community](https://discord.gg/SKbsSf4ptU) to get help and show off what you've built!
288
-
289
- ## Data Policy
290
-
291
- Currently all data is stored by a [Partykit](https://partykit.dev) instance under my account and is not encrypted. This means that anyone with the room name can access the data. In the future, I'd like to enable providing your own custom persistence options via object storage providers (or any generic service that can accept a POST endpoint with a dump of the data).
292
-
293
- ## Contributing
294
-
295
- See [CONTRIBUTING.md](https://github.com/spencerc99/playhtml/blob/main/CONTRIBUTING.md).
296
-
297
- ## Support & Maintenance
298
-
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
- ```