hyperclayjs 1.17.0 → 1.19.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 +8 -8
- package/package.json +1 -1
- package/src/communication/live-sync.js +33 -0
- package/src/core/savePageCore.js +44 -6
- package/src/core/snapshot.js +16 -0
- package/src/hyperclay.js +1 -1
- package/src/ui/theModal.js +1 -1
- package/src/ui/toast.js +52 -2
package/README.md
CHANGED
|
@@ -62,10 +62,10 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
62
62
|
| edit-mode-helpers | 7.5KB | Admin-only functionality: [edit-mode-input], [edit-mode-resource], [edit-mode-onclick] |
|
|
63
63
|
| option-visibility | 7.8KB | Dynamic show/hide based on ancestor state with option:attribute="value" |
|
|
64
64
|
| persist | 2.4KB | Persist input/select/textarea values to the DOM with [persist] attribute |
|
|
65
|
-
| save-core |
|
|
65
|
+
| save-core | 8.9KB | Basic save function only - hyperclay.savePage() |
|
|
66
66
|
| save-system | 12.1KB | CMD+S, [trigger-save] button, savestatus attribute |
|
|
67
67
|
| save-toast | 0.9KB | Toast notifications for save events |
|
|
68
|
-
| snapshot | 10.
|
|
68
|
+
| snapshot | 10.8KB | Source of truth for page state - captures DOM snapshots for save and sync |
|
|
69
69
|
| tailwind-inject | 1.4KB | Injects tailwind CSS link with cache-bust on save |
|
|
70
70
|
| unsaved-warning | 1.3KB | Warn before leaving page with unsaved changes |
|
|
71
71
|
|
|
@@ -85,8 +85,8 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
85
85
|
| Module | Size | Description |
|
|
86
86
|
|--------|------|-------------|
|
|
87
87
|
| dialogs | 7.7KB | ask(), consent(), tell(), snippet() dialog functions |
|
|
88
|
-
| the-modal |
|
|
89
|
-
| toast |
|
|
88
|
+
| the-modal | 21.1KB | Full modal window creation system - window.theModal |
|
|
89
|
+
| toast | 10.7KB | Success/error message notifications, toast(msg, msgType) |
|
|
90
90
|
|
|
91
91
|
### Utilities (Core utilities (often auto-included))
|
|
92
92
|
|
|
@@ -121,7 +121,7 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
121
121
|
| Module | Size | Description |
|
|
122
122
|
|--------|------|-------------|
|
|
123
123
|
| file-upload | 10.7KB | File upload with progress |
|
|
124
|
-
| live-sync |
|
|
124
|
+
| live-sync | 11.4KB | Real-time DOM sync across browsers |
|
|
125
125
|
| send-message | 1.3KB | Message sending utility |
|
|
126
126
|
|
|
127
127
|
### Vendor Libraries (Third-party libraries)
|
|
@@ -132,17 +132,17 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
132
132
|
|
|
133
133
|
## Presets
|
|
134
134
|
|
|
135
|
-
### Minimal (~
|
|
135
|
+
### Minimal (~51.3KB)
|
|
136
136
|
Essential features for basic editing
|
|
137
137
|
|
|
138
138
|
**Modules:** `save-core`, `snapshot`, `save-system`, `edit-mode-helpers`, `toast`, `save-toast`, `export-to-window`, `view-mode-excludes-edit-modules`
|
|
139
139
|
|
|
140
|
-
### Standard (~
|
|
140
|
+
### Standard (~73.6KB)
|
|
141
141
|
Standard feature set for most use cases
|
|
142
142
|
|
|
143
143
|
**Modules:** `save-core`, `snapshot`, `save-system`, `unsaved-warning`, `edit-mode-helpers`, `persist`, `option-visibility`, `event-attrs`, `dom-helpers`, `toast`, `save-toast`, `export-to-window`, `view-mode-excludes-edit-modules`
|
|
144
144
|
|
|
145
|
-
### Everything (~
|
|
145
|
+
### Everything (~207.4KB)
|
|
146
146
|
All available features
|
|
147
147
|
|
|
148
148
|
Includes all available modules across all categories.
|
package/package.json
CHANGED
|
@@ -52,6 +52,7 @@ class LiveSync {
|
|
|
52
52
|
this.onDisconnect = null;
|
|
53
53
|
this.onUpdate = null;
|
|
54
54
|
this.onError = null;
|
|
55
|
+
this.onNotification = null;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
_log(message, data = null) {
|
|
@@ -190,6 +191,12 @@ class LiveSync {
|
|
|
190
191
|
this.sse.onmessage = (event) => {
|
|
191
192
|
const data = JSON.parse(event.data);
|
|
192
193
|
|
|
194
|
+
// Handle notifications (show toast, don't morph)
|
|
195
|
+
if (data.type === "notification") {
|
|
196
|
+
this.handleNotification(data);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
193
200
|
// Handle error events from server
|
|
194
201
|
if (data.error) {
|
|
195
202
|
console.error('[LiveSync] Server error:', data.error);
|
|
@@ -317,6 +324,32 @@ class LiveSync {
|
|
|
317
324
|
this.isPaused = false;
|
|
318
325
|
}
|
|
319
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Handle a notification message from the server
|
|
329
|
+
* Shows a toast and emits an event for custom handling
|
|
330
|
+
* @param {Object} data - { msgType, msg, action? }
|
|
331
|
+
*/
|
|
332
|
+
handleNotification({ msgType, msg, action }) {
|
|
333
|
+
this._log(`Notification received: ${msgType} - ${msg}`);
|
|
334
|
+
|
|
335
|
+
// Show toast if available
|
|
336
|
+
if (window.toast) {
|
|
337
|
+
window.toast(msg, msgType);
|
|
338
|
+
} else {
|
|
339
|
+
console.log(`[LiveSync] Notification: ${msg}`);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Emit event for custom handling (e.g., reload button)
|
|
343
|
+
document.dispatchEvent(new CustomEvent('hyperclay:notification', {
|
|
344
|
+
detail: { msgType, msg, action }
|
|
345
|
+
}));
|
|
346
|
+
|
|
347
|
+
// Call notification callback if set
|
|
348
|
+
if (this.onNotification) {
|
|
349
|
+
this.onNotification({ msgType, msg, action });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
320
353
|
/**
|
|
321
354
|
* Stop LiveSync and clean up resources
|
|
322
355
|
* Can call start() again to restart
|
package/src/core/savePageCore.js
CHANGED
|
@@ -112,12 +112,31 @@ export function savePage(callback = () => {}) {
|
|
|
112
112
|
const controller = new AbortController();
|
|
113
113
|
const timeoutId = setTimeout(() => controller.abort(), 12000);
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
// Check if running on Hyperclay Local - send JSON with both versions for platform sync
|
|
116
|
+
const isHyperclayLocal = window.location.hostname === 'localhost' ||
|
|
117
|
+
window.location.hostname === '127.0.0.1';
|
|
118
|
+
|
|
119
|
+
const fetchOptions = {
|
|
116
120
|
method: 'POST',
|
|
117
121
|
credentials: 'include',
|
|
118
|
-
body: currentContents,
|
|
119
122
|
signal: controller.signal
|
|
120
|
-
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
if (isHyperclayLocal && window.__hyperclaySnapshotHtml) {
|
|
126
|
+
// Send JSON with both stripped content and full snapshot for platform live sync
|
|
127
|
+
fetchOptions.headers = { 'Content-Type': 'application/json' };
|
|
128
|
+
fetchOptions.body = JSON.stringify({
|
|
129
|
+
content: currentContents,
|
|
130
|
+
snapshotHtml: window.__hyperclaySnapshotHtml
|
|
131
|
+
});
|
|
132
|
+
// Clear after use to avoid stale data
|
|
133
|
+
window.__hyperclaySnapshotHtml = null;
|
|
134
|
+
} else {
|
|
135
|
+
// Platform: send plain text as before
|
|
136
|
+
fetchOptions.body = currentContents;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
fetch(saveEndpoint, fetchOptions)
|
|
121
140
|
.then(res => {
|
|
122
141
|
clearTimeout(timeoutId);
|
|
123
142
|
return res.json().then(data => {
|
|
@@ -187,12 +206,31 @@ export function saveHtml(html, callback = () => {}) {
|
|
|
187
206
|
const controller = new AbortController();
|
|
188
207
|
const timeoutId = setTimeout(() => controller.abort(), 12000);
|
|
189
208
|
|
|
190
|
-
|
|
209
|
+
// Check if running on Hyperclay Local - send JSON with both versions for platform sync
|
|
210
|
+
const isHyperclayLocal = window.location.hostname === 'localhost' ||
|
|
211
|
+
window.location.hostname === '127.0.0.1';
|
|
212
|
+
|
|
213
|
+
const fetchOptions = {
|
|
191
214
|
method: 'POST',
|
|
192
215
|
credentials: 'include',
|
|
193
|
-
body: html,
|
|
194
216
|
signal: controller.signal
|
|
195
|
-
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
if (isHyperclayLocal && window.__hyperclaySnapshotHtml) {
|
|
220
|
+
// Send JSON with both stripped content and full snapshot for platform live sync
|
|
221
|
+
fetchOptions.headers = { 'Content-Type': 'application/json' };
|
|
222
|
+
fetchOptions.body = JSON.stringify({
|
|
223
|
+
content: html,
|
|
224
|
+
snapshotHtml: window.__hyperclaySnapshotHtml
|
|
225
|
+
});
|
|
226
|
+
// Clear after use to avoid stale data
|
|
227
|
+
window.__hyperclaySnapshotHtml = null;
|
|
228
|
+
} else {
|
|
229
|
+
// Platform: send plain text as before
|
|
230
|
+
fetchOptions.body = html;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
fetch(saveEndpoint, fetchOptions)
|
|
196
234
|
.then(res => {
|
|
197
235
|
clearTimeout(timeoutId);
|
|
198
236
|
return res.json().then(data => {
|
package/src/core/snapshot.js
CHANGED
|
@@ -85,6 +85,14 @@ export function captureSnapshot() {
|
|
|
85
85
|
hook(clone);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
for (const el of clone.querySelectorAll('[onbeforesnapshot]')) {
|
|
89
|
+
new Function(el.getAttribute('onbeforesnapshot')).call(el);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
for (const el of clone.querySelectorAll('[snapshot-remove]')) {
|
|
93
|
+
el.remove();
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
return clone;
|
|
89
97
|
}
|
|
90
98
|
|
|
@@ -172,6 +180,14 @@ export function captureForSaveAndComparison({ emitForSync = true } = {}) {
|
|
|
172
180
|
document.dispatchEvent(new CustomEvent('hyperclay:snapshot-ready', {
|
|
173
181
|
detail: { documentElement: clone }
|
|
174
182
|
}));
|
|
183
|
+
|
|
184
|
+
// Store snapshot HTML for Hyperclay Local platform sync
|
|
185
|
+
// This allows the save system to send both stripped and full versions
|
|
186
|
+
const isHyperclayLocal = window.location.hostname === 'localhost' ||
|
|
187
|
+
window.location.hostname === '127.0.0.1';
|
|
188
|
+
if (isHyperclayLocal) {
|
|
189
|
+
window.__hyperclaySnapshotHtml = '<!DOCTYPE html>' + clone.outerHTML;
|
|
190
|
+
}
|
|
175
191
|
}
|
|
176
192
|
|
|
177
193
|
// Run inline [onbeforesave] handlers
|
package/src/hyperclay.js
CHANGED
package/src/ui/theModal.js
CHANGED
|
@@ -595,7 +595,7 @@ const themodal = (() => {
|
|
|
595
595
|
const themodalMain = {
|
|
596
596
|
isShowing: false,
|
|
597
597
|
open() {
|
|
598
|
-
document.body.insertAdjacentHTML("afterbegin", "<div save-remove class='micromodal-parent'>" + modalCss + modalHtml + "</div>");
|
|
598
|
+
document.body.insertAdjacentHTML("afterbegin", "<div save-remove snapshot-remove class='micromodal-parent'>" + modalCss + modalHtml + "</div>");
|
|
599
599
|
|
|
600
600
|
const modalOverlayElem = document.querySelector(".micromodal__overlay");
|
|
601
601
|
const modalContentElem = document.querySelector(".micromodal__content");
|
package/src/ui/toast.js
CHANGED
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
// Default modern icons (normalized to 48x48 viewBox)
|
|
5
5
|
const defaultIcons = {
|
|
6
6
|
success: `<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.9404 23.9475L21.9099 31.224L35.1906 15.9045M3 4.5H44.9804V44.309H3V4.5Z" stroke="#33D131" stroke-width="4.3"/></svg>`,
|
|
7
|
-
error: `<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M32.7383 14.4045L14 33.1429M32.7451 33.1429L14.0068 14.4046M3.01 4H44.99V43.809H3.01V4Z" stroke="#FF4450" stroke-width="4"/></svg
|
|
7
|
+
error: `<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M32.7383 14.4045L14 33.1429M32.7451 33.1429L14.0068 14.4046M3.01 4H44.99V43.809H3.01V4Z" stroke="#FF4450" stroke-width="4"/></svg>`,
|
|
8
|
+
warning: `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke="#F5A623" stroke-width="2" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"/></svg>`,
|
|
9
|
+
info: `<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="24" cy="24" r="20" stroke="#4A90D9" stroke-width="4"/><path d="M24 20V32M24 14V16" stroke="#4A90D9" stroke-width="4" stroke-linecap="round"/></svg>`
|
|
8
10
|
};
|
|
9
11
|
|
|
10
12
|
// Hyperclay icons
|
|
11
13
|
export const hyperclayIcons = {
|
|
12
14
|
success: `<svg viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M32 1h-5v3.5h-2.5V8h-2v3.5H20V15h-2.5v3.5h-2V22H13v3.5H9V22H7v-3.5H6V15H1v3.5h1V22h2v3.5h1.5V29H7v3.5h5V29h3.5v-3.5H18V22h2.5v-3.5h2V15H25v-3.5h2.5V8h2V4.5H32V1Z" fill="#76C824"/></svg>`,
|
|
13
|
-
error: `<svg viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M33 1h-5v3.5h-3.5V8H21v3.5h-3.5V15h-2v-3.5H12V8H8.5V4.5H5V1H0v3.5h3.5V8H7v3.5h3.5V15H14v3.5h-3.5V22H7v3.5H3.5V29H0v3.5h5V29h3.5v-3.5H12V22h3.5v-3.5h2V22H21v3.5h3.5V29H28v3.5h5V29h-3.5v-3.5H26V22h-3.5v-3.5H19V15h3.5v-3.5H26V8h3.5V4.5H33V1Z" fill="#DD304F"/></svg
|
|
15
|
+
error: `<svg viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M33 1h-5v3.5h-3.5V8H21v3.5h-3.5V15h-2v-3.5H12V8H8.5V4.5H5V1H0v3.5h3.5V8H7v3.5h3.5V15H14v3.5h-3.5V22H7v3.5H3.5V29H0v3.5h5V29h3.5v-3.5H12V22h3.5v-3.5h2V22H21v3.5h3.5V29H28v3.5h5V29h-3.5v-3.5H26V22h-3.5v-3.5H19V15h3.5v-3.5H26V8h3.5V4.5H33V1Z" fill="#DD304F"/></svg>`,
|
|
16
|
+
warning: `<svg viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 1h-3v3h-2v3h-2v3H9v3H7v3H5v3H3v3H1v6h31v-6h-2v-3h-2v-3h-2v-3h-2v-3h-2V7h-2V4h-2V1zm-2 8h1v10h-1V9zm0 13h1v2h-1v-2z" fill="#F5A623"/></svg>`,
|
|
17
|
+
info: `<svg viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 1v3H9v3H6v3H3v6h3v3h3v3h3v3h9v-3h3v-3h3v-3h3v-6h-3V7h-3V4h-3V1H12zm4 7h1v2h-1V8zm0 5h1v9h-1v-9z" fill="#4A90D9"/></svg>`
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
// Default templates
|
|
@@ -27,6 +31,18 @@ const defaultTemplates = {
|
|
|
27
31
|
<div class="toast-icon">{icon}</div>
|
|
28
32
|
<div class="toast-message">{message}</div>
|
|
29
33
|
</div>
|
|
34
|
+
`,
|
|
35
|
+
warning: `
|
|
36
|
+
<div class="toast hide warning noise-texture">
|
|
37
|
+
<div class="toast-icon">{icon}</div>
|
|
38
|
+
<div class="toast-message">{message}</div>
|
|
39
|
+
</div>
|
|
40
|
+
`,
|
|
41
|
+
info: `
|
|
42
|
+
<div class="toast hide info noise-texture">
|
|
43
|
+
<div class="toast-icon">{icon}</div>
|
|
44
|
+
<div class="toast-message">{message}</div>
|
|
45
|
+
</div>
|
|
30
46
|
`
|
|
31
47
|
}
|
|
32
48
|
};
|
|
@@ -45,6 +61,18 @@ export const hyperclayTemplates = {
|
|
|
45
61
|
{icon}
|
|
46
62
|
<span class="message">{message}</span>
|
|
47
63
|
</div>
|
|
64
|
+
`,
|
|
65
|
+
warning: `
|
|
66
|
+
<div class="toast hide warning">
|
|
67
|
+
{icon}
|
|
68
|
+
<span class="message">{message}</span>
|
|
69
|
+
</div>
|
|
70
|
+
`,
|
|
71
|
+
info: `
|
|
72
|
+
<div class="toast hide info">
|
|
73
|
+
{icon}
|
|
74
|
+
<span class="message">{message}</span>
|
|
75
|
+
</div>
|
|
48
76
|
`
|
|
49
77
|
}
|
|
50
78
|
};
|
|
@@ -94,6 +122,16 @@ const modernStyles = `
|
|
|
94
122
|
background: radial-gradient(85.86% 68.42% at 50% 68.42%, #240A13 0%, #481826 100%);
|
|
95
123
|
}
|
|
96
124
|
|
|
125
|
+
[data-toast-theme="modern"] .toast.warning {
|
|
126
|
+
border-color: #B8860B;
|
|
127
|
+
background: radial-gradient(85.86% 68.42% at 50% 68.42%, #2A2010 0%, #3D3018 100%);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
[data-toast-theme="modern"] .toast.info {
|
|
131
|
+
border-color: #2E6B9E;
|
|
132
|
+
background: radial-gradient(85.86% 68.42% at 50% 68.42%, #0A1A24 0%, #162D3D 100%);
|
|
133
|
+
}
|
|
134
|
+
|
|
97
135
|
[data-toast-theme="modern"] .toast-icon {
|
|
98
136
|
position: relative;
|
|
99
137
|
top: -1px;
|
|
@@ -180,6 +218,16 @@ export const hyperclayStyles = `
|
|
|
180
218
|
color: #DD304F;
|
|
181
219
|
border: 2px dashed #CD2140;
|
|
182
220
|
}
|
|
221
|
+
|
|
222
|
+
[data-toast-theme="hyperclay"] .toast.warning {
|
|
223
|
+
color: #F5A623;
|
|
224
|
+
border: 2px dashed #D4900E;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
[data-toast-theme="hyperclay"] .toast.info {
|
|
228
|
+
color: #4A90D9;
|
|
229
|
+
border: 2px dashed #3A7BBF;
|
|
230
|
+
}
|
|
183
231
|
`;
|
|
184
232
|
|
|
185
233
|
// Track which theme styles have been injected
|
|
@@ -205,6 +253,7 @@ export function injectToastStyles(styles, theme) {
|
|
|
205
253
|
const styleSheet = document.createElement('style');
|
|
206
254
|
styleSheet.className = `toast-styles-${theme}`;
|
|
207
255
|
styleSheet.setAttribute('save-remove', '');
|
|
256
|
+
styleSheet.setAttribute('snapshot-remove', '');
|
|
208
257
|
styleSheet.textContent = styles;
|
|
209
258
|
document.head.appendChild(styleSheet);
|
|
210
259
|
|
|
@@ -224,6 +273,7 @@ export function toastCore(message, messageType = "success", config = {}) {
|
|
|
224
273
|
toastContainer.className = 'toast-container';
|
|
225
274
|
toastContainer.setAttribute('data-toast-theme', theme);
|
|
226
275
|
toastContainer.setAttribute('save-remove', '');
|
|
276
|
+
toastContainer.setAttribute('snapshot-remove', '');
|
|
227
277
|
document.body.append(toastContainer);
|
|
228
278
|
}
|
|
229
279
|
|