New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@udecode/plate-toolbar

Package Overview
Dependencies
Maintainers
2
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@udecode/plate-toolbar - npm Package Compare versions

Comparing version 3.5.1 to 4.0.0

dist/BalloonToolbar/useBalloonPosition.d.ts

13

CHANGELOG.md
# @udecode/plate-toolbar
## 4.0.0
### Major Changes
- [#1048](https://github.com/udecode/plate/pull/1048) [`d5667409`](https://github.com/udecode/plate/commit/d5667409e4e53b4b41a14335a7298c260c52019e) Thanks [@karthikcodes6](https://github.com/karthikcodes6)! - Removed `hiddenDelay` prop from `BalloonToolbar` component.
### Minor Changes
- [#1048](https://github.com/udecode/plate/pull/1048) [`a899c585`](https://github.com/udecode/plate/commit/a899c5850fbe09792113b2b3f4787d869568427d) Thanks [@karthikcodes6](https://github.com/karthikcodes6)! - added:
- `usePopupPosition` hook to position the hovering popup correctly even in the nested scroll, this hook using `react-popper` internally and user can pass modifiers, placements to customise the behaviour
- transition for showing the balloon toolbar smoothly.
- `scrollContainer` prop to the BalloonToolbar as well.
## 3.5.1

@@ -4,0 +17,0 @@

36

dist/BalloonToolbar/BalloonToolbar.types.d.ts
import { ReactNode } from 'react';
import { Modifier } from '@popperjs/core';
import * as PopperJS from '@popperjs/core';
import { TEditor } from '@udecode/plate-core';
import { StyledProps } from '@udecode/plate-styled-components';

@@ -10,10 +13,5 @@ import { ToolbarProps } from '../Toolbar/Toolbar.types';

/**
* When selecting characters, the balloon is hidden for a delay.
* If 0, the balloon is never hidden.
*/
hiddenDelay?: number;
/**
* Below of above the selection.
*/
direction?: 'top' | 'bottom';
direction?: UsePopupPositionProps['placement'];
/**

@@ -28,3 +26,29 @@ * Color theme for the background/foreground.

portalElement?: Element;
/**
* Parent scroll container element of the editor,
* if no scroll container provided, it will take document.documentElement as scrolling container
*/
scrollContainer?: HTMLElement;
}
export interface UsePopupPositionProps {
editor: TEditor;
popupElem: HTMLElement | null;
scrollContainer?: HTMLElement | null;
modifiers?: Array<Partial<Modifier<string, any>>>;
placement?: PopperJS.Placement;
}
export declare type UsePopupPositionReturnType = [
{
[key: string]: React.CSSProperties;
},
{
[key: string]: {
[key: string]: string;
} | undefined;
},
boolean
];
export interface UsePopupPosition {
({ editor, popupElem, scrollContainer, }: UsePopupPositionProps): UsePopupPositionReturnType;
}
//# sourceMappingURL=BalloonToolbar.types.d.ts.map

@@ -9,3 +9,4 @@ /**

export * from './useBalloonMove';
export * from './useBalloonPosition';
export * from './useBalloonShow';
//# sourceMappingURL=index.d.ts.map

232

dist/index.es.js
import { createStyles, PortalBody } from '@udecode/plate-styled-components';
import _styled, { css } from 'styled-components';
import * as React from 'react';
import React__default, { useEffect, useState, useCallback } from 'react';
import React__default, { useEffect as useEffect$1, useState as useState$1, useCallback as useCallback$1 } from 'react';
import { useStoreEditorState, useEventEditorId } from '@udecode/plate-core';
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { usePopper } from 'react-popper';
import { isSelectionExpanded, getSelectionText, someNode, getPreventDefaultHandler, toggleNodeType, isMarkActive, toggleMark } from '@udecode/plate-common';

@@ -37,13 +38,4 @@ import Tippy from '@tippyjs/react';

}
let marginTop;
const arrowStyle = [props.arrow && css(["::after{left:50%;content:' ';position:absolute;margin-top:-1px;transform:translateX(-50%);border-color:", " transparent;border-style:solid;}"], background), props.arrow && props.direction === 'top' && css(["::after{top:100%;bottom:auto;border-width:8px 8px 0;}"]), props.arrow && props.direction !== 'top' && css(["::after{top:auto;bottom:100%;border-width:0 8px 8px;}"])];
const arrowBorderStyle = [props.arrow && props.direction === 'top' && props.theme === 'light' && css(["::before{margin-top:0;border-width:9px 9px 0;border-color:", " transparent;}"], borderColor), props.arrow && props.direction !== 'top' && props.theme === 'light' && css(["::before{margin-top:0;border-width:0 9px 9px;border-color:", " transparent;}"], borderColor)];
if (props.direction === 'top') {
marginTop = -9;
} else {
marginTop = 9;
}
return createStyles({

@@ -56,11 +48,8 @@ prefixClassNames: 'BalloonToolbar',

"whiteSpace": "nowrap",
"paddingTop": "0px",
"paddingBottom": "0px",
"paddingLeft": "0.25rem",
"paddingRight": "0.25rem"
"opacity": "1",
"transition": "opacity .2s ease-in-out"
}, props.hidden && {
"visibility": "hidden"
}, !props.hiddenDelay && {
"transition": "top 75ms ease-out,left 75ms ease-out"
}, css(["color:", ";background:", ";z-index:500;border:1px solid ", ";border-radius:4px;margin-top:", "px;.slate-ToolbarButton-active,.slate-ToolbarButton:hover{color:", ";}::before{", "}"], color, background, borderColor, marginTop, colorActive, arrowBorderStyle), ...arrowStyle, ...arrowBorderStyle]
"visibility": "hidden",
"opacity": "0"
}, css(["color:", ";background:", ";z-index:500;border:1px solid ", ";border-radius:4px;.slate-ToolbarButton-active,.slate-ToolbarButton:hover{color:", ";}::before{", "}"], color, background, borderColor, colorActive, arrowBorderStyle), ...arrowStyle, ...arrowBorderStyle]
});

@@ -99,2 +88,142 @@ };

const {
useEffect,
useState,
useCallback
} = React;
const virtualReference = {
getBoundingClientRect() {
return {
top: 10,
left: 10,
bottom: 20,
right: 100,
width: 90,
height: 10,
x: 0,
y: 0,
toJSON: () => null
};
}
};
const usePopupPosition = ({
editor,
popupElem,
scrollContainer = document.documentElement,
modifiers = [],
placement = 'top'
}) => {
const [isHide, setIsHide] = useState(true);
const selectionExpanded = editor && isSelectionExpanded(editor);
const selectionText = editor && getSelectionText(editor);
const {
styles,
attributes,
update
} = usePopper(virtualReference, popupElem, {
placement,
modifiers: [// default modifiers to position the popup correctly
{
name: 'preventOverflow',
enabled: true,
options: {
boundary: scrollContainer !== null && scrollContainer !== void 0 ? scrollContainer : undefined
}
}, {
name: 'flip',
enabled: true,
options: {
padding: 8
}
}, {
name: 'eventListeners',
enabled: true,
options: {
scroll: !isHide,
resize: true
}
}, {
name: 'offset',
options: {
offset: [0, 8]
}
}, // user modifiers to override the default
...modifiers],
strategy: 'absolute'
});
const show = useCallback(() => {
if (isHide && selectionExpanded) {
setIsHide(false);
}
}, [isHide, selectionExpanded, setIsHide]);
useEffect(() => {
if (!selectionText) {
setIsHide(true);
} else if (selectionText && selectionExpanded) {
setIsHide(false);
}
}, [selectionText, show, selectionExpanded, setIsHide]);
const setPosition = useCallback(() => {
const domSelection = window.getSelection();
if (!domSelection || domSelection.rangeCount < 1) return;
const domRange = domSelection.getRangeAt(0);
const rect = domRange.getBoundingClientRect();
virtualReference.getBoundingClientRect = () => rect;
update === null || update === void 0 ? void 0 : update();
}, [update]);
useEffect(() => {
scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.addEventListener('scroll', setPosition);
return () => scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.removeEventListener('scroll', setPosition);
}, [setPosition, scrollContainer]);
useEffect(() => {
popupElem && selectionExpanded && setPosition();
}, [selectionText === null || selectionText === void 0 ? void 0 : selectionText.length, selectionExpanded, popupElem, setPosition]);
return [styles, attributes, isHide];
};
const BalloonToolbar = props => {
const {
children,
direction = 'top',
theme = 'dark',
arrow = false,
portalElement,
scrollContainer
} = props;
const popupRef = React.useRef(null);
const editor = useStoreEditorState(useEventEditorId('focus'));
const [popperStyles, attributes, hidden] = usePopupPosition({
editor,
popupElem: popupRef.current,
scrollContainer,
placement: direction
});
const styles = getBalloonToolbarStyles({
direction,
theme,
arrow,
hidden,
...props
});
return /*#__PURE__*/jsx(PortalBody, {
element: portalElement,
children: /*#__PURE__*/jsx(_StyledToolbarBase$1, {
ref: popupRef,
className: styles.root.className,
style: popperStyles.popper,
...attributes.popper,
$_css: styles.root.css,
children: children
})
});
};
var _StyledToolbarBase$1 = _styled(ToolbarBase).withConfig({
displayName: "BalloonToolbar___StyledToolbarBase",
componentId: "sc-8umnsm-0"
})(["", ""], p => p.$_css);
const setPositionAtSelection = (el, direction = 'top') => {

@@ -126,3 +255,3 @@ const domSelection = window.getSelection();

const selectionText = editor && getSelectionText(editor);
useEffect(() => {
useEffect$1(() => {
ref.current && selectionExpanded && setPositionAtSelection(ref.current, direction);

@@ -187,6 +316,6 @@ }, [direction, selectionText === null || selectionText === void 0 ? void 0 : selectionText.length, selectionExpanded, ref]);

}) => {
const [hidden, setHidden] = useState(true);
const [hidden, setHidden] = useState$1(true);
const selectionExpanded = editor && isSelectionExpanded(editor);
const selectionText = editor && getSelectionText(editor);
const show = useCallback(() => {
const show = useCallback$1(() => {
if (ref.current && hidden && selectionExpanded) {

@@ -199,3 +328,3 @@ setHidden(false);

useEffect(() => {
useEffect$1(() => {
if (!hiddenDelay) {

@@ -209,3 +338,3 @@ show();

useEffect(() => {
useEffect$1(() => {
if (!hidden && !selectionExpanded) {

@@ -224,3 +353,3 @@ setHidden(true);

useEffect(() => {
useEffect$1(() => {
if (!hiddenDelay) return;

@@ -233,47 +362,2 @@ reset();

const BalloonToolbar = props => {
const {
children,
hiddenDelay = 0,
direction = 'top',
theme = 'dark',
arrow = false,
portalElement
} = props;
const ref = React.useRef(null);
const editor = useStoreEditorState(useEventEditorId('focus'));
const [hidden] = useBalloonShow({
editor,
ref,
hiddenDelay
});
useBalloonMove({
editor,
ref,
direction
});
const styles = getBalloonToolbarStyles({
hiddenDelay,
direction,
theme,
arrow,
hidden,
...props
});
return /*#__PURE__*/jsx(PortalBody, {
element: portalElement,
children: /*#__PURE__*/jsx(_StyledToolbarBase$1, {
ref: ref,
className: styles.root.className,
$_css: styles.root.css,
children: children
})
});
};
var _StyledToolbarBase$1 = _styled(ToolbarBase).withConfig({
displayName: "BalloonToolbar___StyledToolbarBase",
componentId: "sc-8umnsm-0"
})(["", ""], p => p.$_css);
const getHeadingToolbarStyles = props => createStyles({

@@ -421,6 +505,6 @@ prefixClassNames: 'HeadingToolbar',

}) => {
const [referenceElement, setReferenceElement] = useState(null);
const [popperElement, setPopperElement] = useState(null);
const [open, setOpen] = useState(false);
useEffect(() => {
const [referenceElement, setReferenceElement] = useState$1(null);
const [popperElement, setPopperElement] = useState$1(null);
const [open, setOpen] = useState$1(false);
useEffect$1(() => {
const listener = ev => {

@@ -510,3 +594,3 @@ if (open) {

export { BalloonToolbar, HeadingToolbar, Toolbar, ToolbarBase, ToolbarButton, ToolbarDropdown, ToolbarElement, ToolbarMark, getBalloonToolbarStyles, getHeadingToolbarStyles, getToolbarButtonStyles, getToolbarStyles, setPositionAtSelection, useBalloonMove, useBalloonShow };
export { BalloonToolbar, HeadingToolbar, Toolbar, ToolbarBase, ToolbarButton, ToolbarDropdown, ToolbarElement, ToolbarMark, getBalloonToolbarStyles, getHeadingToolbarStyles, getToolbarButtonStyles, getToolbarStyles, setPositionAtSelection, useBalloonMove, useBalloonShow, usePopupPosition };
//# sourceMappingURL=index.es.js.map

@@ -10,2 +10,3 @@ 'use strict';

var jsxRuntime = require('react/jsx-runtime');
var reactPopper = require('react-popper');
var plateCommon = require('@udecode/plate-common');

@@ -68,13 +69,4 @@ var Tippy = require('@tippyjs/react');

}
let marginTop;
const arrowStyle = [props.arrow && _styled.css(["::after{left:50%;content:' ';position:absolute;margin-top:-1px;transform:translateX(-50%);border-color:", " transparent;border-style:solid;}"], background), props.arrow && props.direction === 'top' && _styled.css(["::after{top:100%;bottom:auto;border-width:8px 8px 0;}"]), props.arrow && props.direction !== 'top' && _styled.css(["::after{top:auto;bottom:100%;border-width:0 8px 8px;}"])];
const arrowBorderStyle = [props.arrow && props.direction === 'top' && props.theme === 'light' && _styled.css(["::before{margin-top:0;border-width:9px 9px 0;border-color:", " transparent;}"], borderColor), props.arrow && props.direction !== 'top' && props.theme === 'light' && _styled.css(["::before{margin-top:0;border-width:0 9px 9px;border-color:", " transparent;}"], borderColor)];
if (props.direction === 'top') {
marginTop = -9;
} else {
marginTop = 9;
}
return plateStyledComponents.createStyles({

@@ -87,11 +79,8 @@ prefixClassNames: 'BalloonToolbar',

"whiteSpace": "nowrap",
"paddingTop": "0px",
"paddingBottom": "0px",
"paddingLeft": "0.25rem",
"paddingRight": "0.25rem"
"opacity": "1",
"transition": "opacity .2s ease-in-out"
}, props.hidden && {
"visibility": "hidden"
}, !props.hiddenDelay && {
"transition": "top 75ms ease-out,left 75ms ease-out"
}, _styled.css(["color:", ";background:", ";z-index:500;border:1px solid ", ";border-radius:4px;margin-top:", "px;.slate-ToolbarButton-active,.slate-ToolbarButton:hover{color:", ";}::before{", "}"], color, background, borderColor, marginTop, colorActive, arrowBorderStyle), ...arrowStyle, ...arrowBorderStyle]
"visibility": "hidden",
"opacity": "0"
}, _styled.css(["color:", ";background:", ";z-index:500;border:1px solid ", ";border-radius:4px;.slate-ToolbarButton-active,.slate-ToolbarButton:hover{color:", ";}::before{", "}"], color, background, borderColor, colorActive, arrowBorderStyle), ...arrowStyle, ...arrowBorderStyle]
});

@@ -130,2 +119,142 @@ };

const {
useEffect,
useState,
useCallback
} = React__namespace;
const virtualReference = {
getBoundingClientRect() {
return {
top: 10,
left: 10,
bottom: 20,
right: 100,
width: 90,
height: 10,
x: 0,
y: 0,
toJSON: () => null
};
}
};
const usePopupPosition = ({
editor,
popupElem,
scrollContainer = document.documentElement,
modifiers = [],
placement = 'top'
}) => {
const [isHide, setIsHide] = useState(true);
const selectionExpanded = editor && plateCommon.isSelectionExpanded(editor);
const selectionText = editor && plateCommon.getSelectionText(editor);
const {
styles,
attributes,
update
} = reactPopper.usePopper(virtualReference, popupElem, {
placement,
modifiers: [// default modifiers to position the popup correctly
{
name: 'preventOverflow',
enabled: true,
options: {
boundary: scrollContainer !== null && scrollContainer !== void 0 ? scrollContainer : undefined
}
}, {
name: 'flip',
enabled: true,
options: {
padding: 8
}
}, {
name: 'eventListeners',
enabled: true,
options: {
scroll: !isHide,
resize: true
}
}, {
name: 'offset',
options: {
offset: [0, 8]
}
}, // user modifiers to override the default
...modifiers],
strategy: 'absolute'
});
const show = useCallback(() => {
if (isHide && selectionExpanded) {
setIsHide(false);
}
}, [isHide, selectionExpanded, setIsHide]);
useEffect(() => {
if (!selectionText) {
setIsHide(true);
} else if (selectionText && selectionExpanded) {
setIsHide(false);
}
}, [selectionText, show, selectionExpanded, setIsHide]);
const setPosition = useCallback(() => {
const domSelection = window.getSelection();
if (!domSelection || domSelection.rangeCount < 1) return;
const domRange = domSelection.getRangeAt(0);
const rect = domRange.getBoundingClientRect();
virtualReference.getBoundingClientRect = () => rect;
update === null || update === void 0 ? void 0 : update();
}, [update]);
useEffect(() => {
scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.addEventListener('scroll', setPosition);
return () => scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.removeEventListener('scroll', setPosition);
}, [setPosition, scrollContainer]);
useEffect(() => {
popupElem && selectionExpanded && setPosition();
}, [selectionText === null || selectionText === void 0 ? void 0 : selectionText.length, selectionExpanded, popupElem, setPosition]);
return [styles, attributes, isHide];
};
const BalloonToolbar = props => {
const {
children,
direction = 'top',
theme = 'dark',
arrow = false,
portalElement,
scrollContainer
} = props;
const popupRef = React__namespace.useRef(null);
const editor = plateCore.useStoreEditorState(plateCore.useEventEditorId('focus'));
const [popperStyles, attributes, hidden] = usePopupPosition({
editor,
popupElem: popupRef.current,
scrollContainer,
placement: direction
});
const styles = getBalloonToolbarStyles({
direction,
theme,
arrow,
hidden,
...props
});
return /*#__PURE__*/jsxRuntime.jsx(plateStyledComponents.PortalBody, {
element: portalElement,
children: /*#__PURE__*/jsxRuntime.jsx(_StyledToolbarBase$1, {
ref: popupRef,
className: styles.root.className,
style: popperStyles.popper,
...attributes.popper,
$_css: styles.root.css,
children: children
})
});
};
var _StyledToolbarBase$1 = _styled__default['default'](ToolbarBase).withConfig({
displayName: "BalloonToolbar___StyledToolbarBase",
componentId: "sc-8umnsm-0"
})(["", ""], p => p.$_css);
const setPositionAtSelection = (el, direction = 'top') => {

@@ -259,47 +388,2 @@ const domSelection = window.getSelection();

const BalloonToolbar = props => {
const {
children,
hiddenDelay = 0,
direction = 'top',
theme = 'dark',
arrow = false,
portalElement
} = props;
const ref = React__namespace.useRef(null);
const editor = plateCore.useStoreEditorState(plateCore.useEventEditorId('focus'));
const [hidden] = useBalloonShow({
editor,
ref,
hiddenDelay
});
useBalloonMove({
editor,
ref,
direction
});
const styles = getBalloonToolbarStyles({
hiddenDelay,
direction,
theme,
arrow,
hidden,
...props
});
return /*#__PURE__*/jsxRuntime.jsx(plateStyledComponents.PortalBody, {
element: portalElement,
children: /*#__PURE__*/jsxRuntime.jsx(_StyledToolbarBase$1, {
ref: ref,
className: styles.root.className,
$_css: styles.root.css,
children: children
})
});
};
var _StyledToolbarBase$1 = _styled__default['default'](ToolbarBase).withConfig({
displayName: "BalloonToolbar___StyledToolbarBase",
componentId: "sc-8umnsm-0"
})(["", ""], p => p.$_css);
const getHeadingToolbarStyles = props => plateStyledComponents.createStyles({

@@ -550,2 +634,3 @@ prefixClassNames: 'HeadingToolbar',

exports.useBalloonShow = useBalloonShow;
exports.usePopupPosition = usePopupPosition;
//# sourceMappingURL=index.js.map
{
"name": "@udecode/plate-toolbar",
"version": "3.5.1",
"version": "4.0.0",
"description": "Toolbar UI for Plate",

@@ -35,5 +35,7 @@ "keywords": [

"dependencies": {
"@popperjs/core": "^2.8.3",
"@tippyjs/react": "^4.2.0",
"@udecode/plate-common": "3.4.0",
"@udecode/plate-core": "3.4.0",
"react-popper": "^2.2.4",
"@udecode/plate-styled-components": "3.5.1",

@@ -40,0 +42,0 @@ "react-use": "^17.1.1"

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc