@mezzanine-ui/react 1.0.0-beta.0 → 1.0.0-beta.2
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/Badge/Badge.js +2 -2
- package/Breadcrumb/BreadcrumbItem.d.ts +1 -1
- package/Description/Description.d.ts +40 -0
- package/Description/Description.js +33 -0
- package/Description/DescriptionContent.d.ts +41 -0
- package/Description/DescriptionContent.js +14 -0
- package/Description/DescriptionGroup.d.ts +13 -0
- package/Description/DescriptionGroup.js +12 -0
- package/Description/DescriptionTitle.d.ts +45 -0
- package/Description/DescriptionTitle.js +17 -0
- package/Description/index.d.ts +8 -0
- package/Description/index.js +4 -0
- package/Dropdown/Dropdown.d.ts +128 -15
- package/Dropdown/Dropdown.js +273 -32
- package/Dropdown/DropdownAction.d.ts +50 -0
- package/Dropdown/DropdownAction.js +26 -0
- package/Dropdown/DropdownItem.d.ts +60 -0
- package/Dropdown/DropdownItem.js +318 -0
- package/Dropdown/DropdownItemCard.d.ts +96 -0
- package/Dropdown/DropdownItemCard.js +115 -0
- package/Dropdown/DropdownStatus.d.ts +22 -0
- package/Dropdown/dropdownKeydownHandler.d.ts +15 -0
- package/Dropdown/highlightText.d.ts +9 -0
- package/Dropdown/highlightText.js +32 -0
- package/Dropdown/index.d.ts +1 -1
- package/Form/FormControlContext.d.ts +2 -2
- package/Form/FormField.d.ts +56 -4
- package/Form/FormField.js +8 -6
- package/Form/FormHintText.d.ts +24 -1
- package/Form/FormHintText.js +4 -4
- package/Form/FormLabel.d.ts +6 -3
- package/Form/FormLabel.js +5 -3
- package/Input/PasswordStrengthIndicator/PasswordStrengthIndicator.js +1 -1
- package/Navigation/Navigation.d.ts +17 -14
- package/Navigation/Navigation.js +73 -41
- package/Navigation/NavigationFooter.d.ts +10 -0
- package/Navigation/NavigationFooter.js +28 -0
- package/Navigation/NavigationHeader.d.ts +14 -0
- package/Navigation/NavigationHeader.js +15 -0
- package/Navigation/NavigationIconButton.d.ts +15 -0
- package/Navigation/NavigationIconButton.js +12 -0
- package/Navigation/NavigationOption.d.ts +35 -0
- package/Navigation/NavigationOption.js +54 -0
- package/Navigation/NavigationOptionCategory.d.ts +6 -0
- package/Navigation/NavigationOptionCategory.js +29 -0
- package/Navigation/NavigationUserMenu.d.ts +8 -0
- package/Navigation/NavigationUserMenu.js +18 -0
- package/Navigation/context.d.ts +15 -0
- package/Navigation/context.js +7 -0
- package/Navigation/index.d.ts +12 -6
- package/Navigation/index.js +6 -3
- package/Navigation/useCurrentPathname.d.ts +1 -0
- package/Navigation/useCurrentPathname.js +14 -0
- package/Slider/useSlider.js +1 -1
- package/Table/Table.d.ts +53 -15
- package/Table/Table.js +178 -82
- package/Table/TableContext.d.ts +18 -42
- package/Table/components/TableActionsCell.d.ts +26 -0
- package/Table/components/TableActionsCell.js +78 -0
- package/Table/components/TableBody.d.ts +2 -5
- package/Table/components/TableBody.js +16 -19
- package/Table/components/TableBulkActions.d.ts +15 -0
- package/Table/components/TableBulkActions.js +44 -0
- package/Table/components/TableCell.d.ts +2 -0
- package/Table/components/TableCell.js +42 -10
- package/Table/components/TableColGroup.js +10 -112
- package/Table/components/TableColumnTitleMenu.d.ts +6 -0
- package/Table/components/TableColumnTitleMenu.js +20 -0
- package/Table/components/TableDragHandleCell.d.ts +2 -0
- package/Table/components/TableDragHandleCell.js +8 -1
- package/Table/components/TableExpandCell.d.ts +2 -0
- package/Table/components/TableExpandCell.js +8 -1
- package/Table/components/TableExpandedRow.js +3 -2
- package/Table/components/TableHeader.d.ts +2 -4
- package/Table/components/TableHeader.js +11 -14
- package/Table/components/TableResizeHandle.js +3 -7
- package/Table/components/TableRow.js +54 -20
- package/Table/components/TableSelectionCell.d.ts +5 -0
- package/Table/components/TableSelectionCell.js +12 -1
- package/Table/components/index.d.ts +1 -0
- package/Table/components/index.js +1 -0
- package/Table/hooks/index.d.ts +1 -1
- package/Table/hooks/index.js +1 -1
- package/Table/hooks/useTableDataSource.d.ts +2 -2
- package/Table/hooks/useTableExpansion.js +0 -6
- package/Table/hooks/useTableFixedOffsets.d.ts +1 -1
- package/Table/hooks/useTableFixedOffsets.js +19 -21
- package/Table/hooks/useTableResizedColumns.d.ts +2 -0
- package/Table/hooks/useTableResizedColumns.js +22 -0
- package/Table/hooks/useTableScroll.d.ts +3 -1
- package/Table/hooks/useTableScroll.js +25 -19
- package/Table/hooks/useTableSelection.js +32 -8
- package/Table/hooks/useTableVirtualization.d.ts +1 -1
- package/Table/index.d.ts +4 -4
- package/Table/index.js +5 -3
- package/Table/utils/calculateColumnWidths.d.ts +28 -0
- package/Table/utils/calculateColumnWidths.js +80 -0
- package/Table/utils/index.d.ts +2 -0
- package/Table/utils/index.js +1 -0
- package/Table/utils/useTableRowSelection.d.ts +5 -5
- package/Table/utils/useTableRowSelection.js +1 -1
- package/hooks/useElementHeight.d.ts +8 -0
- package/hooks/useElementHeight.js +41 -0
- package/index.d.ts +8 -6
- package/index.js +9 -3
- package/package.json +5 -4
- package/utils/format-number-with-commas.d.ts +4 -0
- package/utils/format-number-with-commas.js +27 -0
- package/utils/parse-number-with-commas.d.ts +4 -0
- package/utils/parse-number-with-commas.js +22 -0
- package/Navigation/NavigationContext.d.ts +0 -5
- package/Navigation/NavigationContext.js +0 -8
- package/Navigation/NavigationItem.d.ts +0 -31
- package/Navigation/NavigationItem.js +0 -23
- package/Navigation/NavigationSubMenu.d.ts +0 -22
- package/Navigation/NavigationSubMenu.js +0 -50
- package/Table/hooks/useTableColumns.d.ts +0 -8
- package/Table/hooks/useTableColumns.js +0 -91
package/Form/FormField.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FormFieldCounterColor, FormFieldSize } from '@mezzanine-ui/core/form';
|
|
2
2
|
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
3
|
+
import { IconDefinition } from '@mezzanine-ui/icons';
|
|
4
|
+
import { SeverityWithInfo } from '@mezzanine-ui/system/severity';
|
|
3
5
|
export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'> {
|
|
6
|
+
/**
|
|
7
|
+
* The counter text to display in the form field.
|
|
8
|
+
* Typically used to show character count or remaining characters.
|
|
9
|
+
*/
|
|
10
|
+
counter?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The color of the counter text.
|
|
13
|
+
* @default FormFieldCounterColor.INFO
|
|
14
|
+
*/
|
|
15
|
+
counterColor?: FormFieldCounterColor;
|
|
4
16
|
/**
|
|
5
17
|
* To control the field passed from children whether should be disabled.
|
|
6
18
|
* The form message won't appear if disabled.
|
|
@@ -10,17 +22,57 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
|
|
|
10
22
|
* To control the field passed from children whether should be fullWidth.
|
|
11
23
|
*/
|
|
12
24
|
fullWidth?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The hint text to display below the input field.
|
|
27
|
+
* Provides additional information or guidance to the user.
|
|
28
|
+
*/
|
|
29
|
+
hintText?: string;
|
|
30
|
+
/**
|
|
31
|
+
* The icon to display alongside the hint text.
|
|
32
|
+
*/
|
|
33
|
+
hintTextIcon?: IconDefinition;
|
|
34
|
+
/**
|
|
35
|
+
* The label text for the form field.
|
|
36
|
+
*/
|
|
37
|
+
label: string;
|
|
38
|
+
/**
|
|
39
|
+
* The icon to display next to the label.
|
|
40
|
+
* When provided, displays an icon that shows a tooltip on hover.
|
|
41
|
+
*/
|
|
42
|
+
labelInformationIcon?: IconDefinition;
|
|
43
|
+
/**
|
|
44
|
+
* The tooltip text to display when hovering over the label information icon.
|
|
45
|
+
* Only shown when labelInformationIcon is provided.
|
|
46
|
+
*/
|
|
47
|
+
labelInformationText?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Optional marker text to display after the label.
|
|
50
|
+
* Typically used to show "(optional)" or similar text.
|
|
51
|
+
*/
|
|
52
|
+
labelOptionalMarker?: string;
|
|
53
|
+
/**
|
|
54
|
+
* The name attribute for the form field.
|
|
55
|
+
* Used to identify the field in form submissions and as htmlFor in the label.
|
|
56
|
+
*/
|
|
57
|
+
name: string;
|
|
13
58
|
/**
|
|
14
59
|
* To control the field passed from children whether should be required.
|
|
15
60
|
*/
|
|
16
61
|
required?: boolean;
|
|
17
62
|
/**
|
|
18
|
-
*
|
|
63
|
+
* The size variant of the form field.
|
|
64
|
+
* Controls the layout and spacing of label, input, and other elements.
|
|
65
|
+
*/
|
|
66
|
+
size: FormFieldSize;
|
|
67
|
+
/**
|
|
68
|
+
* The severity level of the form field.
|
|
69
|
+
* Used to indicate the importance or urgency of the field.
|
|
70
|
+
* @default 'info'
|
|
19
71
|
*/
|
|
20
|
-
severity?:
|
|
72
|
+
severity?: SeverityWithInfo;
|
|
21
73
|
}
|
|
22
74
|
/**
|
|
23
|
-
* The
|
|
75
|
+
* The React component for `mezzanine` form field.
|
|
24
76
|
*/
|
|
25
77
|
declare const FormField: import("react").ForwardRefExoticComponent<FormFieldProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
26
78
|
export default FormField;
|
package/Form/FormField.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import { jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { forwardRef } from 'react';
|
|
3
|
-
import { formFieldClasses } from '@mezzanine-ui/core/form';
|
|
3
|
+
import { formFieldClasses, FormFieldCounterColor } from '@mezzanine-ui/core/form';
|
|
4
4
|
import { FormControlContext } from './FormControlContext.js';
|
|
5
|
+
import FormHintText from './FormHintText.js';
|
|
6
|
+
import FormLabel from './FormLabel.js';
|
|
5
7
|
import cx from 'clsx';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
|
-
* The
|
|
10
|
+
* The React component for `mezzanine` form field.
|
|
9
11
|
*/
|
|
10
12
|
const FormField = forwardRef(function FormField(props, ref) {
|
|
11
|
-
const { children, className, disabled = false, fullWidth = false, required = false, severity, ...rest } = props;
|
|
13
|
+
const { children, className, counter, counterColor, disabled = false, fullWidth = false, hintText, hintTextIcon, label, labelInformationIcon, labelInformationText, labelOptionalMarker, name, required = false, size, severity = 'info', ...rest } = props;
|
|
12
14
|
const formControl = {
|
|
13
15
|
disabled,
|
|
14
16
|
fullWidth,
|
|
15
17
|
required,
|
|
16
18
|
severity,
|
|
17
19
|
};
|
|
18
|
-
return (jsx("div", { ...rest, ref: ref, className: cx(formFieldClasses.host,
|
|
20
|
+
return (jsx("div", { ...rest, ref: ref, className: cx(formFieldClasses.host, formFieldClasses.size(size), {
|
|
19
21
|
[formFieldClasses.disabled]: disabled,
|
|
20
22
|
[formFieldClasses.fullWidth]: fullWidth,
|
|
21
|
-
}, className), children:
|
|
23
|
+
}, className), children: jsxs(FormControlContext.Provider, { value: formControl, children: [jsx(FormLabel, { className: formFieldClasses.labelArea, htmlFor: name, informationIcon: labelInformationIcon, informationText: labelInformationText, labelText: label, optionalMarker: labelOptionalMarker }), jsxs("div", { className: cx(formFieldClasses.dataEntry), children: [children, jsxs("div", { className: cx(formFieldClasses.hintTextAndCounterArea), children: [(hintText || hintTextIcon) && (jsx(FormHintText, { hintText: hintText, hintTextIcon: hintTextIcon, severity: severity })), counter && (jsx("span", { className: cx(formFieldClasses.counter, formFieldClasses.counterColor(counterColor || FormFieldCounterColor.INFO)), children: counter }))] })] })] }) }));
|
|
22
24
|
});
|
|
23
25
|
|
|
24
26
|
export { FormField as default };
|
package/Form/FormHintText.d.ts
CHANGED
|
@@ -1,17 +1,40 @@
|
|
|
1
1
|
import { formHintIcons } from '@mezzanine-ui/core/form';
|
|
2
2
|
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
3
|
+
import { IconDefinition } from '@mezzanine-ui/icons';
|
|
3
4
|
export type FormHintTextProps = NativeElementPropsWithoutKeyAndRef<'span'> & {
|
|
5
|
+
/**
|
|
6
|
+
* The hint text to display below the input field.
|
|
7
|
+
* Provides additional information or guidance to the user.
|
|
8
|
+
*/
|
|
9
|
+
hintText?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The icon to display alongside the hint text.
|
|
12
|
+
* If provided, this icon will override the default severity icon.
|
|
13
|
+
*/
|
|
14
|
+
hintTextIcon?: IconDefinition;
|
|
4
15
|
/**
|
|
5
16
|
* The severity of form message.
|
|
17
|
+
* if not provided, no icon will be displayed.
|
|
6
18
|
*/
|
|
7
19
|
severity?: keyof typeof formHintIcons | undefined;
|
|
8
20
|
};
|
|
9
21
|
/**
|
|
10
|
-
* The
|
|
22
|
+
* The React component for `mezzanine` form message.
|
|
11
23
|
*/
|
|
12
24
|
declare const FormHintText: import("react").ForwardRefExoticComponent<NativeElementPropsWithoutKeyAndRef<"span"> & {
|
|
25
|
+
/**
|
|
26
|
+
* The hint text to display below the input field.
|
|
27
|
+
* Provides additional information or guidance to the user.
|
|
28
|
+
*/
|
|
29
|
+
hintText?: string;
|
|
30
|
+
/**
|
|
31
|
+
* The icon to display alongside the hint text.
|
|
32
|
+
* If provided, this icon will override the default severity icon.
|
|
33
|
+
*/
|
|
34
|
+
hintTextIcon?: IconDefinition;
|
|
13
35
|
/**
|
|
14
36
|
* The severity of form message.
|
|
37
|
+
* if not provided, no icon will be displayed.
|
|
15
38
|
*/
|
|
16
39
|
severity?: keyof typeof formHintIcons | undefined;
|
|
17
40
|
} & import("react").RefAttributes<HTMLSpanElement>>;
|
package/Form/FormHintText.js
CHANGED
|
@@ -6,12 +6,12 @@ import Icon from '../Icon/Icon.js';
|
|
|
6
6
|
import cx from 'clsx';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* The
|
|
9
|
+
* The React component for `mezzanine` form message.
|
|
10
10
|
*/
|
|
11
11
|
const FormHintText = forwardRef(function FormHintText(props, ref) {
|
|
12
|
-
const {
|
|
13
|
-
const
|
|
14
|
-
return (jsxs("span", { ...rest, ref: ref, className: cx(formFieldClasses.hintText, severity ? formFieldClasses.hintTextSeverity(severity) : undefined, className), children: [icon && jsx(Icon, { className: formFieldClasses.hintTextIcon, icon:
|
|
12
|
+
const { className, hintText, hintTextIcon, severity = 'info', ...rest } = props;
|
|
13
|
+
const defaultIcon = severity ? formHintIcons[severity] : null;
|
|
14
|
+
return (jsxs("span", { ...rest, ref: ref, className: cx(formFieldClasses.hintText, severity ? formFieldClasses.hintTextSeverity(severity) : undefined, className), children: [hintTextIcon ? (jsx(Icon, { className: formFieldClasses.hintTextIcon, icon: hintTextIcon, color: severity })) : (defaultIcon && (jsx(Icon, { className: formFieldClasses.hintTextIcon, icon: defaultIcon, color: severity }))), hintText] }));
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
export { FormHintText as default };
|
package/Form/FormLabel.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
3
|
+
import { IconDefinition } from '@mezzanine-ui/icons';
|
|
3
4
|
export interface FormLabelProps extends NativeElementPropsWithoutKeyAndRef<'label'> {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
informationIcon?: IconDefinition;
|
|
6
|
+
informationText?: string;
|
|
7
|
+
labelText: string;
|
|
8
|
+
optionalMarker?: ReactNode;
|
|
6
9
|
}
|
|
7
10
|
/**
|
|
8
|
-
* The
|
|
11
|
+
* The React component for `mezzanine` form label.
|
|
9
12
|
*/
|
|
10
13
|
declare const FormLabel: import("react").ForwardRefExoticComponent<FormLabelProps & import("react").RefAttributes<HTMLLabelElement>>;
|
|
11
14
|
export default FormLabel;
|
package/Form/FormLabel.js
CHANGED
|
@@ -3,15 +3,17 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
3
3
|
import { forwardRef, useContext } from 'react';
|
|
4
4
|
import { formFieldClasses } from '@mezzanine-ui/core/form';
|
|
5
5
|
import { FormControlContext } from './FormControlContext.js';
|
|
6
|
+
import Tooltip from '../Tooltip/Tooltip.js';
|
|
7
|
+
import Icon from '../Icon/Icon.js';
|
|
6
8
|
import cx from 'clsx';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
* The
|
|
11
|
+
* The React component for `mezzanine` form label.
|
|
10
12
|
*/
|
|
11
13
|
const FormLabel = forwardRef(function FormLabel(props, ref) {
|
|
12
|
-
const {
|
|
14
|
+
const { className, htmlFor, informationIcon, informationText, labelText, optionalMarker, ...rest } = props;
|
|
13
15
|
const { required } = useContext(FormControlContext) || {};
|
|
14
|
-
return (jsxs("label", { ...rest, ref: ref, className: cx(formFieldClasses.label, className), htmlFor: htmlFor, children: [
|
|
16
|
+
return (jsxs("label", { ...rest, ref: ref, className: cx(formFieldClasses.label, className), htmlFor: htmlFor, children: [required && jsx("span", { className: formFieldClasses.labelRequiredMarker, children: "*" }), labelText, optionalMarker && (jsx("span", { className: formFieldClasses.labelOptionalMarker, children: optionalMarker })), informationIcon && (jsx(Tooltip, { title: informationText, children: ({ onMouseEnter, onMouseLeave, ref: tooltipRef }) => (jsx(Icon, { ref: tooltipRef, className: cx(formFieldClasses.labelInformationIcon), color: "neutral-light", icon: informationIcon, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, size: 16 })) })), jsx("span", { className: formFieldClasses.labelColon, children: ":" })] }));
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
export { FormLabel as default };
|
|
@@ -12,7 +12,7 @@ const PasswordStrengthIndicator = forwardRef(function PasswordStrengthIndicator(
|
|
|
12
12
|
const { className, strength = 'weak', strengthText: strengthTextProp, strengthTextPrefix = '密碼強度:', hintTexts, ...rest } = props;
|
|
13
13
|
const strengthText = strengthTextProp ||
|
|
14
14
|
(strength === 'weak' ? '低' : strength === 'medium' ? '中' : '高');
|
|
15
|
-
return (jsxs("div", { ref: ref, className: cx(inputPasswordStrengthIndicatorClasses.host, className), ...rest, children: [jsx("div", { className: cx(inputPasswordStrengthIndicatorClasses.bar, inputPasswordStrengthIndicatorClasses.barState(strength)) }), jsxs("span", { className: inputPasswordStrengthIndicatorClasses.text, children: [strengthTextPrefix, jsx("mark", { children: strengthText })] }), hintTexts && hintTexts.length > 0 && (jsx("div", { className: inputPasswordStrengthIndicatorClasses.hintTextGroup, children: hintTexts.map((hintText, idx) => (jsx(FormHintText, {
|
|
15
|
+
return (jsxs("div", { ref: ref, className: cx(inputPasswordStrengthIndicatorClasses.host, className), ...rest, children: [jsx("div", { className: cx(inputPasswordStrengthIndicatorClasses.bar, inputPasswordStrengthIndicatorClasses.barState(strength)) }), jsxs("span", { className: inputPasswordStrengthIndicatorClasses.text, children: [strengthTextPrefix, jsx("mark", { children: strengthText })] }), hintTexts && hintTexts.length > 0 && (jsx("div", { className: inputPasswordStrengthIndicatorClasses.hintTextGroup, children: hintTexts.map((hintText, idx) => (jsx(FormHintText, { hintText: hintText.hint, severity: hintText.severity }, idx))) }))] }));
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
export { PasswordStrengthIndicator as default };
|
|
@@ -1,29 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { NavigationOrientation } from '@mezzanine-ui/core/navigation';
|
|
1
|
+
import { JSX, ReactElement } from 'react';
|
|
3
2
|
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
3
|
+
import { NavigationOptionProps } from './NavigationOption';
|
|
4
|
+
import { NavigationHeaderProps } from './NavigationHeader';
|
|
5
|
+
import { NavigationFooterProps } from './NavigationFooter';
|
|
6
|
+
export type NavigationChild = ReactElement<NavigationOptionProps | NavigationHeaderProps | NavigationFooterProps> | null | JSX.Element[];
|
|
7
7
|
export type NavigationChildren = NavigationChild | NavigationChild[];
|
|
8
8
|
export interface NavigationProps extends Omit<NativeElementPropsWithoutKeyAndRef<'ul'>, 'onClick'> {
|
|
9
9
|
/**
|
|
10
10
|
* Current active key.
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
activatedPath?: string[];
|
|
13
13
|
/**
|
|
14
|
-
* Strict children with `
|
|
15
|
-
* @default []
|
|
14
|
+
* Strict children with `NavigationOption`, `NavigationHeader` or `NavigationFooter`.
|
|
16
15
|
*/
|
|
17
16
|
children?: NavigationChildren;
|
|
18
17
|
/**
|
|
19
|
-
*
|
|
18
|
+
* Navigation display type.
|
|
19
|
+
* @default false (expanded)
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
collapsed?: boolean;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
* @default 'horizontal'
|
|
23
|
+
* Called when collapsed state changes.
|
|
25
24
|
*/
|
|
26
|
-
|
|
25
|
+
onCollapseChange?: (collapsed: boolean) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Called when a navigation option is clicked.
|
|
28
|
+
*/
|
|
29
|
+
onOptionClick?: (activePath?: string[]) => void;
|
|
27
30
|
}
|
|
28
|
-
declare const Navigation: import("react").ForwardRefExoticComponent<NavigationProps & import("react").RefAttributes<
|
|
31
|
+
declare const Navigation: import("react").ForwardRefExoticComponent<NavigationProps & import("react").RefAttributes<HTMLElement>>;
|
|
29
32
|
export default Navigation;
|
package/Navigation/Navigation.js
CHANGED
|
@@ -1,57 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { forwardRef, useState, useCallback, useMemo, Children, isValidElement, cloneElement } from 'react';
|
|
3
4
|
import { navigationClasses } from '@mezzanine-ui/core/navigation';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import NavigationOption from './NavigationOption.js';
|
|
6
|
+
import NavigationHeader from './NavigationHeader.js';
|
|
7
|
+
import NavigationFooter from './NavigationFooter.js';
|
|
8
|
+
import { flattenChildren } from '../utils/flatten-children.js';
|
|
9
|
+
import NavigationOptionCategory from './NavigationOptionCategory.js';
|
|
10
|
+
import { NavigationActivatedContext, NavigationOptionLevelContext, navigationOptionLevelContextDefaultValues } from './context.js';
|
|
11
|
+
import { useCurrentPathname } from './useCurrentPathname.js';
|
|
12
|
+
import Input from '../Input/Input.js';
|
|
7
13
|
import cx from 'clsx';
|
|
8
14
|
|
|
9
15
|
const Navigation = forwardRef((props, ref) => {
|
|
10
|
-
const {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
const { activatedPath, children = [], className, collapsed: collapsedProp, onOptionClick, onCollapseChange, ...rest } = props;
|
|
17
|
+
const [collapsedState, setCollapsedState] = useState(collapsedProp || false);
|
|
18
|
+
const collapsed = collapsedProp !== null && collapsedProp !== void 0 ? collapsedProp : collapsedState;
|
|
19
|
+
const handleCollapseChange = useCallback((newCollapsed) => {
|
|
20
|
+
setCollapsedState(newCollapsed);
|
|
21
|
+
onCollapseChange === null || onCollapseChange === void 0 ? void 0 : onCollapseChange(newCollapsed);
|
|
22
|
+
}, [onCollapseChange]);
|
|
23
|
+
const [innerActivatedPath, setInnerActivatedPath] = useState([]);
|
|
24
|
+
const combineSetActivatedPath = useCallback((newActivatedPath) => {
|
|
25
|
+
onOptionClick === null || onOptionClick === void 0 ? void 0 : onOptionClick(newActivatedPath);
|
|
26
|
+
setInnerActivatedPath(newActivatedPath);
|
|
27
|
+
}, [onOptionClick]);
|
|
28
|
+
const currentPathname = useCurrentPathname();
|
|
29
|
+
const flattenedChildren = useMemo(() => flattenChildren(children), [children]);
|
|
30
|
+
const { headerComponent, footerComponent, searchInput } = useMemo(() => {
|
|
31
|
+
let headerComponent = null;
|
|
32
|
+
let footerComponent = null;
|
|
33
|
+
let searchInput = null;
|
|
34
|
+
Children.forEach(flattenedChildren, (child) => {
|
|
35
|
+
if (child && isValidElement(child)) {
|
|
15
36
|
switch (child.type) {
|
|
16
|
-
case
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
case NavigationHeader: {
|
|
38
|
+
headerComponent = child;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case NavigationFooter: {
|
|
42
|
+
footerComponent = child;
|
|
43
|
+
break;
|
|
23
44
|
}
|
|
24
|
-
case
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const active = activeKey === groupChild.key || groupChild.props.active;
|
|
30
|
-
if (active) {
|
|
31
|
-
subMenuActive = true;
|
|
32
|
-
}
|
|
33
|
-
return cloneElement(groupChild, {
|
|
34
|
-
active,
|
|
35
|
-
eventKey: groupChild.key,
|
|
36
|
-
onClick: groupChild.props.onClick || onClick,
|
|
37
|
-
});
|
|
45
|
+
case Input: {
|
|
46
|
+
searchInput = cloneElement(child, {
|
|
47
|
+
size: 'sub',
|
|
48
|
+
variant: 'search',
|
|
49
|
+
className: cx(navigationClasses.searchInput, child.props.className),
|
|
38
50
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return { headerComponent, footerComponent, searchInput };
|
|
57
|
+
}, [flattenedChildren]);
|
|
58
|
+
const renderItemChildren = useCallback(function renderItemChildrenImpl(parsedChildren) {
|
|
59
|
+
var _a;
|
|
60
|
+
const childArray = Children.map(parsedChildren, (child) => {
|
|
61
|
+
if (child && isValidElement(child)) {
|
|
62
|
+
switch (child.type) {
|
|
63
|
+
case NavigationOptionCategory:
|
|
64
|
+
case NavigationOption: {
|
|
65
|
+
return child;
|
|
42
66
|
}
|
|
67
|
+
case NavigationHeader:
|
|
68
|
+
case NavigationFooter:
|
|
69
|
+
// already handled in headerComponent and footerComponent
|
|
70
|
+
return null;
|
|
43
71
|
default:
|
|
44
|
-
|
|
45
|
-
return
|
|
72
|
+
console.warn('[Mezzanine][Navigation]: Navigation only accepts NavigationOption, NavigationOptionCategory, NavigationHeader or NavigationFooter as children.');
|
|
73
|
+
return null;
|
|
46
74
|
}
|
|
47
75
|
}
|
|
48
76
|
return null;
|
|
49
77
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
78
|
+
return (_a = childArray === null || childArray === void 0 ? void 0 : childArray.filter((child) => child !== null)) !== null && _a !== void 0 ? _a : null;
|
|
79
|
+
}, []);
|
|
80
|
+
return (jsx("nav", { ...rest, ref: ref, className: cx(navigationClasses.host, collapsed ? navigationClasses.collapsed : navigationClasses.expand, className), children: jsxs(NavigationActivatedContext.Provider, { value: {
|
|
81
|
+
activatedPath: activatedPath || innerActivatedPath,
|
|
82
|
+
setActivatedPath: combineSetActivatedPath,
|
|
83
|
+
currentPathname,
|
|
84
|
+
collapsed,
|
|
85
|
+
handleCollapseChange,
|
|
86
|
+
}, children: [headerComponent, jsx(NavigationOptionLevelContext.Provider, { value: navigationOptionLevelContextDefaultValues, children: jsxs("div", { className: navigationClasses.content, children: [searchInput, jsx("ul", { children: renderItemChildren(flattenedChildren) })] }) }), footerComponent] }) }));
|
|
55
87
|
});
|
|
56
88
|
|
|
57
89
|
export { Navigation as default };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
2
|
+
export interface NavigationFooterProps extends NativeElementPropsWithoutKeyAndRef<'footer'> {
|
|
3
|
+
/**
|
|
4
|
+
* Children of footer, only `NavigationUserMenu` is allowed as direct child,
|
|
5
|
+
* other children will be wrapped in an icons container.
|
|
6
|
+
*/
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
declare const NavigationFooter: import("react").ForwardRefExoticComponent<NavigationFooterProps & import("react").RefAttributes<HTMLElement>>;
|
|
10
|
+
export default NavigationFooter;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { forwardRef, use, Children, isValidElement } from 'react';
|
|
3
|
+
import { navigationFooterClasses } from '@mezzanine-ui/core/navigation';
|
|
4
|
+
import NavigationUserMenu from './NavigationUserMenu.js';
|
|
5
|
+
import { NavigationActivatedContext } from './context.js';
|
|
6
|
+
import cx from 'clsx';
|
|
7
|
+
|
|
8
|
+
const resolveChildren = (children) => {
|
|
9
|
+
let userMenu = null;
|
|
10
|
+
const otherChildren = [];
|
|
11
|
+
Children.map(children, (child) => {
|
|
12
|
+
if (isValidElement(child) && child.type === NavigationUserMenu) {
|
|
13
|
+
userMenu = child;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
otherChildren.push(child);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return { userMenu, otherChildren };
|
|
20
|
+
};
|
|
21
|
+
const NavigationFooter = forwardRef((props, ref) => {
|
|
22
|
+
const { children, className, ...rest } = props;
|
|
23
|
+
const { collapsed } = use(NavigationActivatedContext);
|
|
24
|
+
const { userMenu, otherChildren } = resolveChildren(children);
|
|
25
|
+
return (jsxs("footer", { ...rest, ref: ref, className: cx(navigationFooterClasses.host, collapsed && navigationFooterClasses.collapsed, className), children: [userMenu, jsx("span", { className: navigationFooterClasses.icons, children: otherChildren })] }));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export { NavigationFooter as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
3
|
+
export interface NavigationHeaderProps extends NativeElementPropsWithoutKeyAndRef<'header'> {
|
|
4
|
+
/**
|
|
5
|
+
* Custom content to render inside the header, typically an icon or logo.
|
|
6
|
+
*/
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* The title text displayed in the header.
|
|
10
|
+
*/
|
|
11
|
+
title: string;
|
|
12
|
+
}
|
|
13
|
+
declare const NavigationHeader: import("react").ForwardRefExoticComponent<NavigationHeaderProps & import("react").RefAttributes<HTMLElement>>;
|
|
14
|
+
export default NavigationHeader;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { forwardRef, use } from 'react';
|
|
3
|
+
import { navigationHeaderClasses } from '@mezzanine-ui/core/navigation';
|
|
4
|
+
import { SiderIcon } from '@mezzanine-ui/icons';
|
|
5
|
+
import NavigationIconButton from './NavigationIconButton.js';
|
|
6
|
+
import { NavigationActivatedContext } from './context.js';
|
|
7
|
+
import cx from 'clsx';
|
|
8
|
+
|
|
9
|
+
const NavigationHeader = forwardRef((props, ref) => {
|
|
10
|
+
const { children, className, title, ...rest } = props;
|
|
11
|
+
const { collapsed, handleCollapseChange } = use(NavigationActivatedContext);
|
|
12
|
+
return (jsxs("header", { ...rest, ref: ref, className: cx(navigationHeaderClasses.host, collapsed && navigationHeaderClasses.collapsed, className), children: [jsxs("span", { className: navigationHeaderClasses.content, children: [children, jsx("span", { className: navigationHeaderClasses.title, children: title })] }), jsx(NavigationIconButton, { onClick: () => handleCollapseChange(!collapsed), icon: SiderIcon })] }));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export { NavigationHeader as default };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IconDefinition } from '@mezzanine-ui/icons';
|
|
2
|
+
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
3
|
+
export type NavigationIconButtonProps = Omit<NativeElementPropsWithoutKeyAndRef<'button'>, 'children'> & {
|
|
4
|
+
/**
|
|
5
|
+
* The icon to be displayed.
|
|
6
|
+
*/
|
|
7
|
+
icon: IconDefinition;
|
|
8
|
+
};
|
|
9
|
+
declare const NavigationIconButton: import("react").ForwardRefExoticComponent<Omit<NativeElementPropsWithoutKeyAndRef<"button">, "children"> & {
|
|
10
|
+
/**
|
|
11
|
+
* The icon to be displayed.
|
|
12
|
+
*/
|
|
13
|
+
icon: IconDefinition;
|
|
14
|
+
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
15
|
+
export default NavigationIconButton;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { navigationIconButtonClasses } from '@mezzanine-ui/core/navigation';
|
|
4
|
+
import Icon from '../Icon/Icon.js';
|
|
5
|
+
import cx from 'clsx';
|
|
6
|
+
|
|
7
|
+
const NavigationIconButton = forwardRef((props, ref) => {
|
|
8
|
+
const { className, icon, ...rest } = props;
|
|
9
|
+
return (jsx("button", { ...rest, ref: ref, className: cx(navigationIconButtonClasses.host, className), type: "button", children: jsx(Icon, { icon: icon, size: 16 }) }));
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export { NavigationIconButton as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { IconDefinition } from '@mezzanine-ui/icons';
|
|
3
|
+
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
4
|
+
export type NavigationOptionChild = ReactElement<NavigationOptionProps>;
|
|
5
|
+
export type NavigationOptionChildren = NavigationOptionChild | NavigationOptionChild[];
|
|
6
|
+
export interface NavigationOptionProps extends Omit<NativeElementPropsWithoutKeyAndRef<'li'>, 'onClick' | 'onMouseEnter' | 'onMouseLeave'> {
|
|
7
|
+
/**
|
|
8
|
+
* Whether the item is active.
|
|
9
|
+
*/
|
|
10
|
+
active?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Strict children with `NavigationOption`.
|
|
13
|
+
*/
|
|
14
|
+
children?: NavigationOptionChildren;
|
|
15
|
+
/**
|
|
16
|
+
* Icon of the item.
|
|
17
|
+
*/
|
|
18
|
+
icon?: IconDefinition;
|
|
19
|
+
/**
|
|
20
|
+
* Unique ID of the item.
|
|
21
|
+
*/
|
|
22
|
+
href?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Set display title for sub-menu item.
|
|
25
|
+
*/
|
|
26
|
+
title?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Open menu as default
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
defaultOpen?: boolean;
|
|
32
|
+
onTriggerClick?: (path: string[], href: string) => void;
|
|
33
|
+
}
|
|
34
|
+
declare const NavigationOption: import("react").ForwardRefExoticComponent<NavigationOptionProps & import("react").RefAttributes<HTMLLIElement>>;
|
|
35
|
+
export default NavigationOption;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { forwardRef, useState, use, useMemo, useEffect } from 'react';
|
|
4
|
+
import { navigationOptionClasses } from '@mezzanine-ui/core/navigation';
|
|
5
|
+
import { ChevronUpIcon, ChevronDownIcon } from '@mezzanine-ui/icons';
|
|
6
|
+
import { NavigationOptionLevelContext, NavigationActivatedContext } from './context.js';
|
|
7
|
+
import Tooltip from '../Tooltip/Tooltip.js';
|
|
8
|
+
import Icon from '../Icon/Icon.js';
|
|
9
|
+
import Collapse from '../Transition/Collapse.js';
|
|
10
|
+
import cx from 'clsx';
|
|
11
|
+
|
|
12
|
+
const NavigationOption = forwardRef((props, ref) => {
|
|
13
|
+
const { active, children, className, defaultOpen = false, href, icon, onTriggerClick, title, ...rest } = props;
|
|
14
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
15
|
+
const GroupToggleIcon = open ? ChevronUpIcon : ChevronDownIcon;
|
|
16
|
+
const { level, path: parentPath } = use(NavigationOptionLevelContext);
|
|
17
|
+
const currentLevel = level + 1;
|
|
18
|
+
const currentKey = href || title || 'unknownId';
|
|
19
|
+
const currentPath = useMemo(() => [...parentPath, currentKey], [parentPath, currentKey]);
|
|
20
|
+
const { activatedPath, setActivatedPath, currentPathname, collapsed, handleCollapseChange, } = use(NavigationActivatedContext);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (currentPathname === href) {
|
|
23
|
+
setActivatedPath(currentPath);
|
|
24
|
+
}
|
|
25
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
|
+
}, []);
|
|
27
|
+
const Component = href ? 'a' : 'div';
|
|
28
|
+
return (jsxs("li", { ...rest, ref: ref, className: cx(navigationOptionClasses.host, open && navigationOptionClasses.open, !children && navigationOptionClasses.basic, (active !== null && active !== void 0 ? active : (activatedPath === null || activatedPath === void 0 ? void 0 : activatedPath[currentLevel - 1]) === currentKey) &&
|
|
29
|
+
navigationOptionClasses.active, collapsed && navigationOptionClasses.collapsed, className), "data-id": currentKey, children: [jsx(Tooltip, { options: {
|
|
30
|
+
placement: 'right',
|
|
31
|
+
}, title: collapsed ? title : undefined, children: ({ onMouseEnter, onMouseLeave, ref: tooltipChildRef }) => (jsxs(Component, { className: cx(navigationOptionClasses.content, navigationOptionClasses.level(currentLevel)), onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ref: tooltipChildRef, href: href, onClick: () => {
|
|
32
|
+
setOpen(!open);
|
|
33
|
+
onTriggerClick === null || onTriggerClick === void 0 ? void 0 : onTriggerClick(currentPath, href || '');
|
|
34
|
+
if (collapsed) {
|
|
35
|
+
handleCollapseChange(false);
|
|
36
|
+
}
|
|
37
|
+
if (!children)
|
|
38
|
+
setActivatedPath([...parentPath, currentKey]);
|
|
39
|
+
}, onKeyDown: (e) => {
|
|
40
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
setOpen(!open);
|
|
43
|
+
if (!children)
|
|
44
|
+
setActivatedPath([...parentPath, currentKey]);
|
|
45
|
+
}
|
|
46
|
+
}, role: "menuitem", tabIndex: 0, children: [icon && jsx(Icon, { className: navigationOptionClasses.icon, icon: icon }), jsx("span", { className: navigationOptionClasses.title, children: title }), children && (jsx(Icon, { className: navigationOptionClasses.toggleIcon, icon: GroupToggleIcon }))] })) }), children && !collapsed && (jsx(Collapse, { className: navigationOptionClasses.childrenWrapper, style: {
|
|
47
|
+
width: '100%',
|
|
48
|
+
}, in: !!open, children: jsx(NavigationOptionLevelContext.Provider, { value: {
|
|
49
|
+
level: currentLevel,
|
|
50
|
+
path: currentPath,
|
|
51
|
+
}, children: jsx("ul", { className: navigationOptionClasses.group, children: children }) }) }))] }));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export { NavigationOption as default };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
2
|
+
export interface NavigationOptionCategoryProps extends Omit<NativeElementPropsWithoutKeyAndRef<'li'>, 'onClick'> {
|
|
3
|
+
title: string;
|
|
4
|
+
}
|
|
5
|
+
declare const NavigationOptionCategory: import("react").ForwardRefExoticComponent<NavigationOptionCategoryProps & import("react").RefAttributes<HTMLLIElement>>;
|
|
6
|
+
export default NavigationOptionCategory;
|