@panphora/hyper-cms 0.10.0 → 0.11.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.
@@ -0,0 +1,97 @@
1
+ // The sidebar view: the shell panel and the form inside it. Everything here is
2
+ // chrome for one way of rendering a session — the session core (src/session.js)
3
+ // owns the page, the rules and the data.
4
+
5
+ import { mountShell } from '../shell.js'
6
+ import { buildForm } from '../form-builder.js'
7
+ import { bindEvents, suppressUndo } from '../events.js'
8
+ import { enhanceFields, upgradeRichTextRules } from '../enhance.js'
9
+ import { applyUnresolvedState } from '../unresolved.js'
10
+ import { refreshForm } from '../refresh.js'
11
+
12
+ const FOCUSABLE =
13
+ 'input:not([disabled]):not([type="hidden"]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), [tabindex]:not([tabindex="-1"])'
14
+
15
+ export function createSidebarView({ doc, pageRoot, opts = {} }) {
16
+ // Rich-text upgrade (default on). Opt out with cms.open({ richText: false }).
17
+ const richText = opts.richText !== false
18
+ let shell = null
19
+
20
+ return {
21
+ name: 'sidebar',
22
+ richText,
23
+ // The form IS the editing surface here, so its rich-text fields are the
24
+ // ones richclay has to be on.
25
+ enhanceFormRichText: true,
26
+ ctx: null,
27
+ root: null,
28
+ formRoot: null,
29
+ errorEl: null,
30
+ noticeEl: null,
31
+
32
+ prepareRules(sourceRules) {
33
+ return richText ? upgradeRichTextRules(sourceRules, pageRoot) : sourceRules
34
+ },
35
+
36
+ mount(initialData) {
37
+ const ctx = this.ctx
38
+ // Suppress undo around mountShell: it toggles chrome-only classes on
39
+ // document.body (hcms-open, etc.) which would otherwise land as undoable
40
+ // page edits. The shell subtree itself is already filtered via save-ignore.
41
+ shell = suppressUndo(() => mountShell({
42
+ mountTo: opts.mountTo || doc.body,
43
+ side: opts.side || 'right',
44
+ overlay: !!opts.overlay,
45
+ showSaveButton: !!opts.showSaveButton,
46
+ title: opts.title,
47
+ eyebrow: opts.eyebrow,
48
+ theme: opts.theme,
49
+ doc,
50
+ }))
51
+ this.root = shell.root
52
+ this.formRoot = shell.formRoot
53
+ this.errorEl = shell.errorEl
54
+ this.noticeEl = shell.noticeEl
55
+
56
+ const fragment = buildForm({
57
+ pageRules: ctx.pageRules,
58
+ formRules: ctx.formRules,
59
+ data: initialData,
60
+ doc,
61
+ })
62
+ shell.formRoot.appendChild(fragment)
63
+ ctx.seeder.seed(shell.formRoot)
64
+ enhanceFields(shell.formRoot, doc)
65
+ applyUnresolvedState(ctx)
66
+
67
+ bindEvents(ctx)
68
+ },
69
+
70
+ refresh(reason) {
71
+ if (reason === 'livesync') {
72
+ // A full-document morph can wipe the shell's <head> stylesheet and the
73
+ // <body> chrome classes (both live outside the save-ignore shell subtree).
74
+ // Re-assert them before re-extracting.
75
+ shell?.restoreChrome?.()
76
+ refreshForm(this.ctx, { ignoreActiveValue: true })
77
+ return
78
+ }
79
+ if (reason === 'undo') {
80
+ refreshForm(this.ctx, { ignoreActiveValue: false })
81
+ return
82
+ }
83
+ refreshForm(this.ctx)
84
+ },
85
+
86
+ // Move focus into the shell — survives close+restore via previouslyFocused.
87
+ focusOnOpen() {
88
+ const target = this.root && this.root.querySelector(FOCUSABLE)
89
+ if (target && typeof target.focus === 'function') target.focus()
90
+ },
91
+
92
+ destroy() {
93
+ shell?.destroy()
94
+ shell = null
95
+ },
96
+ }
97
+ }