mirror of
https://github.com/anyproto/anytype-ts.git
synced 2025-06-08 05:57:02 +09:00
Fix a lot
This commit is contained in:
parent
cf542cd1ac
commit
c877d9c68f
16 changed files with 93 additions and 77 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -25,3 +25,5 @@ licenses.json
|
|||
/darwin-amd*/
|
||||
/darwin-arm*/
|
||||
/windows/
|
||||
.aider*
|
||||
.env
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
$easeInQuint: cubic-bezier(0.22, 1, 0.36, 1);
|
||||
$transitionCommon: 0.1s $easeInQuint;
|
||||
$transitionSmoothCommon: 0.35s $easeInQuint;
|
||||
$transitionAllCommon: all $transitionCommon;
|
||||
$transitionSidebarTime: 0.18s;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
@import "./editor";
|
||||
@import "./emptySearch";
|
||||
@import "./error";
|
||||
@import "./floater";
|
||||
@import "./footer";
|
||||
@import "./frame";
|
||||
@import "./header";
|
||||
|
|
1
src/scss/component/floater.scss
Normal file
1
src/scss/component/floater.scss
Normal file
|
@ -0,0 +1 @@
|
|||
.floater { position: absolute; pointer-events: none; z-index: 200; }
|
|
@ -52,5 +52,5 @@
|
|||
}
|
||||
}
|
||||
|
||||
.volume.input-drag-vertical { opacity: 0; transition: opacity $transitionSmoothCommon; pointer-events: none; }
|
||||
.volume.input-drag-vertical { opacity: 0; transition: opacity 0.35s ease-in-out; pointer-events: none; }
|
||||
.volume.input-drag-vertical.visible { opacity: 1; pointer-events: auto; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@import "./button";
|
||||
@import "./dragHorizontal";
|
||||
@import "./dragVertical";
|
||||
@import "./drag/horizontal";
|
||||
@import "./drag/vertical";
|
||||
@import "./filter";
|
||||
@import "./input";
|
||||
@import "./inputWithFile";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from 'react';
|
||||
import { useEffect, useImperativeHandle, useRef } from 'react';
|
||||
import Input from './input';
|
||||
import { Input } from 'Component';
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
|
@ -51,8 +51,8 @@ import Checkbox from './form/checkbox';
|
|||
import Textarea from './form/textarea';
|
||||
import Button from './form/button';
|
||||
import Select from './form/select';
|
||||
import DragHorizontal from './form/dragHorizontal';
|
||||
import DragVertical from './form/dragVertical';
|
||||
import DragHorizontal from './form/drag/horizontal';
|
||||
import DragVertical from './form/drag/vertical';
|
||||
import Pin from './form/pin';
|
||||
import Filter from './form/filter';
|
||||
import Phrase from './form/phrase';
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
import { H } from 'Lib';
|
||||
import React, { useState, useEffect, ReactNode, useRef } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { useElementMovement } from './useMovementObserver';
|
||||
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
anchorEl: HTMLElement | null;
|
||||
anchorTo?: 'top' | 'bottom';
|
||||
anchorTo?: AnchorTo;
|
||||
offset?: {
|
||||
x?: number;
|
||||
y?: number;
|
||||
left?: number;
|
||||
top?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export enum AnchorTo {
|
||||
Top = 'top',
|
||||
Bottom = 'bottom',
|
||||
}
|
||||
|
||||
export const Floater: React.FC<Props> = ({
|
||||
children,
|
||||
anchorEl,
|
||||
anchorTo = 'bottom',
|
||||
offset = { x: 0, y: 0 },
|
||||
anchorTo = AnchorTo.Bottom,
|
||||
offset = { top: 0, left: 0 },
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [ position, setPosition ] = useState({ top: 0, left: 0 });
|
||||
|
@ -24,44 +30,41 @@ export const Floater: React.FC<Props> = ({
|
|||
const onMove = () => {
|
||||
if (anchorEl && ref.current) {
|
||||
const anchorElRect = anchorEl.getBoundingClientRect();
|
||||
const floaterElRect = ref.current.getBoundingClientRect();
|
||||
const elRect = ref.current.getBoundingClientRect();
|
||||
|
||||
const { top, left, bottom, width } = anchorElRect;
|
||||
const fh = floaterElRect.height;
|
||||
const fw = floaterElRect.width;
|
||||
const { top: at, left: al, bottom: ab, width: aw } = anchorElRect;
|
||||
const eh = elRect.height;
|
||||
const ew = elRect.width;
|
||||
|
||||
const x = Number(offset.x) || 0;
|
||||
const y = Number(offset.y) || 0;
|
||||
const ot = Number(offset.top) || 0;
|
||||
const ol = Number(offset.left) || 0;
|
||||
|
||||
let pt = 0;
|
||||
let pl = 0;
|
||||
let nt = 0;
|
||||
let nl = 0;
|
||||
|
||||
if (anchorTo == 'top') {
|
||||
pt = top - fh + y;
|
||||
pl = left + width / 2 - fw / 2 + x;
|
||||
} else {
|
||||
pt = bottom + y;
|
||||
pl = left + width / 2 - fw / 2 + x;
|
||||
switch (anchorTo) {
|
||||
case AnchorTo.Top:
|
||||
nt = at - eh + ot;
|
||||
nl = al + aw / 2 - ew / 2 + ol;
|
||||
break;
|
||||
case AnchorTo.Bottom:
|
||||
nt = ab + ot;
|
||||
nl = al + aw / 2 - ew / 2 + ol;
|
||||
break;
|
||||
};
|
||||
|
||||
setPosition({ top: pt, left: pl });
|
||||
setPosition({ top: nt, left: nl });
|
||||
};
|
||||
};
|
||||
|
||||
useElementMovement(anchorEl, onMove);
|
||||
H.useElementMovement(anchorEl, onMove);
|
||||
useEffect(() => onMove(), [ anchorEl, ref.current ]);
|
||||
|
||||
return ReactDOM.createPortal(
|
||||
<div
|
||||
<div className="floater"
|
||||
ref={ref}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
// This is hopefully the highest z-index in the app
|
||||
zIndex: 200,
|
||||
top: `${position.top}px`,
|
||||
left: `${position.left}px`,
|
||||
}}>
|
||||
style={{ transform: `translate3d(${position.top}px, ${-position.left}px, 0px)`}}
|
||||
>
|
||||
{children}
|
||||
</div>,
|
||||
document.body
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import * as React from 'react';
|
||||
import $ from 'jquery';
|
||||
import { Icon, DragHorizontal } from 'Component';
|
||||
import { Icon, DragHorizontal, DragVertical } from 'Component';
|
||||
import { U } from 'Lib';
|
||||
import DragVertical from 'Component/form/dragVertical';
|
||||
import { Floater } from '../floater';
|
||||
import { AnchorTo, Floater } from '../floater';
|
||||
import _ from 'lodash';
|
||||
|
||||
interface PlaylistItem {
|
||||
|
@ -108,8 +107,8 @@ class MediaAudio extends React.Component<Props, State> {
|
|||
|
||||
<Floater
|
||||
anchorEl={this.volumeIcon?.node}
|
||||
anchorTo={'top'}
|
||||
offset={{ y: -2 }}
|
||||
anchorTo={AnchorTo.Top}
|
||||
offset={{ top: -2 }}
|
||||
>
|
||||
<DragVertical
|
||||
id="volume"
|
||||
|
|
5
src/ts/lib/hook/index.ts
Normal file
5
src/ts/lib/hook/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import useElementMovement from './useElementMovement';
|
||||
|
||||
export {
|
||||
useElementMovement,
|
||||
};
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useState, useEffect, ReactNode, useRef } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface Position {
|
||||
x: number;
|
||||
|
@ -9,9 +8,13 @@ interface Position {
|
|||
}
|
||||
|
||||
class ElementMovementObserver {
|
||||
private observer: MutationObserver;
|
||||
|
||||
private movementObserver: MutationObserver;
|
||||
private resizeObserver: ResizeObserver;
|
||||
|
||||
private element: HTMLElement;
|
||||
private lastPosition: Position;
|
||||
|
||||
private onMove: (position: Position) => void;
|
||||
|
||||
constructor(element: HTMLElement, callback: (position: Position) => void) {
|
||||
|
@ -19,17 +22,31 @@ class ElementMovementObserver {
|
|||
this.onMove = callback;
|
||||
this.lastPosition = this.getPosition();
|
||||
|
||||
// Create observer instance
|
||||
this.observer = new MutationObserver(() => {
|
||||
this.movementObserver = new MutationObserver(() => {
|
||||
this.checkForMovement();
|
||||
});
|
||||
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
this.checkForMovement();
|
||||
});
|
||||
|
||||
// Start observing
|
||||
this.startObserving();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private getPosition(): Position {
|
||||
private checkForMovement = () => {
|
||||
const currentPosition = this.getPosition();
|
||||
|
||||
if (this.hasPositionChanged(currentPosition)) {
|
||||
this.lastPosition = currentPosition;
|
||||
this.onMove(currentPosition);
|
||||
}
|
||||
};
|
||||
|
||||
private getPosition (): Position {
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
x: rect.left + window.scrollX,
|
||||
y: rect.top + window.scrollY,
|
||||
|
@ -38,16 +55,8 @@ class ElementMovementObserver {
|
|||
};
|
||||
}
|
||||
|
||||
private checkForMovement(): void {
|
||||
const currentPosition = this.getPosition();
|
||||
|
||||
if (this.hasPositionChanged(currentPosition)) {
|
||||
this.lastPosition = currentPosition;
|
||||
this.onMove(currentPosition);
|
||||
}
|
||||
}
|
||||
|
||||
private hasPositionChanged(currentPosition: Position): boolean {
|
||||
private hasPositionChanged (currentPosition: Position): boolean {
|
||||
return (
|
||||
currentPosition.x !== this.lastPosition.x ||
|
||||
currentPosition.y !== this.lastPosition.y ||
|
||||
|
@ -56,8 +65,7 @@ class ElementMovementObserver {
|
|||
);
|
||||
}
|
||||
|
||||
private startObserving(): void {
|
||||
// Configure observer options
|
||||
private startObserving (): void {
|
||||
const config: MutationObserverInit = {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
|
@ -65,31 +73,27 @@ class ElementMovementObserver {
|
|||
characterData: true
|
||||
};
|
||||
|
||||
// Start observing the element and its descendants
|
||||
this.observer.observe(this.element, config);
|
||||
// Observe the element and its descendants for movement
|
||||
this.movementObserver.observe(this.element, config);
|
||||
|
||||
// Observe the document body for layout changes
|
||||
this.observer.observe(document.body, config);
|
||||
this.movementObserver.observe(document.body, config);
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
this.checkForMovement();
|
||||
});
|
||||
resizeObserver.observe(this.element);
|
||||
// Observe the element for size changes
|
||||
this.resizeObserver.observe(this.element);
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
this.checkForMovement();
|
||||
});
|
||||
// And handle scroll
|
||||
window.addEventListener('scroll', this.checkForMovement);
|
||||
}
|
||||
|
||||
public disconnect(): void {
|
||||
this.observer.disconnect();
|
||||
public disconnect (): void {
|
||||
this.movementObserver.disconnect();
|
||||
this.resizeObserver.disconnect();
|
||||
window.removeEventListener('scroll', this.checkForMovement);
|
||||
}
|
||||
}
|
||||
|
||||
export function useElementMovement(
|
||||
element: HTMLElement | null,
|
||||
callback: (position: Position) => void
|
||||
) {
|
||||
export default function useElementMovement ( element: HTMLElement | null, callback: (position: Position) => void ) {
|
||||
useEffect(() => {
|
||||
if (!element) return;
|
||||
|
|
@ -4,6 +4,7 @@ import * as M from 'Model'; // Models
|
|||
import * as S from 'Store'; // Stores
|
||||
import * as U from './util'; // Utils
|
||||
import * as C from './api/command'; // Commands
|
||||
import * as H from './hook'; // React Hooks
|
||||
|
||||
import Renderer from './renderer';
|
||||
import { dispatcher } from './api/dispatcher';
|
||||
|
@ -34,6 +35,7 @@ export {
|
|||
S,
|
||||
U,
|
||||
J,
|
||||
H,
|
||||
keyboard,
|
||||
sidebar,
|
||||
focus,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue