help-layer 1.0.1 → 1.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.
- package/README.ja.md +82 -8
- package/README.md +88 -8
- package/dist/help-layer.esm.js +7 -5
- package/dist/help-layer.esm.js.map +3 -3
- package/dist/help-layer.iife.js +6 -4
- package/dist/help-layer.iife.js.map +3 -3
- package/dist/types/floating.d.ts +12 -0
- package/package.json +7 -2
- package/src/floating.js +45 -0
- package/src/style.js +3 -1
package/dist/types/floating.d.ts
CHANGED
|
@@ -23,6 +23,18 @@ export function makeVirtualElement(getDocRect: () => {
|
|
|
23
23
|
height: number;
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Whether the reference lives in a `position: fixed` subtree. Such a reference stays put in the
|
|
28
|
+
* viewport while the page scrolls, so an absolutely-positioned floating element (which scrolls with
|
|
29
|
+
* the document) would have to be re-corrected every frame and visibly jitters. For these we switch the
|
|
30
|
+
* floating element to Floating UI's `fixed` strategy (and position:fixed) so both live in the same
|
|
31
|
+
* viewport space and stay glued without per-frame correction.
|
|
32
|
+
*
|
|
33
|
+
* Virtual elements (free placements) aren't in the DOM and already track scroll via their getRect, so
|
|
34
|
+
* they report false. Walks across shadow boundaries via the host so Shadow DOM targets are handled too.
|
|
35
|
+
* @param {Element|object} reference
|
|
36
|
+
*/
|
|
37
|
+
export function isFixedReference(reference: Element | object): boolean;
|
|
26
38
|
/**
|
|
27
39
|
* Overlap the marker onto a corner of the target (element or virtual element), stick it there, and keep it following.
|
|
28
40
|
* @param {Element|object} reference
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "help-layer",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"engines": {
|
|
@@ -32,11 +32,14 @@
|
|
|
32
32
|
"lint:fix": "eslint src tests --fix",
|
|
33
33
|
"typecheck": "tsc -p jsconfig.json",
|
|
34
34
|
"check": "npm run lint && npm run typecheck && npm test",
|
|
35
|
+
"build:site": "node demo/build-site.js",
|
|
36
|
+
"build:demos": "node demo/build-framework-demos.js",
|
|
35
37
|
"build:bundle": "node scripts/build.js",
|
|
36
38
|
"build:types": "tsc -p jsconfig.json --declaration --emitDeclarationOnly --noEmit false --rootDir src --outDir dist/types",
|
|
37
39
|
"build": "npm run build:bundle && npm run build:types",
|
|
40
|
+
"record:gif": "npm run build:demos && node scripts/record-demo.js",
|
|
38
41
|
"prepublishOnly": "npm run build",
|
|
39
|
-
"demo": "node scripts/serve.js"
|
|
42
|
+
"demo": "npm run build:demos && node scripts/serve.js"
|
|
40
43
|
},
|
|
41
44
|
"devDependencies": {
|
|
42
45
|
"@playwright/test": "^1.61.0",
|
|
@@ -45,8 +48,10 @@
|
|
|
45
48
|
"eslint-plugin-import": "^2.32.0",
|
|
46
49
|
"eslint-plugin-n": "^17.24.0",
|
|
47
50
|
"eslint-plugin-promise": "^7.2.1",
|
|
51
|
+
"gifenc": "^1.0.3",
|
|
48
52
|
"jest": "^29.7.0",
|
|
49
53
|
"jest-environment-jsdom": "^29.7.0",
|
|
54
|
+
"pngjs": "^7.0.0",
|
|
50
55
|
"react": "^19.2.7",
|
|
51
56
|
"react-dom": "^19.2.7",
|
|
52
57
|
"typescript": "^6.0.3",
|
package/src/floating.js
CHANGED
|
@@ -40,6 +40,37 @@ function place(el, x, y) {
|
|
|
40
40
|
el.style.top = `${y}px`;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Whether the reference lives in a `position: fixed` subtree. Such a reference stays put in the
|
|
45
|
+
* viewport while the page scrolls, so an absolutely-positioned floating element (which scrolls with
|
|
46
|
+
* the document) would have to be re-corrected every frame and visibly jitters. For these we switch the
|
|
47
|
+
* floating element to Floating UI's `fixed` strategy (and position:fixed) so both live in the same
|
|
48
|
+
* viewport space and stay glued without per-frame correction.
|
|
49
|
+
*
|
|
50
|
+
* Virtual elements (free placements) aren't in the DOM and already track scroll via their getRect, so
|
|
51
|
+
* they report false. Walks across shadow boundaries via the host so Shadow DOM targets are handled too.
|
|
52
|
+
* @param {Element|object} reference
|
|
53
|
+
*/
|
|
54
|
+
export function isFixedReference(reference) {
|
|
55
|
+
if (!(reference instanceof Element)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
let node = reference;
|
|
59
|
+
while (node) {
|
|
60
|
+
if (getComputedStyle(node).position === 'fixed') {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
const parent = node.parentElement;
|
|
64
|
+
if (parent) {
|
|
65
|
+
node = parent;
|
|
66
|
+
} else {
|
|
67
|
+
const root = node.getRootNode();
|
|
68
|
+
node = root instanceof ShadowRoot ? root.host : null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
43
74
|
// Half of the default marker size (22px). The amount used to overlap the marker onto the
|
|
44
75
|
// target's corner with an "inset". (If the marker-size CSS variable is changed, the resulting
|
|
45
76
|
// drift is left as existing behavior = not compensated for here.)
|
|
@@ -66,9 +97,17 @@ function markerOffset(placement) {
|
|
|
66
97
|
* @returns {() => void} cleanup
|
|
67
98
|
*/
|
|
68
99
|
export function anchorMarker(reference, markerEl, onPlaced, placement = 'top-end') {
|
|
100
|
+
// Match the floating element's strategy to the reference: a fixed reference needs a fixed marker, or
|
|
101
|
+
// it jitters while scrolling (see isFixedReference). Inline !important beats the stylesheet's
|
|
102
|
+
// `position: absolute !important`.
|
|
103
|
+
const strategy = isFixedReference(reference) ? 'fixed' : 'absolute';
|
|
104
|
+
if (strategy === 'fixed') {
|
|
105
|
+
markerEl.style.setProperty('position', 'fixed', 'important');
|
|
106
|
+
}
|
|
69
107
|
const update = () => {
|
|
70
108
|
computePosition(reference, markerEl, {
|
|
71
109
|
placement,
|
|
110
|
+
strategy,
|
|
72
111
|
middleware: [offset(markerOffset(placement))],
|
|
73
112
|
}).then(({ x, y }) => {
|
|
74
113
|
place(markerEl, x, y);
|
|
@@ -95,9 +134,15 @@ export function anchorMarker(reference, markerEl, onPlaced, placement = 'top-end
|
|
|
95
134
|
* calling update repositions immediately (used for reference-side transform moves that autoUpdate doesn't pick up, etc.).
|
|
96
135
|
*/
|
|
97
136
|
export function anchorPopup(reference, popupEl, placement = 'bottom-start') {
|
|
137
|
+
// The reference is the clicked marker. If it's fixed (anchored to a fixed target), the popup must be
|
|
138
|
+
// fixed too or it jitters on scroll. Set position every open so reopening on a normal marker restores
|
|
139
|
+
// absolute. Inline !important beats the stylesheet's `position: absolute !important`.
|
|
140
|
+
const strategy = isFixedReference(reference) ? 'fixed' : 'absolute';
|
|
141
|
+
popupEl.style.setProperty('position', strategy, 'important');
|
|
98
142
|
const update = () => {
|
|
99
143
|
computePosition(reference, popupEl, {
|
|
100
144
|
placement,
|
|
145
|
+
strategy,
|
|
101
146
|
middleware: [offset(8), flip({ padding: 8 }), shift({ padding: 8 })],
|
|
102
147
|
}).then(({ x, y }) => {
|
|
103
148
|
place(popupEl, x, y);
|
package/src/style.js
CHANGED
|
@@ -48,7 +48,9 @@ const CSS = `
|
|
|
48
48
|
border: none;
|
|
49
49
|
/* Structural properties are !important so a host's broad rules (e.g. button { display:none }) can't
|
|
50
50
|
hide or distort the marker. top/left stay non-important because place() writes them inline per
|
|
51
|
-
frame; !important there would override that and pin the marker to 0,0. Theme stays var()-driven.
|
|
51
|
+
frame; !important there would override that and pin the marker to 0,0. Theme stays var()-driven.
|
|
52
|
+
Note: for targets in a position:fixed subtree, floating.js overrides this with an inline
|
|
53
|
+
position:fixed !important (inline important beats this rule) so the marker doesn't jitter. */
|
|
52
54
|
position: absolute !important;
|
|
53
55
|
display: block !important;
|
|
54
56
|
visibility: visible !important;
|