@panphora/clayjs 0.1.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/clay.js +21 -0
  4. package/package.json +27 -0
  5. package/src/attrs/onaftersave.js +38 -0
  6. package/src/attrs/refetch-on-save.js +36 -0
  7. package/src/attrs/save-freeze.js +102 -0
  8. package/src/core/admin-attrs.js +22 -0
  9. package/src/core/admin-contenteditable.js +47 -0
  10. package/src/core/admin-inputs.js +48 -0
  11. package/src/core/admin-onclick.js +50 -0
  12. package/src/core/admin-resources.js +49 -0
  13. package/src/core/autosave.js +61 -0
  14. package/src/core/edit-mode.js +38 -0
  15. package/src/core/is-edit-mode.js +30 -0
  16. package/src/core/persist.js +103 -0
  17. package/src/core/save-core.js +385 -0
  18. package/src/core/save.js +475 -0
  19. package/src/core/snapshot.js +282 -0
  20. package/src/core/unsaved-warning.js +38 -0
  21. package/src/lib/autosave-debug.js +223 -0
  22. package/src/lib/cache-bust.js +12 -0
  23. package/src/lib/cookie.js +37 -0
  24. package/src/lib/dom-ready.js +9 -0
  25. package/src/lib/extension-noise.js +63 -0
  26. package/src/lib/load-vendor-script.js +57 -0
  27. package/src/lib/mutation.js +719 -0
  28. package/src/lib/query.js +3 -0
  29. package/src/lib/region-policy.js +220 -0
  30. package/src/lib/throttle.js +41 -0
  31. package/src/lib/user-gesture.js +126 -0
  32. package/src/loader-logic.js +62 -0
  33. package/src/loader.js +123 -0
  34. package/src/plugins/indicator.js +51 -0
  35. package/src/plugins/sortable.js +119 -0
  36. package/src/plugins/undo.js +23 -0
  37. package/src/sync/live-sync.js +752 -0
  38. package/src/vendor/Sortable.vendor.js +2 -0
  39. package/src/vendor/control-serialize.vendor.js +88 -0
  40. package/src/vendor/hyper-morph.vendor.js +22 -0
  41. package/src/vendor/hyper-undo.vendor.js +11 -0
  42. package/src/vendor/hypercms.vendor.js +1751 -0
  43. package/src/vendor/richclay.vendor.js +456 -0
@@ -0,0 +1,119 @@
1
+ /*
2
+
3
+ Make elements drag-and-drop sortable
4
+
5
+ How to use:
6
+ - add `sortable` attribute to an element to make children sortable
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>
10
+ - add `onsorted` attribute to execute code when items are sorted
11
+ - e.g. <ul sortable onsorted="console.log('Items reordered!')"></ul>
12
+
13
+ This wrapper conditionally loads the full Sortable.js vendor script (~118KB)
14
+ only when in edit mode, using dynamic import().
15
+
16
+ */
17
+ import { isEditMode } from "../core/is-edit-mode.js";
18
+ import Mutation from "../lib/mutation.js";
19
+ import { getVendorUrl } from "../lib/load-vendor-script.js";
20
+
21
+ function makeSortable(sortableElem, Sortable) {
22
+ let options = {};
23
+
24
+ // Check if Sortable instance already exists
25
+ if (Sortable.get(sortableElem)) return;
26
+
27
+ const groupName = sortableElem.getAttribute('sortable');
28
+ if (groupName) options.group = groupName;
29
+
30
+ // Check for handles, but exclude those inside nested sortable elements
31
+ const handles = sortableElem.querySelectorAll('[sortable-handle]');
32
+ const nestedSortables = sortableElem.querySelectorAll('[sortable]');
33
+
34
+ // Check if any handle is NOT inside a nested sortable
35
+ const hasDirectHandle = Array.from(handles).some(handle => {
36
+ return !Array.from(nestedSortables).some(nested => nested.contains(handle));
37
+ });
38
+
39
+ if (hasDirectHandle) {
40
+ options.handle = '[sortable-handle]';
41
+ }
42
+
43
+ // Add onsorting callback if attribute exists (fires during drag)
44
+ const onsortingCode = sortableElem.getAttribute('onsorting');
45
+ if (onsortingCode) {
46
+ options.onMove = function(evt) {
47
+ try {
48
+ const asyncFn = new Function(`return (async function(evt) { ${onsortingCode} })`)();
49
+ asyncFn.call(sortableElem, evt);
50
+ } catch (error) {
51
+ console.error('Error in onsorting execution:', error);
52
+ }
53
+ };
54
+ }
55
+
56
+ // After a drop, run any author onsorted code, then notify reactive libraries.
57
+ const onsortedCode = sortableElem.getAttribute('onsorted');
58
+ options.onEnd = function(evt) {
59
+ if (onsortedCode) {
60
+ try {
61
+ const asyncFn = new Function(`return (async function(evt) { ${onsortedCode} })`)();
62
+ asyncFn.call(sortableElem, evt);
63
+ } catch (error) {
64
+ console.error('Error in onsorted execution:', error);
65
+ }
66
+ }
67
+ // Announce the reorder as a real, self-documenting event carrying what moved.
68
+ // Reactive libs (e.g. Sap) and author code key off this without us knowing
69
+ // about them. Fires only in edit mode, since sortable only inits there.
70
+ sortableElem.dispatchEvent(new CustomEvent('clay:sorted', {
71
+ bubbles: true,
72
+ detail: {
73
+ item: evt.item,
74
+ from: evt.from,
75
+ to: evt.to,
76
+ oldIndex: evt.oldIndex,
77
+ newIndex: evt.newIndex,
78
+ },
79
+ }));
80
+ // DEPRECATED: early versions dispatched a synthetic `input` here so reactive
81
+ // libs would re-derive. It is semantically off (a container has no value) and
82
+ // now redundant with clay:sorted and the mutation observers. Kept as a compat shim.
83
+ sortableElem.dispatchEvent(new Event('input', { bubbles: true }));
84
+ };
85
+
86
+ Sortable.create(sortableElem, options);
87
+ }
88
+
89
+ async function init() {
90
+ if (!isEditMode) return;
91
+
92
+ // Load the vendor script
93
+ const vendorUrl = getVendorUrl(import.meta.url, '../vendor/Sortable.vendor.js');
94
+ await import(vendorUrl);
95
+ const Sortable = window.Sortable;
96
+
97
+ // Set up sortable on page load
98
+ document.querySelectorAll('[sortable]').forEach(el => makeSortable(el, Sortable));
99
+
100
+ // Set up listener for dynamically added elements.
101
+ // require:'observed' so drag works inside no-save / save-* regions (e.g. the
102
+ // CMS panel); pausable:false so it keeps wiring during a live-sync pause.
103
+ Mutation.onAddElement({
104
+ selectorFilter: "[sortable]",
105
+ debounce: 200,
106
+ require: 'observed',
107
+ pausable: false
108
+ }, (changes) => {
109
+ changes.forEach(({ element }) => {
110
+ makeSortable(element, Sortable);
111
+ });
112
+ });
113
+ }
114
+
115
+ // Auto-init when module is imported; the loader awaits `ready` before resolving clay.ready
116
+ const ready = init();
117
+
118
+ export { init, ready };
119
+ export default init;
@@ -0,0 +1,23 @@
1
+ // Re-exports the vendored hyper-undo singleton and auto-starts it in edit mode
2
+ // so apps "just work". The loader wires it onto clay.undo (and mirrors it onto
3
+ // the vendor-compat shim); the vendor's own window auto-export is suppressed by
4
+ // the bootstrap's __hyperclayNoAutoExport flag.
5
+
6
+ import { undo } from '../vendor/hyper-undo.vendor.js'
7
+ import { isEditMode } from '../core/is-edit-mode.js'
8
+
9
+ function init() {
10
+ if (!isEditMode) return
11
+ // Defer until the body exists so the default scope (document.body) is valid.
12
+ if (typeof document === 'undefined') return
13
+ if (document.readyState === 'loading') {
14
+ document.addEventListener('DOMContentLoaded', () => undo.start({ bindKeys: true }))
15
+ } else {
16
+ undo.start({ bindKeys: true })
17
+ }
18
+ }
19
+
20
+ init()
21
+
22
+ export { undo }
23
+ export default undo