mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-08-06 06:47:38 +00:00
add oddbird polyfill - not quite working
Not quite working yet. polyfill is loaded, but positioned elements are spanning whole viewport. Parking this for now.
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import Admin from './admin.jsx';
|
import Admin from './admin.jsx';
|
||||||
|
import { bootstrapAnchorPositioningPolyfill } from '../components/anchorPositioningPolyfill.js';
|
||||||
|
|
||||||
const props = window.__INITIAL_PROPS__ || {};
|
const props = window.__INITIAL_PROPS__ || {};
|
||||||
|
|
||||||
createRoot(document.getElementById('reactRoot')).render(<Admin {...props} />);
|
createRoot(document.getElementById('reactRoot')).render(<Admin {...props} />);
|
||||||
|
bootstrapAnchorPositioningPolyfill();
|
||||||
|
|||||||
@@ -71,10 +71,14 @@ const Anchored = ({ children })=>{
|
|||||||
// forward ref for AnchoredTrigger
|
// forward ref for AnchoredTrigger
|
||||||
const AnchoredTrigger = forwardRef(({ toggleVisibility, visible, children, className, ...props }, ref)=>(
|
const AnchoredTrigger = forwardRef(({ toggleVisibility, visible, children, className, ...props }, ref)=>(
|
||||||
<button
|
<button
|
||||||
ref={ref}
|
ref={(el)=>{
|
||||||
|
// setAttribute bypasses React's style sanitization so the anchor polyfill can read it
|
||||||
|
el?.setAttribute('style', `anchor-name: --${props.id}`);
|
||||||
|
if(typeof ref === 'function') ref(el);
|
||||||
|
else if(ref) ref.current = el;
|
||||||
|
}}
|
||||||
className={`anchored-trigger${visible ? ' active' : ''} ${className}`}
|
className={`anchored-trigger${visible ? ' active' : ''} ${className}`}
|
||||||
onClick={toggleVisibility}
|
onClick={toggleVisibility}
|
||||||
style={{ anchorName: `--${props.id}` }} // setting anchor properties here allows greater recyclability.
|
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -84,9 +88,12 @@ const AnchoredTrigger = forwardRef(({ toggleVisibility, visible, children, class
|
|||||||
// forward ref for AnchoredBox
|
// forward ref for AnchoredBox
|
||||||
const AnchoredBox = forwardRef(({ visible, children, className, anchorId, ...props }, ref)=>(
|
const AnchoredBox = forwardRef(({ visible, children, className, anchorId, ...props }, ref)=>(
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={(el)=>{
|
||||||
|
el?.setAttribute('style', `position-anchor: --${anchorId}`);
|
||||||
|
if(typeof ref === 'function') ref(el);
|
||||||
|
else if(ref) ref.current = el;
|
||||||
|
}}
|
||||||
className={`anchored-box${visible ? ' active' : ''} ${className}`}
|
className={`anchored-box${visible ? ' active' : ''} ${className}`}
|
||||||
style={{ positionAnchor: `--${anchorId}` }} // setting anchor properties here allows greater recyclability.
|
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import './anchorPositioningPolyfill.less';
|
||||||
|
|
||||||
|
let polyfillPromise;
|
||||||
|
|
||||||
|
const supportsAnchorPositioning = ()=>'anchorName' in document.documentElement.style;
|
||||||
|
|
||||||
|
const afterInitialRender = ()=>new Promise((resolve)=>{
|
||||||
|
requestAnimationFrame(()=>{
|
||||||
|
requestAnimationFrame(resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export const bootstrapAnchorPositioningPolyfill = ()=>{
|
||||||
|
if(supportsAnchorPositioning()) return Promise.resolve(false);
|
||||||
|
if(polyfillPromise) return polyfillPromise;
|
||||||
|
|
||||||
|
polyfillPromise = afterInitialRender()
|
||||||
|
.then(async ()=>{
|
||||||
|
const { default: polyfill } = await import('@oddbird/css-anchor-positioning/fn');
|
||||||
|
await polyfill();
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch((error)=>{
|
||||||
|
polyfillPromise = undefined;
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
|
||||||
|
return polyfillPromise;
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
.hb-anchor-source {
|
||||||
|
anchor-name: var(--hb-anchor-name);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hb-anchor-target {
|
||||||
|
position-anchor: var(--hb-position-anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hb-position-area {
|
||||||
|
position-area: var(--hb-position-area);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hb-position-try-fallbacks {
|
||||||
|
position-try-fallbacks: var(--hb-position-try-fallbacks);
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import './dropdown.less';
|
import './dropdown.less';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
// use react context to keep track of the menu depth (menus in menus)
|
// use react context to keep track of the menu depth (menus in menus)
|
||||||
@@ -27,6 +27,16 @@ const Dropdown = ({ groupName, className = null, icon, children, color = null, c
|
|||||||
// A menu is a submenu if depth > 0
|
// A menu is a submenu if depth > 0
|
||||||
const isSubMenu = depth > 0;
|
const isSubMenu = depth > 0;
|
||||||
|
|
||||||
|
const wrapperRef = useRef(null);
|
||||||
|
const menuRef = useRef(null);
|
||||||
|
|
||||||
|
// Use setAttribute instead of the React style prop because React silently strips unknown CSS
|
||||||
|
// properties (like anchor-name) from inline styles in browsers that don't support them.
|
||||||
|
// setAttribute writes raw CSS text that the anchor positioning polyfill can read.
|
||||||
|
useEffect(()=>{
|
||||||
|
wrapperRef.current?.setAttribute('style', `anchor-name: ${anchorName}`);
|
||||||
|
menuRef.current?.setAttribute('style', `position-anchor: ${anchorName}`);
|
||||||
|
}, [anchorName]);
|
||||||
|
|
||||||
// hide popover with click inside iframe (not supported by light dismiss)
|
// hide popover with click inside iframe (not supported by light dismiss)
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
@@ -59,7 +69,7 @@ const Dropdown = ({ groupName, className = null, icon, children, color = null, c
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={['menu-wrapper', className].join(' ')} style={{ anchorName }} role='none' >
|
<div ref={wrapperRef} className={['menu-wrapper', className].join(' ')} role='none' >
|
||||||
<button
|
<button
|
||||||
id={groupName.replace(' ', '-')}
|
id={groupName.replace(' ', '-')}
|
||||||
className={['menu-item', color].join(' ')}
|
className={['menu-item', color].join(' ')}
|
||||||
@@ -73,10 +83,10 @@ const Dropdown = ({ groupName, className = null, icon, children, color = null, c
|
|||||||
</button>
|
</button>
|
||||||
<MenuDepthContext.Provider value={depth + 1}>
|
<MenuDepthContext.Provider value={depth + 1}>
|
||||||
<div
|
<div
|
||||||
|
ref={menuRef}
|
||||||
id={menuId}
|
id={menuId}
|
||||||
className='menu-list'
|
className='menu-list'
|
||||||
popover='auto'
|
popover='auto'
|
||||||
style={{ positionAnchor: anchorName }}
|
|
||||||
role='menu'
|
role='menu'
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import Homebrew from './homebrew.jsx';
|
import Homebrew from './homebrew.jsx';
|
||||||
|
import { bootstrapAnchorPositioningPolyfill } from '../components/anchorPositioningPolyfill.js';
|
||||||
|
|
||||||
const props = window.__INITIAL_PROPS__ || {};
|
const props = window.__INITIAL_PROPS__ || {};
|
||||||
|
|
||||||
createRoot(document.getElementById('reactRoot')).render(<Homebrew {...props} />);
|
createRoot(document.getElementById('reactRoot')).render(<Homebrew {...props} />);
|
||||||
|
bootstrapAnchorPositioningPolyfill();
|
||||||
|
|||||||
Generated
+44
-2
@@ -29,6 +29,7 @@
|
|||||||
"@dmsnell/diff-match-patch": "^1.1.0",
|
"@dmsnell/diff-match-patch": "^1.1.0",
|
||||||
"@googleapis/drive": "^20.1.0",
|
"@googleapis/drive": "^20.1.0",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
|
"@oddbird/css-anchor-positioning": "^0.9.0",
|
||||||
"@sanity/diff-match-patch": "^3.2.0",
|
"@sanity/diff-match-patch": "^3.2.0",
|
||||||
"@vitejs/plugin-react": "^5.1.2",
|
"@vitejs/plugin-react": "^5.1.2",
|
||||||
"body-parser": "^2.2.0",
|
"body-parser": "^2.2.0",
|
||||||
@@ -3337,6 +3338,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@floating-ui/core": {
|
||||||
|
"version": "1.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
|
||||||
|
"integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@floating-ui/utils": "^0.2.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@floating-ui/dom": {
|
||||||
|
"version": "1.7.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
|
||||||
|
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@floating-ui/core": "^1.7.5",
|
||||||
|
"@floating-ui/utils": "^0.2.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@floating-ui/utils": {
|
||||||
|
"version": "0.2.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
|
||||||
|
"integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@googleapis/drive": {
|
"node_modules/@googleapis/drive": {
|
||||||
"version": "20.1.0",
|
"version": "20.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-20.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-20.1.0.tgz",
|
||||||
@@ -4122,6 +4148,18 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@oddbird/css-anchor-positioning": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oddbird/css-anchor-positioning/-/css-anchor-positioning-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-G5nfb4sU0auxJH7VHafPwVJjr1GhH5uPSkmytGqhNftCpT3QEh8pFtMd4YHt1dRwb4o9qVZxlGSKUIc4TIrysQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"@floating-ui/dom": "^1.7.5",
|
||||||
|
"@types/css-tree": "^2.3.11",
|
||||||
|
"css-tree": "^3.1.0",
|
||||||
|
"nanoid": "^5.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@paralleldrive/cuid2": {
|
"node_modules/@paralleldrive/cuid2": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz",
|
||||||
@@ -4609,6 +4647,12 @@
|
|||||||
"@babel/types": "^7.28.2"
|
"@babel/types": "^7.28.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/css-tree": {
|
||||||
|
"version": "2.3.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/css-tree/-/css-tree-2.3.11.tgz",
|
||||||
|
"integrity": "sha512-aEokibJOI77uIlqoBOkVbaQGC9zII0A+JH1kcTNKW2CwyYWD8KM6qdo+4c77wD3wZOQfJuNWAr9M4hdk+YhDIg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||||
@@ -6344,7 +6388,6 @@
|
|||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
|
||||||
"integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
|
"integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mdn-data": "2.27.1",
|
"mdn-data": "2.27.1",
|
||||||
@@ -10366,7 +10409,6 @@
|
|||||||
"version": "2.27.1",
|
"version": "2.27.1",
|
||||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
|
||||||
"integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
|
"integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "CC0-1.0"
|
"license": "CC0-1.0"
|
||||||
},
|
},
|
||||||
"node_modules/media-typer": {
|
"node_modules/media-typer": {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@
|
|||||||
"@dmsnell/diff-match-patch": "^1.1.0",
|
"@dmsnell/diff-match-patch": "^1.1.0",
|
||||||
"@googleapis/drive": "^20.1.0",
|
"@googleapis/drive": "^20.1.0",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
|
"@oddbird/css-anchor-positioning": "^0.9.0",
|
||||||
"@sanity/diff-match-patch": "^3.2.0",
|
"@sanity/diff-match-patch": "^3.2.0",
|
||||||
"@vitejs/plugin-react": "^5.1.2",
|
"@vitejs/plugin-react": "^5.1.2",
|
||||||
"body-parser": "^2.2.0",
|
"body-parser": "^2.2.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user