Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@restart/ui

Package Overview
Dependencies
Maintainers
3
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@restart/ui - npm Package Compare versions

Comparing version 0.0.4 to 0.0.5

cjs/getScrollbarWidth.d.ts

11

cjs/Button.d.ts

@@ -13,3 +13,3 @@ import * as React from 'react';

tabIndex?: number;
tagName?: string;
tagName?: keyof JSX.IntrinsicElements;
}

@@ -29,5 +29,6 @@ export declare function isTrivialHref(href?: string): boolean;

}
export declare function useButtonProps({ tagName, disabled, href, target, rel, onClick, tabIndex, type, }: UseButtonPropsOptions): [AriaButtonProps, {
tagName: string;
}];
export interface UseButtonPropsMetadata {
tagName: React.ElementType;
}
export declare function useButtonProps({ tagName, disabled, href, target, rel, onClick, tabIndex, type, }: UseButtonPropsOptions): [AriaButtonProps, UseButtonPropsMetadata];
export interface BaseButtonProps {

@@ -38,3 +39,3 @@ /**

*/
as?: string | undefined;
as?: keyof JSX.IntrinsicElements | undefined;
/** The disabled state of the button */

@@ -41,0 +42,0 @@ disabled?: boolean | undefined;

@@ -94,3 +94,3 @@ "use strict";

const [buttonProps, {
tagName
tagName: Component
}] = useButtonProps(Object.assign({

@@ -100,3 +100,2 @@ tagName: asProp,

}, props));
const Component = tagName;
return /*#__PURE__*/(0, _jsxRuntime.jsx)(Component, Object.assign({}, props, buttonProps, {

@@ -103,0 +102,0 @@ ref: ref

@@ -12,5 +12,6 @@ import * as React from 'react';

}
export declare type ToggleEvent = React.SyntheticEvent | KeyboardEvent | MouseEvent;
export interface ToggleMetadata {
source: string | undefined;
originalEvent: React.SyntheticEvent | Event | undefined;
originalEvent: ToggleEvent | undefined;
}

@@ -17,0 +18,0 @@ export interface DropdownProps {

@@ -27,19 +27,99 @@ import * as React from 'react';

className?: string;
/**
* Set the visibility of the Modal
*/
show?: boolean;
/**
* A DOM element, a `ref` to an element, or function that returns either. The Modal is appended to it's `container` element.
*
*/
container?: DOMContainer;
/**
* A callback fired when the Modal is opening.
*/
onShow?: () => void;
/**
* A callback fired when either the backdrop is clicked, or the escape key is pressed.
*
* The `onHide` callback only signals intent from the Modal,
* you must actually set the `show` prop to `false` for the Modal to close.
*/
onHide?: () => void;
/**
* A ModalManager instance used to track and manage the state of open
* Modals. Useful when customizing how modals interact within a container
*/
manager?: ModalManager;
/**
* Include a backdrop component.
*/
backdrop?: true | false | 'static';
/**
* A function that returns the dialog component. Useful for custom
* rendering. **Note:** the component should make sure to apply the provided ref.
*
* ```js static
* renderDialog={props => <MyDialog {...props} />}
* ```
*/
renderDialog?: (props: RenderModalDialogProps) => React.ReactNode;
/**
* A function that returns a backdrop component. Useful for custom
* backdrop rendering.
*
* ```js
* renderBackdrop={props => <MyBackdrop {...props} />}
* ```
*/
renderBackdrop?: (props: RenderModalBackdropProps) => React.ReactNode;
/**
* A callback fired when the escape key, if specified in `keyboard`, is pressed.
*
* If preventDefault() is called on the keyboard event, closing the modal will be cancelled.
*/
onEscapeKeyDown?: (e: KeyboardEvent) => void;
/**
* A callback fired when the backdrop, if specified, is clicked.
*/
onBackdropClick?: (e: React.SyntheticEvent) => void;
containerClassName?: string;
/**
* Close the modal when escape key is pressed
*/
keyboard?: boolean;
/**
* A `react-transition-group` `<Transition/>` component used
* to control animations for the dialog component.
*/
transition?: ModalTransitionComponent;
/**
* A `react-transition-group` `<Transition/>` component used
* to control animations for the backdrop components.
*/
backdropTransition?: ModalTransitionComponent;
/**
* When `true` The modal will automatically shift focus to itself when it opens, and
* replace it to the last focused element when it closes. This also
* works correctly with any Modal children that have the `autoFocus` prop.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
autoFocus?: boolean;
/**
* When `true` The modal will prevent focus from leaving the Modal while open.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
enforceFocus?: boolean;
/**
* When `true` The modal will restore focus to previously focused element once
* modal is hidden
*/
restoreFocus?: boolean;
/**
* Options passed to focus function when `restoreFocus` is set to `true`
*
* @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#Parameters
*/
restoreFocusOptions?: {

@@ -46,0 +126,0 @@ preventScroll: boolean;

@@ -14,4 +14,2 @@ "use strict";

var _propTypes = _interopRequireDefault(require("prop-types"));
var React = _interopRequireWildcard(require("react"));

@@ -57,3 +55,3 @@

return Object.assign(modal.current, {
add: (container, className) => modalManager.add(modal.current, container, className),
add: () => modalManager.add(modal.current),
remove: () => modalManager.remove(modal.current),

@@ -91,3 +89,2 @@ isTopModal: () => modalManager.isTopModal(modal.current),

container: containerRef,
containerClassName,
onShow,

@@ -102,3 +99,3 @@ onHide = () => {},

} = _ref,
rest = _objectWithoutPropertiesLoose(_ref, ["show", "role", "className", "style", "children", "backdrop", "keyboard", "onBackdropClick", "onEscapeKeyDown", "transition", "backdropTransition", "autoFocus", "enforceFocus", "restoreFocus", "restoreFocusOptions", "renderDialog", "renderBackdrop", "manager", "container", "containerClassName", "onShow", "onHide", "onExit", "onExited", "onExiting", "onEnter", "onEntering", "onEntered"]);
rest = _objectWithoutPropertiesLoose(_ref, ["show", "role", "className", "style", "children", "backdrop", "keyboard", "onBackdropClick", "onEscapeKeyDown", "transition", "backdropTransition", "autoFocus", "enforceFocus", "restoreFocus", "restoreFocusOptions", "renderDialog", "renderBackdrop", "manager", "container", "onShow", "onHide", "onExit", "onExited", "onExiting", "onEnter", "onEntering", "onEntered"]);

@@ -124,3 +121,3 @@ const container = (0, _useWaitForDOMRef.default)(containerRef);

const handleShow = (0, _useEventCallback.default)(() => {
modal.add(container, containerClassName);
modal.add();
removeKeydownListenerRef.current = (0, _listen.default)(document, 'keydown', handleDocumentKeyDown);

@@ -279,160 +276,3 @@ removeFocusListenerRef.current = (0, _listen.default)(document, 'focus', // the timeout is necessary b/c this will run before the new modal is mounted

});
const propTypes = {
/**
* Set the visibility of the Modal
*/
show: _propTypes.default.bool,
/**
* A DOM element, a `ref` to an element, or function that returns either. The Modal is appended to it's `container` element.
*
* For the sake of assistive technologies, the container should usually be the document body, so that the rest of the
* page content can be placed behind a virtual backdrop as well as a visual one.
*/
container: _propTypes.default.any,
/**
* A callback fired when the Modal is opening.
*/
onShow: _propTypes.default.func,
/**
* A callback fired when either the backdrop is clicked, or the escape key is pressed.
*
* The `onHide` callback only signals intent from the Modal,
* you must actually set the `show` prop to `false` for the Modal to close.
*/
onHide: _propTypes.default.func,
/**
* Include a backdrop component.
*/
backdrop: _propTypes.default.oneOfType([_propTypes.default.bool, _propTypes.default.oneOf(['static'])]),
/**
* A function that returns the dialog component. Useful for custom
* rendering. **Note:** the component should make sure to apply the provided ref.
*
* ```js static
* renderDialog={props => <MyDialog {...props} />}
* ```
*/
renderDialog: _propTypes.default.func,
/**
* A function that returns a backdrop component. Useful for custom
* backdrop rendering.
*
* ```js
* renderBackdrop={props => <MyBackdrop {...props} />}
* ```
*/
renderBackdrop: _propTypes.default.func,
/**
* A callback fired when the escape key, if specified in `keyboard`, is pressed.
*
* If preventDefault() is called on the keyboard event, closing the modal will be cancelled.
*/
onEscapeKeyDown: _propTypes.default.func,
/**
* A callback fired when the backdrop, if specified, is clicked.
*/
onBackdropClick: _propTypes.default.func,
/**
* A css class or set of classes applied to the modal container when the modal is open,
* and removed when it is closed.
*/
containerClassName: _propTypes.default.string,
/**
* Close the modal when escape key is pressed
*/
keyboard: _propTypes.default.bool,
/**
* A `react-transition-group@2.0.0` `<Transition/>` component used
* to control animations for the dialog component.
*/
transition: _propTypes.default.elementType,
/**
* A `react-transition-group@2.0.0` `<Transition/>` component used
* to control animations for the backdrop components.
*/
backdropTransition: _propTypes.default.elementType,
/**
* When `true` The modal will automatically shift focus to itself when it opens, and
* replace it to the last focused element when it closes. This also
* works correctly with any Modal children that have the `autoFocus` prop.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
autoFocus: _propTypes.default.bool,
/**
* When `true` The modal will prevent focus from leaving the Modal while open.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
enforceFocus: _propTypes.default.bool,
/**
* When `true` The modal will restore focus to previously focused element once
* modal is hidden
*/
restoreFocus: _propTypes.default.bool,
/**
* Options passed to focus function when `restoreFocus` is set to `true`
*
* @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#Parameters
*/
restoreFocusOptions: _propTypes.default.shape({
preventScroll: _propTypes.default.bool
}),
/**
* Callback fired before the Modal transitions in
*/
onEnter: _propTypes.default.func,
/**
* Callback fired as the Modal begins to transition in
*/
onEntering: _propTypes.default.func,
/**
* Callback fired after the Modal finishes transitioning in
*/
onEntered: _propTypes.default.func,
/**
* Callback fired right before the Modal transitions out
*/
onExit: _propTypes.default.func,
/**
* Callback fired as the Modal begins to transition out
*/
onExiting: _propTypes.default.func,
/**
* Callback fired after the Modal finishes transitioning out
*/
onExited: _propTypes.default.func,
/**
* A ModalManager instance used to track and manage the state of open
* Modals. Useful when customizing how modals interact within a container
*/
manager: _propTypes.default.instanceOf(_ModalManager.default)
};
Modal.displayName = 'Modal';
Modal.propTypes = propTypes;

@@ -439,0 +279,0 @@ var _default = Object.assign(Modal, {

@@ -5,30 +5,29 @@ export interface ModalInstance {

}
export declare type ContainerState = Record<string, any> & {
isOverflowing?: boolean;
style?: Partial<CSSStyleDeclaration>;
modals: ModalInstance[];
export declare type ContainerState = {
scrollBarWidth: number;
style: Record<string, any>;
[key: string]: any;
};
export declare const OPEN_DATA_ATTRIBUTE: "data-rr-ui-modal-open";
/**
* Proper state management for containers and the modals in those containers.
*
* @internal Used by the Modal to ensure proper styling of containers.
* Manages a stack of Modals as well as ensuring
* body scrolling is is disabled and padding accounted for
*/
declare class ModalManager {
readonly hideSiblingNodes: boolean;
readonly handleContainerOverflow: boolean;
readonly isRTL: boolean;
readonly modals: ModalInstance[];
readonly containers: HTMLElement[];
readonly data: ContainerState[];
readonly scrollbarSize: number;
constructor({ hideSiblingNodes, handleContainerOverflow, isRTL, }?: {
hideSiblingNodes?: boolean | undefined;
private state;
constructor({ handleContainerOverflow, isRTL }?: {
handleContainerOverflow?: boolean | undefined;
isRTL?: boolean | undefined;
});
isContainerOverflowing(modal: ModalInstance): any;
containerIndexFromModal(modal: ModalInstance): number;
setContainerStyle(containerState: ContainerState, container: HTMLElement): void;
removeContainerStyle(containerState: ContainerState, container: HTMLElement): void;
add(modal: ModalInstance, container: HTMLElement, className?: string): number;
getScrollbarWidth(): number;
getElement(): HTMLElement;
setModalAttributes(_modal: ModalInstance): void;
removeModalAttributes(_modal: ModalInstance): void;
setContainerStyle(containerState: ContainerState): void;
reset(): void;
removeContainerStyle(containerState: ContainerState): void;
add(modal: ModalInstance): number;
remove(modal: ModalInstance): void;

@@ -35,0 +34,0 @@ isTopModal(modal: ModalInstance): boolean;

"use strict";
exports.__esModule = true;
exports.default = void 0;
exports.default = exports.OPEN_DATA_ATTRIBUTE = void 0;
var _addClass = _interopRequireDefault(require("dom-helpers/addClass"));
var _removeClass = _interopRequireDefault(require("dom-helpers/removeClass"));
var _css = _interopRequireDefault(require("dom-helpers/css"));
var _scrollbarSize = _interopRequireDefault(require("dom-helpers/scrollbarSize"));
var _DataKey = require("./DataKey");
var _isOverflowing = _interopRequireDefault(require("./isOverflowing"));
var _getScrollbarWidth = _interopRequireDefault(require("./getScrollbarWidth"));
var _manageAriaHidden = require("./manageAriaHidden");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function findIndexOf(arr, cb) {
let idx = -1;
arr.some((d, i) => {
if (cb(d, i)) {
idx = i;
return true;
}
const OPEN_DATA_ATTRIBUTE = (0, _DataKey.dataAttr)('modal-open');
/**
* Manages a stack of Modals as well as ensuring
* body scrolling is is disabled and padding accounted for
*/
return false;
});
return idx;
}
exports.OPEN_DATA_ATTRIBUTE = OPEN_DATA_ATTRIBUTE;
/**
* Proper state management for containers and the modals in those containers.
*
* @internal Used by the Modal to ensure proper styling of containers.
*/
class ModalManager {
constructor({
hideSiblingNodes = true,
handleContainerOverflow = true,
isRTL = false
} = {}) {
this.hideSiblingNodes = hideSiblingNodes;
this.handleContainerOverflow = handleContainerOverflow;
this.isRTL = isRTL;
this.modals = [];
this.containers = [];
this.data = [];
this.scrollbarSize = (0, _scrollbarSize.default)();
}
isContainerOverflowing(modal) {
const data = this.data[this.containerIndexFromModal(modal)];
return data ? data.overflowing : false;
getScrollbarWidth() {
return (0, _getScrollbarWidth.default)();
}
containerIndexFromModal(modal) {
return findIndexOf(this.data, d => d.modals.indexOf(modal) !== -1);
getElement() {
return document.body;
}
setContainerStyle(containerState, container) {
setModalAttributes(_modal) {// For overriding
}
removeModalAttributes(_modal) {// For overriding
}
setContainerStyle(containerState) {
const style = {

@@ -69,2 +53,3 @@ overflow: 'hidden'

const paddingProp = this.isRTL ? 'paddingLeft' : 'paddingRight';
const container = this.getElement();
containerState.style = {

@@ -75,18 +60,24 @@ overflow: container.style.overflow,

if (containerState.overflowing) {
if (containerState.scrollBarWidth) {
// use computed style, here to get the real padding
// to add our scrollbar width
style[paddingProp] = `${parseInt((0, _css.default)(container, paddingProp) || '0', 10) + this.scrollbarSize}px`;
style[paddingProp] = `${parseInt((0, _css.default)(container, paddingProp) || '0', 10) + containerState.scrollBarWidth}px`;
}
container.setAttribute(OPEN_DATA_ATTRIBUTE, '');
(0, _css.default)(container, style);
}
removeContainerStyle(containerState, container) {
reset() {
[...this.modals].forEach(m => this.remove(m));
}
removeContainerStyle(containerState) {
const container = this.getElement();
container.removeAttribute(OPEN_DATA_ATTRIBUTE);
Object.assign(container.style, containerState.style);
}
add(modal, container, className) {
add(modal) {
let modalIdx = this.modals.indexOf(modal);
const containerIdx = this.containers.indexOf(container);

@@ -99,26 +90,17 @@ if (modalIdx !== -1) {

this.modals.push(modal);
this.setModalAttributes(modal);
if (this.hideSiblingNodes) {
(0, _manageAriaHidden.hideSiblings)(container, modal);
}
if (containerIdx !== -1) {
this.data[containerIdx].modals.push(modal);
if (modalIdx !== 0) {
return modalIdx;
}
const data = {
modals: [modal],
// right now only the first modal of a container will have its classes applied
classes: className ? className.split(/\s+/) : [],
overflowing: (0, _isOverflowing.default)(container)
this.state = {
scrollBarWidth: this.getScrollbarWidth(),
style: {}
};
if (this.handleContainerOverflow) {
this.setContainerStyle(data, container);
this.setContainerStyle(this.state);
}
data.classes.forEach(_addClass.default.bind(null, container));
this.containers.push(container);
this.data.push(data);
return modalIdx;

@@ -134,31 +116,10 @@ }

const containerIdx = this.containerIndexFromModal(modal);
const data = this.data[containerIdx];
const container = this.containers[containerIdx];
data.modals.splice(data.modals.indexOf(modal), 1);
this.modals.splice(modalIdx, 1); // if that was the last modal in a container,
// clean up the container
if (data.modals.length === 0) {
data.classes.forEach(_removeClass.default.bind(null, container));
if (!this.modals.length && this.handleContainerOverflow) {
this.removeContainerStyle(this.state);
}
if (this.handleContainerOverflow) {
this.removeContainerStyle(data, container);
}
if (this.hideSiblingNodes) {
(0, _manageAriaHidden.showSiblings)(container, modal);
}
this.containers.splice(containerIdx, 1);
this.data.splice(containerIdx, 1);
} else if (this.hideSiblingNodes) {
// otherwise make sure the next top modal is visible to a SR
const {
backdrop,
dialog
} = data.modals[data.modals.length - 1];
(0, _manageAriaHidden.ariaHidden)(false, dialog);
(0, _manageAriaHidden.ariaHidden)(false, backdrop);
}
this.removeModalAttributes(modal);
}

@@ -165,0 +126,0 @@

@@ -23,8 +23,26 @@ import * as React from 'react';

export interface TransitionCallbacks {
/**
* Callback fired before the component transitions in
*/
onEnter?(node: HTMLElement, isAppearing: boolean): any;
/**
* Callback fired as the component begins to transition in
*/
onEntering?(node: HTMLElement, isAppearing: boolean): any;
/**
* Callback fired after the component finishes transitioning in
*/
onEntered?(node: HTMLElement, isAppearing: boolean): any;
onEntering?(node: HTMLElement, isAppearing: boolean): any;
/**
* Callback fired right before the component transitions out
*/
onExit?(node: HTMLElement): any;
/**
* Callback fired as the component begins to transition out
*/
onExiting?(node: HTMLElement): any;
/**
* Callback fired after the component finishes transitioning out
*/
onExited?(node: HTMLElement): any;
onExiting?(node: HTMLElement): any;
}

@@ -31,0 +49,0 @@ export interface TransitionProps extends TransitionCallbacks {

@@ -13,3 +13,3 @@ import * as React from 'react';

tabIndex?: number;
tagName?: string;
tagName?: keyof JSX.IntrinsicElements;
}

@@ -29,5 +29,6 @@ export declare function isTrivialHref(href?: string): boolean;

}
export declare function useButtonProps({ tagName, disabled, href, target, rel, onClick, tabIndex, type, }: UseButtonPropsOptions): [AriaButtonProps, {
tagName: string;
}];
export interface UseButtonPropsMetadata {
tagName: React.ElementType;
}
export declare function useButtonProps({ tagName, disabled, href, target, rel, onClick, tabIndex, type, }: UseButtonPropsOptions): [AriaButtonProps, UseButtonPropsMetadata];
export interface BaseButtonProps {

@@ -38,3 +39,3 @@ /**

*/
as?: string | undefined;
as?: keyof JSX.IntrinsicElements | undefined;
/** The disabled state of the button */

@@ -41,0 +42,0 @@ disabled?: boolean | undefined;

@@ -79,3 +79,3 @@ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

const [buttonProps, {
tagName
tagName: Component
}] = useButtonProps(Object.assign({

@@ -85,3 +85,2 @@ tagName: asProp,

}, props));
const Component = tagName;
return /*#__PURE__*/_jsx(Component, Object.assign({}, props, buttonProps, {

@@ -88,0 +87,0 @@ ref: ref

@@ -12,5 +12,6 @@ import * as React from 'react';

}
export declare type ToggleEvent = React.SyntheticEvent | KeyboardEvent | MouseEvent;
export interface ToggleMetadata {
source: string | undefined;
originalEvent: React.SyntheticEvent | Event | undefined;
originalEvent: ToggleEvent | undefined;
}

@@ -17,0 +18,0 @@ export interface DropdownProps {

@@ -27,19 +27,99 @@ import * as React from 'react';

className?: string;
/**
* Set the visibility of the Modal
*/
show?: boolean;
/**
* A DOM element, a `ref` to an element, or function that returns either. The Modal is appended to it's `container` element.
*
*/
container?: DOMContainer;
/**
* A callback fired when the Modal is opening.
*/
onShow?: () => void;
/**
* A callback fired when either the backdrop is clicked, or the escape key is pressed.
*
* The `onHide` callback only signals intent from the Modal,
* you must actually set the `show` prop to `false` for the Modal to close.
*/
onHide?: () => void;
/**
* A ModalManager instance used to track and manage the state of open
* Modals. Useful when customizing how modals interact within a container
*/
manager?: ModalManager;
/**
* Include a backdrop component.
*/
backdrop?: true | false | 'static';
/**
* A function that returns the dialog component. Useful for custom
* rendering. **Note:** the component should make sure to apply the provided ref.
*
* ```js static
* renderDialog={props => <MyDialog {...props} />}
* ```
*/
renderDialog?: (props: RenderModalDialogProps) => React.ReactNode;
/**
* A function that returns a backdrop component. Useful for custom
* backdrop rendering.
*
* ```js
* renderBackdrop={props => <MyBackdrop {...props} />}
* ```
*/
renderBackdrop?: (props: RenderModalBackdropProps) => React.ReactNode;
/**
* A callback fired when the escape key, if specified in `keyboard`, is pressed.
*
* If preventDefault() is called on the keyboard event, closing the modal will be cancelled.
*/
onEscapeKeyDown?: (e: KeyboardEvent) => void;
/**
* A callback fired when the backdrop, if specified, is clicked.
*/
onBackdropClick?: (e: React.SyntheticEvent) => void;
containerClassName?: string;
/**
* Close the modal when escape key is pressed
*/
keyboard?: boolean;
/**
* A `react-transition-group` `<Transition/>` component used
* to control animations for the dialog component.
*/
transition?: ModalTransitionComponent;
/**
* A `react-transition-group` `<Transition/>` component used
* to control animations for the backdrop components.
*/
backdropTransition?: ModalTransitionComponent;
/**
* When `true` The modal will automatically shift focus to itself when it opens, and
* replace it to the last focused element when it closes. This also
* works correctly with any Modal children that have the `autoFocus` prop.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
autoFocus?: boolean;
/**
* When `true` The modal will prevent focus from leaving the Modal while open.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
enforceFocus?: boolean;
/**
* When `true` The modal will restore focus to previously focused element once
* modal is hidden
*/
restoreFocus?: boolean;
/**
* Options passed to focus function when `restoreFocus` is set to `true`
*
* @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#Parameters
*/
restoreFocusOptions?: {

@@ -46,0 +126,0 @@ preventScroll: boolean;

@@ -8,3 +8,2 @@ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

import listen from 'dom-helpers/listen';
import PropTypes from 'prop-types';
import { useState, useRef, useCallback, useImperativeHandle, forwardRef, useEffect } from 'react';

@@ -36,3 +35,3 @@ import * as React from 'react';

return Object.assign(modal.current, {
add: (container, className) => modalManager.add(modal.current, container, className),
add: () => modalManager.add(modal.current),
remove: () => modalManager.remove(modal.current),

@@ -70,3 +69,2 @@ isTopModal: () => modalManager.isTopModal(modal.current),

container: containerRef,
containerClassName,
onShow,

@@ -81,3 +79,3 @@ onHide = () => {},

} = _ref,
rest = _objectWithoutPropertiesLoose(_ref, ["show", "role", "className", "style", "children", "backdrop", "keyboard", "onBackdropClick", "onEscapeKeyDown", "transition", "backdropTransition", "autoFocus", "enforceFocus", "restoreFocus", "restoreFocusOptions", "renderDialog", "renderBackdrop", "manager", "container", "containerClassName", "onShow", "onHide", "onExit", "onExited", "onExiting", "onEnter", "onEntering", "onEntered"]);
rest = _objectWithoutPropertiesLoose(_ref, ["show", "role", "className", "style", "children", "backdrop", "keyboard", "onBackdropClick", "onEscapeKeyDown", "transition", "backdropTransition", "autoFocus", "enforceFocus", "restoreFocus", "restoreFocusOptions", "renderDialog", "renderBackdrop", "manager", "container", "onShow", "onHide", "onExit", "onExited", "onExiting", "onEnter", "onEntering", "onEntered"]);

@@ -103,3 +101,3 @@ const container = useWaitForDOMRef(containerRef);

const handleShow = useEventCallback(() => {
modal.add(container, containerClassName);
modal.add();
removeKeydownListenerRef.current = listen(document, 'keydown', handleDocumentKeyDown);

@@ -258,162 +256,5 @@ removeFocusListenerRef.current = listen(document, 'focus', // the timeout is necessary b/c this will run before the new modal is mounted

});
const propTypes = {
/**
* Set the visibility of the Modal
*/
show: PropTypes.bool,
/**
* A DOM element, a `ref` to an element, or function that returns either. The Modal is appended to it's `container` element.
*
* For the sake of assistive technologies, the container should usually be the document body, so that the rest of the
* page content can be placed behind a virtual backdrop as well as a visual one.
*/
container: PropTypes.any,
/**
* A callback fired when the Modal is opening.
*/
onShow: PropTypes.func,
/**
* A callback fired when either the backdrop is clicked, or the escape key is pressed.
*
* The `onHide` callback only signals intent from the Modal,
* you must actually set the `show` prop to `false` for the Modal to close.
*/
onHide: PropTypes.func,
/**
* Include a backdrop component.
*/
backdrop: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['static'])]),
/**
* A function that returns the dialog component. Useful for custom
* rendering. **Note:** the component should make sure to apply the provided ref.
*
* ```js static
* renderDialog={props => <MyDialog {...props} />}
* ```
*/
renderDialog: PropTypes.func,
/**
* A function that returns a backdrop component. Useful for custom
* backdrop rendering.
*
* ```js
* renderBackdrop={props => <MyBackdrop {...props} />}
* ```
*/
renderBackdrop: PropTypes.func,
/**
* A callback fired when the escape key, if specified in `keyboard`, is pressed.
*
* If preventDefault() is called on the keyboard event, closing the modal will be cancelled.
*/
onEscapeKeyDown: PropTypes.func,
/**
* A callback fired when the backdrop, if specified, is clicked.
*/
onBackdropClick: PropTypes.func,
/**
* A css class or set of classes applied to the modal container when the modal is open,
* and removed when it is closed.
*/
containerClassName: PropTypes.string,
/**
* Close the modal when escape key is pressed
*/
keyboard: PropTypes.bool,
/**
* A `react-transition-group@2.0.0` `<Transition/>` component used
* to control animations for the dialog component.
*/
transition: PropTypes.elementType,
/**
* A `react-transition-group@2.0.0` `<Transition/>` component used
* to control animations for the backdrop components.
*/
backdropTransition: PropTypes.elementType,
/**
* When `true` The modal will automatically shift focus to itself when it opens, and
* replace it to the last focused element when it closes. This also
* works correctly with any Modal children that have the `autoFocus` prop.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
autoFocus: PropTypes.bool,
/**
* When `true` The modal will prevent focus from leaving the Modal while open.
*
* Generally this should never be set to `false` as it makes the Modal less
* accessible to assistive technologies, like screen readers.
*/
enforceFocus: PropTypes.bool,
/**
* When `true` The modal will restore focus to previously focused element once
* modal is hidden
*/
restoreFocus: PropTypes.bool,
/**
* Options passed to focus function when `restoreFocus` is set to `true`
*
* @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#Parameters
*/
restoreFocusOptions: PropTypes.shape({
preventScroll: PropTypes.bool
}),
/**
* Callback fired before the Modal transitions in
*/
onEnter: PropTypes.func,
/**
* Callback fired as the Modal begins to transition in
*/
onEntering: PropTypes.func,
/**
* Callback fired after the Modal finishes transitioning in
*/
onEntered: PropTypes.func,
/**
* Callback fired right before the Modal transitions out
*/
onExit: PropTypes.func,
/**
* Callback fired as the Modal begins to transition out
*/
onExiting: PropTypes.func,
/**
* Callback fired after the Modal finishes transitioning out
*/
onExited: PropTypes.func,
/**
* A ModalManager instance used to track and manage the state of open
* Modals. Useful when customizing how modals interact within a container
*/
manager: PropTypes.instanceOf(ModalManager)
};
Modal.displayName = 'Modal';
Modal.propTypes = propTypes;
export default Object.assign(Modal, {
Manager: ModalManager
});

@@ -5,30 +5,29 @@ export interface ModalInstance {

}
export declare type ContainerState = Record<string, any> & {
isOverflowing?: boolean;
style?: Partial<CSSStyleDeclaration>;
modals: ModalInstance[];
export declare type ContainerState = {
scrollBarWidth: number;
style: Record<string, any>;
[key: string]: any;
};
export declare const OPEN_DATA_ATTRIBUTE: "data-rr-ui-modal-open";
/**
* Proper state management for containers and the modals in those containers.
*
* @internal Used by the Modal to ensure proper styling of containers.
* Manages a stack of Modals as well as ensuring
* body scrolling is is disabled and padding accounted for
*/
declare class ModalManager {
readonly hideSiblingNodes: boolean;
readonly handleContainerOverflow: boolean;
readonly isRTL: boolean;
readonly modals: ModalInstance[];
readonly containers: HTMLElement[];
readonly data: ContainerState[];
readonly scrollbarSize: number;
constructor({ hideSiblingNodes, handleContainerOverflow, isRTL, }?: {
hideSiblingNodes?: boolean | undefined;
private state;
constructor({ handleContainerOverflow, isRTL }?: {
handleContainerOverflow?: boolean | undefined;
isRTL?: boolean | undefined;
});
isContainerOverflowing(modal: ModalInstance): any;
containerIndexFromModal(modal: ModalInstance): number;
setContainerStyle(containerState: ContainerState, container: HTMLElement): void;
removeContainerStyle(containerState: ContainerState, container: HTMLElement): void;
add(modal: ModalInstance, container: HTMLElement, className?: string): number;
getScrollbarWidth(): number;
getElement(): HTMLElement;
setModalAttributes(_modal: ModalInstance): void;
removeModalAttributes(_modal: ModalInstance): void;
setContainerStyle(containerState: ContainerState): void;
reset(): void;
removeContainerStyle(containerState: ContainerState): void;
add(modal: ModalInstance): number;
remove(modal: ModalInstance): void;

@@ -35,0 +34,0 @@ isTopModal(modal: ModalInstance): boolean;

@@ -1,51 +0,35 @@

import addClass from 'dom-helpers/addClass';
import removeClass from 'dom-helpers/removeClass';
import css from 'dom-helpers/css';
import getScrollbarSize from 'dom-helpers/scrollbarSize';
import isOverflowing from './isOverflowing';
import { ariaHidden, hideSiblings, showSiblings } from './manageAriaHidden';
function findIndexOf(arr, cb) {
let idx = -1;
arr.some((d, i) => {
if (cb(d, i)) {
idx = i;
return true;
}
return false;
});
return idx;
}
import { dataAttr } from './DataKey';
import getBodyScrollbarWidth from './getScrollbarWidth';
export const OPEN_DATA_ATTRIBUTE = dataAttr('modal-open');
/**
* Proper state management for containers and the modals in those containers.
*
* @internal Used by the Modal to ensure proper styling of containers.
* Manages a stack of Modals as well as ensuring
* body scrolling is is disabled and padding accounted for
*/
class ModalManager {
constructor({
hideSiblingNodes = true,
handleContainerOverflow = true,
isRTL = false
} = {}) {
this.hideSiblingNodes = hideSiblingNodes;
this.handleContainerOverflow = handleContainerOverflow;
this.isRTL = isRTL;
this.modals = [];
this.containers = [];
this.data = [];
this.scrollbarSize = getScrollbarSize();
}
isContainerOverflowing(modal) {
const data = this.data[this.containerIndexFromModal(modal)];
return data ? data.overflowing : false;
getScrollbarWidth() {
return getBodyScrollbarWidth();
}
containerIndexFromModal(modal) {
return findIndexOf(this.data, d => d.modals.indexOf(modal) !== -1);
getElement() {
return document.body;
}
setContainerStyle(containerState, container) {
setModalAttributes(_modal) {// For overriding
}
removeModalAttributes(_modal) {// For overriding
}
setContainerStyle(containerState) {
const style = {

@@ -57,2 +41,3 @@ overflow: 'hidden'

const paddingProp = this.isRTL ? 'paddingLeft' : 'paddingRight';
const container = this.getElement();
containerState.style = {

@@ -63,18 +48,24 @@ overflow: container.style.overflow,

if (containerState.overflowing) {
if (containerState.scrollBarWidth) {
// use computed style, here to get the real padding
// to add our scrollbar width
style[paddingProp] = `${parseInt(css(container, paddingProp) || '0', 10) + this.scrollbarSize}px`;
style[paddingProp] = `${parseInt(css(container, paddingProp) || '0', 10) + containerState.scrollBarWidth}px`;
}
container.setAttribute(OPEN_DATA_ATTRIBUTE, '');
css(container, style);
}
removeContainerStyle(containerState, container) {
reset() {
[...this.modals].forEach(m => this.remove(m));
}
removeContainerStyle(containerState) {
const container = this.getElement();
container.removeAttribute(OPEN_DATA_ATTRIBUTE);
Object.assign(container.style, containerState.style);
}
add(modal, container, className) {
add(modal) {
let modalIdx = this.modals.indexOf(modal);
const containerIdx = this.containers.indexOf(container);

@@ -87,26 +78,17 @@ if (modalIdx !== -1) {

this.modals.push(modal);
this.setModalAttributes(modal);
if (this.hideSiblingNodes) {
hideSiblings(container, modal);
}
if (containerIdx !== -1) {
this.data[containerIdx].modals.push(modal);
if (modalIdx !== 0) {
return modalIdx;
}
const data = {
modals: [modal],
// right now only the first modal of a container will have its classes applied
classes: className ? className.split(/\s+/) : [],
overflowing: isOverflowing(container)
this.state = {
scrollBarWidth: this.getScrollbarWidth(),
style: {}
};
if (this.handleContainerOverflow) {
this.setContainerStyle(data, container);
this.setContainerStyle(this.state);
}
data.classes.forEach(addClass.bind(null, container));
this.containers.push(container);
this.data.push(data);
return modalIdx;

@@ -122,31 +104,10 @@ }

const containerIdx = this.containerIndexFromModal(modal);
const data = this.data[containerIdx];
const container = this.containers[containerIdx];
data.modals.splice(data.modals.indexOf(modal), 1);
this.modals.splice(modalIdx, 1); // if that was the last modal in a container,
// clean up the container
if (data.modals.length === 0) {
data.classes.forEach(removeClass.bind(null, container));
if (!this.modals.length && this.handleContainerOverflow) {
this.removeContainerStyle(this.state);
}
if (this.handleContainerOverflow) {
this.removeContainerStyle(data, container);
}
if (this.hideSiblingNodes) {
showSiblings(container, modal);
}
this.containers.splice(containerIdx, 1);
this.data.splice(containerIdx, 1);
} else if (this.hideSiblingNodes) {
// otherwise make sure the next top modal is visible to a SR
const {
backdrop,
dialog
} = data.modals[data.modals.length - 1];
ariaHidden(false, dialog);
ariaHidden(false, backdrop);
}
this.removeModalAttributes(modal);
}

@@ -153,0 +114,0 @@

@@ -23,8 +23,26 @@ import * as React from 'react';

export interface TransitionCallbacks {
/**
* Callback fired before the component transitions in
*/
onEnter?(node: HTMLElement, isAppearing: boolean): any;
/**
* Callback fired as the component begins to transition in
*/
onEntering?(node: HTMLElement, isAppearing: boolean): any;
/**
* Callback fired after the component finishes transitioning in
*/
onEntered?(node: HTMLElement, isAppearing: boolean): any;
onEntering?(node: HTMLElement, isAppearing: boolean): any;
/**
* Callback fired right before the component transitions out
*/
onExit?(node: HTMLElement): any;
/**
* Callback fired as the component begins to transition out
*/
onExiting?(node: HTMLElement): any;
/**
* Callback fired after the component finishes transitioning out
*/
onExited?(node: HTMLElement): any;
onExiting?(node: HTMLElement): any;
}

@@ -31,0 +49,0 @@ export interface TransitionProps extends TransitionCallbacks {

{
"name": "@restart/ui",
"version": "0.0.4",
"version": "0.0.5",
"description": "Utilities for creating robust overlay components",

@@ -5,0 +5,0 @@ "author": {

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