@mezzanine-ui/react 1.0.0-rc.5 → 1.0.0-rc.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Accordion/Accordion.d.ts +36 -0
- package/Accordion/Accordion.js +37 -1
- package/AlertBanner/AlertBanner.d.ts +30 -1
- package/AlertBanner/AlertBanner.js +56 -12
- package/AutoComplete/AutoComplete.d.ts +75 -11
- package/AutoComplete/AutoComplete.js +145 -25
- package/AutoComplete/AutoCompleteInside.d.ts +54 -0
- package/AutoComplete/AutoCompleteInside.js +17 -0
- package/AutoComplete/useAutoCompleteKeyboard.d.ts +2 -1
- package/AutoComplete/useAutoCompleteKeyboard.js +4 -1
- package/Backdrop/Backdrop.d.ts +33 -1
- package/Backdrop/Backdrop.js +33 -1
- package/Badge/Badge.d.ts +26 -1
- package/Badge/Badge.js +26 -1
- package/Badge/typings.d.ts +15 -0
- package/Breadcrumb/BreadcrumbDropdown.d.ts +1 -1
- package/Breadcrumb/BreadcrumbOverflowMenuDropdown.d.ts +1 -1
- package/Breadcrumb/typings.d.ts +1 -1
- package/Button/Button.d.ts +26 -1
- package/Button/Button.js +33 -5
- package/COMPONENTS.md +267 -0
- package/Calendar/useCalendarControls.d.ts +18 -0
- package/Calendar/useCalendarControls.js +18 -0
- package/Card/FourThumbnailCard.js +1 -1
- package/Card/SingleThumbnailCard.js +1 -1
- package/Checkbox/Checkbox.d.ts +30 -1
- package/Checkbox/Checkbox.js +54 -4
- package/Checkbox/CheckboxGroup.d.ts +39 -1
- package/Checkbox/CheckboxGroup.js +49 -3
- package/Cropper/Cropper.d.ts +2 -2
- package/Cropper/Cropper.js +2 -3
- package/Cropper/CropperElement.js +1 -1
- package/Cropper/utils/cropper-calculations.d.ts +1 -1
- package/Cropper/utils/cropper-calculations.js +16 -14
- package/DatePicker/DatePicker.d.ts +36 -2
- package/DatePicker/DatePicker.js +36 -2
- package/DateRangePicker/useDateRangePickerValue.d.ts +24 -0
- package/DateRangePicker/useDateRangePickerValue.js +24 -0
- package/Description/Description.d.ts +1 -1
- package/Description/Description.js +1 -1
- package/Description/DescriptionTitle.d.ts +6 -1
- package/Description/DescriptionTitle.js +2 -2
- package/Drawer/Drawer.d.ts +78 -33
- package/Drawer/Drawer.js +72 -34
- package/Dropdown/Dropdown.d.ts +63 -1
- package/Dropdown/Dropdown.js +203 -9
- package/Dropdown/DropdownItem.d.ts +26 -2
- package/Dropdown/DropdownItem.js +91 -43
- package/Dropdown/DropdownItemCard.d.ts +3 -2
- package/Dropdown/DropdownItemCard.js +8 -5
- package/Dropdown/DropdownStatus.d.ts +2 -2
- package/Dropdown/DropdownStatus.js +3 -2
- package/Dropdown/dropdownKeydownHandler.d.ts +6 -0
- package/Dropdown/dropdownKeydownHandler.js +14 -7
- package/Empty/icons/EmptyMainInitialDataIcon.js +1 -1
- package/Empty/icons/EmptyMainNotificationIcon.js +1 -1
- package/Empty/icons/EmptyMainResultIcon.js +1 -1
- package/Empty/icons/EmptyMainSystemIcon.js +1 -1
- package/FilterArea/Filter.d.ts +25 -2
- package/FilterArea/Filter.js +43 -2
- package/FilterArea/FilterArea.d.ts +43 -4
- package/FilterArea/FilterArea.js +39 -4
- package/FilterArea/FilterAreaContext.d.ts +6 -0
- package/FilterArea/FilterAreaContext.js +6 -0
- package/FilterArea/FilterLine.d.ts +19 -0
- package/FilterArea/FilterLine.js +19 -0
- package/FilterArea/index.d.ts +2 -2
- package/FilterArea/index.js +1 -1
- package/Form/FormField.d.ts +43 -2
- package/Form/FormField.js +40 -3
- package/Form/typings.d.ts +2 -0
- package/Form/useAutoCompleteValueControl.d.ts +20 -0
- package/Form/useAutoCompleteValueControl.js +20 -0
- package/Form/useCheckboxControlValue.d.ts +19 -0
- package/Form/useCheckboxControlValue.js +19 -0
- package/Form/useControlValueState.d.ts +16 -0
- package/Form/useControlValueState.js +16 -0
- package/Form/useCustomControlValue.d.ts +17 -0
- package/Form/useCustomControlValue.js +17 -0
- package/Form/useInputControlValue.d.ts +19 -0
- package/Form/useInputControlValue.js +19 -0
- package/Form/useInputWithClearControlValue.d.ts +20 -0
- package/Form/useInputWithClearControlValue.js +20 -0
- package/Form/useRadioControlValue.d.ts +19 -0
- package/Form/useRadioControlValue.js +19 -0
- package/Form/useSelectValueControl.d.ts +19 -0
- package/Form/useSelectValueControl.js +19 -0
- package/Form/useSwitchControlValue.d.ts +18 -0
- package/Form/useSwitchControlValue.js +18 -0
- package/Icon/Icon.d.ts +23 -1
- package/Icon/Icon.js +23 -1
- package/Input/Input.d.ts +31 -1
- package/Input/Input.js +31 -1
- package/Input/SpinnerButton/SpinnerButton.js +1 -1
- package/Message/Message.d.ts +56 -6
- package/Message/Message.js +59 -52
- package/Modal/Modal.d.ts +76 -4
- package/Modal/Modal.js +117 -6
- package/Modal/ModalBodyForVerification.js +3 -1
- package/Modal/ModalFooter.d.ts +21 -6
- package/Modal/ModalHeader.d.ts +50 -11
- package/Modal/ModalHeader.js +1 -1
- package/Modal/index.d.ts +1 -1
- package/Navigation/Navigation.js +20 -11
- package/Navigation/NavigationHeader.js +2 -1
- package/Navigation/NavigationIconButton.d.ts +8 -0
- package/Navigation/NavigationIconButton.js +2 -2
- package/Navigation/NavigationOption.js +6 -3
- package/Navigation/NavigationOverflowMenu.js +9 -6
- package/Navigation/NavigationUserMenu.js +3 -1
- package/Navigation/context.d.ts +1 -0
- package/NotificationCenter/NotificationCenter.d.ts +59 -9
- package/NotificationCenter/NotificationCenter.js +150 -54
- package/NotificationCenter/NotificationCenterDrawer.d.ts +56 -6
- package/NotificationCenter/NotificationCenterDrawer.js +6 -8
- package/NotificationCenter/index.d.ts +1 -1
- package/OverflowTooltip/OverflowTooltip.js +46 -5
- package/PageFooter/PageFooter.d.ts +1 -1
- package/PageFooter/PageFooter.js +8 -16
- package/Pagination/Pagination.d.ts +38 -1
- package/Pagination/Pagination.js +38 -1
- package/Pagination/PaginationPageSize.js +1 -1
- package/Pagination/usePagination.d.ts +20 -0
- package/Pagination/usePagination.js +20 -0
- package/Progress/Progress.d.ts +24 -1
- package/Progress/Progress.js +24 -1
- package/README.md +82 -0
- package/Radio/Radio.d.ts +35 -1
- package/Radio/Radio.js +50 -12
- package/Radio/RadioGroup.d.ts +2 -2
- package/Radio/RadioGroupContext.d.ts +3 -2
- package/Section/SectionGroup.d.ts +20 -0
- package/Section/SectionGroup.js +16 -0
- package/Section/index.d.ts +2 -0
- package/Section/index.js +1 -0
- package/Select/Select.d.ts +55 -1
- package/Select/Select.js +37 -2
- package/Select/typings.d.ts +9 -0
- package/{Selection/Selection.d.ts → SelectionCard/SelectionCard.d.ts} +23 -11
- package/{Selection/Selection.js → SelectionCard/SelectionCard.js} +14 -14
- package/SelectionCard/SelectionCardGroup.d.ts +28 -0
- package/SelectionCard/index.d.ts +12 -0
- package/SelectionCard/index.js +5 -0
- package/Separator/Separator.d.ts +19 -1
- package/Separator/Separator.js +19 -1
- package/Slider/Slider.d.ts +11 -0
- package/Slider/useSlider.d.ts +21 -0
- package/Spin/Spin.d.ts +14 -5
- package/Spin/Spin.js +6 -8
- package/Stepper/Stepper.d.ts +34 -1
- package/Stepper/Stepper.js +34 -1
- package/Stepper/useStepper.d.ts +18 -0
- package/Stepper/useStepper.js +18 -0
- package/Tab/Tab.d.ts +33 -1
- package/Tab/Tab.js +33 -1
- package/Table/Table.d.ts +51 -3
- package/Table/Table.js +52 -4
- package/Table/hooks/useTableDataSource.d.ts +4 -4
- package/Table/hooks/useTableDataSource.js +1 -1
- package/Tag/Tag.d.ts +27 -1
- package/Tag/Tag.js +27 -1
- package/Tag/typings.d.ts +28 -0
- package/Textarea/Textarea.d.ts +28 -1
- package/Textarea/Textarea.js +25 -1
- package/TimePicker/TimePicker.js +1 -1
- package/TimeRangePicker/TimeRangePicker.js +1 -1
- package/Toggle/Toggle.d.ts +34 -1
- package/Toggle/Toggle.js +34 -1
- package/Tooltip/Tooltip.d.ts +39 -1
- package/Tooltip/Tooltip.js +39 -1
- package/Tooltip/useDelayMouseEnterLeave.d.ts +17 -0
- package/Tooltip/useDelayMouseEnterLeave.js +17 -0
- package/Typography/Typography.d.ts +23 -1
- package/Typography/Typography.js +23 -1
- package/Upload/Upload.d.ts +13 -7
- package/Upload/Upload.js +55 -20
- package/Upload/UploadItem.d.ts +3 -3
- package/Upload/UploadItem.js +11 -8
- package/Upload/UploadPictureCard.d.ts +5 -0
- package/Upload/UploadPictureCard.js +10 -6
- package/Upload/Uploader.d.ts +32 -31
- package/Upload/Uploader.js +10 -9
- package/hooks/useClickAway.d.ts +16 -0
- package/hooks/useClickAway.js +16 -0
- package/hooks/useComposeRefs.d.ts +15 -0
- package/hooks/useComposeRefs.js +15 -0
- package/hooks/useDocumentEscapeKeyDown.d.ts +15 -0
- package/hooks/useDocumentEscapeKeyDown.js +15 -0
- package/hooks/useDocumentEvents.d.ts +16 -0
- package/hooks/useDocumentEvents.js +16 -0
- package/hooks/useDocumentTabKeyDown.d.ts +15 -0
- package/hooks/useDocumentTabKeyDown.js +15 -0
- package/hooks/useIsomorphicLayoutEffect.d.ts +16 -0
- package/hooks/useIsomorphicLayoutEffect.js +16 -0
- package/hooks/useLastCallback.d.ts +15 -0
- package/hooks/useLastCallback.js +15 -0
- package/hooks/useLastValue.d.ts +18 -0
- package/hooks/useLastValue.js +18 -0
- package/hooks/usePreviousValue.d.ts +14 -0
- package/hooks/usePreviousValue.js +14 -0
- package/hooks/useScrollLock.d.ts +6 -4
- package/hooks/useScrollLock.js +6 -4
- package/hooks/useTopStack.d.ts +17 -0
- package/hooks/useTopStack.js +17 -0
- package/hooks/useWindowWidth.d.ts +14 -0
- package/hooks/useWindowWidth.js +14 -0
- package/index.d.ts +6 -4
- package/index.js +3 -2
- package/llms.txt +200 -0
- package/package.json +5 -4
- package/Selection/SelectionGroup.d.ts +0 -28
- package/Selection/index.d.ts +0 -12
- package/Selection/index.js +0 -5
package/Upload/Uploader.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChangeEventHandler, ReactNode, Ref } from 'react';
|
|
2
|
-
import { type UploaderHintType, type UploadPictureControl, type UploadType } from '@mezzanine-ui/core/upload';
|
|
2
|
+
import { type UploaderHintType, type UploaderMode, type UploadPictureControl, type UploadType } from '@mezzanine-ui/core/upload';
|
|
3
3
|
import { type IconDefinition } from '@mezzanine-ui/icons';
|
|
4
4
|
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
5
5
|
type UploaderInputElementProps = Omit<NativeElementPropsWithoutKeyAndRef<'input'>, 'accept' | 'disabled' | 'multiple' | 'onChange' | 'type' | `aria-${'disabled'}`> & {
|
|
@@ -42,7 +42,7 @@ export interface UploaderLabel {
|
|
|
42
42
|
*/
|
|
43
43
|
error?: string;
|
|
44
44
|
/**
|
|
45
|
-
* Label text for "Click to upload"
|
|
45
|
+
* Label text for "Click to upload" in `mode="dropzone"`.
|
|
46
46
|
* @default 'Click to upload'
|
|
47
47
|
*/
|
|
48
48
|
clickToUpload?: string;
|
|
@@ -87,20 +87,31 @@ export interface UploaderProps extends Omit<NativeElementPropsWithoutKeyAndRef<'
|
|
|
87
87
|
* @example 'image/*', '.pdf,.doc,.docx'
|
|
88
88
|
*/
|
|
89
89
|
accept?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Provide `controllerRef` if you need detail data of file.
|
|
92
|
+
*/
|
|
93
|
+
controllerRef?: Ref<UploadPictureControl | null>;
|
|
90
94
|
/**
|
|
91
95
|
* Whether the input is disabled.
|
|
92
96
|
* @default false
|
|
93
97
|
*/
|
|
94
98
|
disabled?: boolean;
|
|
95
99
|
/**
|
|
96
|
-
*
|
|
100
|
+
* Array of hints to display outside the uploader (below the label element).
|
|
97
101
|
*/
|
|
98
|
-
|
|
102
|
+
externalHints?: UploaderHint[];
|
|
99
103
|
/**
|
|
100
|
-
*
|
|
101
|
-
|
|
104
|
+
* Array of hints to display with the upload component.
|
|
105
|
+
*/
|
|
106
|
+
hints?: UploaderHint[];
|
|
107
|
+
/**
|
|
108
|
+
* Icon configuration for different actions and states.
|
|
102
109
|
*/
|
|
103
|
-
|
|
110
|
+
icon?: UploaderIcon;
|
|
111
|
+
/**
|
|
112
|
+
* The id of input element.
|
|
113
|
+
*/
|
|
114
|
+
id?: string;
|
|
104
115
|
/**
|
|
105
116
|
* Since at Mezzanine we use a host element to wrap our input, most derived props will be passed to the host element.
|
|
106
117
|
* If you need direct control to the input element, use this prop to provide to it.
|
|
@@ -110,37 +121,25 @@ export interface UploaderProps extends Omit<NativeElementPropsWithoutKeyAndRef<'
|
|
|
110
121
|
* The react ref passed to input element.
|
|
111
122
|
*/
|
|
112
123
|
inputRef?: React.Ref<HTMLInputElement>;
|
|
124
|
+
/**
|
|
125
|
+
* Label configuration for different states.
|
|
126
|
+
*/
|
|
127
|
+
label?: UploaderLabel;
|
|
113
128
|
/**
|
|
114
129
|
* The name attribute of the input element.
|
|
115
130
|
*/
|
|
116
131
|
name?: string;
|
|
132
|
+
/**
|
|
133
|
+
* The mode for upload component.
|
|
134
|
+
* @default 'basic'
|
|
135
|
+
* @example 'basic' | 'dropzone'
|
|
136
|
+
*/
|
|
137
|
+
mode?: UploaderMode;
|
|
117
138
|
/**
|
|
118
139
|
* Whether can select multiple files to upload.
|
|
119
140
|
* @default false
|
|
120
141
|
*/
|
|
121
142
|
multiple?: boolean;
|
|
122
|
-
/**
|
|
123
|
-
* The type for upload component.
|
|
124
|
-
* @default 'base'
|
|
125
|
-
* @example 'base' | 'button'
|
|
126
|
-
*/
|
|
127
|
-
type?: UploadType;
|
|
128
|
-
/**
|
|
129
|
-
* Array of hints to display with the upload component.
|
|
130
|
-
*/
|
|
131
|
-
hints?: UploaderHint[];
|
|
132
|
-
/**
|
|
133
|
-
* Label configuration for different states.
|
|
134
|
-
*/
|
|
135
|
-
label?: UploaderLabel;
|
|
136
|
-
/**
|
|
137
|
-
* Icon configuration for different actions and states.
|
|
138
|
-
*/
|
|
139
|
-
icon?: UploaderIcon;
|
|
140
|
-
/**
|
|
141
|
-
* Provide `controllerRef` if you need detail data of file.
|
|
142
|
-
*/
|
|
143
|
-
controllerRef?: Ref<UploadPictureControl | null>;
|
|
144
143
|
/**
|
|
145
144
|
* Invoked by input change event.
|
|
146
145
|
*/
|
|
@@ -150,9 +149,11 @@ export interface UploaderProps extends Omit<NativeElementPropsWithoutKeyAndRef<'
|
|
|
150
149
|
*/
|
|
151
150
|
onUpload?: (files: File[]) => void;
|
|
152
151
|
/**
|
|
153
|
-
*
|
|
152
|
+
* The type for upload component.
|
|
153
|
+
* @default 'base'
|
|
154
|
+
* @example 'base' | 'button'
|
|
154
155
|
*/
|
|
155
|
-
|
|
156
|
+
type?: UploadType;
|
|
156
157
|
}
|
|
157
158
|
/**
|
|
158
159
|
* The react component for `mezzanine` uploader.
|
package/Upload/Uploader.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { forwardRef, useId, useRef, useState, useMemo } from 'react';
|
|
4
4
|
import { uploaderClasses } from '@mezzanine-ui/core/upload';
|
|
5
|
-
import { UploadIcon } from '@mezzanine-ui/icons';
|
|
5
|
+
import { UploadIcon, InfoFilledIcon, DangerousFilledIcon } from '@mezzanine-ui/icons';
|
|
6
6
|
import Button from '../Button/Button.js';
|
|
7
7
|
import Typography from '../Typography/Typography.js';
|
|
8
8
|
import { composeRefs } from '../utils/composeRefs.js';
|
|
@@ -14,7 +14,7 @@ import cx from 'clsx';
|
|
|
14
14
|
*/
|
|
15
15
|
const Uploader = forwardRef(function Uploader(props, ref) {
|
|
16
16
|
var _a, _b, _c;
|
|
17
|
-
const { accept, className, disabled = false, id, inputProps, inputRef: inputRefProp,
|
|
17
|
+
const { accept, className, controllerRef: _controllerRef, disabled = false, externalHints, id, hints, icon: iconConfig, inputProps, inputRef: inputRefProp, label: labelConfig, mode = 'basic', multiple = false, name, onChange: onChangeProp, onUpload, type, ...rest } = props;
|
|
18
18
|
const { name: nameFromInputProps, id: idFromInputProps, ...restInputProps } = inputProps || {};
|
|
19
19
|
// Generate unique id if not provided
|
|
20
20
|
const generatedId = useId();
|
|
@@ -23,6 +23,7 @@ const Uploader = forwardRef(function Uploader(props, ref) {
|
|
|
23
23
|
const [isDragging, setIsDragging] = useState(false);
|
|
24
24
|
const composedInputRef = useMemo(() => composeRefs([inputRefProp, inputElementRef]), [inputRefProp]);
|
|
25
25
|
const resolvedName = (_b = name !== null && name !== void 0 ? name : nameFromInputProps) !== null && _b !== void 0 ? _b : finalInputId;
|
|
26
|
+
const isDropzone = mode === 'dropzone';
|
|
26
27
|
const handleChange = (event) => {
|
|
27
28
|
if (onChangeProp) {
|
|
28
29
|
onChangeProp(event);
|
|
@@ -98,7 +99,7 @@ const Uploader = forwardRef(function Uploader(props, ref) {
|
|
|
98
99
|
}, [iconConfig]);
|
|
99
100
|
const uploadLabel = (labelConfig === null || labelConfig === void 0 ? void 0 : labelConfig.uploadLabel)
|
|
100
101
|
? labelConfig === null || labelConfig === void 0 ? void 0 : labelConfig.uploadLabel
|
|
101
|
-
:
|
|
102
|
+
: isDropzone
|
|
102
103
|
? 'Drag the file here or'
|
|
103
104
|
: 'Upload';
|
|
104
105
|
const clickToUploadLabel = (_c = labelConfig === null || labelConfig === void 0 ? void 0 : labelConfig.clickToUpload) !== null && _c !== void 0 ? _c : 'Click to upload';
|
|
@@ -109,12 +110,12 @@ const Uploader = forwardRef(function Uploader(props, ref) {
|
|
|
109
110
|
inputElementRef.current.click();
|
|
110
111
|
}
|
|
111
112
|
};
|
|
112
|
-
return (jsx("label", { className: cx(uploaderClasses.host, type && uploaderClasses.type(type), type !== 'button' &&
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
return (jsxs(Fragment, { children: [jsx("label", { className: cx(uploaderClasses.host, type && uploaderClasses.type(type), type !== 'button' && isDropzone && uploaderClasses.fillWidth, isDragging && uploaderClasses.dragging, type !== 'button' && disabled && uploaderClasses.disabled, className), onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, ref: ref, ...rest, children: jsxs(Fragment, { children: [type === 'base'
|
|
114
|
+
&& isDropzone
|
|
115
|
+
&& jsxs("div", { className: uploaderClasses.uploadContent, children: [uploadIcon, jsxs(Typography, { className: uploaderClasses.uploadLabel, children: [uploadLabel && jsxs(Fragment, { children: [uploadLabel, ' '] }), jsx("span", { className: uploaderClasses.clickToUpload, children: clickToUploadLabel })] }), hints === null || hints === void 0 ? void 0 : hints.map((hint, index) => (jsx(Typography, { className: uploaderClasses.fillWidthHints, children: hint.label }, index)))] }), type === 'base'
|
|
116
|
+
&& !isDropzone
|
|
117
|
+
&& jsxs("div", { className: uploaderClasses.uploadContent, children: [uploadIcon, jsx(Typography, { className: uploaderClasses.uploadLabel, children: uploadLabel })] }), type === 'button'
|
|
118
|
+
&& (jsx(Button, { disabled: disabled, iconType: "leading", icon: UploadIcon, onClick: handleClickToUpload, children: jsx(Typography, { align: "center", color: "text-fixed-light", variant: "button-highlight", className: uploaderClasses.uploadButtonText, children: uploadLabel }) })), jsx("input", { ...restInputProps, accept: accept, "aria-disabled": disabled, className: uploaderClasses.input, disabled: disabled, id: finalInputId, multiple: multiple, name: resolvedName, onChange: handleChange, ref: composedInputRef, type: "file" })] }) }), externalHints && externalHints.length > 0 && (jsx("ul", { className: uploaderClasses.externalHints, children: externalHints.map((hint) => (jsxs("li", { className: uploaderClasses.externalHint(hint.type || 'info'), children: [jsx(Icon, { icon: hint.type === 'info' ? InfoFilledIcon : DangerousFilledIcon, color: hint.type === 'info' ? 'info' : 'error', size: 14 }), hint.label] }, hint.label))) }))] }));
|
|
118
119
|
});
|
|
119
120
|
|
|
120
121
|
export { Uploader as default };
|
package/hooks/useClickAway.d.ts
CHANGED
|
@@ -2,4 +2,20 @@ import { RefObject, DependencyList } from 'react';
|
|
|
2
2
|
export type ClickAwayEvent = MouseEvent | TouchEvent | PointerEvent;
|
|
3
3
|
export type ClickAwayHandler = (event: ClickAwayEvent) => void;
|
|
4
4
|
export type ClickAwayHandlerFactory = () => ClickAwayHandler | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* 偵測點擊發生在指定容器外部的 Hook。
|
|
7
|
+
*
|
|
8
|
+
* 監聽 `click` 與 `touchend` 事件,當點擊目標不在 `containerRef` 的 DOM 節點內時,
|
|
9
|
+
* 呼叫 `factory` 回傳的處理器;若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { useClickAway } from '@mezzanine-ui/react';
|
|
14
|
+
*
|
|
15
|
+
* const containerRef = useRef<HTMLDivElement>(null);
|
|
16
|
+
* useClickAway(() => {
|
|
17
|
+
* if (open) return () => setOpen(false);
|
|
18
|
+
* }, containerRef, [open]);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
5
21
|
export declare function useClickAway(factory: ClickAwayHandlerFactory, containerRef: RefObject<HTMLElement | null>, deps?: DependencyList): void;
|
package/hooks/useClickAway.js
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { useDocumentEvents } from './useDocumentEvents.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 偵測點擊發生在指定容器外部的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 監聽 `click` 與 `touchend` 事件,當點擊目標不在 `containerRef` 的 DOM 節點內時,
|
|
7
|
+
* 呼叫 `factory` 回傳的處理器;若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useClickAway } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* const containerRef = useRef<HTMLDivElement>(null);
|
|
14
|
+
* useClickAway(() => {
|
|
15
|
+
* if (open) return () => setOpen(false);
|
|
16
|
+
* }, containerRef, [open]);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
3
19
|
function useClickAway(factory, containerRef, deps) {
|
|
4
20
|
useDocumentEvents(() => {
|
|
5
21
|
const clickAwayHandler = factory();
|
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
import { ComposableRef, ComposedRef } from '../utils/composeRefs';
|
|
2
|
+
/**
|
|
3
|
+
* 將多個 React ref 合併成單一 callback ref 的 Hook。
|
|
4
|
+
*
|
|
5
|
+
* 回傳一個穩定的 callback ref(依賴陣列永遠為空),
|
|
6
|
+
* 每次渲染時仍能正確呼叫最新的 ref 集合,適用於需要同時傳遞 forwardRef 與內部 ref 的情境。
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { useComposeRefs } from '@mezzanine-ui/react';
|
|
11
|
+
*
|
|
12
|
+
* const internalRef = useRef<HTMLDivElement>(null);
|
|
13
|
+
* const composedRef = useComposeRefs([internalRef, forwardedRef]);
|
|
14
|
+
* return <div ref={composedRef} />;
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
2
17
|
export declare function useComposeRefs<T>(refs: ComposableRef<T>[]): ComposedRef<T>;
|
package/hooks/useComposeRefs.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { useRef, useCallback } from 'react';
|
|
2
2
|
import { composeRefs } from '../utils/composeRefs.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 將多個 React ref 合併成單一 callback ref 的 Hook。
|
|
6
|
+
*
|
|
7
|
+
* 回傳一個穩定的 callback ref(依賴陣列永遠為空),
|
|
8
|
+
* 每次渲染時仍能正確呼叫最新的 ref 集合,適用於需要同時傳遞 forwardRef 與內部 ref 的情境。
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { useComposeRefs } from '@mezzanine-ui/react';
|
|
13
|
+
*
|
|
14
|
+
* const internalRef = useRef<HTMLDivElement>(null);
|
|
15
|
+
* const composedRef = useComposeRefs([internalRef, forwardedRef]);
|
|
16
|
+
* return <div ref={composedRef} />;
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
4
19
|
function useComposeRefs(refs) {
|
|
5
20
|
const refsRef = useRef(refs);
|
|
6
21
|
refsRef.current = refs;
|
|
@@ -1,3 +1,18 @@
|
|
|
1
1
|
import { DependencyList } from 'react';
|
|
2
2
|
export type DocumentEscapeKeyDownHandlerFactory = () => ((event: KeyboardEvent) => void) | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* 在 document 上監聽 Escape 鍵按下事件的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 當鍵盤觸發 `keydown` 且 `event.key === 'Escape'` 時,呼叫 `factory` 回傳的處理器並阻止預設行為;
|
|
7
|
+
* 若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useDocumentEscapeKeyDown } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* useDocumentEscapeKeyDown(() => {
|
|
14
|
+
* if (open) return () => setOpen(false);
|
|
15
|
+
* }, [open]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
3
18
|
export declare function useDocumentEscapeKeyDown(factory: DocumentEscapeKeyDownHandlerFactory, deps?: DependencyList): void;
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { useDocumentEvents } from './useDocumentEvents.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 在 document 上監聽 Escape 鍵按下事件的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 當鍵盤觸發 `keydown` 且 `event.key === 'Escape'` 時,呼叫 `factory` 回傳的處理器並阻止預設行為;
|
|
7
|
+
* 若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useDocumentEscapeKeyDown } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* useDocumentEscapeKeyDown(() => {
|
|
14
|
+
* if (open) return () => setOpen(false);
|
|
15
|
+
* }, [open]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
3
18
|
function useDocumentEscapeKeyDown(factory, deps) {
|
|
4
19
|
useDocumentEvents(() => {
|
|
5
20
|
const handler = factory();
|
|
@@ -2,4 +2,20 @@ import { DependencyList } from 'react';
|
|
|
2
2
|
export type DocumentEventHandlersFactory = () => {
|
|
3
3
|
[event in keyof DocumentEventMap]?: (event: DocumentEventMap[event]) => void;
|
|
4
4
|
} | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* 在 document 上批次註冊/移除事件監聽器的 Hook。
|
|
7
|
+
*
|
|
8
|
+
* `factory` 回傳一個事件名稱到處理器的映射物件;依賴項變化時舊監聽器會先被移除,
|
|
9
|
+
* 再重新掛載新的;若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { useDocumentEvents } from '@mezzanine-ui/react';
|
|
14
|
+
*
|
|
15
|
+
* useDocumentEvents(() => ({
|
|
16
|
+
* click: handleClick,
|
|
17
|
+
* keydown: handleKeyDown,
|
|
18
|
+
* }), [handleClick, handleKeyDown]);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
5
21
|
export declare function useDocumentEvents(factory: DocumentEventHandlersFactory, deps?: DependencyList): void;
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 在 document 上批次註冊/移除事件監聽器的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* `factory` 回傳一個事件名稱到處理器的映射物件;依賴項變化時舊監聽器會先被移除,
|
|
7
|
+
* 再重新掛載新的;若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useDocumentEvents } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* useDocumentEvents(() => ({
|
|
14
|
+
* click: handleClick,
|
|
15
|
+
* keydown: handleKeyDown,
|
|
16
|
+
* }), [handleClick, handleKeyDown]);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
3
19
|
function useDocumentEvents(factory, deps) {
|
|
4
20
|
useIsomorphicLayoutEffect(() => {
|
|
5
21
|
const handlers = factory();
|
|
@@ -1,3 +1,18 @@
|
|
|
1
1
|
import { DependencyList } from 'react';
|
|
2
2
|
export type DocumentTabKeyDownHandlerFactory = () => ((event: KeyboardEvent) => void) | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* 在 document 上監聽 Tab 鍵按下事件的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 當鍵盤觸發 `keydown` 且 `event.key === 'Tab'` 時,呼叫 `factory` 回傳的處理器;
|
|
7
|
+
* 若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useDocumentTabKeyDown } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* useDocumentTabKeyDown(() => {
|
|
14
|
+
* if (open) return (e) => trapFocus(e);
|
|
15
|
+
* }, [open]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
3
18
|
export declare function useDocumentTabKeyDown(factory: DocumentTabKeyDownHandlerFactory, deps?: DependencyList): void;
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { useDocumentEvents } from './useDocumentEvents.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 在 document 上監聽 Tab 鍵按下事件的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 當鍵盤觸發 `keydown` 且 `event.key === 'Tab'` 時,呼叫 `factory` 回傳的處理器;
|
|
7
|
+
* 若 `factory` 回傳 `undefined` 則不掛載任何監聽器。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useDocumentTabKeyDown } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* useDocumentTabKeyDown(() => {
|
|
14
|
+
* if (open) return (e) => trapFocus(e);
|
|
15
|
+
* }, [open]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
3
18
|
function useDocumentTabKeyDown(factory, deps) {
|
|
4
19
|
useDocumentEvents(() => {
|
|
5
20
|
const handler = factory();
|
|
@@ -1,2 +1,18 @@
|
|
|
1
1
|
import { useLayoutEffect } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* 在瀏覽器環境使用 `useLayoutEffect`、在 SSR 環境降級為 `useEffect` 的 Hook。
|
|
4
|
+
*
|
|
5
|
+
* 用於需要在 DOM 繪製前同步執行副作用的場景(例如讀取 layout 資訊),
|
|
6
|
+
* 同時避免伺服器端渲染時因 `useLayoutEffect` 產生警告。
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { useIsomorphicLayoutEffect } from '@mezzanine-ui/react';
|
|
11
|
+
*
|
|
12
|
+
* useIsomorphicLayoutEffect(() => {
|
|
13
|
+
* // 在 DOM 更新後、繪製前同步執行
|
|
14
|
+
* measureElement();
|
|
15
|
+
* }, [deps]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
2
18
|
export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { useLayoutEffect, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 在瀏覽器環境使用 `useLayoutEffect`、在 SSR 環境降級為 `useEffect` 的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 用於需要在 DOM 繪製前同步執行副作用的場景(例如讀取 layout 資訊),
|
|
7
|
+
* 同時避免伺服器端渲染時因 `useLayoutEffect` 產生警告。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useIsomorphicLayoutEffect } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* useIsomorphicLayoutEffect(() => {
|
|
14
|
+
* // 在 DOM 更新後、繪製前同步執行
|
|
15
|
+
* measureElement();
|
|
16
|
+
* }, [deps]);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
3
19
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' &&
|
|
4
20
|
window.document &&
|
|
5
21
|
!!window.document.createElement
|
|
@@ -1 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 回傳一個引用永遠穩定但呼叫時使用最新版本 callback 的 Hook。
|
|
3
|
+
*
|
|
4
|
+
* 內部以 ref 儲存最新的 callback,對外回傳一個依賴陣列為空的 `useCallback` wrapper,
|
|
5
|
+
* 可安全地傳遞給子元件或事件處理器而不觸發不必要的 re-render。
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useLastCallback } from '@mezzanine-ui/react';
|
|
10
|
+
*
|
|
11
|
+
* const stableOnChange = useLastCallback((value: string) => {
|
|
12
|
+
* doSomethingWith(value);
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
1
16
|
export declare function useLastCallback<F extends (...args: any[]) => any>(callback: F): (...args: Parameters<F>) => ReturnType<F>;
|
package/hooks/useLastCallback.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { useLastValue } from './useLastValue.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 回傳一個引用永遠穩定但呼叫時使用最新版本 callback 的 Hook。
|
|
6
|
+
*
|
|
7
|
+
* 內部以 ref 儲存最新的 callback,對外回傳一個依賴陣列為空的 `useCallback` wrapper,
|
|
8
|
+
* 可安全地傳遞給子元件或事件處理器而不觸發不必要的 re-render。
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { useLastCallback } from '@mezzanine-ui/react';
|
|
13
|
+
*
|
|
14
|
+
* const stableOnChange = useLastCallback((value: string) => {
|
|
15
|
+
* doSomethingWith(value);
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
4
19
|
function useLastCallback(callback) {
|
|
5
20
|
const lastCallback = useLastValue(callback);
|
|
6
21
|
return useCallback(
|
package/hooks/useLastValue.d.ts
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 追蹤並回傳最新值的 ref Hook。
|
|
3
|
+
*
|
|
4
|
+
* 每次渲染時同步更新 ref 的 `current` 屬性,
|
|
5
|
+
* 可用於在非同步回調或 effect 中存取最新的 prop 或 state,而無需將其加入依賴陣列。
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useLastValue } from '@mezzanine-ui/react';
|
|
10
|
+
*
|
|
11
|
+
* const latestCount = useLastValue(count);
|
|
12
|
+
* useEffect(() => {
|
|
13
|
+
* setTimeout(() => {
|
|
14
|
+
* console.log(latestCount.current); // 總是最新的值
|
|
15
|
+
* }, 1000);
|
|
16
|
+
* }, []);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
1
19
|
export declare function useLastValue<T>(value: T): {
|
|
2
20
|
readonly current: T;
|
|
3
21
|
};
|
package/hooks/useLastValue.js
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import { useRef } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 追蹤並回傳最新值的 ref Hook。
|
|
5
|
+
*
|
|
6
|
+
* 每次渲染時同步更新 ref 的 `current` 屬性,
|
|
7
|
+
* 可用於在非同步回調或 effect 中存取最新的 prop 或 state,而無需將其加入依賴陣列。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useLastValue } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* const latestCount = useLastValue(count);
|
|
14
|
+
* useEffect(() => {
|
|
15
|
+
* setTimeout(() => {
|
|
16
|
+
* console.log(latestCount.current); // 總是最新的值
|
|
17
|
+
* }, 1000);
|
|
18
|
+
* }, []);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
3
21
|
function useLastValue(value) {
|
|
4
22
|
const ref = useRef(value);
|
|
5
23
|
ref.current = value;
|
|
@@ -1 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 回傳上一次渲染時的值的 Hook。
|
|
3
|
+
*
|
|
4
|
+
* 以 `useEffect` 在渲染完成後更新 ref,因此在本次渲染中取得的是前一次的值,
|
|
5
|
+
* 適用於需要比較前後值差異的情境。
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { usePreviousValue } from '@mezzanine-ui/react';
|
|
10
|
+
*
|
|
11
|
+
* const previousCount = usePreviousValue(count);
|
|
12
|
+
* // previousCount 為 count 上一次渲染的值
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
1
15
|
export declare function usePreviousValue<T>(value: T): T;
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { useRef, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 回傳上一次渲染時的值的 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 以 `useEffect` 在渲染完成後更新 ref,因此在本次渲染中取得的是前一次的值,
|
|
7
|
+
* 適用於需要比較前後值差異的情境。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { usePreviousValue } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* const previousCount = usePreviousValue(count);
|
|
14
|
+
* // previousCount 為 count 上一次渲染的值
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
3
17
|
function usePreviousValue(value) {
|
|
4
18
|
const ref = useRef(value);
|
|
5
19
|
useEffect(() => {
|
package/hooks/useScrollLock.d.ts
CHANGED
|
@@ -11,13 +11,15 @@ interface ScrollLockOptions {
|
|
|
11
11
|
reserveScrollBarGap?: boolean;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* Hook
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* 鎖定/解鎖頁面捲動的 Hook。
|
|
15
|
+
*
|
|
16
|
+
* 支援多層巢狀鎖定(nested modals/overlays),保留捲軸寬度以防止版面偏移,
|
|
17
|
+
* 並針對 iOS Safari 的 rubber band scrolling 進行特別處理。
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```tsx
|
|
21
|
+
* import { useScrollLock } from '@mezzanine-ui/react';
|
|
22
|
+
*
|
|
21
23
|
* function Modal({ open }) {
|
|
22
24
|
* useScrollLock({ enabled: open });
|
|
23
25
|
* return <div>...</div>;
|
package/hooks/useScrollLock.js
CHANGED
|
@@ -93,13 +93,15 @@ function isIOS() {
|
|
|
93
93
|
return isIOSDevice || isSafariOnMac;
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
|
-
* Hook
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
96
|
+
* 鎖定/解鎖頁面捲動的 Hook。
|
|
97
|
+
*
|
|
98
|
+
* 支援多層巢狀鎖定(nested modals/overlays),保留捲軸寬度以防止版面偏移,
|
|
99
|
+
* 並針對 iOS Safari 的 rubber band scrolling 進行特別處理。
|
|
100
100
|
*
|
|
101
101
|
* @example
|
|
102
102
|
* ```tsx
|
|
103
|
+
* import { useScrollLock } from '@mezzanine-ui/react';
|
|
104
|
+
*
|
|
103
105
|
* function Modal({ open }) {
|
|
104
106
|
* useScrollLock({ enabled: open });
|
|
105
107
|
* return <div>...</div>;
|
package/hooks/useTopStack.d.ts
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 管理多個浮層 z-index 堆疊順序的 Hook。
|
|
3
|
+
*
|
|
4
|
+
* 每個元件呼叫此 Hook 時會取得一個唯一的 seed 值;當 `open` 為 `true` 時,
|
|
5
|
+
* 該 seed 會被推入全域堆疊,回傳的函式可用於查詢自己是否位於最頂層。
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import useTopStack from '@mezzanine-ui/react/hooks/useTopStack';
|
|
10
|
+
*
|
|
11
|
+
* const isTopStack = useTopStack(open);
|
|
12
|
+
* // 在 Escape 鍵處理時,只有最頂層的浮層才關閉
|
|
13
|
+
* useDocumentEscapeKeyDown(() => {
|
|
14
|
+
* if (isTopStack()) return () => setOpen(false);
|
|
15
|
+
* }, [isTopStack]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
1
18
|
export default function useTopStack(open?: boolean): () => boolean;
|
package/hooks/useTopStack.js
CHANGED
|
@@ -2,6 +2,23 @@ import { useMemo, useEffect, useCallback } from 'react';
|
|
|
2
2
|
|
|
3
3
|
let seedStack = [];
|
|
4
4
|
let seed = 1;
|
|
5
|
+
/**
|
|
6
|
+
* 管理多個浮層 z-index 堆疊順序的 Hook。
|
|
7
|
+
*
|
|
8
|
+
* 每個元件呼叫此 Hook 時會取得一個唯一的 seed 值;當 `open` 為 `true` 時,
|
|
9
|
+
* 該 seed 會被推入全域堆疊,回傳的函式可用於查詢自己是否位於最頂層。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import useTopStack from '@mezzanine-ui/react/hooks/useTopStack';
|
|
14
|
+
*
|
|
15
|
+
* const isTopStack = useTopStack(open);
|
|
16
|
+
* // 在 Escape 鍵處理時,只有最頂層的浮層才關閉
|
|
17
|
+
* useDocumentEscapeKeyDown(() => {
|
|
18
|
+
* if (isTopStack()) return () => setOpen(false);
|
|
19
|
+
* }, [isTopStack]);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
5
22
|
function useTopStack(open) {
|
|
6
23
|
const modalSeed = useMemo(() => {
|
|
7
24
|
// eslint-disable-next-line react-hooks/globals
|
|
@@ -1 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 追蹤目前視窗寬度的 Hook。
|
|
3
|
+
*
|
|
4
|
+
* 在元件掛載時以 `window.innerWidth` 初始化,並監聽 `resize` 事件持續更新,
|
|
5
|
+
* 元件卸載時自動移除監聽器。
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useWindowWidth } from '@mezzanine-ui/react';
|
|
10
|
+
*
|
|
11
|
+
* const width = useWindowWidth();
|
|
12
|
+
* const isMobile = width !== undefined && width < 768;
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
1
15
|
export declare function useWindowWidth(): number | undefined;
|