@kywi-software/core 0.10.0 → 0.12.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/AGENT-PATTERNS.md +111 -23
- package/README.md +67 -0
- package/dist/admin/content-form.d.ts.map +1 -1
- package/dist/admin/content-form.js +97 -10
- package/dist/admin/content-form.js.map +1 -1
- package/dist/admin/layout-editor/component-actions.d.ts +219 -22
- package/dist/admin/layout-editor/component-actions.d.ts.map +1 -1
- package/dist/admin/layout-editor/component-actions.js +356 -36
- package/dist/admin/layout-editor/component-actions.js.map +1 -1
- package/dist/admin/layout-editor/component-fork.d.ts +224 -0
- package/dist/admin/layout-editor/component-fork.d.ts.map +1 -0
- package/dist/admin/layout-editor/component-fork.js +342 -0
- package/dist/admin/layout-editor/component-fork.js.map +1 -0
- package/dist/admin/layout-editor/editor-canvas.d.ts +28 -7
- package/dist/admin/layout-editor/editor-canvas.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-canvas.js +145 -32
- package/dist/admin/layout-editor/editor-canvas.js.map +1 -1
- package/dist/admin/layout-editor/editor-dialog.d.ts +164 -0
- package/dist/admin/layout-editor/editor-dialog.d.ts.map +1 -0
- package/dist/admin/layout-editor/editor-dialog.js +195 -0
- package/dist/admin/layout-editor/editor-dialog.js.map +1 -0
- package/dist/admin/layout-editor/editor-state.d.ts +76 -0
- package/dist/admin/layout-editor/editor-state.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-state.js +47 -1
- package/dist/admin/layout-editor/editor-state.js.map +1 -1
- package/dist/admin/layout-editor/editor.css +366 -4
- package/dist/admin/layout-editor/index.d.ts +10 -1
- package/dist/admin/layout-editor/index.d.ts.map +1 -1
- package/dist/admin/layout-editor/index.js +11 -1
- package/dist/admin/layout-editor/index.js.map +1 -1
- package/dist/admin/layout-editor/inline-text.d.ts +56 -4
- package/dist/admin/layout-editor/inline-text.d.ts.map +1 -1
- package/dist/admin/layout-editor/inline-text.js +134 -11
- package/dist/admin/layout-editor/inline-text.js.map +1 -1
- package/dist/admin/layout-editor/layout-editor.d.ts +58 -1
- package/dist/admin/layout-editor/layout-editor.d.ts.map +1 -1
- package/dist/admin/layout-editor/layout-editor.js +160 -190
- package/dist/admin/layout-editor/layout-editor.js.map +1 -1
- package/dist/admin/layout-editor/linked-component.d.ts +39 -0
- package/dist/admin/layout-editor/linked-component.d.ts.map +1 -0
- package/dist/admin/layout-editor/linked-component.js +42 -0
- package/dist/admin/layout-editor/linked-component.js.map +1 -0
- package/dist/admin/layout-editor/module-overlay.d.ts +36 -14
- package/dist/admin/layout-editor/module-overlay.d.ts.map +1 -1
- package/dist/admin/layout-editor/module-overlay.js +233 -25
- package/dist/admin/layout-editor/module-overlay.js.map +1 -1
- package/dist/admin/layout-editor/node-lookup.d.ts +35 -0
- package/dist/admin/layout-editor/node-lookup.d.ts.map +1 -1
- package/dist/admin/layout-editor/node-lookup.js +91 -0
- package/dist/admin/layout-editor/node-lookup.js.map +1 -1
- package/dist/admin/layout-editor/overlay-shell.d.ts.map +1 -1
- package/dist/admin/layout-editor/overlay-shell.js +150 -32
- package/dist/admin/layout-editor/overlay-shell.js.map +1 -1
- package/dist/admin/layout-editor/props-panel.d.ts +54 -1
- package/dist/admin/layout-editor/props-panel.d.ts.map +1 -1
- package/dist/admin/layout-editor/props-panel.js +119 -10
- package/dist/admin/layout-editor/props-panel.js.map +1 -1
- package/dist/admin/layout-editor/section-overlay.d.ts +16 -1
- package/dist/admin/layout-editor/section-overlay.d.ts.map +1 -1
- package/dist/admin/layout-editor/section-overlay.js +21 -11
- package/dist/admin/layout-editor/section-overlay.js.map +1 -1
- package/dist/admin/layout-editor/section-template-picker.d.ts +27 -1
- package/dist/admin/layout-editor/section-template-picker.d.ts.map +1 -1
- package/dist/admin/layout-editor/section-template-picker.js +71 -17
- package/dist/admin/layout-editor/section-template-picker.js.map +1 -1
- package/dist/admin/layout-editor/section-variant-container-config.js +5 -5
- package/dist/admin/layout-editor/section-variant-container-config.js.map +1 -1
- package/dist/admin/layout-editor/use-chrome-flip.d.ts +111 -11
- package/dist/admin/layout-editor/use-chrome-flip.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-chrome-flip.js +233 -33
- package/dist/admin/layout-editor/use-chrome-flip.js.map +1 -1
- package/dist/admin/layout-editor/use-component-connect.d.ts +61 -0
- package/dist/admin/layout-editor/use-component-connect.d.ts.map +1 -0
- package/dist/admin/layout-editor/use-component-connect.js +292 -0
- package/dist/admin/layout-editor/use-component-connect.js.map +1 -0
- package/dist/admin/layout-editor/use-component-fork.d.ts +123 -0
- package/dist/admin/layout-editor/use-component-fork.d.ts.map +1 -0
- package/dist/admin/layout-editor/use-component-fork.js +346 -0
- package/dist/admin/layout-editor/use-component-fork.js.map +1 -0
- package/dist/admin/layout-editor/use-component-library.d.ts +94 -0
- package/dist/admin/layout-editor/use-component-library.d.ts.map +1 -0
- package/dist/admin/layout-editor/use-component-library.js +55 -0
- package/dist/admin/layout-editor/use-component-library.js.map +1 -0
- package/dist/admin/registry.d.ts +11 -2
- package/dist/admin/registry.d.ts.map +1 -1
- package/dist/admin/registry.js +40 -4
- package/dist/admin/registry.js.map +1 -1
- package/dist/admin/server.d.ts +1 -0
- package/dist/admin/server.d.ts.map +1 -1
- package/dist/admin/server.js +5 -0
- package/dist/admin/server.js.map +1 -1
- package/dist/admin/styles/admin.css +57 -1
- package/dist/admin/surfaces/components/component-edit.d.ts +3 -0
- package/dist/admin/surfaces/components/component-edit.d.ts.map +1 -0
- package/dist/admin/surfaces/components/component-edit.js +235 -0
- package/dist/admin/surfaces/components/component-edit.js.map +1 -0
- package/dist/admin/surfaces/components/components-data.d.ts +153 -0
- package/dist/admin/surfaces/components/components-data.d.ts.map +1 -0
- package/dist/admin/surfaces/components/components-data.js +154 -0
- package/dist/admin/surfaces/components/components-data.js.map +1 -0
- package/dist/admin/surfaces/components/components-list.d.ts +3 -0
- package/dist/admin/surfaces/components/components-list.d.ts.map +1 -0
- package/dist/admin/surfaces/components/components-list.js +196 -0
- package/dist/admin/surfaces/components/components-list.js.map +1 -0
- package/dist/admin/surfaces/components/definition-canvas.d.ts +73 -0
- package/dist/admin/surfaces/components/definition-canvas.d.ts.map +1 -0
- package/dist/admin/surfaces/components/definition-canvas.js +207 -0
- package/dist/admin/surfaces/components/definition-canvas.js.map +1 -0
- package/dist/admin/surfaces/layouts/layout-editor-client.d.ts.map +1 -1
- package/dist/admin/surfaces/layouts/layout-editor-client.js +14 -2
- package/dist/admin/surfaces/layouts/layout-editor-client.js.map +1 -1
- package/dist/admin/surfaces/layouts/layouts-data.d.ts +3 -14
- package/dist/admin/surfaces/layouts/layouts-data.d.ts.map +1 -1
- package/dist/admin/surfaces/layouts/layouts-data.js +4 -7
- package/dist/admin/surfaces/layouts/layouts-data.js.map +1 -1
- package/dist/admin/surfaces/layouts/layouts-list.d.ts.map +1 -1
- package/dist/admin/surfaces/layouts/layouts-list.js +16 -22
- package/dist/admin/surfaces/layouts/layouts-list.js.map +1 -1
- package/dist/admin/surfaces/settings/admin-features.d.ts.map +1 -1
- package/dist/admin/surfaces/settings/admin-features.js +1 -0
- package/dist/admin/surfaces/settings/admin-features.js.map +1 -1
- package/dist/api/bulk-routes.d.ts.map +1 -1
- package/dist/api/bulk-routes.js +25 -0
- package/dist/api/bulk-routes.js.map +1 -1
- package/dist/api/changeset-routes.d.ts.map +1 -1
- package/dist/api/changeset-routes.js +17 -3
- package/dist/api/changeset-routes.js.map +1 -1
- package/dist/api/component-routes.d.ts.map +1 -1
- package/dist/api/component-routes.js +228 -8
- package/dist/api/component-routes.js.map +1 -1
- package/dist/api/content-routes.d.ts.map +1 -1
- package/dist/api/content-routes.js +64 -0
- package/dist/api/content-routes.js.map +1 -1
- package/dist/api/feed-routes.d.ts +6 -6
- package/dist/api/graphql/resolvers.d.ts +4 -4
- package/dist/api/layout-routes.d.ts.map +1 -1
- package/dist/api/layout-routes.js +4 -17
- package/dist/api/layout-routes.js.map +1 -1
- package/dist/api/layout-write-guard.d.ts +80 -0
- package/dist/api/layout-write-guard.d.ts.map +1 -0
- package/dist/api/layout-write-guard.js +88 -0
- package/dist/api/layout-write-guard.js.map +1 -0
- package/dist/api/section-template-routes.d.ts.map +1 -1
- package/dist/api/section-template-routes.js +11 -0
- package/dist/api/section-template-routes.js.map +1 -1
- package/dist/api/translation-routes.d.ts.map +1 -1
- package/dist/api/translation-routes.js +8 -0
- package/dist/api/translation-routes.js.map +1 -1
- package/dist/api/version-routes.d.ts.map +1 -1
- package/dist/api/version-routes.js +20 -8
- package/dist/api/version-routes.js.map +1 -1
- package/dist/api/workflow-routes.d.ts.map +1 -1
- package/dist/api/workflow-routes.js +53 -8
- package/dist/api/workflow-routes.js.map +1 -1
- package/dist/db/analytics-queries.d.ts +3 -3
- package/dist/db/apply-snapshot.d.ts +75 -8
- package/dist/db/apply-snapshot.d.ts.map +1 -1
- package/dist/db/apply-snapshot.js +104 -8
- package/dist/db/apply-snapshot.js.map +1 -1
- package/dist/db/audit-queries.d.ts +12 -12
- package/dist/db/category-queries.d.ts +3 -3
- package/dist/db/changeset-audit-queries.d.ts +4 -4
- package/dist/db/changeset-queries.d.ts +7 -7
- package/dist/db/comment-queries.d.ts +8 -8
- package/dist/db/comment-subscription-queries.d.ts +2 -2
- package/dist/db/component-instance-queries.d.ts +197 -0
- package/dist/db/component-instance-queries.d.ts.map +1 -0
- package/dist/db/component-instance-queries.js +405 -0
- package/dist/db/component-instance-queries.js.map +1 -0
- package/dist/db/content-queries.d.ts.map +1 -1
- package/dist/db/content-queries.js +39 -2
- package/dist/db/content-queries.js.map +1 -1
- package/dist/db/extension-queries.d.ts +7 -7
- package/dist/db/feed-queries.d.ts +3 -3
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/layout-queries.d.ts +13 -1
- package/dist/db/layout-queries.d.ts.map +1 -1
- package/dist/db/layout-queries.js +52 -7
- package/dist/db/layout-queries.js.map +1 -1
- package/dist/db/locale-queries.d.ts.map +1 -1
- package/dist/db/locale-queries.js +0 -0
- package/dist/db/locale-queries.js.map +1 -1
- package/dist/db/media-queries.d.ts +12 -12
- package/dist/db/revision-queries.d.ts +3 -3
- package/dist/db/site-admin-queries.d.ts +2 -2
- package/dist/db/site-membership-queries.d.ts +3 -3
- package/dist/db/site-plugin-queries.d.ts +2 -2
- package/dist/db/site-queries.d.ts +6 -6
- package/dist/db/version-queries.d.ts +12 -12
- package/dist/db/webhook-queries.d.ts +11 -11
- package/dist/db/workflow-queries.d.ts +6 -6
- package/dist/db/workflow-queries.d.ts.map +1 -1
- package/dist/db/workflow-queries.js +11 -2
- package/dist/db/workflow-queries.js.map +1 -1
- package/dist/layout/comments-module.d.ts.map +1 -1
- package/dist/layout/comments-module.js +6 -2
- package/dist/layout/comments-module.js.map +1 -1
- package/dist/layout/component-refs.d.ts +465 -0
- package/dist/layout/component-refs.d.ts.map +1 -0
- package/dist/layout/component-refs.js +848 -0
- package/dist/layout/component-refs.js.map +1 -0
- package/dist/layout/index.d.ts +2 -1
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +1 -0
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/module-permissions.d.ts +49 -1
- package/dist/layout/module-permissions.d.ts.map +1 -1
- package/dist/layout/module-permissions.js +117 -6
- package/dist/layout/module-permissions.js.map +1 -1
- package/dist/layout/module-render-context.d.ts +32 -0
- package/dist/layout/module-render-context.d.ts.map +1 -1
- package/dist/layout/module-render-context.js +32 -1
- package/dist/layout/module-render-context.js.map +1 -1
- package/dist/layout/modules-extended.d.ts.map +1 -1
- package/dist/layout/modules-extended.js +21 -11
- package/dist/layout/modules-extended.js.map +1 -1
- package/dist/layout/modules.d.ts.map +1 -1
- package/dist/layout/modules.js +15 -10
- package/dist/layout/modules.js.map +1 -1
- package/dist/layout/renderer.d.ts +51 -4
- package/dist/layout/renderer.d.ts.map +1 -1
- package/dist/layout/renderer.js +36 -38
- package/dist/layout/renderer.js.map +1 -1
- package/dist/layout/types.d.ts +42 -0
- package/dist/layout/types.d.ts.map +1 -1
- package/dist/layout/types.js +54 -11
- package/dist/layout/types.js.map +1 -1
- package/dist/schema/base.d.ts +1 -1
- package/dist/schema/components.d.ts +150 -0
- package/dist/schema/components.d.ts.map +1 -1
- package/dist/schema/components.js +50 -4
- package/dist/schema/components.js.map +1 -1
- package/dist/scope/inline-editing.d.ts.map +1 -1
- package/dist/scope/inline-editing.js +10 -0
- package/dist/scope/inline-editing.js.map +1 -1
- package/dist/scope/sticky-offset.d.ts +185 -0
- package/dist/scope/sticky-offset.d.ts.map +1 -0
- package/dist/scope/sticky-offset.js +432 -0
- package/dist/scope/sticky-offset.js.map +1 -0
- package/dist/site/styles.css +41 -3
- package/dist/versioning/scheduler.d.ts +8 -0
- package/dist/versioning/scheduler.d.ts.map +1 -1
- package/dist/versioning/scheduler.js +21 -7
- package/dist/versioning/scheduler.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Site-authored top-anchored chrome vs. the editor's own fixed bars
|
|
3
|
+
* (kywi-cms#146).
|
|
4
|
+
*
|
|
5
|
+
* Both front-of-site bars are `position: fixed; top: 0` — the edit-mode
|
|
6
|
+
* `.kywi-overlay-toolbar` (46px) and the browse-mode `.kywi-edit-toolbar`
|
|
7
|
+
* (44px). Each pushes the DOCUMENT down by its own height
|
|
8
|
+
* (`.kywi-frontend-edit--editing` / `--browsing` in editor.css), which is
|
|
9
|
+
* enough for a header in normal flow: it starts one bar lower and stays
|
|
10
|
+
* visible.
|
|
11
|
+
*
|
|
12
|
+
* It is NOT enough for `position: sticky; top: 0`, the most common theme
|
|
13
|
+
* pattern there is — and the one the marketing site uses. Document padding
|
|
14
|
+
* moves an element's FLOW position; it does nothing to where the element pins
|
|
15
|
+
* once it sticks. So the moment the reader scrolls, a `top: 0` header pins to
|
|
16
|
+
* viewport y=0, underneath a bar that outranks it by ~950 z-index tiers, and
|
|
17
|
+
* the top 46px of the site's own navigation is covered and unclickable for the
|
|
18
|
+
* rest of the session. Measured on the reference app at 1280×720: header rect
|
|
19
|
+
* `top: 0, height: 65` against a bar occupying 0–46.
|
|
20
|
+
*
|
|
21
|
+
* z-index cannot fix this (the bar has to stay on top — it is the way out of
|
|
22
|
+
* edit mode), and neither can CSS alone: the offset a sticky element needs is
|
|
23
|
+
* `top: <bar height>`, a declaration only the site's own stylesheet can carry
|
|
24
|
+
* and only for the elements it knows are sticky. So the editor patches it, for
|
|
25
|
+
* exactly as long as a bar is mounted, and puts it back on the way out.
|
|
26
|
+
*
|
|
27
|
+
* Two things come out of one scan:
|
|
28
|
+
* - each detected element gets an inline `top: var(<bar height token>, <px>)`
|
|
29
|
+
* — plus its own original offset, for a second tier — so the theme's whole
|
|
30
|
+
* top stack pins UNDER the bar instead of behind it, gaps intact;
|
|
31
|
+
* - the tallest detected top BAND is published as `--kywi-editor-sticky-offset`
|
|
32
|
+
* on `documentElement`, which `useChromeFlip` (use-chrome-flip.ts) adds to
|
|
33
|
+
* the strip it clamps in-place chrome below — otherwise the chrome clears
|
|
34
|
+
* the editor's bar only to land inside the site's nav (kywi-cms#122 pinned
|
|
35
|
+
* it at y≈62 into a nav band of 46–111).
|
|
36
|
+
*
|
|
37
|
+
* Lives in `scope/` rather than `admin/layout-editor/` because BOTH bars need
|
|
38
|
+
* it and only one of them is the layout editor: `scope/inline-editing.tsx`
|
|
39
|
+
* (the browse toolbar) is a public-site module, and `admin/` already imports
|
|
40
|
+
* `scope/` while nothing in `scope/` imports `admin/`. Putting it the other way
|
|
41
|
+
* round would invert that.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Height of the tallest site-authored top band the editor offset, in px, on
|
|
45
|
+
* `documentElement` — 0/absent when the page has none.
|
|
46
|
+
*
|
|
47
|
+
* Published as an INLINE custom property deliberately, not a stylesheet rule:
|
|
48
|
+
* `useChromeFlip` reads it on every scroll frame, and
|
|
49
|
+
* `documentElement.style.getPropertyValue()` is a CSSOM read of a declaration
|
|
50
|
+
* this module wrote, not a `getComputedStyle` that can force a style recalc.
|
|
51
|
+
* It is an editor-published measurement, not a theme token — a theme has
|
|
52
|
+
* nothing useful to say about it.
|
|
53
|
+
*/
|
|
54
|
+
export declare const STICKY_OFFSET_VAR = "--kywi-editor-sticky-offset";
|
|
55
|
+
/** Height token of the edit-mode bar (`.kywi-overlay-toolbar`), editor.css. */
|
|
56
|
+
export declare const EDIT_BAR_HEIGHT_VAR = "--kywi-overlay-bar-height";
|
|
57
|
+
/**
|
|
58
|
+
* The literal behind {@link EDIT_BAR_HEIGHT_VAR}, for the `var()` fallback.
|
|
59
|
+
*
|
|
60
|
+
* Kept beside the token rather than only in CSS because a `var()` whose token
|
|
61
|
+
* is undefined resolves to the property's INITIAL value, and `top`'s initial
|
|
62
|
+
* value is `auto` — i.e. the patch below would un-stick every header it touched
|
|
63
|
+
* rather than merely mis-offsetting it. See {@link applyStickyOffset}.
|
|
64
|
+
*/
|
|
65
|
+
export declare const EDIT_BAR_HEIGHT_PX = 46;
|
|
66
|
+
/** Height token of the browse-mode bar (`.kywi-edit-toolbar`), editor.css. */
|
|
67
|
+
export declare const BROWSE_BAR_HEIGHT_VAR = "--kywi-browse-bar-height";
|
|
68
|
+
/** The literal behind {@link BROWSE_BAR_HEIGHT_VAR} — see {@link EDIT_BAR_HEIGHT_PX}. */
|
|
69
|
+
export declare const BROWSE_BAR_HEIGHT_PX = 44;
|
|
70
|
+
/**
|
|
71
|
+
* Marks an element the editor is currently holding an offset on. Public so a
|
|
72
|
+
* test (or a confused developer looking at the DOM) can tell an editor-applied
|
|
73
|
+
* `top` from one the site authored, and so a second `applyStickyOffset` can
|
|
74
|
+
* never capture an already-patched value as the "original".
|
|
75
|
+
*/
|
|
76
|
+
export declare const STICKY_PATCH_ATTR = "data-kywi-sticky-offset";
|
|
77
|
+
/**
|
|
78
|
+
* How far from y=0 still counts as "anchored to the top of the viewport" — the
|
|
79
|
+
* FIRST tier of a theme's sticky stack, offset by exactly one bar height.
|
|
80
|
+
*
|
|
81
|
+
* Not just `top: 0`: a sub-pixel or `0.5px` theme value is the same intent, and
|
|
82
|
+
* `top: -1px` is a widely-copied trick for detecting the stuck state with an
|
|
83
|
+
* IntersectionObserver sentinel.
|
|
84
|
+
*/
|
|
85
|
+
export declare const STICKY_TOP_THRESHOLD_PX = 4;
|
|
86
|
+
/**
|
|
87
|
+
* How far down a SECOND sticky tier may be anchored and still be treated as
|
|
88
|
+
* part of the same top stack (kywi-cms#146 fix round).
|
|
89
|
+
*
|
|
90
|
+
* A theme that stacks — `header { top: 0 }` with a sub-nav at `top: 64px`, the
|
|
91
|
+
* pattern behind every docs site's category bar — used to be half-patched: the
|
|
92
|
+
* header moved to 46 and the sub-nav did not, so a 65px-tall header now covered
|
|
93
|
+
* 46–111 and ate the sub-nav's 64–104 outright. Leaving the second tier alone
|
|
94
|
+
* was not neutral; it was an overlap the PATCH created, and the earlier claim
|
|
95
|
+
* that such an element "is already positioned relative to something" only holds
|
|
96
|
+
* while the thing it is positioned relative to has not moved.
|
|
97
|
+
*
|
|
98
|
+
* So the whole stack shifts by the same delta — `calc(var(<bar>) + <original>)`
|
|
99
|
+
* — which preserves every gap the theme built rather than flattening them.
|
|
100
|
+
*
|
|
101
|
+
* 200px is the ceiling because it is comfortably taller than any real header +
|
|
102
|
+
* sub-nav pair and comfortably shorter than "parked in the middle of the page":
|
|
103
|
+
* a sticky filter panel at `top: 320px` is anchored to page content, not to the
|
|
104
|
+
* top of the viewport, and moving it would be the very break this avoids.
|
|
105
|
+
*/
|
|
106
|
+
export declare const STICKY_SECOND_TIER_MAX_PX = 200;
|
|
107
|
+
/** A live offset patch. Reverting twice is a no-op, not a double-restore. */
|
|
108
|
+
export interface StickyOffsetPatch {
|
|
109
|
+
/** Elements currently carrying an editor-applied `top`. Exposed for tests. */
|
|
110
|
+
readonly elements: readonly HTMLElement[];
|
|
111
|
+
/**
|
|
112
|
+
* Height published as {@link STICKY_OFFSET_VAR} AT MOUNT, in px (0 when the
|
|
113
|
+
* page has no top band). A snapshot, not a live value — the observer below
|
|
114
|
+
* can re-publish a taller one; read {@link readStickyOffsetPx} for current.
|
|
115
|
+
*/
|
|
116
|
+
readonly bandPx: number;
|
|
117
|
+
/** Puts every `top` back exactly as it was and drops the published band. */
|
|
118
|
+
revert(): void;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The inline `top` the editor writes for one tier of a theme's sticky stack.
|
|
122
|
+
*
|
|
123
|
+
* The token, not its resolved px: `var()` in an inline style resolves at
|
|
124
|
+
* used-value time, so a bar height that changes (a theme override, a media
|
|
125
|
+
* query) moves everything this patched without a re-scan. The fallback is
|
|
126
|
+
* mandatory — see {@link applyStickyOffset}'s `fallbackPx`.
|
|
127
|
+
*
|
|
128
|
+
* A pure function so the exact declaration can be pinned by a test: happy-dom's
|
|
129
|
+
* CSS value parser understands neither `calc(var(…))` nor a `var()` fallback
|
|
130
|
+
* written with a space after the comma, and silently DROPS the whole
|
|
131
|
+
* declaration in both cases, so a DOM read-back cannot see this string. Which is
|
|
132
|
+
* also why the comma is written tight — browsers treat `var(--x,4px)` and
|
|
133
|
+
* `var(--x, 4px)` identically, and the tight form is the one that survives the
|
|
134
|
+
* test environment, keeping the first-tier DOM assertions (and the integration
|
|
135
|
+
* ones in inline-editing / overlay-editor) real rather than vacuous.
|
|
136
|
+
*
|
|
137
|
+
* @param shift how far down the stack this tier sits — 0 for the first.
|
|
138
|
+
*/
|
|
139
|
+
export declare function stickyTopValue(barHeightVar: string, fallbackPx: number, shift: number): string;
|
|
140
|
+
/**
|
|
141
|
+
* Offset every site-authored top-anchored element by one bar height, for as
|
|
142
|
+
* long as the returned patch is held.
|
|
143
|
+
*
|
|
144
|
+
* ONE scan, at bar mount. A `MutationObserver` is deliberately not part of
|
|
145
|
+
* this: it would have to re-run `getComputedStyle` on every subtree the site
|
|
146
|
+
* (or the editor's own canvas) inserts for the whole session, and the elements
|
|
147
|
+
* this exists for — the site's header — are in the document before the editor
|
|
148
|
+
* mounts. **Accepted limitation:** a sticky bar that MOUNTS mid-session (a
|
|
149
|
+
* cookie banner that appears on a timer, a mobile menu that is `display: none`
|
|
150
|
+
* at editor open, a site header rendered by a client-only component that has
|
|
151
|
+
* not hydrated yet) is not offset, and pins under the bar as it does today.
|
|
152
|
+
* Re-entering edit mode re-scans.
|
|
153
|
+
*
|
|
154
|
+
* The measured band IS re-published when a patched element resizes (a header
|
|
155
|
+
* whose nav wraps to two rows on a narrower viewport, or the responsive-preview
|
|
156
|
+
* switch), via a `ResizeObserver` — the same reason `useChromeFlip` grew one in
|
|
157
|
+
* kywi-cms#132's fix round: no window event fires for that.
|
|
158
|
+
*
|
|
159
|
+
* @param barHeightVar the CSS custom property holding the mounted bar's height
|
|
160
|
+
* — {@link EDIT_BAR_HEIGHT_VAR} or {@link BROWSE_BAR_HEIGHT_VAR}. Passed as a
|
|
161
|
+
* token rather than a number so a theme that re-declares the token moves the
|
|
162
|
+
* offset with the bar, and so nothing here has to re-parse px.
|
|
163
|
+
* @param fallbackPx that token's literal — {@link EDIT_BAR_HEIGHT_PX} or
|
|
164
|
+
* {@link BROWSE_BAR_HEIGHT_PX} — emitted as the `var()` fallback. NOT
|
|
165
|
+
* optional, because the case it covers is the default one on a generated app:
|
|
166
|
+
* both tokens are declared in `editor.css`, which a scaffold loads LAZILY
|
|
167
|
+
* (behind `next/dynamic`, only once the overlay editor opens — see
|
|
168
|
+
* `create-kywi-app/lib/templates.mjs`), so the BROWSE bar renders with
|
|
169
|
+
* neither token defined. A fallback-less `var()` there resolves to `top`'s
|
|
170
|
+
* initial value, `auto`, and a sticky header with `top: auto` stops sticking
|
|
171
|
+
* at all — strictly worse than the overlap this fixes, and for the whole
|
|
172
|
+
* session. `site/styles.css` declares both on `:root` for the same reason
|
|
173
|
+
* (belt to this brace); the fallback is what holds if a host ships neither
|
|
174
|
+
* stylesheet.
|
|
175
|
+
*/
|
|
176
|
+
export declare function applyStickyOffset(barHeightVar: string, fallbackPx: number): StickyOffsetPatch;
|
|
177
|
+
/**
|
|
178
|
+
* The published sticky band, in px — 0 when the page has no offset top band.
|
|
179
|
+
*
|
|
180
|
+
* Cheap enough for a scroll handler: this reads the inline declaration
|
|
181
|
+
* {@link applyStickyOffset} wrote, so unlike `getComputedStyle` it cannot force
|
|
182
|
+
* a style recalculation.
|
|
183
|
+
*/
|
|
184
|
+
export declare function readStickyOffsetPx(): number;
|
|
185
|
+
//# sourceMappingURL=sticky-offset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sticky-offset.d.ts","sourceRoot":"","sources":["../../src/scope/sticky-offset.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,gCAAgC,CAAA;AAE9D,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,8BAA8B,CAAA;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,6BAA6B,CAAA;AAE/D,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAA;AAE1D;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAA;AA2E5C,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAA;IACzC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,4EAA4E;IAC5E,MAAM,IAAI,IAAI,CAAA;CACf;AAaD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG9F;AAkFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAwF7F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAK3C"}
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* Site-authored top-anchored chrome vs. the editor's own fixed bars
|
|
4
|
+
* (kywi-cms#146).
|
|
5
|
+
*
|
|
6
|
+
* Both front-of-site bars are `position: fixed; top: 0` — the edit-mode
|
|
7
|
+
* `.kywi-overlay-toolbar` (46px) and the browse-mode `.kywi-edit-toolbar`
|
|
8
|
+
* (44px). Each pushes the DOCUMENT down by its own height
|
|
9
|
+
* (`.kywi-frontend-edit--editing` / `--browsing` in editor.css), which is
|
|
10
|
+
* enough for a header in normal flow: it starts one bar lower and stays
|
|
11
|
+
* visible.
|
|
12
|
+
*
|
|
13
|
+
* It is NOT enough for `position: sticky; top: 0`, the most common theme
|
|
14
|
+
* pattern there is — and the one the marketing site uses. Document padding
|
|
15
|
+
* moves an element's FLOW position; it does nothing to where the element pins
|
|
16
|
+
* once it sticks. So the moment the reader scrolls, a `top: 0` header pins to
|
|
17
|
+
* viewport y=0, underneath a bar that outranks it by ~950 z-index tiers, and
|
|
18
|
+
* the top 46px of the site's own navigation is covered and unclickable for the
|
|
19
|
+
* rest of the session. Measured on the reference app at 1280×720: header rect
|
|
20
|
+
* `top: 0, height: 65` against a bar occupying 0–46.
|
|
21
|
+
*
|
|
22
|
+
* z-index cannot fix this (the bar has to stay on top — it is the way out of
|
|
23
|
+
* edit mode), and neither can CSS alone: the offset a sticky element needs is
|
|
24
|
+
* `top: <bar height>`, a declaration only the site's own stylesheet can carry
|
|
25
|
+
* and only for the elements it knows are sticky. So the editor patches it, for
|
|
26
|
+
* exactly as long as a bar is mounted, and puts it back on the way out.
|
|
27
|
+
*
|
|
28
|
+
* Two things come out of one scan:
|
|
29
|
+
* - each detected element gets an inline `top: var(<bar height token>, <px>)`
|
|
30
|
+
* — plus its own original offset, for a second tier — so the theme's whole
|
|
31
|
+
* top stack pins UNDER the bar instead of behind it, gaps intact;
|
|
32
|
+
* - the tallest detected top BAND is published as `--kywi-editor-sticky-offset`
|
|
33
|
+
* on `documentElement`, which `useChromeFlip` (use-chrome-flip.ts) adds to
|
|
34
|
+
* the strip it clamps in-place chrome below — otherwise the chrome clears
|
|
35
|
+
* the editor's bar only to land inside the site's nav (kywi-cms#122 pinned
|
|
36
|
+
* it at y≈62 into a nav band of 46–111).
|
|
37
|
+
*
|
|
38
|
+
* Lives in `scope/` rather than `admin/layout-editor/` because BOTH bars need
|
|
39
|
+
* it and only one of them is the layout editor: `scope/inline-editing.tsx`
|
|
40
|
+
* (the browse toolbar) is a public-site module, and `admin/` already imports
|
|
41
|
+
* `scope/` while nothing in `scope/` imports `admin/`. Putting it the other way
|
|
42
|
+
* round would invert that.
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Height of the tallest site-authored top band the editor offset, in px, on
|
|
46
|
+
* `documentElement` — 0/absent when the page has none.
|
|
47
|
+
*
|
|
48
|
+
* Published as an INLINE custom property deliberately, not a stylesheet rule:
|
|
49
|
+
* `useChromeFlip` reads it on every scroll frame, and
|
|
50
|
+
* `documentElement.style.getPropertyValue()` is a CSSOM read of a declaration
|
|
51
|
+
* this module wrote, not a `getComputedStyle` that can force a style recalc.
|
|
52
|
+
* It is an editor-published measurement, not a theme token — a theme has
|
|
53
|
+
* nothing useful to say about it.
|
|
54
|
+
*/
|
|
55
|
+
export const STICKY_OFFSET_VAR = '--kywi-editor-sticky-offset';
|
|
56
|
+
/** Height token of the edit-mode bar (`.kywi-overlay-toolbar`), editor.css. */
|
|
57
|
+
export const EDIT_BAR_HEIGHT_VAR = '--kywi-overlay-bar-height';
|
|
58
|
+
/**
|
|
59
|
+
* The literal behind {@link EDIT_BAR_HEIGHT_VAR}, for the `var()` fallback.
|
|
60
|
+
*
|
|
61
|
+
* Kept beside the token rather than only in CSS because a `var()` whose token
|
|
62
|
+
* is undefined resolves to the property's INITIAL value, and `top`'s initial
|
|
63
|
+
* value is `auto` — i.e. the patch below would un-stick every header it touched
|
|
64
|
+
* rather than merely mis-offsetting it. See {@link applyStickyOffset}.
|
|
65
|
+
*/
|
|
66
|
+
export const EDIT_BAR_HEIGHT_PX = 46;
|
|
67
|
+
/** Height token of the browse-mode bar (`.kywi-edit-toolbar`), editor.css. */
|
|
68
|
+
export const BROWSE_BAR_HEIGHT_VAR = '--kywi-browse-bar-height';
|
|
69
|
+
/** The literal behind {@link BROWSE_BAR_HEIGHT_VAR} — see {@link EDIT_BAR_HEIGHT_PX}. */
|
|
70
|
+
export const BROWSE_BAR_HEIGHT_PX = 44;
|
|
71
|
+
/**
|
|
72
|
+
* Marks an element the editor is currently holding an offset on. Public so a
|
|
73
|
+
* test (or a confused developer looking at the DOM) can tell an editor-applied
|
|
74
|
+
* `top` from one the site authored, and so a second `applyStickyOffset` can
|
|
75
|
+
* never capture an already-patched value as the "original".
|
|
76
|
+
*/
|
|
77
|
+
export const STICKY_PATCH_ATTR = 'data-kywi-sticky-offset';
|
|
78
|
+
/**
|
|
79
|
+
* How far from y=0 still counts as "anchored to the top of the viewport" — the
|
|
80
|
+
* FIRST tier of a theme's sticky stack, offset by exactly one bar height.
|
|
81
|
+
*
|
|
82
|
+
* Not just `top: 0`: a sub-pixel or `0.5px` theme value is the same intent, and
|
|
83
|
+
* `top: -1px` is a widely-copied trick for detecting the stuck state with an
|
|
84
|
+
* IntersectionObserver sentinel.
|
|
85
|
+
*/
|
|
86
|
+
export const STICKY_TOP_THRESHOLD_PX = 4;
|
|
87
|
+
/**
|
|
88
|
+
* How far down a SECOND sticky tier may be anchored and still be treated as
|
|
89
|
+
* part of the same top stack (kywi-cms#146 fix round).
|
|
90
|
+
*
|
|
91
|
+
* A theme that stacks — `header { top: 0 }` with a sub-nav at `top: 64px`, the
|
|
92
|
+
* pattern behind every docs site's category bar — used to be half-patched: the
|
|
93
|
+
* header moved to 46 and the sub-nav did not, so a 65px-tall header now covered
|
|
94
|
+
* 46–111 and ate the sub-nav's 64–104 outright. Leaving the second tier alone
|
|
95
|
+
* was not neutral; it was an overlap the PATCH created, and the earlier claim
|
|
96
|
+
* that such an element "is already positioned relative to something" only holds
|
|
97
|
+
* while the thing it is positioned relative to has not moved.
|
|
98
|
+
*
|
|
99
|
+
* So the whole stack shifts by the same delta — `calc(var(<bar>) + <original>)`
|
|
100
|
+
* — which preserves every gap the theme built rather than flattening them.
|
|
101
|
+
*
|
|
102
|
+
* 200px is the ceiling because it is comfortably taller than any real header +
|
|
103
|
+
* sub-nav pair and comfortably shorter than "parked in the middle of the page":
|
|
104
|
+
* a sticky filter panel at `top: 320px` is anchored to page content, not to the
|
|
105
|
+
* top of the viewport, and moving it would be the very break this avoids.
|
|
106
|
+
*/
|
|
107
|
+
export const STICKY_SECOND_TIER_MAX_PX = 200;
|
|
108
|
+
/**
|
|
109
|
+
* Below this in either dimension an element is a probe, not chrome. Next's dev
|
|
110
|
+
* overlay parks a 1×1 `position: fixed; top: 0` div at (-1, -1) on every page,
|
|
111
|
+
* and giving it an inline `top` is pure noise in the DOM the owner inspects.
|
|
112
|
+
*/
|
|
113
|
+
const MIN_PATCHABLE_PX = 8;
|
|
114
|
+
/**
|
|
115
|
+
* A top-anchored element taller than this share of the viewport is a drawer, a
|
|
116
|
+
* scrim or a full-height sidebar — not a band across the top of the page — so
|
|
117
|
+
* it must not drag the chrome clamp down with it. It still gets the offset (it
|
|
118
|
+
* is still covered by the bar); it just does not define a band to clamp below.
|
|
119
|
+
*/
|
|
120
|
+
const MAX_BAND_VIEWPORT_FRACTION = 0.25;
|
|
121
|
+
/**
|
|
122
|
+
* …but a band no taller than this is a header whatever the viewport is doing,
|
|
123
|
+
* so it publishes even when the fraction above says otherwise (kywi-cms#146 fix
|
|
124
|
+
* round).
|
|
125
|
+
*
|
|
126
|
+
* The fraction alone is a trap on a short window: a nav whose links wrap to two
|
|
127
|
+
* rows measures ~170px, and at a 640px-tall viewport (a laptop with devtools
|
|
128
|
+
* docked, or the editor's own responsive preview) a quarter is 160 — so the
|
|
129
|
+
* band silently published as 0 while the elements stayed patched, and the
|
|
130
|
+
* chrome clamped straight back INTO the nav, which is the exact collision the
|
|
131
|
+
* band exists to end. The two rules are a UNION, never an intersection: a band
|
|
132
|
+
* that is short in ABSOLUTE terms or short RELATIVE to the viewport publishes;
|
|
133
|
+
* only one that is both tall and viewport-dominating is read as a drawer. A
|
|
134
|
+
* 700px full-height drawer fails both at any viewport, which is the case the
|
|
135
|
+
* fraction was written for and still catches.
|
|
136
|
+
*/
|
|
137
|
+
const ALWAYS_A_BAND_MAX_PX = 200;
|
|
138
|
+
/**
|
|
139
|
+
* The editor's OWN top-anchored chrome, which must never be offset: these
|
|
140
|
+
* elements ARE the bars being cleared, and pushing them down by their own
|
|
141
|
+
* height would walk them off the screen one mode-switch at a time.
|
|
142
|
+
*
|
|
143
|
+
* An explicit list, not a `[class*="kywi-overlay"]` wildcard, for one specific
|
|
144
|
+
* reason: `.kywi-overlay-shell` is `display: contents` and WRAPS the whole
|
|
145
|
+
* in-place canvas, i.e. the site's own sections and modules. A wildcard would
|
|
146
|
+
* match it, and `closest()` would then exclude every sticky element the owner
|
|
147
|
+
* is actually editing. `[data-kywi-editor-chrome]` is the extension point —
|
|
148
|
+
* new chrome marks itself with it (the attribute already exists for the
|
|
149
|
+
* inline-edit exclusions) rather than growing this list.
|
|
150
|
+
*/
|
|
151
|
+
const EDITOR_CHROME_SELECTOR = [
|
|
152
|
+
'[data-kywi-editor-chrome]',
|
|
153
|
+
'.kywi-edit-toolbar',
|
|
154
|
+
'.kywi-overlay-toolbar',
|
|
155
|
+
'.kywi-overlay-rail',
|
|
156
|
+
'.kywi-overlay-dialog-host',
|
|
157
|
+
'.kywi-editor-template-overlay',
|
|
158
|
+
'.kywi-admin-shell',
|
|
159
|
+
'.kywi-ip-chrome',
|
|
160
|
+
'.kywi-ip-chip',
|
|
161
|
+
].join(',');
|
|
162
|
+
/**
|
|
163
|
+
* Keyed by element rather than carried on the handle so a patch applied while
|
|
164
|
+
* another is somehow still live restores the SITE's value, never the previous
|
|
165
|
+
* patch's `var(...)`. React unmounts the outgoing bar's effect before it runs
|
|
166
|
+
* the incoming one's, so browse→edit already swaps cleanly; this is the belt to
|
|
167
|
+
* that braces, and it is a WeakMap so a detached element is not retained.
|
|
168
|
+
*/
|
|
169
|
+
const originalTops = new WeakMap();
|
|
170
|
+
const NOOP_PATCH = {
|
|
171
|
+
elements: [],
|
|
172
|
+
bandPx: 0,
|
|
173
|
+
revert() { },
|
|
174
|
+
};
|
|
175
|
+
/** True for an element the editor's own chrome owns (or lives inside). */
|
|
176
|
+
function isEditorChrome(el) {
|
|
177
|
+
return el.closest(EDITOR_CHROME_SELECTOR) !== null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The inline `top` the editor writes for one tier of a theme's sticky stack.
|
|
181
|
+
*
|
|
182
|
+
* The token, not its resolved px: `var()` in an inline style resolves at
|
|
183
|
+
* used-value time, so a bar height that changes (a theme override, a media
|
|
184
|
+
* query) moves everything this patched without a re-scan. The fallback is
|
|
185
|
+
* mandatory — see {@link applyStickyOffset}'s `fallbackPx`.
|
|
186
|
+
*
|
|
187
|
+
* A pure function so the exact declaration can be pinned by a test: happy-dom's
|
|
188
|
+
* CSS value parser understands neither `calc(var(…))` nor a `var()` fallback
|
|
189
|
+
* written with a space after the comma, and silently DROPS the whole
|
|
190
|
+
* declaration in both cases, so a DOM read-back cannot see this string. Which is
|
|
191
|
+
* also why the comma is written tight — browsers treat `var(--x,4px)` and
|
|
192
|
+
* `var(--x, 4px)` identically, and the tight form is the one that survives the
|
|
193
|
+
* test environment, keeping the first-tier DOM assertions (and the integration
|
|
194
|
+
* ones in inline-editing / overlay-editor) real rather than vacuous.
|
|
195
|
+
*
|
|
196
|
+
* @param shift how far down the stack this tier sits — 0 for the first.
|
|
197
|
+
*/
|
|
198
|
+
export function stickyTopValue(barHeightVar, fallbackPx, shift) {
|
|
199
|
+
const bar = `var(${barHeightVar},${fallbackPx}px)`;
|
|
200
|
+
return shift === 0 ? bar : `calc(${bar} + ${shift}px)`;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* True when a sticky element pins against the VIEWPORT rather than inside some
|
|
204
|
+
* ancestor's scroll pane.
|
|
205
|
+
*
|
|
206
|
+
* Only ever asked of a second-tier candidate, and it is what keeps a sticky
|
|
207
|
+
* table head at `top: 40px` inside an `overflow: auto` pane out of the patch:
|
|
208
|
+
* that element's `top` is measured from its scrollport, not from the top of the
|
|
209
|
+
* window, so the editor's bar never covers it and shifting it by a bar height
|
|
210
|
+
* would push it down inside its own pane for no reason. The overflow test is
|
|
211
|
+
* the same one the browser applies — any `overflow-y` other than `visible` or
|
|
212
|
+
* `clip` makes that ancestor the scrollport (which is also why `overflow-x:
|
|
213
|
+
* hidden`, whose `overflow-y` computes to `auto`, famously "breaks" sticky).
|
|
214
|
+
*/
|
|
215
|
+
function pinsToViewport(el, view) {
|
|
216
|
+
const doc = el.ownerDocument;
|
|
217
|
+
for (let parent = el.parentElement; parent && parent !== doc.body && parent !== doc.documentElement; parent = parent.parentElement) {
|
|
218
|
+
const overflowY = view.getComputedStyle(parent).overflowY;
|
|
219
|
+
if (overflowY && overflowY !== 'visible' && overflowY !== 'clip')
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* How far down the top stack this element is anchored — 0 for the first tier,
|
|
226
|
+
* its own `top` in px for a second tier — or null when it is not part of the
|
|
227
|
+
* stack at all and must be left exactly as the theme wrote it.
|
|
228
|
+
*/
|
|
229
|
+
function topAnchorOf(el, view) {
|
|
230
|
+
const style = view.getComputedStyle(el);
|
|
231
|
+
const position = style.position;
|
|
232
|
+
// `-webkit-sticky` still shows up in older Safari's computed style.
|
|
233
|
+
const sticky = position === 'sticky' || position === '-webkit-sticky';
|
|
234
|
+
if (!sticky && position !== 'fixed')
|
|
235
|
+
return null;
|
|
236
|
+
// A px length and nothing else. `top: auto` — a sticky element with no
|
|
237
|
+
// vertical anchor, which never pins to the top at all — is the obvious
|
|
238
|
+
// rejection, but the one that matters is a PERCENTAGE: `.kywi-selfid-modal`
|
|
239
|
+
// is `position: fixed; top: 50%` (centred, then pulled back by a transform),
|
|
240
|
+
// and a bare `parseFloat` reads that as "50", i.e. a second tier to shift by
|
|
241
|
+
// a bar height. A resolved `top` is normally px, but it is a percentage for
|
|
242
|
+
// an element the box tree has no used value for, and half a viewport is a
|
|
243
|
+
// second tier on any short window. Anchoring on the UNIT rather than the
|
|
244
|
+
// number rejects both without a special case.
|
|
245
|
+
const match = /^(-?[0-9]*\.?[0-9]+)px$/.exec(style.top.trim());
|
|
246
|
+
if (!match)
|
|
247
|
+
return null;
|
|
248
|
+
const top = Number.parseFloat(match[1]);
|
|
249
|
+
if (!Number.isFinite(top))
|
|
250
|
+
return null;
|
|
251
|
+
if (Math.abs(top) <= STICKY_TOP_THRESHOLD_PX)
|
|
252
|
+
return 0;
|
|
253
|
+
// Below the top, but within one header stack of it: a second tier, shifted by
|
|
254
|
+
// the same delta so the theme's own gap survives (see
|
|
255
|
+
// {@link STICKY_SECOND_TIER_MAX_PX}). Negative values beyond the threshold
|
|
256
|
+
// are scroll tricks, not tiers, and are left alone.
|
|
257
|
+
if (top < 0 || top > STICKY_SECOND_TIER_MAX_PX)
|
|
258
|
+
return null;
|
|
259
|
+
if (sticky && !pinsToViewport(el, view))
|
|
260
|
+
return null;
|
|
261
|
+
return top;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* The height this element contributes to the clamp band, or 0 if it is not a
|
|
265
|
+
* band: it has to cross the viewport's horizontal midline (a left sidebar or a
|
|
266
|
+
* corner badge does not) and read as a header rather than a drawer (see
|
|
267
|
+
* {@link ALWAYS_A_BAND_MAX_PX}).
|
|
268
|
+
*
|
|
269
|
+
* The band a tier is responsible for is measured from the TOP of the stack —
|
|
270
|
+
* `shift + height`, not the element's own height — because that is the strip
|
|
271
|
+
* the chrome has to clear: a sub-nav at `top: 64px` and 40px tall leaves the
|
|
272
|
+
* chrome nothing until 104.
|
|
273
|
+
*/
|
|
274
|
+
function bandHeightOf(el, view, shift) {
|
|
275
|
+
const { height, left, right } = el.getBoundingClientRect();
|
|
276
|
+
const midX = view.innerWidth / 2;
|
|
277
|
+
if (left > midX || right < midX)
|
|
278
|
+
return 0;
|
|
279
|
+
const band = shift + height;
|
|
280
|
+
if (band > ALWAYS_A_BAND_MAX_PX && band > view.innerHeight * MAX_BAND_VIEWPORT_FRACTION)
|
|
281
|
+
return 0;
|
|
282
|
+
return band;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Offset every site-authored top-anchored element by one bar height, for as
|
|
286
|
+
* long as the returned patch is held.
|
|
287
|
+
*
|
|
288
|
+
* ONE scan, at bar mount. A `MutationObserver` is deliberately not part of
|
|
289
|
+
* this: it would have to re-run `getComputedStyle` on every subtree the site
|
|
290
|
+
* (or the editor's own canvas) inserts for the whole session, and the elements
|
|
291
|
+
* this exists for — the site's header — are in the document before the editor
|
|
292
|
+
* mounts. **Accepted limitation:** a sticky bar that MOUNTS mid-session (a
|
|
293
|
+
* cookie banner that appears on a timer, a mobile menu that is `display: none`
|
|
294
|
+
* at editor open, a site header rendered by a client-only component that has
|
|
295
|
+
* not hydrated yet) is not offset, and pins under the bar as it does today.
|
|
296
|
+
* Re-entering edit mode re-scans.
|
|
297
|
+
*
|
|
298
|
+
* The measured band IS re-published when a patched element resizes (a header
|
|
299
|
+
* whose nav wraps to two rows on a narrower viewport, or the responsive-preview
|
|
300
|
+
* switch), via a `ResizeObserver` — the same reason `useChromeFlip` grew one in
|
|
301
|
+
* kywi-cms#132's fix round: no window event fires for that.
|
|
302
|
+
*
|
|
303
|
+
* @param barHeightVar the CSS custom property holding the mounted bar's height
|
|
304
|
+
* — {@link EDIT_BAR_HEIGHT_VAR} or {@link BROWSE_BAR_HEIGHT_VAR}. Passed as a
|
|
305
|
+
* token rather than a number so a theme that re-declares the token moves the
|
|
306
|
+
* offset with the bar, and so nothing here has to re-parse px.
|
|
307
|
+
* @param fallbackPx that token's literal — {@link EDIT_BAR_HEIGHT_PX} or
|
|
308
|
+
* {@link BROWSE_BAR_HEIGHT_PX} — emitted as the `var()` fallback. NOT
|
|
309
|
+
* optional, because the case it covers is the default one on a generated app:
|
|
310
|
+
* both tokens are declared in `editor.css`, which a scaffold loads LAZILY
|
|
311
|
+
* (behind `next/dynamic`, only once the overlay editor opens — see
|
|
312
|
+
* `create-kywi-app/lib/templates.mjs`), so the BROWSE bar renders with
|
|
313
|
+
* neither token defined. A fallback-less `var()` there resolves to `top`'s
|
|
314
|
+
* initial value, `auto`, and a sticky header with `top: auto` stops sticking
|
|
315
|
+
* at all — strictly worse than the overlap this fixes, and for the whole
|
|
316
|
+
* session. `site/styles.css` declares both on `:root` for the same reason
|
|
317
|
+
* (belt to this brace); the fallback is what holds if a host ships neither
|
|
318
|
+
* stylesheet.
|
|
319
|
+
*/
|
|
320
|
+
export function applyStickyOffset(barHeightVar, fallbackPx) {
|
|
321
|
+
if (typeof document === 'undefined' || typeof window === 'undefined')
|
|
322
|
+
return NOOP_PATCH;
|
|
323
|
+
const body = document.body;
|
|
324
|
+
if (!body)
|
|
325
|
+
return NOOP_PATCH;
|
|
326
|
+
const patched = [];
|
|
327
|
+
/** Each patched element's tier depth, for the band it is responsible for. */
|
|
328
|
+
const shifts = new Map();
|
|
329
|
+
for (const el of Array.from(body.querySelectorAll('*'))) {
|
|
330
|
+
if (el.hasAttribute(STICKY_PATCH_ATTR))
|
|
331
|
+
continue;
|
|
332
|
+
if (isEditorChrome(el))
|
|
333
|
+
continue;
|
|
334
|
+
const shift = topAnchorOf(el, window);
|
|
335
|
+
if (shift === null)
|
|
336
|
+
continue;
|
|
337
|
+
const { width, height } = el.getBoundingClientRect();
|
|
338
|
+
if (width < MIN_PATCHABLE_PX || height < MIN_PATCHABLE_PX)
|
|
339
|
+
continue;
|
|
340
|
+
originalTops.set(el, {
|
|
341
|
+
value: el.style.getPropertyValue('top'),
|
|
342
|
+
priority: el.style.getPropertyPriority('top'),
|
|
343
|
+
});
|
|
344
|
+
el.setAttribute(STICKY_PATCH_ATTR, '');
|
|
345
|
+
// A second tier keeps its own offset ON TOP of the bar, so the theme's
|
|
346
|
+
// stack arrives intact one bar lower rather than collapsing onto itself.
|
|
347
|
+
el.style.setProperty('top', stickyTopValue(barHeightVar, fallbackPx, shift));
|
|
348
|
+
patched.push(el);
|
|
349
|
+
shifts.set(el, shift);
|
|
350
|
+
}
|
|
351
|
+
const root = document.documentElement;
|
|
352
|
+
const publishBand = () => {
|
|
353
|
+
let band = 0;
|
|
354
|
+
for (const el of patched)
|
|
355
|
+
band = Math.max(band, bandHeightOf(el, window, shifts.get(el) ?? 0));
|
|
356
|
+
// Rounded up: a fractional band rounded DOWN would clamp chrome half a
|
|
357
|
+
// pixel INTO the nav, which is the collision this exists to end.
|
|
358
|
+
const px = Math.ceil(band);
|
|
359
|
+
if (px > 0)
|
|
360
|
+
root.style.setProperty(STICKY_OFFSET_VAR, `${px}px`);
|
|
361
|
+
// Same gate as `revert` below, for the same reason: a scan that patched
|
|
362
|
+
// NOTHING has no band of its own and must not clear the live patch's. Two
|
|
363
|
+
// bars overlapping by a frame is the ordinary case (browse → edit), and
|
|
364
|
+
// without this the second one's empty scan wipes the first one's band and
|
|
365
|
+
// the chrome clamps back into the nav.
|
|
366
|
+
else if (patched.length > 0)
|
|
367
|
+
root.style.removeProperty(STICKY_OFFSET_VAR);
|
|
368
|
+
return px;
|
|
369
|
+
};
|
|
370
|
+
const bandPx = publishBand();
|
|
371
|
+
// Feature-detected, exactly as in use-chrome-flip.ts: happy-dom ships an
|
|
372
|
+
// inert stub and older hosts have none, so a missing observer degrades to
|
|
373
|
+
// "the band is what it measured at mount" instead of throwing.
|
|
374
|
+
const ResizeObserverCtor = window
|
|
375
|
+
.ResizeObserver;
|
|
376
|
+
let observer = null;
|
|
377
|
+
if (patched.length > 0 && typeof ResizeObserverCtor === 'function') {
|
|
378
|
+
observer = new ResizeObserverCtor(() => { publishBand(); });
|
|
379
|
+
for (const el of patched)
|
|
380
|
+
observer.observe(el);
|
|
381
|
+
}
|
|
382
|
+
let reverted = false;
|
|
383
|
+
return {
|
|
384
|
+
elements: patched,
|
|
385
|
+
bandPx,
|
|
386
|
+
revert() {
|
|
387
|
+
if (reverted)
|
|
388
|
+
return;
|
|
389
|
+
reverted = true;
|
|
390
|
+
observer?.disconnect();
|
|
391
|
+
for (const el of patched) {
|
|
392
|
+
el.removeAttribute(STICKY_PATCH_ATTR);
|
|
393
|
+
const original = originalTops.get(el);
|
|
394
|
+
originalTops.delete(el);
|
|
395
|
+
if (original && original.value !== '') {
|
|
396
|
+
el.style.setProperty('top', original.value, original.priority);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
el.style.removeProperty('top');
|
|
400
|
+
}
|
|
401
|
+
// An element that carried no `style` attribute before must carry none
|
|
402
|
+
// after — "restored exactly" has to include leaving no empty husk
|
|
403
|
+
// behind for the next reader of the DOM to wonder about.
|
|
404
|
+
if (el.getAttribute('style') === '')
|
|
405
|
+
el.removeAttribute('style');
|
|
406
|
+
}
|
|
407
|
+
// Only a patch that could have published the band may clear it — the
|
|
408
|
+
// same reasoning as restoring `top` from the recorded original rather
|
|
409
|
+
// than blindly: a revert must never undo something it did not do.
|
|
410
|
+
if (patched.length > 0) {
|
|
411
|
+
root.style.removeProperty(STICKY_OFFSET_VAR);
|
|
412
|
+
if (root.getAttribute('style') === '')
|
|
413
|
+
root.removeAttribute('style');
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* The published sticky band, in px — 0 when the page has no offset top band.
|
|
420
|
+
*
|
|
421
|
+
* Cheap enough for a scroll handler: this reads the inline declaration
|
|
422
|
+
* {@link applyStickyOffset} wrote, so unlike `getComputedStyle` it cannot force
|
|
423
|
+
* a style recalculation.
|
|
424
|
+
*/
|
|
425
|
+
export function readStickyOffsetPx() {
|
|
426
|
+
if (typeof document === 'undefined')
|
|
427
|
+
return 0;
|
|
428
|
+
const raw = document.documentElement.style.getPropertyValue(STICKY_OFFSET_VAR);
|
|
429
|
+
const parsed = Number.parseFloat(raw);
|
|
430
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=sticky-offset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sticky-offset.js","sourceRoot":"","sources":["../../src/scope/sticky-offset.ts"],"names":[],"mappings":"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"}
|