@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
|
@@ -2,6 +2,25 @@ import { useLastCallback } from '../hooks/useLastCallback.js';
|
|
|
2
2
|
import { useControlValueState } from './useControlValueState.js';
|
|
3
3
|
|
|
4
4
|
const equalityFn = (a, b) => a === b;
|
|
5
|
+
/**
|
|
6
|
+
* 管理 Input/Textarea 文字值的受控狀態 Hook。
|
|
7
|
+
*
|
|
8
|
+
* 支援受控(`value`)與非受控(`defaultValue`)兩種用法,
|
|
9
|
+
* 回傳當前文字值與穩定的 `onChange` 事件處理器。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { useInputControlValue } from '@mezzanine-ui/react';
|
|
14
|
+
*
|
|
15
|
+
* function MyInput({ value, onChange }) {
|
|
16
|
+
* const [inputValue, handleChange] = useInputControlValue({ value, onChange });
|
|
17
|
+
* return <input value={inputValue} onChange={handleChange} />;
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @see {@link Input} 搭配的元件
|
|
22
|
+
* @see {@link Textarea} 搭配的元件
|
|
23
|
+
*/
|
|
5
24
|
function useInputControlValue(props) {
|
|
6
25
|
const { defaultValue = '', onChange: onChangeProp, value: valueProp } = props;
|
|
7
26
|
const [value, setValue] = useControlValueState({
|
|
@@ -3,4 +3,24 @@ import { UseInputControlValueProps } from './useInputControlValue';
|
|
|
3
3
|
export interface UseInputWithClearControlValueProps<E extends HTMLInputElement | HTMLTextAreaElement> extends UseInputControlValueProps<E> {
|
|
4
4
|
ref: RefObject<E | null>;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* 為可清除 Input 提供值管理的受控狀態 Hook。
|
|
8
|
+
*
|
|
9
|
+
* 在 `useInputControlValue` 的基礎上額外提供 `onClear` 清除處理器,
|
|
10
|
+
* 透過操作原生 DOM ref 模擬一個值為空字串的 change 事件,確保受控流程完整。
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { useInputWithClearControlValue } from '@mezzanine-ui/react';
|
|
15
|
+
*
|
|
16
|
+
* const inputRef = useRef<HTMLInputElement>(null);
|
|
17
|
+
* const [value, onChange, onClear] = useInputWithClearControlValue({
|
|
18
|
+
* ref: inputRef,
|
|
19
|
+
* value: controlledValue,
|
|
20
|
+
* onChange: handleChange,
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @see {@link Input} 搭配的元件(clearable 變體)
|
|
25
|
+
*/
|
|
6
26
|
export declare function useInputWithClearControlValue<E extends HTMLInputElement | HTMLTextAreaElement>(props: UseInputWithClearControlValueProps<E>): readonly [string, (event: ChangeEvent<E>) => void, (event: MouseEvent) => void];
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { useInputControlValue } from './useInputControlValue.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 為可清除 Input 提供值管理的受控狀態 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 在 `useInputControlValue` 的基礎上額外提供 `onClear` 清除處理器,
|
|
7
|
+
* 透過操作原生 DOM ref 模擬一個值為空字串的 change 事件,確保受控流程完整。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useInputWithClearControlValue } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* const inputRef = useRef<HTMLInputElement>(null);
|
|
14
|
+
* const [value, onChange, onClear] = useInputWithClearControlValue({
|
|
15
|
+
* ref: inputRef,
|
|
16
|
+
* value: controlledValue,
|
|
17
|
+
* onChange: handleChange,
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @see {@link Input} 搭配的元件(clearable 變體)
|
|
22
|
+
*/
|
|
3
23
|
function useInputWithClearControlValue(props) {
|
|
4
24
|
const { defaultValue, onChange: onChangeProp, ref, value: valueProp } = props;
|
|
5
25
|
const [value, onChange] = useInputControlValue({
|
|
@@ -8,4 +8,23 @@ export interface UseRadioControlValueProps extends UseSwitchControlValueProps {
|
|
|
8
8
|
radioGroup?: RadioGroupControlContextValue;
|
|
9
9
|
value?: string;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* 管理 Radio 選取狀態的受控 Hook。
|
|
13
|
+
*
|
|
14
|
+
* 支援獨立使用與在 RadioGroup 內使用兩種情境:
|
|
15
|
+
* 當傳入 `radioGroup` 上下文時,會以群組的 `value` 與本身的 `value` 進行比對來決定是否選中。
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { useRadioControlValue } from '@mezzanine-ui/react';
|
|
20
|
+
*
|
|
21
|
+
* const [checked, handleChange] = useRadioControlValue({
|
|
22
|
+
* value: 'option-a',
|
|
23
|
+
* radioGroup: { value: selectedValue, onChange: handleGroupChange },
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @see {@link Radio} 搭配的元件
|
|
28
|
+
* @see {@link RadioGroup} 搭配的元件
|
|
29
|
+
*/
|
|
11
30
|
export declare function useRadioControlValue(props: UseRadioControlValueProps): readonly [boolean, (event: import("react").ChangeEvent<HTMLInputElement>) => void];
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { useSwitchControlValue } from './useSwitchControlValue.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 管理 Radio 選取狀態的受控 Hook。
|
|
5
|
+
*
|
|
6
|
+
* 支援獨立使用與在 RadioGroup 內使用兩種情境:
|
|
7
|
+
* 當傳入 `radioGroup` 上下文時,會以群組的 `value` 與本身的 `value` 進行比對來決定是否選中。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useRadioControlValue } from '@mezzanine-ui/react';
|
|
12
|
+
*
|
|
13
|
+
* const [checked, handleChange] = useRadioControlValue({
|
|
14
|
+
* value: 'option-a',
|
|
15
|
+
* radioGroup: { value: selectedValue, onChange: handleGroupChange },
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see {@link Radio} 搭配的元件
|
|
20
|
+
* @see {@link RadioGroup} 搭配的元件
|
|
21
|
+
*/
|
|
3
22
|
function useRadioControlValue(props) {
|
|
4
23
|
const { checked: checkedProp, defaultChecked, onChange: onChangeProp, radioGroup, value, } = props;
|
|
5
24
|
const { onChange: onChangeFromGroup } = radioGroup || {};
|
|
@@ -29,4 +29,23 @@ export type SelectSingleValueControl = SelectBaseValueControl & {
|
|
|
29
29
|
value: SelectValue | null;
|
|
30
30
|
};
|
|
31
31
|
export type SelectValueControl = SelectMultipleValueControl | SelectSingleValueControl;
|
|
32
|
+
/**
|
|
33
|
+
* 管理 Select 單選/多選值的受控狀態 Hook。
|
|
34
|
+
*
|
|
35
|
+
* 根據 `mode` 分別處理單選(`single`)與多選(`multiple`)邏輯,
|
|
36
|
+
* 提供 `value`、`onChange` 與 `onClear` 等操作介面。
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* import { useSelectValueControl } from '@mezzanine-ui/react';
|
|
41
|
+
*
|
|
42
|
+
* const control = useSelectValueControl({
|
|
43
|
+
* mode: 'single',
|
|
44
|
+
* value: selectedOption,
|
|
45
|
+
* onChange: (option) => setSelectedOption(option),
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @see {@link Select} 搭配的元件
|
|
50
|
+
*/
|
|
32
51
|
export declare const useSelectValueControl: (props: UseSelectValueControl) => SelectMultipleValueControl | SelectSingleValueControl;
|
|
@@ -76,6 +76,25 @@ function useSelectBaseValueControl(props) {
|
|
|
76
76
|
},
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* 管理 Select 單選/多選值的受控狀態 Hook。
|
|
81
|
+
*
|
|
82
|
+
* 根據 `mode` 分別處理單選(`single`)與多選(`multiple`)邏輯,
|
|
83
|
+
* 提供 `value`、`onChange` 與 `onClear` 等操作介面。
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* import { useSelectValueControl } from '@mezzanine-ui/react';
|
|
88
|
+
*
|
|
89
|
+
* const control = useSelectValueControl({
|
|
90
|
+
* mode: 'single',
|
|
91
|
+
* value: selectedOption,
|
|
92
|
+
* onChange: (option) => setSelectedOption(option),
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @see {@link Select} 搭配的元件
|
|
97
|
+
*/
|
|
79
98
|
const useSelectValueControl = (props) => {
|
|
80
99
|
if (props.mode === 'multiple') {
|
|
81
100
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
@@ -4,4 +4,22 @@ export interface UseSwitchControlValueProps {
|
|
|
4
4
|
defaultChecked?: boolean;
|
|
5
5
|
onChange?: ChangeEventHandler<HTMLInputElement>;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* 管理布林開關(checked)狀態的受控 Hook。
|
|
9
|
+
*
|
|
10
|
+
* 適用於任何基於 `<input type="checkbox">` 的切換元件,
|
|
11
|
+
* 回傳當前勾選狀態與穩定的 `onChange` 事件處理器。
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { useSwitchControlValue } from '@mezzanine-ui/react';
|
|
16
|
+
*
|
|
17
|
+
* const [checked, handleChange] = useSwitchControlValue({
|
|
18
|
+
* defaultChecked: false,
|
|
19
|
+
* onChange: (e) => console.log(e.target.checked),
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @see {@link Switch} 搭配的元件
|
|
24
|
+
*/
|
|
7
25
|
export declare function useSwitchControlValue(props: UseSwitchControlValueProps): readonly [boolean, (event: import("react").ChangeEvent<HTMLInputElement>) => void];
|
|
@@ -2,6 +2,24 @@ import { useLastCallback } from '../hooks/useLastCallback.js';
|
|
|
2
2
|
import { useControlValueState } from './useControlValueState.js';
|
|
3
3
|
|
|
4
4
|
const equalityFn = (a, b) => a === b;
|
|
5
|
+
/**
|
|
6
|
+
* 管理布林開關(checked)狀態的受控 Hook。
|
|
7
|
+
*
|
|
8
|
+
* 適用於任何基於 `<input type="checkbox">` 的切換元件,
|
|
9
|
+
* 回傳當前勾選狀態與穩定的 `onChange` 事件處理器。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { useSwitchControlValue } from '@mezzanine-ui/react';
|
|
14
|
+
*
|
|
15
|
+
* const [checked, handleChange] = useSwitchControlValue({
|
|
16
|
+
* defaultChecked: false,
|
|
17
|
+
* onChange: (e) => console.log(e.target.checked),
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @see {@link Switch} 搭配的元件
|
|
22
|
+
*/
|
|
5
23
|
function useSwitchControlValue(props) {
|
|
6
24
|
const { checked: checkedProp, defaultChecked = false, onChange: onChangeProp, } = props;
|
|
7
25
|
const [checked, setChecked] = useControlValueState({
|
package/Icon/Icon.d.ts
CHANGED
|
@@ -25,7 +25,29 @@ export interface IconProps extends NativeElementPropsWithoutKeyAndRef<'i'> {
|
|
|
25
25
|
title?: string;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* 渲染來自 `@mezzanine-ui/icons` 的 SVG 圖示元件。
|
|
29
|
+
*
|
|
30
|
+
* 透過 `icon` prop 傳入圖示定義物件,支援調整顏色、尺寸與旋轉動畫。
|
|
31
|
+
* 當元件綁定 `onClick` 或 `onMouseOver` 事件時,游標樣式會自動切換為 pointer。
|
|
32
|
+
* 可透過 `title` prop 提供無障礙標題文字。
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* import Icon from '@mezzanine-ui/react/Icon';
|
|
37
|
+
* import { SearchIcon, LoadingIcon, CheckCircleFilledIcon } from '@mezzanine-ui/icons';
|
|
38
|
+
*
|
|
39
|
+
* // 基本用法
|
|
40
|
+
* <Icon icon={SearchIcon} />
|
|
41
|
+
*
|
|
42
|
+
* // 自訂顏色與尺寸
|
|
43
|
+
* <Icon icon={CheckCircleFilledIcon} color="success" size={24} />
|
|
44
|
+
*
|
|
45
|
+
* // 旋轉動畫(常用於載入狀態)
|
|
46
|
+
* <Icon icon={LoadingIcon} spin />
|
|
47
|
+
*
|
|
48
|
+
* // 加入無障礙標題
|
|
49
|
+
* <Icon icon={SearchIcon} title="搜尋" />
|
|
50
|
+
* ```
|
|
29
51
|
*/
|
|
30
52
|
declare const Icon: import("react").ForwardRefExoticComponent<IconProps & import("react").RefAttributes<HTMLElement>>;
|
|
31
53
|
export default Icon;
|
package/Icon/Icon.js
CHANGED
|
@@ -4,7 +4,29 @@ import { toIconCssVars, iconClasses } from '@mezzanine-ui/core/icon';
|
|
|
4
4
|
import cx from 'clsx';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* 渲染來自 `@mezzanine-ui/icons` 的 SVG 圖示元件。
|
|
8
|
+
*
|
|
9
|
+
* 透過 `icon` prop 傳入圖示定義物件,支援調整顏色、尺寸與旋轉動畫。
|
|
10
|
+
* 當元件綁定 `onClick` 或 `onMouseOver` 事件時,游標樣式會自動切換為 pointer。
|
|
11
|
+
* 可透過 `title` prop 提供無障礙標題文字。
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import Icon from '@mezzanine-ui/react/Icon';
|
|
16
|
+
* import { SearchIcon, LoadingIcon, CheckCircleFilledIcon } from '@mezzanine-ui/icons';
|
|
17
|
+
*
|
|
18
|
+
* // 基本用法
|
|
19
|
+
* <Icon icon={SearchIcon} />
|
|
20
|
+
*
|
|
21
|
+
* // 自訂顏色與尺寸
|
|
22
|
+
* <Icon icon={CheckCircleFilledIcon} color="success" size={24} />
|
|
23
|
+
*
|
|
24
|
+
* // 旋轉動畫(常用於載入狀態)
|
|
25
|
+
* <Icon icon={LoadingIcon} spin />
|
|
26
|
+
*
|
|
27
|
+
* // 加入無障礙標題
|
|
28
|
+
* <Icon icon={SearchIcon} title="搜尋" />
|
|
29
|
+
* ```
|
|
8
30
|
*/
|
|
9
31
|
const Icon = forwardRef(function Icon(props, ref) {
|
|
10
32
|
const { className, color, icon, size, spin = false, style: styleProp, title, ...rest } = props;
|
package/Input/Input.d.ts
CHANGED
|
@@ -205,7 +205,37 @@ export type PasswordInputProps = InputBaseProps & ClearableInput & WithPasswordS
|
|
|
205
205
|
};
|
|
206
206
|
export type InputProps = BaseInputProps | WithAffixInputProps | SearchInputProps | NumberInputProps | MeasureInputProps | ActionInputProps | SelectInputProps | PasswordInputProps;
|
|
207
207
|
/**
|
|
208
|
-
*
|
|
208
|
+
* 多功能輸入框元件,透過 `variant` 支援多種輸入類型。
|
|
209
|
+
*
|
|
210
|
+
* 支援以下八種 variant:`base`(基本輸入)、`affix`(帶前後綴裝飾)、`search`(搜尋,預設帶清除鍵)、
|
|
211
|
+
* `number`(原生數字輸入)、`measure`(格式化數字,可選轉盤按鈕)、`action`(帶操作按鈕)、
|
|
212
|
+
* `select`(帶下拉選單按鈕)、`password`(密碼,可切換可見性並顯示強度指示器)。
|
|
213
|
+
* `measure` variant 會自動以千分位格式化顯示值,並在 `onChange` 時回傳原始數值。
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```tsx
|
|
217
|
+
* import Input from '@mezzanine-ui/react/Input';
|
|
218
|
+
*
|
|
219
|
+
* // 基本輸入(可清除)
|
|
220
|
+
* <Input variant="base" clearable placeholder="請輸入文字" />
|
|
221
|
+
*
|
|
222
|
+
* // 搜尋輸入
|
|
223
|
+
* <Input variant="search" placeholder="搜尋關鍵字" />
|
|
224
|
+
*
|
|
225
|
+
* // 密碼輸入(含強度指示器)
|
|
226
|
+
* <Input
|
|
227
|
+
* variant="password"
|
|
228
|
+
* placeholder="請輸入密碼"
|
|
229
|
+
* showPasswordStrengthIndicator
|
|
230
|
+
* passwordStrengthIndicator={{ strength: 2 }}
|
|
231
|
+
* />
|
|
232
|
+
*
|
|
233
|
+
* // 數字計量輸入(含轉盤按鈕)
|
|
234
|
+
* <Input variant="measure" suffix="px" showSpinner min={0} max={100} />
|
|
235
|
+
* ```
|
|
236
|
+
*
|
|
237
|
+
* @see {@link FormField} 用於包裹 Input 並提供標籤與錯誤訊息
|
|
238
|
+
* @see {@link TextField} Input 底層使用的文字框容器元件
|
|
209
239
|
*/
|
|
210
240
|
declare const Input: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
211
241
|
export default Input;
|
package/Input/Input.js
CHANGED
|
@@ -17,7 +17,37 @@ import PasswordStrengthIndicator from './PasswordStrengthIndicator/PasswordStren
|
|
|
17
17
|
import cx from 'clsx';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* 多功能輸入框元件,透過 `variant` 支援多種輸入類型。
|
|
21
|
+
*
|
|
22
|
+
* 支援以下八種 variant:`base`(基本輸入)、`affix`(帶前後綴裝飾)、`search`(搜尋,預設帶清除鍵)、
|
|
23
|
+
* `number`(原生數字輸入)、`measure`(格式化數字,可選轉盤按鈕)、`action`(帶操作按鈕)、
|
|
24
|
+
* `select`(帶下拉選單按鈕)、`password`(密碼,可切換可見性並顯示強度指示器)。
|
|
25
|
+
* `measure` variant 會自動以千分位格式化顯示值,並在 `onChange` 時回傳原始數值。
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import Input from '@mezzanine-ui/react/Input';
|
|
30
|
+
*
|
|
31
|
+
* // 基本輸入(可清除)
|
|
32
|
+
* <Input variant="base" clearable placeholder="請輸入文字" />
|
|
33
|
+
*
|
|
34
|
+
* // 搜尋輸入
|
|
35
|
+
* <Input variant="search" placeholder="搜尋關鍵字" />
|
|
36
|
+
*
|
|
37
|
+
* // 密碼輸入(含強度指示器)
|
|
38
|
+
* <Input
|
|
39
|
+
* variant="password"
|
|
40
|
+
* placeholder="請輸入密碼"
|
|
41
|
+
* showPasswordStrengthIndicator
|
|
42
|
+
* passwordStrengthIndicator={{ strength: 2 }}
|
|
43
|
+
* />
|
|
44
|
+
*
|
|
45
|
+
* // 數字計量輸入(含轉盤按鈕)
|
|
46
|
+
* <Input variant="measure" suffix="px" showSpinner min={0} max={100} />
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @see {@link FormField} 用於包裹 Input 並提供標籤與錯誤訊息
|
|
50
|
+
* @see {@link TextField} Input 底層使用的文字框容器元件
|
|
21
51
|
*/
|
|
22
52
|
const Input = forwardRef(function Input(props, ref) {
|
|
23
53
|
const { active, className, defaultValue, disabled = false, error = false, formatter: formatterProp, fullWidth = true, id, inputProps, inputType, inputRef: inputRefProp, name, onChange: onChangeProp, parser: parserProp, placeholder, readonly, size = 'main', typing, variant = 'base', value: valueProp, } = props;
|
|
@@ -8,7 +8,7 @@ import cx from 'clsx';
|
|
|
8
8
|
|
|
9
9
|
const SpinnerButton = forwardRef(function SpinnerButton(props, ref) {
|
|
10
10
|
const { className, disabled, size = 'main', type, ...rest } = props;
|
|
11
|
-
return (jsx("button", { ref: ref, type: "button", disabled: disabled, className: cx(inputSpinnerButtonClasses.host, disabled && inputSpinnerButtonClasses.disabled, size === 'main' ? inputSpinnerButtonClasses.main : inputSpinnerButtonClasses.sub, className), title: type === 'up' ? 'Increase value' : 'Decrease value', ...rest, children: jsx(Icon, { icon: type === 'up' ? CaretUpFlatIcon : CaretDownFlatIcon }) }));
|
|
11
|
+
return (jsx("button", { ref: ref, type: "button", disabled: disabled, className: cx(inputSpinnerButtonClasses.host, disabled && inputSpinnerButtonClasses.disabled, size === 'main' ? inputSpinnerButtonClasses.main : inputSpinnerButtonClasses.sub, className), "aria-label": type === 'up' ? 'Increase value' : 'Decrease value', title: type === 'up' ? 'Increase value' : 'Decrease value', ...rest, children: jsx(Icon, { "aria-hidden": "true", icon: type === 'up' ? CaretUpFlatIcon : CaretDownFlatIcon }) }));
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
export { SpinnerButton as default };
|
package/Message/Message.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MessageSeverity } from '@mezzanine-ui/core/message';
|
|
2
2
|
import { IconDefinition } from '@mezzanine-ui/icons';
|
|
3
3
|
import type { FC, Key } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { NotifierData, NotifierConfig } from '../Notifier';
|
|
5
5
|
import { TranslateProps } from '../Transition';
|
|
6
6
|
export interface MessageConfigProps extends Pick<NotifierConfig, 'duration'>, Pick<TranslateProps, 'onEnter' | 'onEntering' | 'onEntered' | 'onExit' | 'onExiting' | 'onExited' | 'easing' | 'from'> {
|
|
7
7
|
}
|
|
@@ -25,14 +25,64 @@ export interface MessageData extends Omit<NotifierData, 'onClose'>, MessageConfi
|
|
|
25
25
|
*/
|
|
26
26
|
severity?: MessageSeverity;
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Props accepted by Message severity shorthand methods such as `Message.success`.
|
|
30
|
+
* Includes an optional `key` to identify the message for later updates or dismissal.
|
|
31
|
+
*/
|
|
32
|
+
export type MessageShorthandProps = Omit<MessageData, 'children' | 'severity' | 'icon'> & {
|
|
29
33
|
key?: Key;
|
|
30
|
-
}
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Signature shared by all Message severity shorthand methods.
|
|
37
|
+
* @param message - The notification content.
|
|
38
|
+
* @param props - Optional configuration; mirrors {@link MessageData} minus `children`, `severity`, and `icon`.
|
|
39
|
+
*/
|
|
40
|
+
export type MessageShorthandMethod = (message: MessageData['children'], props?: MessageShorthandProps) => Key;
|
|
41
|
+
/** Static severity shorthand methods attached to the {@link Message} component. */
|
|
42
|
+
export interface MessageSeverityMethods {
|
|
43
|
+
/** Display an error message. */
|
|
44
|
+
error: MessageShorthandMethod;
|
|
45
|
+
/** Display an informational message. */
|
|
46
|
+
info: MessageShorthandMethod;
|
|
47
|
+
/** Display a loading message that will **not** auto-close. */
|
|
48
|
+
loading: MessageShorthandMethod;
|
|
49
|
+
/** Display a success message. */
|
|
50
|
+
success: MessageShorthandMethod;
|
|
51
|
+
/** Display a warning message. */
|
|
52
|
+
warning: MessageShorthandMethod;
|
|
53
|
+
}
|
|
31
54
|
/**
|
|
32
55
|
* The react component for `mezzanine` message.
|
|
33
56
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
57
|
+
* Trigger messages imperatively via severity shorthand methods:
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import Message from '@mezzanine-ui/react/message';
|
|
62
|
+
*
|
|
63
|
+
* Message.success('Saved!');
|
|
64
|
+
* Message.error('Something went wrong.');
|
|
65
|
+
*
|
|
66
|
+
* // With custom key for later update/dismissal
|
|
67
|
+
* const key = Message.loading('Uploading…');
|
|
68
|
+
* Message.success('Done!', { key });
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @see {@link MessageData} for the full set of options accepted by `Message.add`.
|
|
36
72
|
*/
|
|
37
|
-
declare const Message:
|
|
73
|
+
declare const Message: FC<MessageData> & {
|
|
74
|
+
add: (notifier: MessageData & {
|
|
75
|
+
key?: Key;
|
|
76
|
+
}) => Key;
|
|
77
|
+
config: (configs: MessageConfigProps) => void;
|
|
78
|
+
destroy: VoidFunction;
|
|
79
|
+
remove: (key: Key) => void;
|
|
80
|
+
error: (message: MessageData["children"], props?: MessageShorthandProps) => Key;
|
|
81
|
+
info: (message: MessageData["children"], props?: MessageShorthandProps) => Key;
|
|
82
|
+
loading: (message: MessageData["children"], props?: MessageShorthandProps) => Key;
|
|
83
|
+
success: (message: MessageData["children"], props?: MessageShorthandProps) => Key;
|
|
84
|
+
warning: (message: MessageData["children"], props?: MessageShorthandProps) => Key;
|
|
85
|
+
};
|
|
86
|
+
/** Full type of the {@link Message} component including all static notification API methods. */
|
|
87
|
+
export type MessageType = typeof Message;
|
|
38
88
|
export default Message;
|
package/Message/Message.js
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useState, useRef, useCallback, useEffect, createElement } from 'react';
|
|
3
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
-
import {
|
|
4
|
+
import { messageIcons, messageClasses } from '@mezzanine-ui/core/message';
|
|
5
5
|
import { messageTimerController } from './MessageTimerController.js';
|
|
6
6
|
import Translate from '../Transition/Translate.js';
|
|
7
|
+
import Spin from '../Spin/Spin.js';
|
|
7
8
|
import Icon from '../Icon/Icon.js';
|
|
8
|
-
import cx from 'clsx';
|
|
9
9
|
import { createNotifier } from '../Notifier/createNotifier.js';
|
|
10
|
+
import cx from 'clsx';
|
|
10
11
|
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
*
|
|
14
|
-
* Use the API from the Message instance such as `Message.add` and `Message.success`
|
|
15
|
-
* to display a notification message globally.
|
|
16
|
-
*/
|
|
17
|
-
const Message = ((props) => {
|
|
12
|
+
/** @internal Underlying React element rendered by the Message notifier. */
|
|
13
|
+
const MessageFC = (props) => {
|
|
18
14
|
const { children, duration, icon, reference, severity, onExited: onExitedProp, ...restTransitionProps } = props;
|
|
19
15
|
const [open, setOpen] = useState(true);
|
|
20
16
|
const timerRef = useRef(null);
|
|
21
17
|
const remainingTimeRef = useRef(duration || 0);
|
|
22
|
-
const startTimeRef = useRef(
|
|
18
|
+
const startTimeRef = useRef(0);
|
|
23
19
|
// 清理計時器
|
|
24
20
|
const clearTimer = useCallback(() => {
|
|
25
21
|
if (timerRef.current) {
|
|
@@ -102,59 +98,70 @@ const Message = ((props) => {
|
|
|
102
98
|
const handleBlur = () => {
|
|
103
99
|
messageTimerController.resume();
|
|
104
100
|
};
|
|
105
|
-
return (jsx(Translate, { in: open, appear: true, onExited: onExited, from: "bottom", ...restTransitionProps, children: jsxs("div", { className: cx(messageClasses.host, severity ? messageClasses.severity(severity) : ''), onBlur: handleBlur, onFocus: handleFocus, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, role: "status", children: [
|
|
106
|
-
}
|
|
101
|
+
return (jsx(Translate, { in: open, appear: true, onExited: onExited, from: "bottom", ...restTransitionProps, children: jsxs("div", { className: cx(messageClasses.host, severity ? messageClasses.severity(severity) : ''), onBlur: handleBlur, onFocus: handleFocus, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, role: "status", children: [severity === 'loading' ? (jsx("span", { className: messageClasses.icon, children: jsx(Spin, { loading: true, size: "minor" }) })) : icon ? (jsx(Icon, { className: messageClasses.icon, icon: icon })) : null, jsx("span", { className: messageClasses.content, children: children })] }) }));
|
|
102
|
+
};
|
|
107
103
|
const { add, config, destroy, remove } = createNotifier({
|
|
108
104
|
duration: 3000,
|
|
109
105
|
maxCount: 4,
|
|
110
|
-
render: (message) => (createElement(
|
|
106
|
+
render: (message) => (createElement(MessageFC, { ...message, reference: message.key, key: undefined })),
|
|
111
107
|
setRoot: (root) => {
|
|
112
108
|
root === null || root === void 0 ? void 0 : root.setAttribute('class', messageClasses.root);
|
|
113
109
|
},
|
|
114
110
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
111
|
+
/**
|
|
112
|
+
* The react component for `mezzanine` message.
|
|
113
|
+
*
|
|
114
|
+
* Trigger messages imperatively via severity shorthand methods:
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```tsx
|
|
118
|
+
* import Message from '@mezzanine-ui/react/message';
|
|
119
|
+
*
|
|
120
|
+
* Message.success('Saved!');
|
|
121
|
+
* Message.error('Something went wrong.');
|
|
122
|
+
*
|
|
123
|
+
* // With custom key for later update/dismissal
|
|
124
|
+
* const key = Message.loading('Uploading…');
|
|
125
|
+
* Message.success('Done!', { key });
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @see {@link MessageData} for the full set of options accepted by `Message.add`.
|
|
129
|
+
*/
|
|
130
|
+
const Message = Object.assign(MessageFC, {
|
|
131
|
+
add,
|
|
132
|
+
config,
|
|
133
|
+
destroy,
|
|
134
|
+
remove,
|
|
135
|
+
error: (message, props) => add({
|
|
136
|
+
...props,
|
|
137
|
+
children: message,
|
|
130
138
|
icon: messageIcons.error,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
severity: 'error',
|
|
140
|
+
}),
|
|
141
|
+
info: (message, props) => add({
|
|
142
|
+
...props,
|
|
143
|
+
children: message,
|
|
134
144
|
icon: messageIcons.info,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
'error',
|
|
145
|
-
'info',
|
|
146
|
-
'loading',
|
|
147
|
-
];
|
|
148
|
-
severities.forEach((severity) => {
|
|
149
|
-
Message[severity.key] = (message, props) => Message.add({
|
|
145
|
+
severity: 'info',
|
|
146
|
+
}),
|
|
147
|
+
loading: (message, props) => add({
|
|
148
|
+
...props,
|
|
149
|
+
children: message,
|
|
150
|
+
severity: 'loading',
|
|
151
|
+
duration: false,
|
|
152
|
+
}),
|
|
153
|
+
success: (message, props) => add({
|
|
150
154
|
...props,
|
|
151
155
|
children: message,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
icon: messageIcons.success,
|
|
157
|
+
severity: 'success',
|
|
158
|
+
}),
|
|
159
|
+
warning: (message, props) => add({
|
|
160
|
+
...props,
|
|
161
|
+
children: message,
|
|
162
|
+
icon: messageIcons.warning,
|
|
163
|
+
severity: 'warning',
|
|
164
|
+
}),
|
|
158
165
|
});
|
|
159
166
|
|
|
160
167
|
export { Message as default };
|