hyperclayjs 1.6.0 → 1.8.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.
Files changed (61) hide show
  1. package/README.md +14 -14
  2. package/package.json +17 -25
  3. package/src/core/adminContenteditable.js +51 -0
  4. package/{core → src/core}/adminInputs.js +29 -8
  5. package/src/core/adminOnClick.js +54 -0
  6. package/{core → src/core}/adminResources.js +25 -5
  7. package/src/core/optionVisibility.js +216 -0
  8. package/{core → src/core}/savePage.js +1 -1
  9. package/{core → src/core}/savePageCore.js +13 -3
  10. package/{custom-attributes → src/custom-attributes}/domHelpers.js +17 -4
  11. package/{custom-attributes → src/custom-attributes}/events.js +2 -0
  12. package/src/custom-attributes/onmutation.js +90 -0
  13. package/src/custom-attributes/onpagemutation.js +32 -0
  14. package/{custom-attributes → src/custom-attributes}/sortable.js +16 -1
  15. package/{dom-utilities → src/dom-utilities}/All.js +22 -0
  16. package/{hyperclay.js → src/hyperclay.js} +4 -4
  17. package/{module-dependency-graph.json → src/module-dependency-graph.json} +16 -26
  18. package/{ui → src/ui}/prompts.js +13 -18
  19. package/{ui → src/ui}/theModal.js +101 -0
  20. package/{ui → src/ui}/toast.js +4 -3
  21. package/core/adminContenteditable.js +0 -36
  22. package/core/adminOnClick.js +0 -31
  23. package/core/optionVisibilityRuleGenerator.js +0 -171
  24. package/custom-attributes/onpagemutation.js +0 -20
  25. /package/{communication → src/communication}/behaviorCollector.js +0 -0
  26. /package/{communication → src/communication}/sendMessage.js +0 -0
  27. /package/{communication → src/communication}/uploadFile.js +0 -0
  28. /package/{core → src/core}/adminSystem.js +0 -0
  29. /package/{core → src/core}/autosave.js +0 -0
  30. /package/{core → src/core}/editmode.js +0 -0
  31. /package/{core → src/core}/editmodeSystem.js +0 -0
  32. /package/{core → src/core}/enablePersistentFormInputValues.js +0 -0
  33. /package/{core → src/core}/exportToWindow.js +0 -0
  34. /package/{core → src/core}/isAdminOfCurrentResource.js +0 -0
  35. /package/{core → src/core}/saveToast.js +0 -0
  36. /package/{core → src/core}/setPageTypeOnDocumentElement.js +0 -0
  37. /package/{custom-attributes → src/custom-attributes}/ajaxElements.js +0 -0
  38. /package/{custom-attributes → src/custom-attributes}/autosize.js +0 -0
  39. /package/{custom-attributes → src/custom-attributes}/inputHelpers.js +0 -0
  40. /package/{custom-attributes → src/custom-attributes}/onaftersave.js +0 -0
  41. /package/{custom-attributes → src/custom-attributes}/onclickaway.js +0 -0
  42. /package/{custom-attributes → src/custom-attributes}/onclone.js +0 -0
  43. /package/{custom-attributes → src/custom-attributes}/onrender.js +0 -0
  44. /package/{custom-attributes → src/custom-attributes}/preventEnter.js +0 -0
  45. /package/{dom-utilities → src/dom-utilities}/getDataFromForm.js +0 -0
  46. /package/{dom-utilities → src/dom-utilities}/insertStyleTag.js +0 -0
  47. /package/{dom-utilities → src/dom-utilities}/onDomReady.js +0 -0
  48. /package/{dom-utilities → src/dom-utilities}/onLoad.js +0 -0
  49. /package/{string-utilities → src/string-utilities}/copy-to-clipboard.js +0 -0
  50. /package/{string-utilities → src/string-utilities}/query.js +0 -0
  51. /package/{string-utilities → src/string-utilities}/slugify.js +0 -0
  52. /package/{ui → src/ui}/toast-hyperclay.js +0 -0
  53. /package/{utilities → src/utilities}/cookie.js +0 -0
  54. /package/{utilities → src/utilities}/debounce.js +0 -0
  55. /package/{utilities → src/utilities}/loadVendorScript.js +0 -0
  56. /package/{utilities → src/utilities}/mutation.js +0 -0
  57. /package/{utilities → src/utilities}/nearest.js +0 -0
  58. /package/{utilities → src/utilities}/pipe.js +0 -0
  59. /package/{utilities → src/utilities}/throttle.js +0 -0
  60. /package/{vendor → src/vendor}/Sortable.vendor.js +0 -0
  61. /package/{vendor → src/vendor}/idiomorph.min.js +0 -0
