Upgrade react-menu and bug fixes

This commit is contained in:
Lim Chee Aun 2023-06-13 17:46:37 +08:00
parent f6ef727cae
commit a1ee5be54b
13 changed files with 120 additions and 75 deletions

49
package-lock.json generated
View file

@ -12,7 +12,8 @@
"@github/text-expander-element": "~2.3.0",
"@iconify-icons/mingcute": "~1.2.5",
"@justinribeiro/lite-youtube": "~1.5.0",
"@szhsin/react-menu": "~3.5.3",
"@szhsin/react-menu": "~4.0.0",
"@uidotdev/usehooks": "~2.0.1",
"dayjs": "~1.11.8",
"dayjs-twitter": "~0.5.0",
"fast-blurhash": "~1.1.2",
@ -3126,12 +3127,12 @@
}
},
"node_modules/@szhsin/react-menu": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.5.3.tgz",
"integrity": "sha512-jxo8oaRwxmVjUzkyOi/ZJiXaZiuFPMIxFzyJdUKfnhBLYiEOVTU9M2CiPuEkirILoareR2GJj2K3y8a81CBPlw==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.0.tgz",
"integrity": "sha512-DOl+IWddgHofcEzSTJfILGvpU67O/y8r07LOVUhfThke9VEZ5LAZNkp2Q3mEFaN7PkmnmJtjPBEdIK3oN1/ZfQ==",
"dependencies": {
"prop-types": "^15.7.2",
"react-transition-state": "^1.1.5"
"react-transition-state": "^2.1.0"
},
"peerDependencies": {
"react": ">=16.14.0",
@ -3271,6 +3272,18 @@
"integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==",
"dev": true
},
"node_modules/@uidotdev/usehooks": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.0.1.tgz",
"integrity": "sha512-rJXxE3Y8g9utRbOS9Pj9tIvrnOdaakHIhLbMxBlErV8HydnGD0DveD82aLBfVTh1hBp5IXqpeHpMrPE9WIT7vQ==",
"engines": {
"node": ">=16"
},
"peerDependencies": {
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
}
},
"node_modules/@vue/compiler-core": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
@ -6334,9 +6347,9 @@
}
},
"node_modules/react-transition-state": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/react-transition-state/-/react-transition-state-1.1.5.tgz",
"integrity": "sha512-ITY2mZqc2dWG2eitJkYNdcSFW8aKeOlkL2A/vowRrLL8GH3J6Re/SpD/BLvQzrVOTqjsP0b5S9N10vgNNzwMUQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-transition-state/-/react-transition-state-2.1.0.tgz",
"integrity": "sha512-b8ldw2pbZk++XM43vcD4ETaFWlzTsjpUX33CmT8BBPPFYlQ2R50wxcY4ZeJ1TesJYziYZ9/rNPFnyA9tR0iKDw==",
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
@ -9619,12 +9632,12 @@
}
},
"@szhsin/react-menu": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.5.3.tgz",
"integrity": "sha512-jxo8oaRwxmVjUzkyOi/ZJiXaZiuFPMIxFzyJdUKfnhBLYiEOVTU9M2CiPuEkirILoareR2GJj2K3y8a81CBPlw==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.0.tgz",
"integrity": "sha512-DOl+IWddgHofcEzSTJfILGvpU67O/y8r07LOVUhfThke9VEZ5LAZNkp2Q3mEFaN7PkmnmJtjPBEdIK3oN1/ZfQ==",
"requires": {
"prop-types": "^15.7.2",
"react-transition-state": "^1.1.5"
"react-transition-state": "^2.1.0"
}
},
"@trivago/prettier-plugin-sort-imports": {
@ -9740,6 +9753,12 @@
"integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==",
"dev": true
},
"@uidotdev/usehooks": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.0.1.tgz",
"integrity": "sha512-rJXxE3Y8g9utRbOS9Pj9tIvrnOdaakHIhLbMxBlErV8HydnGD0DveD82aLBfVTh1hBp5IXqpeHpMrPE9WIT7vQ==",
"requires": {}
},
"@vue/compiler-core": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
@ -11832,9 +11851,9 @@
}
},
"react-transition-state": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/react-transition-state/-/react-transition-state-1.1.5.tgz",
"integrity": "sha512-ITY2mZqc2dWG2eitJkYNdcSFW8aKeOlkL2A/vowRrLL8GH3J6Re/SpD/BLvQzrVOTqjsP0b5S9N10vgNNzwMUQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-transition-state/-/react-transition-state-2.1.0.tgz",
"integrity": "sha512-b8ldw2pbZk++XM43vcD4ETaFWlzTsjpUX33CmT8BBPPFYlQ2R50wxcY4ZeJ1TesJYziYZ9/rNPFnyA9tR0iKDw==",
"requires": {}
},
"regenerate": {

View file

@ -14,7 +14,8 @@
"@github/text-expander-element": "~2.3.0",
"@iconify-icons/mingcute": "~1.2.5",
"@justinribeiro/lite-youtube": "~1.5.0",
"@szhsin/react-menu": "~3.5.3",
"@szhsin/react-menu": "~4.0.0",
"@uidotdev/usehooks": "~2.0.1",
"dayjs": "~1.11.8",
"dayjs-twitter": "~0.5.0",
"fast-blurhash": "~1.1.2",

View file

@ -673,7 +673,7 @@ function RelatedActions({ info, instance, authenticated }) {
openTrigger="clickOnly"
direction="bottom"
overflow="auto"
offsetX={-16}
shift={-16}
label={
<>
<Icon icon="mute" />

View file

@ -191,7 +191,7 @@ function MediaModal({
align="end"
position="anchor"
boundingBoxPadding="8 8 8 8"
offsetY={4}
gap={4}
menuClassName="glass-menu"
menuButton={
<button type="button" class="carousel-button plain3">

31
src/components/menu2.jsx Normal file
View file

@ -0,0 +1,31 @@
import { Menu } from '@szhsin/react-menu';
import { useWindowSize } from '@uidotdev/usehooks';
import { useRef } from 'preact/hooks';
import safeBoundingBoxPadding from '../utils/safe-bounding-box-padding';
// It's like Menu but with sensible defaults, bug fixes and improvements.
function Menu2(props) {
const { containerProps } = props;
const size = useWindowSize();
const instanceRef = useRef();
return (
<Menu
boundingBoxPadding={safeBoundingBoxPadding()}
repositionFlag={`${size.width}x${size.height}`}
{...props}
instanceRef={instanceRef}
containerProps={{
onClick: (e) => {
if (e.target === e.currentTarget) {
instanceRef.current?.closeMenu?.();
}
containerProps?.onClick?.(e);
},
...containerProps,
}}
/>
);
}
export default Menu2;

View file

@ -132,7 +132,7 @@ function Shortcuts() {
viewScroll="close"
boundingBoxPadding="8 8 8 8"
menuClassName="glass-menu shortcuts-menu"
offsetY={8}
gap={8}
position="anchor"
menuButton={
<button

View file

@ -34,6 +34,7 @@ import htmlContentLength from '../utils/html-content-length';
import isMastodonLinkMaybe from '../utils/isMastodonLinkMaybe';
import localeMatch from '../utils/locale-match';
import niceDateTime from '../utils/nice-date-time';
import safeBoundingBoxPadding from '../utils/safe-bounding-box-padding';
import shortenNumber from '../utils/shorten-number';
import showToast from '../utils/show-toast';
import states, { getStatus, saveStatus, statusKey } from '../utils/states';
@ -824,7 +825,7 @@ function Status({
},
}}
align="end"
offsetY={4}
gap={4}
overflow="auto"
viewScroll="close"
boundingBoxPadding="8 8 8 8"
@ -1182,7 +1183,7 @@ function Status({
document.querySelector('.status-deck') || document.body,
}}
align="end"
offsetY={4}
gap={4}
overflow="auto"
viewScroll="close"
boundingBoxPadding="8 8 8 8"
@ -1817,30 +1818,6 @@ const unfurlMastodonLink = throttle(
}),
);
const root = document.documentElement;
const defaultBoundingBoxPadding = 8;
function _safeBoundingBoxPadding() {
// Get safe area inset variables from root
const style = getComputedStyle(root);
const safeAreaInsetTop = style.getPropertyValue('--sai-top');
const safeAreaInsetRight = style.getPropertyValue('--sai-right');
const safeAreaInsetBottom = style.getPropertyValue('--sai-bottom');
const safeAreaInsetLeft = style.getPropertyValue('--sai-left');
const str = [
safeAreaInsetTop,
safeAreaInsetRight,
safeAreaInsetBottom,
safeAreaInsetLeft,
]
.map((v) => parseInt(v, 10) || defaultBoundingBoxPadding)
.join(' ');
// console.log(str);
return str;
}
const safeBoundingBoxPadding = mem(_safeBoundingBoxPadding, {
maxAge: 10_000, // 10 seconds
});
function FilteredStatus({ status, filterInfo, instance, containerProps = {} }) {
const {
account: { avatar, avatarStatic, bot },

View file

@ -6,6 +6,7 @@ import { useSnapshot } from 'valtio';
import AccountInfo from '../components/account-info';
import Icon from '../components/icon';
import Link from '../components/link';
import Menu2 from '../components/menu2';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
import emojifyText from '../utils/emojify-text';
@ -255,15 +256,12 @@ function AccountStatuses() {
timelineStart={TimelineStart}
refresh={excludeReplies + excludeBoosts + tagged + media}
headerEnd={
<Menu
portal={{
target: document.body,
}}
<Menu2
portal
// setDownOverflow
overflow="auto"
viewScroll="close"
position="anchor"
boundingBoxPadding="8 8 8 8"
menuButton={
<button type="button" class="plain">
<Icon icon="more" size="l" />
@ -295,7 +293,7 @@ function AccountStatuses() {
Switch to account's instance (<b>{accountInstance}</b>)
</small>
</MenuItem>
</Menu>
</Menu2>
}
/>
);

View file

@ -9,6 +9,7 @@ import { useEffect, useRef, useState } from 'preact/hooks';
import { useNavigate, useParams } from 'react-router-dom';
import Icon from '../components/icon';
import Menu2 from '../components/menu2';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
import showToast from '../utils/show-toast';
@ -122,15 +123,12 @@ function Hashtags(props) {
checkForUpdates={checkForUpdates}
useItemID
headerEnd={
<Menu
portal={{
target: document.body,
}}
<Menu2
portal
setDownOverflow
overflow="auto"
viewScroll="close"
position="anchor"
boundingBoxPadding="8 8 8 8"
menuButton={
<button type="button" class="plain">
<Icon icon="more" size="l" />
@ -306,7 +304,7 @@ function Hashtags(props) {
>
<Icon icon="bus" /> <span>Go to another instance</span>
</MenuItem>
</Menu>
</Menu2>
}
/>
);

View file

@ -10,6 +10,7 @@ import AccountBlock from '../components/account-block';
import Icon from '../components/icon';
import Link from '../components/link';
import ListAddEdit from '../components/list-add-edit';
import Menu2 from '../components/menu2';
import Modal from '../components/modal';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
@ -108,15 +109,12 @@ function List(props) {
</Link>
}
headerEnd={
<Menu
portal={{
target: document.body,
}}
<Menu2
portal
setDownOverflow
overflow="auto"
viewScroll="close"
position="anchor"
boundingBoxPadding="8 8 8 8"
menuButton={
<button type="button" class="plain">
<Icon icon="more" size="l" />
@ -137,7 +135,7 @@ function List(props) {
<Icon icon="group" size="l" />
<span>Manage members</span>
</MenuItem>
</Menu>
</Menu2>
}
/>
{showListAddEditModal && (

View file

@ -4,6 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import { useSnapshot } from 'valtio';
import Icon from '../components/icon';
import Menu2 from '../components/menu2';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
import { filteredItems } from '../utils/filters';
@ -92,15 +93,12 @@ function Public({ local, ...props }) {
boostsCarousel={snapStates.settings.boostsCarousel}
allowFilters
headerEnd={
<Menu
portal={{
target: document.body,
}}
<Menu2
portal
// setDownOverflow
overflow="auto"
viewScroll="close"
position="anchor"
boundingBoxPadding="8 8 8 8"
menuButton={
<button type="button" class="plain">
<Icon icon="more" size="l" />
@ -136,7 +134,7 @@ function Public({ local, ...props }) {
>
<Icon icon="bus" /> <span>Go to another instance</span>
</MenuItem>
</Menu>
</Menu2>
}
/>
);

View file

@ -4,6 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import { useSnapshot } from 'valtio';
import Icon from '../components/icon';
import Menu2 from '../components/menu2';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
import { filteredItems } from '../utils/filters';
@ -92,15 +93,12 @@ function Trending(props) {
boostsCarousel={snapStates.settings.boostsCarousel}
allowFilters
headerEnd={
<Menu
portal={{
target: document.body,
}}
<Menu2
portal
// setDownOverflow
overflow="auto"
viewScroll="close"
position="anchor"
boundingBoxPadding="8 8 8 8"
menuButton={
<button type="button" class="plain">
<Icon icon="more" size="l" />
@ -124,7 +122,7 @@ function Trending(props) {
>
<Icon icon="bus" /> <span>Go to another instance</span>
</MenuItem>
</Menu>
</Menu2>
}
/>
);

View file

@ -0,0 +1,27 @@
import mem from 'mem';
const root = document.documentElement;
const defaultBoundingBoxPadding = 8;
function _safeBoundingBoxPadding() {
// Get safe area inset variables from root
const style = getComputedStyle(root);
const safeAreaInsetTop = style.getPropertyValue('--sai-top');
const safeAreaInsetRight = style.getPropertyValue('--sai-right');
const safeAreaInsetBottom = style.getPropertyValue('--sai-bottom');
const safeAreaInsetLeft = style.getPropertyValue('--sai-left');
const str = [
safeAreaInsetTop,
safeAreaInsetRight,
safeAreaInsetBottom,
safeAreaInsetLeft,
]
.map((v) => parseInt(v, 10) || defaultBoundingBoxPadding)
.join(' ');
// console.log(str);
return str;
}
const safeBoundingBoxPadding = mem(_safeBoundingBoxPadding, {
maxAge: 10000, // 10 seconds
});
export default safeBoundingBoxPadding;