hyperclayjs 1.17.0 → 1.18.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
@@ -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 | 7.4KB | Basic save function only - hyperclay.savePage() |
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.2KB | Source of truth for page state - captures DOM snapshots for save and sync |
68
+ | snapshot | 10.6KB | 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
 
@@ -86,7 +86,7 @@ import 'hyperclayjs/presets/standard.js';
86
86
  |--------|------|-------------|
87
87
  | dialogs | 7.7KB | ask(), consent(), tell(), snippet() dialog functions |
88
88
  | the-modal | 21KB | Full modal window creation system - window.theModal |
89
- | toast | 8.3KB | Success/error message notifications, toast(msg, msgType) |
89
+ | toast | 10.5KB | 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 | 10.4KB | Real-time DOM sync across browsers |
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 (~46.8KB)
135
+ ### Minimal (~50.9KB)
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 (~69.1KB)
140
+ ### Standard (~73.2KB)
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 (~201.8KB)
145
+ ### Everything (~206.9KB)
146
146
  All available features
147
147
 
148
148
  Includes all available modules across all categories.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperclayjs",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "Modular JavaScript library for building interactive HTML applications with Hyperclay",
5
5
  "type": "module",
6
6
  "main": "src/hyperclay.js",
@@ -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
@@ -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
- fetch(saveEndpoint, {
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
- fetch(saveEndpoint, {
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 => {
@@ -172,6 +172,14 @@ export function captureForSaveAndComparison({ emitForSync = true } = {}) {
172
172
  document.dispatchEvent(new CustomEvent('hyperclay:snapshot-ready', {
173
173
  detail: { documentElement: clone }
174
174
  }));
175
+
176
+ // Store snapshot HTML for Hyperclay Local platform sync
177
+ // This allows the save system to send both stripped and full versions
178
+ const isHyperclayLocal = window.location.hostname === 'localhost' ||
179
+ window.location.hostname === '127.0.0.1';
180
+ if (isHyperclayLocal) {
181
+ window.__hyperclaySnapshotHtml = '<!DOCTYPE html>' + clone.outerHTML;
182
+ }
175
183
  }
176
184
 
177
185
  // Run inline [onbeforesave] handlers
package/src/hyperclay.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * HyperclayJS v1.17.0 - Minimal Browser-Native Loader
2
+ * HyperclayJS v1.18.0 - Minimal Browser-Native Loader
3
3
  *
4
4
  * Modules auto-init when imported (no separate init call needed).
5
5
  * Include `export-to-window` feature to export to window.hyperclay.
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 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 8L4 40H44L24 8Z" stroke="#F5A623" stroke-width="4" stroke-linejoin="round"/><path d="M24 20V28M24 34V36" stroke="#F5A623" stroke-width="4" stroke-linecap="round"/></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