@@ -0,0 +1,90 @@
1
+ /*
2
+ [onmutation] - Trigger code when this element or its children change
3
+
4
+ Usage:
5
+ <div onmutation="console.log('My content changed')">
6
+ <span contenteditable>Edit me</span>
7
+ </div>
8
+
9
+ Unlike [onglobalmutation]/[onpagemutation] which fires on ANY DOM change,
10
+ [onmutation] only fires when the element itself or its descendants mutate.
11
+ */
12
+ import Mutation from "../utilities/mutation.js";
13
+
14
+ const observers = new WeakMap();
15
+
16
+ function setupMutationObserver(element) {
17
+ if (observers.has(element)) return;
18
+
19
+ const executeMutation = async () => {
20
+ try {
21
+ const code = element.getAttribute('onmutation');
22
+ if (!code) return;
23
+ const asyncFn = new Function(`return (async function() { ${code} })`)();
24
+ await asyncFn.call(element);
25
+ } catch (error) {
26
+ console.error('Error in onmutation execution:', error);
27
+ }
28
+ };
29
+
30
+ const observer = new MutationObserver(() => {
31
+ executeMutation();
32
+ });
33
+
34
+ observer.observe(element, {
35
+ childList: true,
36
+ subtree: true,
37
+ characterData: true,
38
+ attributes: true
39
+ });
40
+
41
+ observers.set(element, observer);
42
+ }
43
+
44
+ function teardownMutationObserver(element) {
45
+ const observer = observers.get(element);
46
+ if (observer) {
47
+ observer.disconnect();
48
+ observers.delete(element);
49
+ }
50
+ }
51
+
52
+ function init() {
53
+ // Set up existing elements
54
+ document.querySelectorAll('[onmutation]').forEach(setupMutationObserver);
55
+
56
+ // Watch for dynamically added elements with onmutation
57
+ Mutation.onAddElement({
58
+ selectorFilter: '[onmutation]',
59
+ debounce: 200
60
+ }, (changes) => {
61
+ changes.forEach(({ element }) => {
62
+ setupMutationObserver(element);
63
+ });
64
+ });
65
+
66
+ // Clean up when elements are removed
67
+ Mutation.onRemoveElement({
68
+ selectorFilter: '[onmutation]',
69
+ debounce: 200
70
+ }, (changes) => {
71
+ changes.forEach(({ element }) => {
72
+ teardownMutationObserver(element);
73
+ });
74
+ });
75
+
76
+ // Watch for attribute removal
77
+ Mutation.onAttribute({
78
+ selectorFilter: '[onmutation]',
79
+ debounce: 200
80
+ }, (changes) => {
81
+ changes.forEach(({ element, attribute, newValue }) => {
82
+ if (attribute === 'onmutation' && newValue === null) {
83
+ teardownMutationObserver(element);
84
+ }
85
+ });
86
+ });
87
+ }
88
+
89
+ export { init };
90
+ export default init;
@@ -0,0 +1,32 @@
1
+ /*
2
+ [onpagemutation] / [onglobalmutation] - Trigger code when ANY element on the page changes
3
+
4
+ Usage:
5
+ <span onglobalmutation="this.textContent = All('li').length">0</span>
6
+ <span onpagemutation="this.textContent = All('li').length">0</span>
7
+
8
+ Both attributes are equivalent - onglobalmutation is the preferred name for clarity.
9
+ */
10
+ import Mutation from "../utilities/mutation.js";
11
+
12
+ function init() {
13
+ const executeGlobalMutation = async element => {
14
+ try {
15
+ // Support both onglobalmutation and onpagemutation (legacy)
16
+ const code = element.getAttribute('onglobalmutation') || element.getAttribute('onpagemutation');
17
+ const asyncFn = new Function(`return (async function() { ${code} })`)();
18
+ await asyncFn.call(element);
19
+ } catch (error) {
20
+ console.error('Error in onglobalmutation/onpagemutation execution:', error);
21
+ }
22
+ };
23
+
24
+ Mutation.onAnyChange({
25
+ debounce: 200,
26
+ omitChangeDetails: true
27
+ }, () => {
28
+ document.querySelectorAll('[onglobalmutation], [onpagemutation]').forEach(executeGlobalMutation);
29
+ });
30
+ }
31
+ export { init };
32
+ export default init;
@@ -5,6 +5,8 @@
5
5
  How to use:
6
6
  - add `sortable` attribute to an element to make children sortable
7
7
  - e.g. <div sortable></div>
8
+ - add `onsorting` attribute to execute code during drag
9
+ - e.g. <ul sortable onsorting="console.log('Dragging!')"></ul>
8
10
  - add `onsorted` attribute to execute code when items are sorted
9
11
  - e.g. <ul sortable onsorted="console.log('Items reordered!')"></ul>
10
12
 
@@ -39,7 +41,20 @@ function makeSortable(sortableElem, Sortable) {
39
41
  options.handle = '[sortable-handle]';
40
42
  }
41
43
 
42
- // Add onsorted callback if attribute exists
44
+ // Add onsorting callback if attribute exists (fires during drag)
45
+ const onsortingCode = sortableElem.getAttribute('onsorting');
46
+ if (onsortingCode) {
47
+ options.onMove = function(evt) {
48
+ try {
49
+ const asyncFn = new Function(`return (async function(evt) { ${onsortingCode} })`)();
50
+ asyncFn.call(sortableElem, evt);
51
+ } catch (error) {
52
+ console.error('Error in onsorting execution:', error);
53
+ }
54
+ };
55
+ }
56
+
57
+ // Add onsorted callback if attribute exists (fires after drop)
43
58
  const onsortedCode = sortableElem.getAttribute('onsorted');
44
59
  if (onsortedCode) {
45
60
  options.onEnd = function(evt) {
@@ -336,6 +336,28 @@ const defaultPlugins = {
336
336
  });
337
337
 
338
338
  return this;
339
+ },
340
+
341
+ pluck(attr) {
342
+ return this.map(el => el.getAttribute(attr));
343
+ },
344
+
345
+ unique() {
346
+ return [...new Set(this)];
347
+ },
348
+
349
+ sortBy(fn) {
350
+ if (typeof fn === 'string') {
351
+ const attr = fn;
352
+ fn = el => el.getAttribute(attr);
353
+ }
354
+ return [...this].sort((a, b) => {
355
+ const aVal = fn(a);
356
+ const bVal = fn(b);
357
+ if (aVal < bVal) return -1;
358
+ if (aVal > bVal) return 1;
359
+ return 0;
360
+ });
339
361
  }
340
362
  }
341
363
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * HyperclayJS v1.6.0 - Minimal Browser-Native Loader
2
+ * HyperclayJS v1.8.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.
@@ -8,11 +8,11 @@
8
8
  *
9
9
  * <script type="module">
10
10
  * // With window.hyperclay (default presets include export-to-window):
11
- * await import('https://cdn.jsdelivr.net/npm/hyperclayjs@1/hyperclay.js?preset=minimal');
11
+ * await import('https://cdn.jsdelivr.net/npm/hyperclayjs@1/src/hyperclay.js?preset=minimal');
12
12
  * const { toast, savePage } = window.hyperclay;
13
13
  *
14
14
  * // ES modules only (exclude export-to-window):
15
- * const hyperclay = await import('https://cdn.jsdelivr.net/npm/hyperclayjs@1/hyperclay.js?preset=minimal&exclude=export-to-window');
15
+ * const hyperclay = await import('https://cdn.jsdelivr.net/npm/hyperclayjs@1/src/hyperclay.js?preset=minimal&exclude=export-to-window');
16
16
  * const modules = window.hyperclayModules;
17
17
  * </script>
18
18
  *
@@ -31,7 +31,7 @@ const MODULE_PATHS = {
31
31
  "save-toast": "./core/saveToast.js",
32
32
  "edit-mode-helpers": "./core/adminSystem.js",
33
33
  "persist": "./core/enablePersistentFormInputValues.js",
34
- "option-visibility": "./core/optionVisibilityRuleGenerator.js",
34
+ "option-visibility": "./core/optionVisibility.js",
35
35
  "edit-mode": "./core/editmodeSystem.js",
36
36
  "event-attrs": "./custom-attributes/events.js",
37
37
  "ajax-elements": "./custom-attributes/ajaxElements.js",
@@ -1,15 +1,5 @@
1
1
  {
2
2
  "rawDependencies": {
3
- "__tests__/All.test.js": [
4
- "dom-utilities/All.js"
5
- ],
6
- "babel.config.js": [],
7
- "build/build-loader.js": [],
8
- "build/generate-dependency-graph.js": [],
9
- "build/generate-load-jsdelivr.js": [],
10
- "build/generate-readme.js": [],
11
- "build/hyperclay.template.js": [],
12
- "build/update-index-url.js": [],
13
3
  "communication/behaviorCollector.js": [],
14
4
  "communication/sendMessage.js": [
15
5
  "communication/behaviorCollector.js",
@@ -68,7 +58,7 @@
68
58
  "string-utilities/query.js",
69
59
  "utilities/cookie.js"
70
60
  ],
71
- "core/optionVisibilityRuleGenerator.js": [
61
+ "core/optionVisibility.js": [
72
62
  "utilities/mutation.js"
73
63
  ],
74
64
  "core/savePage.js": [
@@ -89,9 +79,6 @@
89
79
  "core/savePage.js",
90
80
  "dom-utilities/onDomReady.js"
91
81
  ],
92
- "coverage/lcov-report/block-navigation.js": [],
93
- "coverage/lcov-report/prettify.js": [],
94
- "coverage/lcov-report/sorter.js": [],
95
82
  "custom-attributes/ajaxElements.js": [
96
83
  "dom-utilities/getDataFromForm.js"
97
84
  ],
@@ -103,6 +90,7 @@
103
90
  "custom-attributes/events.js": [
104
91
  "custom-attributes/onclickaway.js",
105
92
  "custom-attributes/onclone.js",
93
+ "custom-attributes/onmutation.js",
106
94
  "custom-attributes/onpagemutation.js",
107
95
  "custom-attributes/onrender.js"
108
96
  ],
@@ -113,6 +101,9 @@
113
101
  "custom-attributes/onaftersave.js": [],
114
102
  "custom-attributes/onclickaway.js": [],
115
103
  "custom-attributes/onclone.js": [],
104
+ "custom-attributes/onmutation.js": [
105
+ "utilities/mutation.js"
106
+ ],
116
107
  "custom-attributes/onpagemutation.js": [
117
108
  "utilities/mutation.js"
118
109
  ],
@@ -132,7 +123,6 @@
132
123
  "dom-utilities/onDomReady.js": [],
133
124
  "dom-utilities/onLoad.js": [],
134
125
  "hyperclay.js": [],
135
- "jest.config.js": [],
136
126
  "string-utilities/copy-to-clipboard.js": [],
137
127
  "string-utilities/query.js": [],
138
128
  "string-utilities/slugify.js": [],
@@ -161,7 +151,7 @@
161
151
  "save-core": {
162
152
  "name": "save-core",
163
153
  "category": "core",
164
- "size": 6.3,
154
+ "size": 6.5,
165
155
  "files": [
166
156
  "core/savePageCore.js"
167
157
  ],
@@ -218,7 +208,7 @@
218
208
  "edit-mode-helpers": {
219
209
  "name": "edit-mode-helpers",
220
210
  "category": "core",
221
- "size": 5.4,
211
+ "size": 7.500000000000001,
222
212
  "files": [
223
213
  "core/adminSystem.js",
224
214
  "core/adminContenteditable.js",
@@ -242,9 +232,9 @@
242
232
  "option-visibility": {
243
233
  "name": "option-visibility",
244
234
  "category": "core",
245
- "size": 4.7,
235
+ "size": 5.9,
246
236
  "files": [
247
- "core/optionVisibilityRuleGenerator.js"
237
+ "core/optionVisibility.js"
248
238
  ],
249
239
  "description": "Dynamic show/hide based on ancestor state with option:attribute=\"value\"",
250
240
  "exports": {}
@@ -274,7 +264,7 @@
274
264
  "event-attrs": {
275
265
  "name": "event-attrs",
276
266
  "category": "custom-attributes",
277
- "size": 3.6000000000000005,
267
+ "size": 4.1000000000000005,
278
268
  "files": [
279
269
  "custom-attributes/events.js",
280
270
  "custom-attributes/onclickaway.js",
@@ -298,7 +288,7 @@
298
288
  "sortable": {
299
289
  "name": "sortable",
300
290
  "category": "custom-attributes",
301
- "size": 2.8,
291
+ "size": 3.4,
302
292
  "files": [
303
293
  "custom-attributes/sortable.js"
304
294
  ],
@@ -308,7 +298,7 @@
308
298
  "dom-helpers": {
309
299
  "name": "dom-helpers",
310
300
  "category": "custom-attributes",
311
- "size": 5.7,
301
+ "size": 6.2,
312
302
  "files": [
313
303
  "custom-attributes/domHelpers.js"
314
304
  ],
@@ -340,7 +330,7 @@
340
330
  "dialogs": {
341
331
  "name": "dialogs",
342
332
  "category": "ui",
343
- "size": 8.4,
333
+ "size": 7.7,
344
334
  "files": [
345
335
  "ui/prompts.js"
346
336
  ],
@@ -396,7 +386,7 @@
396
386
  "the-modal": {
397
387
  "name": "the-modal",
398
388
  "category": "ui",
399
- "size": 19.8,
389
+ "size": 21.8,
400
390
  "files": [
401
391
  "ui/theModal.js"
402
392
  ],
@@ -512,7 +502,7 @@
512
502
  "all-js": {
513
503
  "name": "all-js",
514
504
  "category": "dom-utilities",
515
- "size": 14,
505
+ "size": 14.4,
516
506
  "files": [
517
507
  "dom-utilities/All.js"
518
508
  ],
@@ -678,7 +668,7 @@
678
668
  "save-toast": "./core/saveToast.js",
679
669
  "edit-mode-helpers": "./core/adminSystem.js",
680
670
  "persist": "./core/enablePersistentFormInputValues.js",
681
- "option-visibility": "./core/optionVisibilityRuleGenerator.js",
671
+ "option-visibility": "./core/optionVisibility.js",
682
672
  "edit-mode": "./core/editmodeSystem.js",
683
673
  "event-attrs": "./custom-attributes/events.js",
684
674
  "ajax-elements": "./custom-attributes/ajaxElements.js",
@@ -3,7 +3,7 @@ import onDomReady from "../dom-utilities/onDomReady.js";
3
3
  import toast from "./toast.js";
4
4
  import copyToClipboard from "../string-utilities/copy-to-clipboard.js";
5
5
 
6
- const CLOSE_BUTTON_SVG = `<svg class="group" viewBox="0 0 134 134" fill="none" xmlns="http://www.w3.org/2000/svg"><path class="fill-[#1D2032] group-hover:fill-[#212543]" d="M132 132.5 1 1.5h131v131Z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M0 0h3v1.5h1.5V3H6v1.5h1.5V6H9v1.5h1.5V9H12v1.5h1.5V12H15v1.5h1.5V15H18v1.5h1.5V18H21v1.5h1.5V21H24v1.5h1.5V24H27v1.5h1.5V27H30v1.5h1.5V30H33v1.5h1.5V33H36v1.5h1.5V36H39v1.5h1.5V39H42v1.5h1.5V42H45v1.5h1.5V45H48v1.5h1.5V48H51v1.5h1.5V51H54v1.5h1.5V54H57v1.5h1.5V57H60v1.5h1.5V60H63v1.5h1.5V63H66v1.5h1.5V66H69v1.5h1.5V69H72v1.5h1.5V72H75v1.5h1.5V75H78v1.5h1.5V78H81v1.5h1.5V81H84v1.5h1.5V84H87v1.5h1.5V87H90v1.5h1.5V90H93v1.5h1.5V93H96v1.5h1.5V96H99v1.5h1.5V99h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v3h-3V132H129v-1.5h-1.5V129H126v-1.5h-1.5V126H123v-1.5h-1.5V123H120v-1.5h-1.5V120H117v-1.5h-1.5V117H114v-1.5h-1.5V114H111v-1.5h-1.5V111H108v-1.5h-1.5V108H105v-1.5h-1.5V105H102v-1.5h-1.5V102H99v-1.5h-1.5V99H96v-1.5h-1.5V96H93v-1.5h-1.5V93H90v-1.5h-1.5V90H87v-1.5h-1.5V87H84v-1.5h-1.5V84H81v-1.5h-1.5V81H78v-1.5h-1.5V78H75v-1.5h-1.5V75H72v-1.5h-1.5V72H69v-1.5h-1.5V69H66v-1.5h-1.5V66H63v-1.5h-1.5V63H60v-1.5h-1.5V60H57v-1.5h-1.5V57H54v-1.5h-1.5V54H51v-1.5h-1.5V51H48v-1.5h-1.5V48H45v-1.5h-1.5V45H42v-1.5h-1.5V42H39v-1.5h-1.5V39H36v-1.5h-1.5V36H33v-1.5h-1.5V33H30v-1.5h-1.5V30H27v-1.5h-1.5V27H24v-1.5h-1.5V24H21v-1.5h-1.5V21H18v-1.5h-1.5V18H15v-1.5h-1.5V15H12v-1.5h-1.5V12H9v-1.5H7.5V9H6V7.5H4.5V6H3V4.5H1.5V3H0V0ZM108.8 22h5.2v5.1h-2.6v2.6H109v2.6h-2.6v2.6h-2.6v2.5h-2.6v5.2h2.6V45h2.6v2.6h2.6v2.6h2.5v2.6h2.6V58h-5.1v-2.6h-2.6V53h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6h-5.2v2.6H91v2.6h-2.6v2.6h-2.6v2.5h-2.6V58H78v-5.1h2.6v-2.6H83v-2.6h2.6v-2.6h2.6v-2.5h2.6v-5.2h-2.6V35h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6H78V22h5.2v2.6h2.5V27h2.6v2.6h2.6v2.6h2.5v2.6h5.2v-2.6h2.5v-2.6h2.6v-2.6h2.6v-2.5h2.5V22Z" fill="#fff"/></svg>`;
6
+ const CLOSE_BUTTON_SVG = `<svg viewBox="0 0 134 134" fill="none" xmlns="http://www.w3.org/2000/svg"><path class="micromodal__close-bg" d="M132 132.5 1 1.5h131v131Z" /><path class="micromodal__close-x" fill-rule="evenodd" clip-rule="evenodd" d="M0 0h3v1.5h1.5V3H6v1.5h1.5V6H9v1.5h1.5V9H12v1.5h1.5V12H15v1.5h1.5V15H18v1.5h1.5V18H21v1.5h1.5V21H24v1.5h1.5V24H27v1.5h1.5V27H30v1.5h1.5V30H33v1.5h1.5V33H36v1.5h1.5V36H39v1.5h1.5V39H42v1.5h1.5V42H45v1.5h1.5V45H48v1.5h1.5V48H51v1.5h1.5V51H54v1.5h1.5V54H57v1.5h1.5V57H60v1.5h1.5V60H63v1.5h1.5V63H66v1.5h1.5V66H69v1.5h1.5V69H72v1.5h1.5V72H75v1.5h1.5V75H78v1.5h1.5V78H81v1.5h1.5V81H84v1.5h1.5V84H87v1.5h1.5V87H90v1.5h1.5V90H93v1.5h1.5V93H96v1.5h1.5V96H99v1.5h1.5V99h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v3h-3V132H129v-1.5h-1.5V129H126v-1.5h-1.5V126H123v-1.5h-1.5V123H120v-1.5h-1.5V120H117v-1.5h-1.5V117H114v-1.5h-1.5V114H111v-1.5h-1.5V111H108v-1.5h-1.5V108H105v-1.5h-1.5V105H102v-1.5h-1.5V102H99v-1.5h-1.5V99H96v-1.5h-1.5V96H93v-1.5h-1.5V93H90v-1.5h-1.5V90H87v-1.5h-1.5V87H84v-1.5h-1.5V84H81v-1.5h-1.5V81H78v-1.5h-1.5V78H75v-1.5h-1.5V75H72v-1.5h-1.5V72H69v-1.5h-1.5V69H66v-1.5h-1.5V66H63v-1.5h-1.5V63H60v-1.5h-1.5V60H57v-1.5h-1.5V57H54v-1.5h-1.5V54H51v-1.5h-1.5V51H48v-1.5h-1.5V48H45v-1.5h-1.5V45H42v-1.5h-1.5V42H39v-1.5h-1.5V39H36v-1.5h-1.5V36H33v-1.5h-1.5V33H30v-1.5h-1.5V30H27v-1.5h-1.5V27H24v-1.5h-1.5V24H21v-1.5h-1.5V21H18v-1.5h-1.5V18H15v-1.5h-1.5V15H12v-1.5h-1.5V12H9v-1.5H7.5V9H6V7.5H4.5V6H3V4.5H1.5V3H0V0ZM108.8 22h5.2v5.1h-2.6v2.6H109v2.6h-2.6v2.6h-2.6v2.5h-2.6v5.2h2.6V45h2.6v2.6h2.6v2.6h2.5v2.6h2.6V58h-5.1v-2.6h-2.6V53h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6h-5.2v2.6H91v2.6h-2.6v2.6h-2.6v2.5h-2.6V58H78v-5.1h2.6v-2.6H83v-2.6h2.6v-2.6h2.6v-2.5h2.6v-5.2h-2.6V35h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6H78V22h5.2v2.6h2.5V27h2.6v2.6h2.6v2.6h2.5v2.6h5.2v-2.6h2.5v-2.6h2.6v-2.6h2.6v-2.5h2.5V22Z" /></svg>`;
7
7
  const CONFIRM_BUTTON_SVG = `<div style="width: 28px;"><svg viewBox="0 0 60 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M34.5 0.75H43.5V5.25H49V9.75H54.5V14.25H60V18.75H54.5V23.25H49V27.75H43.5V32.25H34.5V27.75H40V23.25H45.5V18.75H0V14.25H45.5V9.75H40V5.25H34.5V0.75Z" fill="white"/></svg></div>`;
8
8
 
9
9
  function createModal(promptText, yesCallback, extraContent = "", includeInput = false, defaultValue = "") {
@@ -70,11 +70,11 @@ export function consent(promptText, yesCallback, extraContent = "") {
70
70
  */
71
71
  export function tell(promptText, ...content) {
72
72
  const contentHtml = content.length > 0
73
- ? content.map(c => `<div class="text-[16px] sm:text-[18px] font-normal">${c}</div>`).join("")
73
+ ? content.map(c => `<div class="micromodal__tell-content">${c}</div>`).join("")
74
74
  : "";
75
75
 
76
- themodal.html = `<div class="max-w-[440px] space-y-5 mb-7">
77
- <div class="text-[20px] sm:text-[22px] font-bold">${promptText}</div>
76
+ themodal.html = `<div class="micromodal__tell">
77
+ <div class="micromodal__tell-title">${promptText}</div>
78
78
  ${contentHtml}
79
79
  </div>`;
80
80
  themodal.closeHtml = CLOSE_BUTTON_SVG;
@@ -98,27 +98,22 @@ export function tell(promptText, ...content) {
98
98
 
99
99
  /**
100
100
  * Display a modal with a code snippet and copy functionality
101
- * Following the existing modal pattern from prompts.js
101
+ * @param {string} title - The modal heading
102
+ * @param {string} content - The code to display
103
+ * @param {string} extraContent - Optional warning/info text below the copy button
102
104
  */
103
- export function snippet(title, content, options = {}) {
104
- const {
105
- extraContent = 'Save this, it won\'t be shown again. Expires in 1 year.'
106
- } = options;
105
+ export function snippet(title, content, extraContent = '') {
107
106
 
108
107
  // Create the modal content with copy button
109
108
  const modalContent = `
110
- <div class="bg-[#292E54] p-4 mb-[14px] max-w-[420px]">
111
- <div class="overflow-x-auto">
112
- <pre class="text-white font-mono text-sm whitespace-nowrap">${content}</pre>
113
- </div>
109
+ <div class="snippet-code-block">
110
+ <pre>${content}</pre>
114
111
  </div>
115
112
 
116
- <button type="button" class="custom-button group font-fixedsys text-center cursor-pointer border-[3px] border-t-[#474C65] border-r-[#131725] border-b-[#131725] border-l-[#474C65] bg-[#1D1F2F] hover:bg-[#232639] active:border-b-[#474C65] active:border-l-[#131725] active:border-t-[#131725] active:border-r-[#474C65] text-[23px] p-[2px_16px_4px] w-full mb-4 copy-snippet-btn">
117
- <span class="whitespace-nowrap select-none inline-block group-active:translate-x-[1.5px] group-active:translate-y-[1.5px]">copy</span>
118
- </button>
113
+ <button type="button" class="micromodal__secondary-btn copy-snippet-btn" style="margin-bottom: 14px;">copy</button>
119
114
 
120
115
  ${extraContent ? `
121
- <div class="p-3 border-2 border-[#989742] bg-[#1E1E11] text-sm text-[#FBF7B7] max-w-[420px]">
116
+ <div class="snippet-warning">
122
117
  ${extraContent}
123
118
  </div>
124
119
  ` : ''}
@@ -131,7 +126,7 @@ export function snippet(title, content, options = {}) {
131
126
  </div>`;
132
127
 
133
128
  themodal.closeHtml = CLOSE_BUTTON_SVG;
134
- themodal.yes = CONFIRM_BUTTON_SVG;
129
+ themodal.yes = '';
135
130
 
136
131
  const promise = new Promise((resolve) => {
137
132
  // Local copy function
@@ -429,6 +429,7 @@ const modalCss = `<style class="micromodal-css">
429
429
  align-items: center;
430
430
  width: 100%;
431
431
  height: 39px;
432
+ line-height: 0;
432
433
  border: 3px solid;
433
434
  border-top-color: #94BA6F;
434
435
  border-left-color: #94BA6F;
@@ -449,6 +450,66 @@ const modalCss = `<style class="micromodal-css">
449
450
  border-right-color: #94BA6F;
450
451
  }
451
452
 
453
+ .micromodal button.micromodal__secondary-btn {
454
+ display: flex;
455
+ justify-content: center;
456
+ align-items: center;
457
+ width: 100%;
458
+ height: 39px;
459
+ line-height: 0;
460
+ border: 3px solid;
461
+ border-top-color: #474C65;
462
+ border-left-color: #474C65;
463
+ border-bottom-color: #131725;
464
+ border-right-color: #131725;
465
+ background-color: #1D1F2F;
466
+ color: #E5E7EB;
467
+ font-family: inherit;
468
+ font-size: 16px;
469
+ font-weight: bold;
470
+ }
471
+
472
+ .micromodal button.micromodal__secondary-btn:focus,
473
+ .micromodal button.micromodal__secondary-btn:hover {
474
+ background-color: #232639;
475
+ }
476
+
477
+ .micromodal button.micromodal__secondary-btn:active {
478
+ border-top-color: #131725;
479
+ border-left-color: #131725;
480
+ border-bottom-color: #474C65;
481
+ border-right-color: #474C65;
482
+ }
483
+
484
+ .micromodal:has(.snippet-code-block) .micromodal__content {
485
+ margin-bottom: 0;
486
+ }
487
+
488
+ .micromodal .snippet-code-block {
489
+ background-color: #292E54;
490
+ padding: 1rem;
491
+ margin-bottom: 14px;
492
+ max-width: 420px;
493
+ overflow-x: auto;
494
+ }
495
+
496
+ .micromodal .snippet-code-block pre {
497
+ color: white;
498
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
499
+ font-size: 0.875rem;
500
+ white-space: nowrap;
501
+ margin: 0;
502
+ }
503
+
504
+ .micromodal .snippet-warning {
505
+ padding: 0.75rem;
506
+ border: 2px solid #989742;
507
+ background-color: #1E1E11;
508
+ font-size: 0.875rem;
509
+ color: #FBF7B7;
510
+ max-width: 420px;
511
+ }
512
+
452
513
  .micromodal button.micromodal__close {
453
514
  clip-path: polygon(0% 4%, 0% 0%, 100% 0%, 100% 100%, 94% 100%);
454
515
  position: absolute;
@@ -456,6 +517,46 @@ const modalCss = `<style class="micromodal-css">
456
517
  right: -1px;
457
518
  width: 68px;
458
519
  }
520
+
521
+ .micromodal .micromodal__close-bg {
522
+ fill: #1D2032;
523
+ }
524
+
525
+ .micromodal .micromodal__close:hover .micromodal__close-bg {
526
+ fill: #212543;
527
+ }
528
+
529
+ .micromodal .micromodal__close-x {
530
+ fill: #fff;
531
+ }
532
+
533
+ .micromodal .micromodal__tell {
534
+ max-width: 440px;
535
+ margin-bottom: 28px;
536
+ }
537
+
538
+ .micromodal .micromodal__tell > * + * {
539
+ margin-top: 20px;
540
+ }
541
+
542
+ .micromodal .micromodal__tell-title {
543
+ font-size: 20px;
544
+ font-weight: bold;
545
+ }
546
+
547
+ .micromodal .micromodal__tell-content {
548
+ font-size: 16px;
549
+ font-weight: normal;
550
+ }
551
+
552
+ @media (min-width: 640px) {
553
+ .micromodal .micromodal__tell-title {
554
+ font-size: 22px;
555
+ }
556
+ .micromodal .micromodal__tell-content {
557
+ font-size: 18px;
558
+ }
559
+ }
459
560
  </style>`;
460
561
 
461
562
  const modalHtml = `<div class="micromodal" id="micromodal" aria-hidden="true">
@@ -1,10 +1,10 @@
1
1
  // a nice, simple alert
2
2
  // ❗️ don't use too much text!
3
3
 
4
- // Default modern icons
4
+ // Default modern icons (normalized to 48x48 viewBox)
5
5
  const defaultIcons = {
6
- success: `<svg viewBox="0 0 48 45" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.9404 22.4475L21.9099 29.724L35.1906 14.4045M3 3H44.9804V42.809H3V3Z" stroke="#33D131" stroke-width="4.3"/></svg>`,
7
- error: `<svg viewBox="0 0 46 44" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M31.7383 12.4045L13 31.1429M31.7451 31.1429L13.0068 12.4046M2.00977 2H43.9902V41.809H2.00977V2Z" stroke="#FF4450" stroke-width="4"/></svg>`
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>`
8
8
  };
9
9
 
10
10
  // Hyperclay icons
@@ -100,6 +100,7 @@ const modernStyles = `
100
100
  }
101
101
 
102
102
  [data-toast-theme="modern"] .toast-icon svg {
103
+ display: block;
103
104
  width: 22px;
104
105
  height: 22px;
105
106
  }
@@ -1,36 +0,0 @@
1
- import { isEditMode, isOwner } from "./isAdminOfCurrentResource.js";
2
- import onDomReady from "../dom-utilities/onDomReady.js";
3
- import {beforeSave} from "./savePage.js";
4
-
5
- export function disableContentEditableBeforeSave () {
6
- beforeSave(docElem => {
7
- docElem.querySelectorAll('[edit-mode-contenteditable]').forEach(resource => {
8
- const originalValue = resource.getAttribute("contenteditable");
9
- resource.setAttribute("inert-contenteditable", originalValue);
10
- resource.removeAttribute("contenteditable");
11
- });
12
- });
13
- }
14
-
15
- export function enableContentEditableForAdminOnPageLoad () {
16
- if (!isEditMode) return;
17
-
18
- onDomReady(() => {
19
- document.querySelectorAll('[edit-mode-contenteditable]').forEach(resource => {
20
- let originalValue = resource.getAttribute("inert-contenteditable");
21
-
22
- if (!["false", "plaintext-only"].includes(originalValue)) {
23
- originalValue = "true";
24
- }
25
-
26
- resource.setAttribute("contenteditable", originalValue);
27
- resource.removeAttribute("inert-contenteditable");
28
- });
29
- });
30
- }
31
-
32
- // Auto-initialize
33
- export function init() {
34
- disableContentEditableBeforeSave();
35
- enableContentEditableForAdminOnPageLoad();
36
- }
@@ -1,31 +0,0 @@
1
- import { isEditMode, isOwner } from "./isAdminOfCurrentResource.js";
2
- import onDomReady from "../dom-utilities/onDomReady.js";
3
- import {beforeSave} from "./savePage.js";
4
-
5
- export function disableOnClickBeforeSave () {
6
- beforeSave(docElem => {
7
- docElem.querySelectorAll('[edit-mode-onclick]').forEach(resource => {
8
- const originalValue = resource.getAttribute("onclick");
9
- resource.setAttribute("inert-onclick", originalValue);
10
- resource.removeAttribute("onclick");
11
- });
12
- });
13
- }
14
-
15
- export function enableOnClickForAdminOnPageLoad () {
16
- if (!isEditMode) return;
17
-
18
- onDomReady(() => {
19
- document.querySelectorAll('[edit-mode-onclick]').forEach(resource => {
20
- const originalValue = resource.getAttribute("inert-onclick");
21
- resource.setAttribute("onclick", originalValue);
22
- resource.removeAttribute("inert-onclick");
23
- });
24
- });
25
- }
26
-
27
- // Auto-initialize
28
- export function init() {
29
- disableOnClickBeforeSave();
30
- enableOnClickForAdminOnPageLoad();
31
- }