@neo4j-ndl/react 4.22.0 → 4.22.1
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/lib/cjs/_common/form-control/FormFieldLabel.js +52 -0
- package/lib/cjs/_common/form-control/FormFieldLabel.js.map +1 -0
- package/lib/cjs/_common/form-control/FormFieldMessage.js +72 -0
- package/lib/cjs/_common/form-control/FormFieldMessage.js.map +1 -0
- package/lib/cjs/_common/form-control/form-control-types.js +23 -0
- package/lib/cjs/_common/form-control/form-control-types.js.map +1 -0
- package/lib/cjs/_common/form-control/index.js +39 -0
- package/lib/cjs/_common/form-control/index.js.map +1 -0
- package/lib/cjs/_common/form-control/use-form-field.js +76 -0
- package/lib/cjs/_common/form-control/use-form-field.js.map +1 -0
- package/lib/cjs/_common/form-control/use-inline-field-label.js +76 -0
- package/lib/cjs/_common/form-control/use-inline-field-label.js.map +1 -0
- package/lib/cjs/checkbox/Checkbox.js +9 -21
- package/lib/cjs/checkbox/Checkbox.js.map +1 -1
- package/lib/cjs/combobox/Combobox.js +61 -45
- package/lib/cjs/combobox/Combobox.js.map +1 -1
- package/lib/cjs/combobox/combobox-types.js.map +1 -1
- package/lib/cjs/date-picker/DatePicker.js.map +1 -1
- package/lib/cjs/radio/Radio.js +12 -22
- package/lib/cjs/radio/Radio.js.map +1 -1
- package/lib/cjs/select/Select.js +14 -5
- package/lib/cjs/select/Select.js.map +1 -1
- package/lib/cjs/select/types.js.map +1 -1
- package/lib/cjs/switch/Switch.js +9 -21
- package/lib/cjs/switch/Switch.js.map +1 -1
- package/lib/cjs/text-area/TextArea.js +8 -21
- package/lib/cjs/text-area/TextArea.js.map +1 -1
- package/lib/cjs/text-input/TextInput.js +15 -38
- package/lib/cjs/text-input/TextInput.js.map +1 -1
- package/lib/cjs/text-input/stories/text-input-sizes.story.js +1 -1
- package/lib/cjs/text-input/stories/text-input-sizes.story.js.map +1 -1
- package/lib/cjs/time-picker/TimePicker.js +13 -7
- package/lib/cjs/time-picker/TimePicker.js.map +1 -1
- package/lib/cjs/timezone-picker/TimeZonePicker.js +13 -7
- package/lib/cjs/timezone-picker/TimeZonePicker.js.map +1 -1
- package/lib/esm/_common/form-control/FormFieldLabel.js +45 -0
- package/lib/esm/_common/form-control/FormFieldLabel.js.map +1 -0
- package/lib/esm/_common/form-control/FormFieldMessage.js +65 -0
- package/lib/esm/_common/form-control/FormFieldMessage.js.map +1 -0
- package/lib/esm/_common/form-control/form-control-types.js +22 -0
- package/lib/esm/_common/form-control/form-control-types.js.map +1 -0
- package/lib/esm/_common/form-control/index.js +32 -0
- package/lib/esm/_common/form-control/index.js.map +1 -0
- package/lib/esm/_common/form-control/use-form-field.js +72 -0
- package/lib/esm/_common/form-control/use-form-field.js.map +1 -0
- package/lib/esm/_common/form-control/use-inline-field-label.js +69 -0
- package/lib/esm/_common/form-control/use-inline-field-label.js.map +1 -0
- package/lib/esm/checkbox/Checkbox.js +10 -22
- package/lib/esm/checkbox/Checkbox.js.map +1 -1
- package/lib/esm/combobox/Combobox.js +62 -46
- package/lib/esm/combobox/Combobox.js.map +1 -1
- package/lib/esm/combobox/combobox-types.js.map +1 -1
- package/lib/esm/date-picker/DatePicker.js.map +1 -1
- package/lib/esm/radio/Radio.js +12 -22
- package/lib/esm/radio/Radio.js.map +1 -1
- package/lib/esm/select/Select.js +14 -5
- package/lib/esm/select/Select.js.map +1 -1
- package/lib/esm/select/types.js.map +1 -1
- package/lib/esm/switch/Switch.js +10 -22
- package/lib/esm/switch/Switch.js.map +1 -1
- package/lib/esm/text-area/TextArea.js +9 -22
- package/lib/esm/text-area/TextArea.js.map +1 -1
- package/lib/esm/text-input/TextInput.js +15 -38
- package/lib/esm/text-input/TextInput.js.map +1 -1
- package/lib/esm/text-input/stories/text-input-sizes.story.js +1 -1
- package/lib/esm/text-input/stories/text-input-sizes.story.js.map +1 -1
- package/lib/esm/time-picker/TimePicker.js +13 -7
- package/lib/esm/time-picker/TimePicker.js.map +1 -1
- package/lib/esm/timezone-picker/TimeZonePicker.js +13 -7
- package/lib/esm/timezone-picker/TimeZonePicker.js.map +1 -1
- package/lib/types/_common/form-control/FormFieldLabel.d.ts +58 -0
- package/lib/types/_common/form-control/FormFieldLabel.d.ts.map +1 -0
- package/lib/types/_common/form-control/FormFieldMessage.d.ts +46 -0
- package/lib/types/_common/form-control/FormFieldMessage.d.ts.map +1 -0
- package/lib/types/_common/form-control/form-control-types.d.ts +92 -0
- package/lib/types/_common/form-control/form-control-types.d.ts.map +1 -0
- package/lib/types/_common/form-control/index.d.ts +33 -0
- package/lib/types/_common/form-control/index.d.ts.map +1 -0
- package/lib/types/_common/form-control/use-form-field.d.ts +53 -0
- package/lib/types/_common/form-control/use-form-field.d.ts.map +1 -0
- package/lib/types/_common/form-control/use-inline-field-label.d.ts +69 -0
- package/lib/types/_common/form-control/use-inline-field-label.d.ts.map +1 -0
- package/lib/types/checkbox/Checkbox.d.ts.map +1 -1
- package/lib/types/combobox/Combobox.d.ts.map +1 -1
- package/lib/types/combobox/combobox-types.d.ts +1 -1
- package/lib/types/combobox/combobox-types.d.ts.map +1 -1
- package/lib/types/radio/Radio.d.ts.map +1 -1
- package/lib/types/select/Select.d.ts.map +1 -1
- package/lib/types/select/types.d.ts.map +1 -1
- package/lib/types/switch/Switch.d.ts.map +1 -1
- package/lib/types/text-area/TextArea.d.ts.map +1 -1
- package/lib/types/text-input/TextInput.d.ts.map +1 -1
- package/lib/types/text-input/stories/text-input-sizes.story.d.ts.map +1 -1
- package/lib/types/time-picker/TimePicker.d.ts +3 -1
- package/lib/types/time-picker/TimePicker.d.ts.map +1 -1
- package/lib/types/timezone-picker/TimeZonePicker.d.ts +4 -1
- package/lib/types/timezone-picker/TimeZonePicker.d.ts.map +1 -1
- package/package.json +2 -2
- package/skills/ndl-react/SKILL.md +1 -1
- package/skills/ndl-react/components/color-picker.md +32 -32
- package/skills/ndl-react/components/combobox.md +2 -2
- package/skills/ndl-react/components/dropzone.md +5 -5
- package/skills/ndl-react/components/next/tree-view.md +87 -1
- package/skills/ndl-react/components/text-input.md +6 -0
- package/skills/ndl-react/components/time-picker.md +1 -0
- package/skills/ndl-react/components/timezone-picker.md +1 -0
|
@@ -31,12 +31,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
31
31
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
32
32
|
*/
|
|
33
33
|
import classNames from 'classnames';
|
|
34
|
-
import {
|
|
34
|
+
import { useMemo } from 'react';
|
|
35
|
+
import { FormFieldLabel, FormFieldMessage, useFormField, } from '../_common/form-control';
|
|
35
36
|
import { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';
|
|
36
37
|
import { needleWarningMessage } from '../_common/utils';
|
|
37
|
-
import { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';
|
|
38
|
-
import { InformationCircleIconOutline } from '../icons/generated/heroIcons/InformationCircleIconOutline';
|
|
39
|
-
import { Tooltip } from '../tooltip';
|
|
40
38
|
/**
|
|
41
39
|
*
|
|
42
40
|
*
|
|
@@ -46,8 +44,12 @@ import { Tooltip } from '../tooltip';
|
|
|
46
44
|
*/
|
|
47
45
|
export const TextArea = (_a) => {
|
|
48
46
|
var { label, isFluid = false, errorText, helpText, isOptional = false, moreInformationText, size = 'medium', ariaLabel, tooltipProps, isDisabled = false, className, isReadOnly = false, style, value, placeholder, htmlAttributes, ref } = _a, restProps = __rest(_a, ["label", "isFluid", "errorText", "helpText", "isOptional", "moreInformationText", "size", "ariaLabel", "tooltipProps", "isDisabled", "className", "isReadOnly", "style", "value", "placeholder", "htmlAttributes", "ref"]);
|
|
49
|
-
const
|
|
50
|
-
|
|
47
|
+
const { field, controlProps } = useFormField({
|
|
48
|
+
errorText,
|
|
49
|
+
hasRequiredIndicator: isOptional,
|
|
50
|
+
helpText,
|
|
51
|
+
label,
|
|
52
|
+
});
|
|
51
53
|
const containerWrappingClasses = classNames(`ndl-text-area ndl-type-text`, className, {
|
|
52
54
|
'ndl-disabled': isDisabled,
|
|
53
55
|
'ndl-has-error': errorText,
|
|
@@ -60,7 +62,6 @@ export const TextArea = (_a) => {
|
|
|
60
62
|
const hasEmptyLabelValue = !label || label === '';
|
|
61
63
|
const labelWrappingClasses = classNames('ndl-text-area-label', {
|
|
62
64
|
'ndl-fluid': isFluid,
|
|
63
|
-
'ndl-text-area-no-label': hasEmptyLabelValue,
|
|
64
65
|
});
|
|
65
66
|
const isCustomLabel = label && typeof label !== 'string';
|
|
66
67
|
const hasCustomLabelAndNoAriaLabel = isCustomLabel && !ariaLabel;
|
|
@@ -72,20 +73,6 @@ export const TextArea = (_a) => {
|
|
|
72
73
|
needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);
|
|
73
74
|
}
|
|
74
75
|
}, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);
|
|
75
|
-
|
|
76
|
-
'ndl-information-icon-large': size === 'large',
|
|
77
|
-
'ndl-information-icon-small': size === 'small' || size === 'medium',
|
|
78
|
-
});
|
|
79
|
-
const combinedAriaDescribedby = useMemo(() => {
|
|
80
|
-
const ariaDescribedby = [];
|
|
81
|
-
if (helpText && !errorText) {
|
|
82
|
-
ariaDescribedby.push(helpTextId);
|
|
83
|
-
}
|
|
84
|
-
else if (errorText) {
|
|
85
|
-
ariaDescribedby.push(errorTextId);
|
|
86
|
-
}
|
|
87
|
-
return ariaDescribedby.join(' ');
|
|
88
|
-
}, [helpText, errorText, helpTextId, errorTextId]);
|
|
89
|
-
return (_jsxs("div", { className: containerWrappingClasses, children: [_jsxs("label", { className: labelWrappingClasses, children: [_jsx("div", { className: "ndl-text-area-wrapper", children: _jsx("textarea", Object.assign({ disabled: isDisabled, ref: ref, "aria-label": ariaLabel, "aria-invalid": Boolean(errorText), readOnly: isReadOnly, value: value, placeholder: placeholder, style: style, "aria-describedby": combinedAriaDescribedby }, restProps, htmlAttributes)) }), !hasEmptyLabelValue && (_jsxs("div", { className: "ndl-text-area-wrapper", children: [_jsx("span", { className: "ndl-text-area-label-text", children: label }), Boolean(moreInformationText) && (_jsxs(Tooltip, Object.assign({ type: "simple" }, tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.root, { children: [_jsx(Tooltip.Trigger, Object.assign({}, tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.trigger, { children: _jsx("div", { className: informationIconClasses, "data-testid": "ndl-information-icon", children: _jsx(InformationCircleIconOutline, {}) }) })), _jsx(Tooltip.Content, Object.assign({}, tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.content, { children: moreInformationText }))] }))), isOptional && (_jsx("span", { className: "ndl-text-area-optional", children: "Optional" }))] }))] }), helpText && !errorText && (_jsx("div", { className: "ndl-text-area-msg", "aria-live": "polite", id: helpTextId, children: helpText })), errorText && (_jsxs("div", { className: "ndl-text-area-msg", children: [_jsx("div", { className: "ndl-error-icon", children: _jsx(ExclamationCircleIconSolid, {}) }), _jsx("div", { className: "ndl-error-text", id: errorTextId, "aria-live": "polite", children: errorText })] }))] }));
|
|
76
|
+
return (_jsxs("div", { className: containerWrappingClasses, children: [_jsxs("label", { className: labelWrappingClasses, children: [!hasEmptyLabelValue && (_jsx(FormFieldLabel, { field: field, size: size, association: "implicit", moreInformationText: moreInformationText, tooltipProps: tooltipProps })), _jsx("div", { className: "ndl-text-area-wrapper", children: _jsx("textarea", Object.assign({ disabled: isDisabled, ref: ref, "aria-label": ariaLabel, readOnly: isReadOnly, value: value, placeholder: placeholder, style: style }, controlProps, restProps, htmlAttributes)) })] }), _jsx(FormFieldMessage, { field: field, size: size })] }));
|
|
90
77
|
};
|
|
91
78
|
//# sourceMappingURL=TextArea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextArea.js","sourceRoot":"","sources":["../../../src/text-area/TextArea.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\nimport type React from 'react';\nimport { type ReactNode, useId, useMemo } from 'react';\n\nimport { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';\nimport {\n type CommonProps,\n type HtmlAttributes,\n type TooltipObjectProps,\n} from '../_common/types';\nimport { needleWarningMessage } from '../_common/utils';\nimport { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';\nimport { InformationCircleIconOutline } from '../icons/generated/heroIcons/InformationCircleIconOutline';\nimport { Tooltip } from '../tooltip';\n\n/**\n *\n *\n * Types\n *\n *\n */\n\n/**\n * @remarks\n * When `moreInformationText` is provided, a tooltip is rendered next to the label, and the `tooltipProps` prop is used to configure the tooltip. The `TooltipObjectProps` type is defined as: `{ root?: Partial<React.ComponentProps<typeof Tooltip>>; trigger?: Partial<React.ComponentProps<typeof Tooltip.Trigger>>; content?: Partial<React.ComponentProps<typeof Tooltip.Content>>; }`, see the Tooltip component for more details.\n */\ntype TextAreaProps = {\n /** The label displayed above the textarea */\n label?: ReactNode;\n\n /** Whether the textarea should take the full available width */\n isFluid?: boolean;\n\n /** Assistive text displayed below the textarea */\n helpText?: string | ReactNode;\n\n /** Error message displayed below the textarea. When provided, it overrides `helpText` and shows an error icon */\n errorText?: string | ReactNode;\n\n /** Size of the textarea */\n size?: 'small' | 'medium' | 'large';\n\n // TODO v5: replace with isRequired and hasRequiredIndicator, matching Combobox\n /** Whether to display the Optional label next to the field label */\n isOptional?: boolean;\n\n /** Text displayed in the information tooltip shown next to the label */\n moreInformationText?: React.ReactNode;\n\n /** Props for the Tooltip component used by the information icon */\n tooltipProps?: TooltipObjectProps;\n\n /** Whether the textarea is disabled */\n isDisabled?: boolean;\n\n /** Additional HTML attributes passed to the textarea element */\n htmlAttributes?: HtmlAttributes<'textarea'>;\n\n /** Aria label for accessibility when no visible label is provided */\n ariaLabel?: string;\n\n /** Additional class names */\n className?: string;\n\n /** Additional styles applied to the root element */\n style?: React.CSSProperties;\n\n /** Whether the textarea is read-only */\n isReadOnly?: boolean;\n\n /** The current value of the textarea */\n value?: React.ComponentPropsWithoutRef<'textarea'>['value'];\n\n /** Placeholder text displayed when the textarea is empty */\n placeholder?: React.ComponentPropsWithoutRef<'textarea'>['placeholder'];\n};\n\n/**\n *\n *\n * TextArea Component\n *\n *\n */\n\nexport const TextArea = ({\n label,\n isFluid = false,\n errorText,\n helpText,\n isOptional = false,\n moreInformationText,\n size = 'medium',\n ariaLabel,\n tooltipProps,\n isDisabled = false,\n className,\n isReadOnly = false,\n style,\n value,\n placeholder,\n htmlAttributes,\n ref,\n ...restProps\n}: CommonProps<'textarea', TextAreaProps>) => {\n const helpTextId = useId();\n const errorTextId = useId();\n const containerWrappingClasses = classNames(\n `ndl-text-area ndl-type-text`,\n className,\n {\n 'ndl-disabled': isDisabled,\n 'ndl-has-error': errorText,\n 'ndl-has-icon': errorText,\n 'ndl-has-trailing-icon': errorText,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-small': size === 'small',\n },\n );\n\n const hasEmptyLabelValue = !label || label === '';\n\n const labelWrappingClasses = classNames('ndl-text-area-label', {\n 'ndl-fluid': isFluid,\n 'ndl-text-area-no-label': hasEmptyLabelValue,\n });\n\n const isCustomLabel = label && typeof label !== 'string';\n const hasCustomLabelAndNoAriaLabel = isCustomLabel && !ariaLabel;\n\n useMemo(() => {\n if (!label && !ariaLabel) {\n needleWarningMessage(\n 'A TextArea without a label does not have an aria label, be sure to include an aria label for screen readers link: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI',\n );\n }\n\n if (hasCustomLabelAndNoAriaLabel) {\n needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);\n }\n }, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);\n\n const informationIconClasses = classNames({\n 'ndl-information-icon-large': size === 'large',\n 'ndl-information-icon-small': size === 'small' || size === 'medium',\n });\n\n const combinedAriaDescribedby = useMemo(() => {\n const ariaDescribedby = [];\n if (helpText && !errorText) {\n ariaDescribedby.push(helpTextId);\n } else if (errorText) {\n ariaDescribedby.push(errorTextId);\n }\n return ariaDescribedby.join(' ');\n }, [helpText, errorText, helpTextId, errorTextId]);\n\n return (\n <div className={containerWrappingClasses}>\n {/* We enable implicit label wrapping */}\n {/* Source: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI */}\n <label className={labelWrappingClasses}>\n <div className=\"ndl-text-area-wrapper\">\n <textarea\n disabled={isDisabled}\n ref={ref}\n aria-label={ariaLabel}\n aria-invalid={Boolean(errorText)}\n readOnly={isReadOnly}\n value={value}\n placeholder={placeholder}\n style={style}\n aria-describedby={combinedAriaDescribedby}\n {...restProps}\n {...htmlAttributes}\n />\n </div>\n {!hasEmptyLabelValue && (\n <div className=\"ndl-text-area-wrapper\">\n <span className=\"ndl-text-area-label-text\">{label}</span>\n {Boolean(moreInformationText) && (\n <Tooltip type=\"simple\" {...tooltipProps?.root}>\n <Tooltip.Trigger {...tooltipProps?.trigger}>\n <div\n className={informationIconClasses}\n data-testid=\"ndl-information-icon\"\n >\n <InformationCircleIconOutline />\n </div>\n </Tooltip.Trigger>\n <Tooltip.Content {...tooltipProps?.content}>\n {moreInformationText}\n </Tooltip.Content>\n </Tooltip>\n )}\n {isOptional && (\n <span className=\"ndl-text-area-optional\">Optional</span>\n )}\n </div>\n )}\n </label>\n {helpText && !errorText && (\n <div className=\"ndl-text-area-msg\" aria-live=\"polite\" id={helpTextId}>\n {helpText}\n </div>\n )}\n {errorText && (\n <div className=\"ndl-text-area-msg\">\n <div className=\"ndl-error-icon\">\n <ExclamationCircleIconSolid />\n </div>\n <div className=\"ndl-error-text\" id={errorTextId} aria-live=\"polite\">\n {errorText}\n </div>\n </div>\n )}\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"TextArea.js","sourceRoot":"","sources":["../../../src/text-area/TextArea.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\nimport type React from 'react';\nimport { type ReactNode, useMemo } from 'react';\n\nimport {\n FormFieldLabel,\n FormFieldMessage,\n useFormField,\n} from '../_common/form-control';\nimport { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';\nimport {\n type CommonProps,\n type HtmlAttributes,\n type TooltipObjectProps,\n} from '../_common/types';\nimport { needleWarningMessage } from '../_common/utils';\n\n/**\n *\n *\n * Types\n *\n *\n */\n\n/**\n * @remarks\n * When `moreInformationText` is provided, a tooltip is rendered next to the label, and the `tooltipProps` prop is used to configure the tooltip. The `TooltipObjectProps` type is defined as: `{ root?: Partial<React.ComponentProps<typeof Tooltip>>; trigger?: Partial<React.ComponentProps<typeof Tooltip.Trigger>>; content?: Partial<React.ComponentProps<typeof Tooltip.Content>>; }`, see the Tooltip component for more details.\n */\ntype TextAreaProps = {\n // TODO v5: inconsistent naming. The label is optional here and pairs with the\n // `ariaLabel` prop below, while Combobox requires the label and clips it with\n // `hasVisuallyHiddenLabel`, and TextInput has no aria label prop at all.\n /** The label displayed above the textarea */\n label?: ReactNode;\n\n /** Whether the textarea should take the full available width */\n isFluid?: boolean;\n\n /** Assistive text displayed below the textarea */\n helpText?: string | ReactNode;\n\n /** Error message displayed below the textarea. When provided, it overrides `helpText` and shows an error icon */\n errorText?: string | ReactNode;\n\n /** Size of the textarea */\n size?: 'small' | 'medium' | 'large';\n\n // TODO v5: inconsistent naming, and one prop doing two jobs. The same switch\n // is `showRequiredOrOptionalLabel` on TextInput and `hasRequiredIndicator` on\n // Combobox and on the internal form control this maps onto. Here it also\n // decides both whether the indicator shows at all and which word it shows,\n // because TextArea exposes no `isRequired` to pair it with: requiredness has\n // to be set through htmlAttributes.required, and exposing `isRequired` on its\n // own would silently render no indicator.\n /** Whether to display the Optional label next to the field label */\n isOptional?: boolean;\n\n /** Text displayed in the information tooltip shown next to the label */\n moreInformationText?: React.ReactNode;\n\n /** Props for the Tooltip component used by the information icon */\n tooltipProps?: TooltipObjectProps;\n\n /** Whether the textarea is disabled */\n isDisabled?: boolean;\n\n /** Additional HTML attributes passed to the textarea element */\n htmlAttributes?: HtmlAttributes<'textarea'>;\n\n // TODO v5: inconsistent naming. This replaces the accessible name rather than\n // hiding the label, which is a second way of naming the control alongside\n // `label` above. TextInput reaches for htmlAttributes['aria-label'] for the\n // same case and Combobox clips the label with `hasVisuallyHiddenLabel`.\n /** Aria label for accessibility when no visible label is provided */\n ariaLabel?: string;\n\n /** Additional class names */\n className?: string;\n\n /** Additional styles applied to the root element */\n style?: React.CSSProperties;\n\n /** Whether the textarea is read-only */\n isReadOnly?: boolean;\n\n /** The current value of the textarea */\n value?: React.ComponentPropsWithoutRef<'textarea'>['value'];\n\n /** Placeholder text displayed when the textarea is empty */\n placeholder?: React.ComponentPropsWithoutRef<'textarea'>['placeholder'];\n};\n\n/**\n *\n *\n * TextArea Component\n *\n *\n */\n\nexport const TextArea = ({\n label,\n isFluid = false,\n errorText,\n helpText,\n isOptional = false,\n moreInformationText,\n size = 'medium',\n ariaLabel,\n tooltipProps,\n isDisabled = false,\n className,\n isReadOnly = false,\n style,\n value,\n placeholder,\n htmlAttributes,\n ref,\n ...restProps\n}: CommonProps<'textarea', TextAreaProps>) => {\n const { field, controlProps } = useFormField({\n errorText,\n hasRequiredIndicator: isOptional,\n helpText,\n label,\n });\n const containerWrappingClasses = classNames(\n `ndl-text-area ndl-type-text`,\n className,\n {\n 'ndl-disabled': isDisabled,\n 'ndl-has-error': errorText,\n 'ndl-has-icon': errorText,\n 'ndl-has-trailing-icon': errorText,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-small': size === 'small',\n },\n );\n\n const hasEmptyLabelValue = !label || label === '';\n\n const labelWrappingClasses = classNames('ndl-text-area-label', {\n 'ndl-fluid': isFluid,\n });\n\n const isCustomLabel = label && typeof label !== 'string';\n const hasCustomLabelAndNoAriaLabel = isCustomLabel && !ariaLabel;\n\n useMemo(() => {\n if (!label && !ariaLabel) {\n needleWarningMessage(\n 'A TextArea without a label does not have an aria label, be sure to include an aria label for screen readers link: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI',\n );\n }\n\n if (hasCustomLabelAndNoAriaLabel) {\n needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);\n }\n }, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);\n\n return (\n <div className={containerWrappingClasses}>\n {/* We enable implicit label wrapping */}\n {/* Source: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI */}\n <label className={labelWrappingClasses}>\n {!hasEmptyLabelValue && (\n <FormFieldLabel\n field={field}\n size={size}\n association=\"implicit\"\n moreInformationText={moreInformationText}\n tooltipProps={tooltipProps}\n />\n )}\n <div className=\"ndl-text-area-wrapper\">\n <textarea\n disabled={isDisabled}\n ref={ref}\n aria-label={ariaLabel}\n readOnly={isReadOnly}\n value={value}\n placeholder={placeholder}\n style={style}\n {...controlProps}\n {...restProps}\n {...htmlAttributes}\n />\n </div>\n </label>\n <FormFieldMessage field={field} size={size} />\n </div>\n );\n};\n"]}
|
|
@@ -32,16 +32,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
32
32
|
*/
|
|
33
33
|
import classNames from 'classnames';
|
|
34
34
|
import { useId, useMemo, } from 'react';
|
|
35
|
+
import { FormFieldLabel, FormFieldMessage, useFormField, } from '../_common/form-control';
|
|
35
36
|
import { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';
|
|
36
37
|
import { useSemiControlledInput } from '../_common/use-semi-controlled-input';
|
|
37
38
|
import { needleWarningMessage } from '../_common/utils';
|
|
38
|
-
import { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';
|
|
39
|
-
import { InformationCircleIconOutline } from '../icons/generated/heroIcons/InformationCircleIconOutline';
|
|
40
39
|
import { XMarkIconOutline } from '../icons/generated/heroIcons/XMarkIconOutline';
|
|
41
40
|
import { LoadingSpinner } from '../loading-spinner';
|
|
42
41
|
import { Skeleton } from '../skeleton';
|
|
43
|
-
import { Tooltip } from '../tooltip';
|
|
44
|
-
import { Typography } from '../typography';
|
|
45
42
|
/**
|
|
46
43
|
*
|
|
47
44
|
*
|
|
@@ -58,8 +55,16 @@ export const TextInput = (_a) => {
|
|
|
58
55
|
state: value !== null && value !== void 0 ? value : '',
|
|
59
56
|
});
|
|
60
57
|
const hintId = useId();
|
|
61
|
-
const
|
|
62
|
-
const
|
|
58
|
+
const shouldRenderHint = isClearable || isLoading;
|
|
59
|
+
const { field, controlProps } = useFormField({
|
|
60
|
+
errorText,
|
|
61
|
+
// The clear/loading hint describes the input alongside the message.
|
|
62
|
+
extraDescribedByIds: [shouldRenderHint && hintId],
|
|
63
|
+
hasRequiredIndicator: showRequiredOrOptionalLabel,
|
|
64
|
+
helpText,
|
|
65
|
+
isRequired,
|
|
66
|
+
label,
|
|
67
|
+
});
|
|
63
68
|
const containerWrappingClasses = classNames(`ndl-text-input`, className, {
|
|
64
69
|
'ndl-disabled': isDisabled,
|
|
65
70
|
'ndl-has-error': errorText,
|
|
@@ -72,15 +77,13 @@ export const TextInput = (_a) => {
|
|
|
72
77
|
'ndl-small': size === 'small',
|
|
73
78
|
});
|
|
74
79
|
const hasEmptyLabelValue = label === undefined || label === null || label === '';
|
|
75
|
-
const labelWrappingClasses = classNames('ndl-
|
|
80
|
+
const labelWrappingClasses = classNames('ndl-text-input-label', {
|
|
76
81
|
'ndl-fluid': isFluid,
|
|
77
|
-
'ndl-form-item-no-label': hasEmptyLabelValue,
|
|
78
82
|
});
|
|
79
83
|
const combinedHtmlInputAttributes = Object.assign(Object.assign({}, htmlAttributes), { className: classNames('ndl-input', htmlAttributes === null || htmlAttributes === void 0 ? void 0 : htmlAttributes.className) });
|
|
80
84
|
const ariaLabel = combinedHtmlInputAttributes['aria-label'];
|
|
81
85
|
const isCustomLabel = Boolean(label) && typeof label !== 'string';
|
|
82
86
|
const hasCustomLabelAndNoAriaLabel = isCustomLabel && (ariaLabel === undefined || ariaLabel === '');
|
|
83
|
-
const shouldRenderHint = isClearable || isLoading;
|
|
84
87
|
const handleInputKeyDown = (event) => {
|
|
85
88
|
var _a;
|
|
86
89
|
if (isClearable && event.key === 'Escape' && Boolean(currentValue)) {
|
|
@@ -100,42 +103,16 @@ export const TextInput = (_a) => {
|
|
|
100
103
|
needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);
|
|
101
104
|
}
|
|
102
105
|
}, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);
|
|
103
|
-
|
|
104
|
-
'ndl-information-icon-large': size === 'large',
|
|
105
|
-
'ndl-information-icon-small': size === 'small' || size === 'medium',
|
|
106
|
-
});
|
|
107
|
-
const combinedAriaDescribedby = useMemo(() => {
|
|
108
|
-
const ariaDescribedby = [];
|
|
109
|
-
if (hintId && shouldRenderHint) {
|
|
110
|
-
ariaDescribedby.push(hintId);
|
|
111
|
-
}
|
|
112
|
-
if (helpText && !errorText) {
|
|
113
|
-
ariaDescribedby.push(helpTextId);
|
|
114
|
-
}
|
|
115
|
-
else if (errorText) {
|
|
116
|
-
ariaDescribedby.push(errorTextId);
|
|
117
|
-
}
|
|
118
|
-
return ariaDescribedby.join(' ');
|
|
119
|
-
}, [hintId, shouldRenderHint, helpText, errorText, helpTextId, errorTextId]);
|
|
120
|
-
return (_jsxs("div", { className: containerWrappingClasses, style: style, children: [_jsxs("label", { className: labelWrappingClasses, children: [!hasEmptyLabelValue && (_jsx(Skeleton, Object.assign({ onBackground: "weak", shape: "rectangular" }, skeletonProps, { isLoading: isSkeletonLoading, children: _jsxs("div", { className: "ndl-label-text-wrapper", children: [_jsx(Typography, { variant: size === 'large' ? 'body-large' : 'body-medium', className: "ndl-label-text", children: label }), Boolean(moreInformationText) && (_jsxs(Tooltip, Object.assign({}, tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.root, { type: "simple", children: [_jsx(Tooltip.Trigger, Object.assign({}, tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.trigger, { className: informationIconClasses, hasButtonWrapper: true, children: _jsx("div", { tabIndex: 0, role: "button", "aria-label": "Information icon", children: _jsx(InformationCircleIconOutline, {}) }) })), _jsx(Tooltip.Content, Object.assign({}, tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.content, { children: moreInformationText }))] }))), showRequiredOrOptionalLabel && (_jsx(Typography, { variant: size === 'large' ? 'body-large' : 'body-medium', className: "ndl-form-item-optional", children: isRequired === true ? 'Required' : 'Optional' }))] }) }))), _jsx(Skeleton, Object.assign({ onBackground: "weak", shape: "rectangular" }, skeletonProps, { isLoading: isSkeletonLoading, children: _jsxs("div", { className: "ndl-input-wrapper", children: [(leadingElement || (isLoading && !trailingElement)) && (_jsx("div", { className: "ndl-element-leading ndl-element", children: isLoading ? (_jsx(LoadingSpinner, { size: size === 'large' ? 'medium' : 'small', className: size === 'large'
|
|
106
|
+
return (_jsxs("div", { className: containerWrappingClasses, style: style, children: [_jsxs("label", { className: labelWrappingClasses, children: [!hasEmptyLabelValue && (_jsx(FormFieldLabel, { field: field, size: size, association: "implicit", moreInformationText: moreInformationText, tooltipProps: tooltipProps, wrap: (row) => (_jsx(Skeleton, Object.assign({ onBackground: "weak", shape: "rectangular" }, skeletonProps, { isLoading: isSkeletonLoading, children: row }))) })), _jsx(Skeleton, Object.assign({ onBackground: "weak", shape: "rectangular" }, skeletonProps, { isLoading: isSkeletonLoading, children: _jsxs("div", { className: "ndl-input-wrapper", children: [(leadingElement || (isLoading && !trailingElement)) && (_jsx("div", { className: "ndl-element-leading ndl-element", children: isLoading ? (_jsx(LoadingSpinner, { size: size === 'large' ? 'medium' : 'small', className: size === 'large'
|
|
121
107
|
? 'ndl-medium-spinner'
|
|
122
108
|
: 'ndl-small-spinner' })) : (leadingElement) })), _jsxs("div", { className: classNames('ndl-input-container', {
|
|
123
109
|
'ndl-clearable': isClearable,
|
|
124
|
-
}), children: [_jsx("input", Object.assign({ ref: ref, readOnly: isReadOnly, disabled: isDisabled, required: isRequired, value: currentValue, placeholder: placeholder, type: "text", onChange: handleChange
|
|
110
|
+
}), children: [_jsx("input", Object.assign({ ref: ref, readOnly: isReadOnly, disabled: isDisabled, required: isRequired, value: currentValue, placeholder: placeholder, type: "text", onChange: handleChange }, controlProps, combinedHtmlInputAttributes, { onKeyDown: handleInputKeyDown }, restProps)), shouldRenderHint && (_jsxs("span", { id: hintId, className: "ndl-text-input-hint", "aria-hidden": true, children: [isLoading && 'Loading ', isClearable && 'Press Escape to clear input.'] })), isClearable && Boolean(currentValue) && (_jsx("div", { className: "ndl-element-clear ndl-element", children: _jsx("button", { tabIndex: -1, "aria-hidden": true, type: "button", title: "Clear input (Esc)", onClick: () => {
|
|
125
111
|
handleChange === null || handleChange === void 0 ? void 0 : handleChange({
|
|
126
112
|
target: { value: '' },
|
|
127
113
|
});
|
|
128
114
|
}, children: _jsx(XMarkIconOutline, { className: "n-size-4" }) }) }))] }), trailingElement && (_jsx("div", { className: "ndl-element-trailing ndl-element", children: isLoading && !leadingElement ? (_jsx(LoadingSpinner, { size: size === 'large' ? 'medium' : 'small', className: size === 'large'
|
|
129
115
|
? 'ndl-medium-spinner'
|
|
130
|
-
: 'ndl-small-spinner' })) : (trailingElement) }))] }) }))] }),
|
|
131
|
-
'aria-live': 'polite',
|
|
132
|
-
id: helpTextId,
|
|
133
|
-
}, children: helpText }) })), Boolean(errorText) && (
|
|
134
|
-
// TODO v4: We might want to have a min width for the container for the messages to help skeleton loading.
|
|
135
|
-
// Currently the message fills 100% of the width while the rest of the text input has a set width.
|
|
136
|
-
_jsx(Skeleton, Object.assign({ onBackground: "weak", shape: "rectangular", width: "fit-content" }, skeletonProps, { isLoading: isSkeletonLoading, children: _jsxs("div", { className: "ndl-form-message", children: [_jsx("div", { className: "ndl-error-icon", children: _jsx(ExclamationCircleIconSolid, {}) }), _jsx(Typography, { className: "ndl-error-text", variant: size === 'large' ? 'body-medium' : 'body-small', htmlAttributes: {
|
|
137
|
-
'aria-live': 'polite',
|
|
138
|
-
id: errorTextId,
|
|
139
|
-
}, children: errorText })] }) })))] }));
|
|
116
|
+
: 'ndl-small-spinner' })) : (trailingElement) }))] }) }))] }), _jsx(FormFieldMessage, { field: field, size: size, wrap: (content) => (_jsx(Skeleton, Object.assign({ onBackground: "weak", shape: "rectangular" }, skeletonProps, { isLoading: isSkeletonLoading, children: content }))) })] }));
|
|
140
117
|
};
|
|
141
118
|
//# sourceMappingURL=TextInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../../src/text-input/TextInput.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport classNames from 'classnames';\nimport {\n type InputHTMLAttributes,\n type ReactElement,\n type ReactNode,\n useId,\n useMemo,\n} from 'react';\n\nimport { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';\nimport { type CommonProps, type TooltipObjectProps } from '../_common/types';\nimport { useSemiControlledInput } from '../_common/use-semi-controlled-input';\nimport { needleWarningMessage } from '../_common/utils';\nimport { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';\nimport { InformationCircleIconOutline } from '../icons/generated/heroIcons/InformationCircleIconOutline';\nimport { XMarkIconOutline } from '../icons/generated/heroIcons/XMarkIconOutline';\nimport { LoadingSpinner } from '../loading-spinner';\nimport { Skeleton } from '../skeleton';\nimport { Tooltip } from '../tooltip';\nimport { Typography } from '../typography';\n\n/**\n * @remarks\n * When `moreInformationText` is provided, a tooltip is rendered next to the label, and the `tooltipProps` prop is used to configure the tooltip. The `TooltipObjectProps` type is defined as: `{ root?: Partial<React.ComponentProps<typeof Tooltip>>; trigger?: Partial<React.ComponentProps<typeof Tooltip.Trigger>>; content?: Partial<React.ComponentProps<typeof Tooltip.Content>>; }`, see the Tooltip component for more details.\n *\n * @remarks\n * When `isSkeletonLoading` is true, the input is rendered as a loading skeleton and the `skeletonProps` prop is used to configure the skeleton. For more information, see the Skeleton documentation.\n */\ntype TextInputProps = {\n /** Assistive text displayed below the input */\n helpText?: string | ReactNode;\n\n /** Error message displayed below the input. When provided, it overrides `helpText` and shows an error icon */\n errorText?: string | ReactNode;\n\n /** Leading element rendered inside the input */\n leadingElement?: ReactElement;\n\n /** Trailing element rendered inside the input */\n trailingElement?: ReactElement;\n\n /** Size of the input */\n size?: 'small' | 'medium' | 'large';\n\n /** Whether the input is read-only */\n isReadOnly?: boolean;\n\n /**\n * Whether to display the Required/Optional label next to the field label.\n * Shows Required if isRequired is true, otherwise shows Optional.\n * @default false\n */\n // TODO v5: rename to hasRequiredIndicator, matching Combobox. That also drops\n // the naming-convention disable below, since has is an allowed prefix.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n showRequiredOrOptionalLabel?: boolean;\n\n /** Whether the input is disabled */\n isDisabled?: boolean;\n\n /** Whether the input is required */\n isRequired?: boolean;\n\n /** The current value of the input */\n value?: React.ComponentPropsWithoutRef<'input'>['value'];\n\n /** Placeholder text displayed when the input is empty */\n placeholder?: React.ComponentPropsWithoutRef<'input'>['placeholder'];\n\n /** Callback function triggered when the input value changes */\n onChange?: React.ComponentPropsWithoutRef<'input'>['onChange'];\n\n /** Whether the input should take the full available width */\n isFluid?: boolean;\n\n /** Text displayed in the information tooltip shown next to the label */\n moreInformationText?: React.ReactNode;\n\n /** The label displayed above the input */\n label?: string | React.ReactNode;\n\n /** Props for the Tooltip component used by the information icon */\n tooltipProps?: TooltipObjectProps;\n\n /** Whether to render skeletons instead of content */\n isSkeletonLoading?: boolean;\n\n /** Additional props forwarded to the underlying Skeleton components */\n skeletonProps?: React.ComponentProps<typeof Skeleton>;\n\n /** Whether to show the clear button */\n isClearable?: boolean;\n\n /** Whether to show the loading spinner */\n isLoading?: boolean;\n};\n\n/**\n *\n *\n * TextInput Component\n *\n *\n */\n\nexport const TextInput = ({\n label,\n isFluid,\n errorText,\n helpText,\n leadingElement,\n trailingElement,\n showRequiredOrOptionalLabel = false,\n moreInformationText,\n size = 'medium',\n placeholder,\n value,\n tooltipProps,\n htmlAttributes,\n isDisabled,\n isReadOnly,\n isRequired,\n onChange,\n isClearable = false,\n className,\n style,\n isSkeletonLoading = false,\n isLoading = false,\n skeletonProps,\n ref,\n ...restProps\n}: CommonProps<'input', TextInputProps>) => {\n const [currentValue, handleChange] = useSemiControlledInput({\n inputType: 'text',\n isControlled: value !== undefined,\n onChange,\n state: value ?? '',\n });\n const hintId = useId();\n const helpTextId = useId();\n const errorTextId = useId();\n\n const containerWrappingClasses = classNames(`ndl-text-input`, className, {\n 'ndl-disabled': isDisabled,\n 'ndl-has-error': errorText,\n 'ndl-has-icon': leadingElement || trailingElement || errorText,\n 'ndl-has-leading-icon': leadingElement,\n 'ndl-has-trailing-icon': trailingElement || errorText,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-read-only': isReadOnly,\n 'ndl-small': size === 'small',\n });\n\n const hasEmptyLabelValue =\n label === undefined || label === null || label === '';\n\n const labelWrappingClasses = classNames('ndl-form-item-label', {\n 'ndl-fluid': isFluid,\n 'ndl-form-item-no-label': hasEmptyLabelValue,\n });\n\n const combinedHtmlInputAttributes: InputHTMLAttributes<HTMLInputElement> = {\n ...htmlAttributes,\n className: classNames('ndl-input', htmlAttributes?.className),\n };\n const ariaLabel = combinedHtmlInputAttributes['aria-label'];\n const isCustomLabel = Boolean(label) && typeof label !== 'string';\n const hasCustomLabelAndNoAriaLabel =\n isCustomLabel && (ariaLabel === undefined || ariaLabel === '');\n const shouldRenderHint = isClearable || isLoading;\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (isClearable && event.key === 'Escape' && Boolean(currentValue)) {\n event.preventDefault();\n event.stopPropagation();\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }\n htmlAttributes?.onKeyDown?.(event);\n };\n\n useMemo(() => {\n if (!label && !ariaLabel) {\n needleWarningMessage(\n 'A TextInput without a label does not have an aria label, be sure to include an aria label for screen readers. Link: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI',\n );\n }\n\n if (hasCustomLabelAndNoAriaLabel) {\n needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);\n }\n }, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);\n\n const informationIconClasses = classNames({\n 'ndl-information-icon-large': size === 'large',\n 'ndl-information-icon-small': size === 'small' || size === 'medium',\n });\n\n const combinedAriaDescribedby = useMemo(() => {\n const ariaDescribedby = [];\n\n if (hintId && shouldRenderHint) {\n ariaDescribedby.push(hintId);\n }\n if (helpText && !errorText) {\n ariaDescribedby.push(helpTextId);\n } else if (errorText) {\n ariaDescribedby.push(errorTextId);\n }\n return ariaDescribedby.join(' ');\n }, [hintId, shouldRenderHint, helpText, errorText, helpTextId, errorTextId]);\n\n return (\n <div className={containerWrappingClasses} style={style}>\n {/* We enable implicit label wrapping */}\n {/* Source: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI */}\n <label className={labelWrappingClasses}>\n {!hasEmptyLabelValue && (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-label-text-wrapper\">\n <Typography\n variant={size === 'large' ? 'body-large' : 'body-medium'}\n className=\"ndl-label-text\"\n >\n {label}\n </Typography>\n {Boolean(moreInformationText) && (\n <Tooltip {...tooltipProps?.root} type=\"simple\">\n <Tooltip.Trigger\n {...tooltipProps?.trigger}\n className={informationIconClasses}\n hasButtonWrapper\n >\n <div\n tabIndex={0}\n role=\"button\"\n aria-label=\"Information icon\"\n >\n <InformationCircleIconOutline />\n </div>\n </Tooltip.Trigger>\n <Tooltip.Content {...tooltipProps?.content}>\n {moreInformationText}\n </Tooltip.Content>\n </Tooltip>\n )}\n {showRequiredOrOptionalLabel && (\n <Typography\n variant={size === 'large' ? 'body-large' : 'body-medium'}\n className=\"ndl-form-item-optional\"\n >\n {isRequired === true ? 'Required' : 'Optional'}\n </Typography>\n )}\n </div>\n </Skeleton>\n )}\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-input-wrapper\">\n {(leadingElement || (isLoading && !trailingElement)) && (\n <div className=\"ndl-element-leading ndl-element\">\n {isLoading ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n leadingElement\n )}\n </div>\n )}\n <div\n className={classNames('ndl-input-container', {\n 'ndl-clearable': isClearable,\n })}\n >\n <input\n ref={ref}\n readOnly={isReadOnly}\n disabled={isDisabled}\n required={isRequired}\n value={currentValue}\n placeholder={placeholder}\n type=\"text\"\n onChange={handleChange}\n aria-describedby={combinedAriaDescribedby}\n aria-invalid={Boolean(errorText)}\n {...combinedHtmlInputAttributes}\n onKeyDown={handleInputKeyDown}\n {...restProps}\n />\n {shouldRenderHint && (\n <span\n id={hintId}\n className=\"ndl-text-input-hint\"\n aria-hidden={true}\n >\n {isLoading && 'Loading '}\n {isClearable && 'Press Escape to clear input.'}\n </span>\n )}\n {isClearable && Boolean(currentValue) && (\n <div className=\"ndl-element-clear ndl-element\">\n <button\n tabIndex={-1}\n aria-hidden={true}\n type=\"button\"\n title=\"Clear input (Esc)\"\n onClick={() => {\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }}\n >\n <XMarkIconOutline className=\"n-size-4\" />\n </button>\n </div>\n )}\n </div>\n {trailingElement && (\n <div className=\"ndl-element-trailing ndl-element\">\n {isLoading && !leadingElement ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n trailingElement\n )}\n </div>\n )}\n </div>\n </Skeleton>\n </label>\n {Boolean(helpText) && !errorText && (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n isLoading={isSkeletonLoading}\n >\n <Typography\n variant={size === 'large' ? 'body-medium' : 'body-small'}\n className=\"ndl-form-message\"\n htmlAttributes={{\n 'aria-live': 'polite',\n id: helpTextId,\n }}\n >\n {helpText}\n </Typography>\n </Skeleton>\n )}\n {Boolean(errorText) && (\n // TODO v4: We might want to have a min width for the container for the messages to help skeleton loading.\n // Currently the message fills 100% of the width while the rest of the text input has a set width.\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n width=\"fit-content\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-form-message\">\n <div className=\"ndl-error-icon\">\n <ExclamationCircleIconSolid />\n </div>\n <Typography\n className=\"ndl-error-text\"\n variant={size === 'large' ? 'body-medium' : 'body-small'}\n htmlAttributes={{\n 'aria-live': 'polite',\n id: errorTextId,\n }}\n >\n {errorText}\n </Typography>\n </div>\n </Skeleton>\n )}\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../../src/text-input/TextInput.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport classNames from 'classnames';\nimport {\n type InputHTMLAttributes,\n type ReactElement,\n type ReactNode,\n useId,\n useMemo,\n} from 'react';\n\nimport {\n FormFieldLabel,\n FormFieldMessage,\n useFormField,\n} from '../_common/form-control';\nimport { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';\nimport { type CommonProps, type TooltipObjectProps } from '../_common/types';\nimport { useSemiControlledInput } from '../_common/use-semi-controlled-input';\nimport { needleWarningMessage } from '../_common/utils';\nimport { XMarkIconOutline } from '../icons/generated/heroIcons/XMarkIconOutline';\nimport { LoadingSpinner } from '../loading-spinner';\nimport { Skeleton } from '../skeleton';\n\n/**\n * @remarks\n * When `moreInformationText` is provided, a tooltip is rendered next to the label, and the `tooltipProps` prop is used to configure the tooltip. The `TooltipObjectProps` type is defined as: `{ root?: Partial<React.ComponentProps<typeof Tooltip>>; trigger?: Partial<React.ComponentProps<typeof Tooltip.Trigger>>; content?: Partial<React.ComponentProps<typeof Tooltip.Content>>; }`, see the Tooltip component for more details.\n *\n * @remarks\n * When `isSkeletonLoading` is true, the input is rendered as a loading skeleton and the `skeletonProps` prop is used to configure the skeleton. For more information, see the Skeleton documentation.\n */\ntype TextInputProps = {\n /** Assistive text displayed below the input */\n helpText?: string | ReactNode;\n\n /** Error message displayed below the input. When provided, it overrides `helpText` and shows an error icon */\n errorText?: string | ReactNode;\n\n /** Leading element rendered inside the input */\n leadingElement?: ReactElement;\n\n /** Trailing element rendered inside the input */\n trailingElement?: ReactElement;\n\n /** Size of the input */\n size?: 'small' | 'medium' | 'large';\n\n /** Whether the input is read-only */\n isReadOnly?: boolean;\n\n /**\n * Whether to display the Required/Optional label next to the field label.\n * Shows Required if isRequired is true, otherwise shows Optional.\n * @default false\n */\n // TODO v5: inconsistent naming. The same switch is `hasRequiredIndicator` on\n // Combobox and on the internal form control this maps onto, and `isOptional`\n // on TextArea. The name also needs the disable below, which a name using one\n // of the allowed boolean prefixes would not.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n showRequiredOrOptionalLabel?: boolean;\n\n /** Whether the input is disabled */\n isDisabled?: boolean;\n\n /** Whether the input is required */\n isRequired?: boolean;\n\n /** The current value of the input */\n value?: React.ComponentPropsWithoutRef<'input'>['value'];\n\n /** Placeholder text displayed when the input is empty */\n placeholder?: React.ComponentPropsWithoutRef<'input'>['placeholder'];\n\n /** Callback function triggered when the input value changes */\n onChange?: React.ComponentPropsWithoutRef<'input'>['onChange'];\n\n /** Whether the input should take the full available width */\n isFluid?: boolean;\n\n /** Text displayed in the information tooltip shown next to the label */\n moreInformationText?: React.ReactNode;\n\n // TODO v5: inconsistent naming. Every form control names itself differently:\n // the label is optional here and a design with no room for it reaches for\n // htmlAttributes['aria-label'], TextArea, Select, Checkbox, Radio and Switch\n // expose an `ariaLabel` prop instead, and Combobox requires the label and\n // clips it with `hasVisuallyHiddenLabel`.\n /** The label displayed above the input */\n label?: string | React.ReactNode;\n\n /** Props for the Tooltip component used by the information icon */\n tooltipProps?: TooltipObjectProps;\n\n /** Whether to render skeletons instead of content */\n isSkeletonLoading?: boolean;\n\n /** Additional props forwarded to the underlying Skeleton components */\n skeletonProps?: React.ComponentProps<typeof Skeleton>;\n\n /** Whether to show the clear button */\n isClearable?: boolean;\n\n /** Whether to show the loading spinner */\n isLoading?: boolean;\n};\n\n/**\n *\n *\n * TextInput Component\n *\n *\n */\n\nexport const TextInput = ({\n label,\n isFluid,\n errorText,\n helpText,\n leadingElement,\n trailingElement,\n showRequiredOrOptionalLabel = false,\n moreInformationText,\n size = 'medium',\n placeholder,\n value,\n tooltipProps,\n htmlAttributes,\n isDisabled,\n isReadOnly,\n isRequired,\n onChange,\n isClearable = false,\n className,\n style,\n isSkeletonLoading = false,\n isLoading = false,\n skeletonProps,\n ref,\n ...restProps\n}: CommonProps<'input', TextInputProps>) => {\n const [currentValue, handleChange] = useSemiControlledInput({\n inputType: 'text',\n isControlled: value !== undefined,\n onChange,\n state: value ?? '',\n });\n const hintId = useId();\n const shouldRenderHint = isClearable || isLoading;\n const { field, controlProps } = useFormField({\n errorText,\n // The clear/loading hint describes the input alongside the message.\n extraDescribedByIds: [shouldRenderHint && hintId],\n hasRequiredIndicator: showRequiredOrOptionalLabel,\n helpText,\n isRequired,\n label,\n });\n\n const containerWrappingClasses = classNames(`ndl-text-input`, className, {\n 'ndl-disabled': isDisabled,\n 'ndl-has-error': errorText,\n 'ndl-has-icon': leadingElement || trailingElement || errorText,\n 'ndl-has-leading-icon': leadingElement,\n 'ndl-has-trailing-icon': trailingElement || errorText,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-read-only': isReadOnly,\n 'ndl-small': size === 'small',\n });\n\n const hasEmptyLabelValue =\n label === undefined || label === null || label === '';\n\n const labelWrappingClasses = classNames('ndl-text-input-label', {\n 'ndl-fluid': isFluid,\n });\n\n const combinedHtmlInputAttributes: InputHTMLAttributes<HTMLInputElement> = {\n ...htmlAttributes,\n className: classNames('ndl-input', htmlAttributes?.className),\n };\n const ariaLabel = combinedHtmlInputAttributes['aria-label'];\n const isCustomLabel = Boolean(label) && typeof label !== 'string';\n const hasCustomLabelAndNoAriaLabel =\n isCustomLabel && (ariaLabel === undefined || ariaLabel === '');\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (isClearable && event.key === 'Escape' && Boolean(currentValue)) {\n event.preventDefault();\n event.stopPropagation();\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }\n htmlAttributes?.onKeyDown?.(event);\n };\n\n useMemo(() => {\n if (!label && !ariaLabel) {\n needleWarningMessage(\n 'A TextInput without a label does not have an aria label, be sure to include an aria label for screen readers. Link: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI',\n );\n }\n\n if (hasCustomLabelAndNoAriaLabel) {\n needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);\n }\n }, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);\n\n return (\n <div className={containerWrappingClasses} style={style}>\n {/* We enable implicit label wrapping */}\n {/* Source: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI */}\n <label className={labelWrappingClasses}>\n {!hasEmptyLabelValue && (\n <FormFieldLabel\n field={field}\n size={size}\n association=\"implicit\"\n moreInformationText={moreInformationText}\n tooltipProps={tooltipProps}\n wrap={(row) => (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n {row}\n </Skeleton>\n )}\n />\n )}\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-input-wrapper\">\n {(leadingElement || (isLoading && !trailingElement)) && (\n <div className=\"ndl-element-leading ndl-element\">\n {isLoading ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n leadingElement\n )}\n </div>\n )}\n <div\n className={classNames('ndl-input-container', {\n 'ndl-clearable': isClearable,\n })}\n >\n <input\n ref={ref}\n readOnly={isReadOnly}\n disabled={isDisabled}\n required={isRequired}\n value={currentValue}\n placeholder={placeholder}\n type=\"text\"\n onChange={handleChange}\n {...controlProps}\n {...combinedHtmlInputAttributes}\n onKeyDown={handleInputKeyDown}\n {...restProps}\n />\n {shouldRenderHint && (\n <span\n id={hintId}\n className=\"ndl-text-input-hint\"\n aria-hidden={true}\n >\n {isLoading && 'Loading '}\n {isClearable && 'Press Escape to clear input.'}\n </span>\n )}\n {isClearable && Boolean(currentValue) && (\n <div className=\"ndl-element-clear ndl-element\">\n <button\n tabIndex={-1}\n aria-hidden={true}\n type=\"button\"\n title=\"Clear input (Esc)\"\n onClick={() => {\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }}\n >\n <XMarkIconOutline className=\"n-size-4\" />\n </button>\n </div>\n )}\n </div>\n {trailingElement && (\n <div className=\"ndl-element-trailing ndl-element\">\n {isLoading && !leadingElement ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n trailingElement\n )}\n </div>\n )}\n </div>\n </Skeleton>\n </label>\n\n <FormFieldMessage\n field={field}\n size={size}\n wrap={(content) => (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n {content}\n </Skeleton>\n )}\n />\n </div>\n );\n};\n"]}
|
|
@@ -22,7 +22,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
22
22
|
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
23
23
|
import { TextInput } from '@neo4j-ndl/react';
|
|
24
24
|
const Component = () => {
|
|
25
|
-
return (_jsxs("div", { className: "n-flex n-gap-token-16", children: [_jsx(TextInput, { label: "Small Input", size: "small", htmlAttributes: { id: 'text-input-small' } }), _jsx(TextInput, { label: "Medium Input", size: "medium", htmlAttributes: { id: 'text-input-medium' } }), _jsx(TextInput, { label: "Large Input", size: "large", htmlAttributes: { id: 'text-input-large' } })] }));
|
|
25
|
+
return (_jsxs("div", { className: "n-flex n-gap-token-16", children: [_jsx(TextInput, { label: "Small Input", size: "small", placeholder: "Small Input", helpText: "Help text", htmlAttributes: { id: 'text-input-small' } }), _jsx(TextInput, { label: "Medium Input", size: "medium", placeholder: "Medium Input", helpText: "Help text", htmlAttributes: { id: 'text-input-medium' } }), _jsx(TextInput, { label: "Large Input", size: "large", placeholder: "Large Input", helpText: "Help text", htmlAttributes: { id: 'text-input-large' } })] }));
|
|
26
26
|
};
|
|
27
27
|
export default Component;
|
|
28
28
|
//# sourceMappingURL=text-input-sizes.story.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-input-sizes.story.js","sourceRoot":"","sources":["../../../../src/text-input/stories/text-input-sizes.story.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,yCAAyC,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,OAAO,CACL,eAAK,SAAS,EAAC,uBAAuB,aACpC,KAAC,SAAS,IACR,KAAK,EAAC,aAAa,EACnB,IAAI,EAAC,OAAO,EACZ,cAAc,EAAE,EAAE,EAAE,EAAE,kBAAkB,EAAE,GAC1C,EACF,KAAC,SAAS,IACR,KAAK,EAAC,cAAc,EACpB,IAAI,EAAC,QAAQ,EACb,cAAc,EAAE,EAAE,EAAE,EAAE,mBAAmB,EAAE,GAC3C,EACF,KAAC,SAAS,IACR,KAAK,EAAC,aAAa,EACnB,IAAI,EAAC,OAAO,EACZ,cAAc,EAAE,EAAE,EAAE,EAAE,kBAAkB,EAAE,GAC1C,IACE,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport { TextInput } from '@neo4j-ndl/react';\n\nconst Component = () => {\n return (\n <div className=\"n-flex n-gap-token-16\">\n <TextInput\n label=\"Small Input\"\n size=\"small\"\n htmlAttributes={{ id: 'text-input-small' }}\n />\n <TextInput\n label=\"Medium Input\"\n size=\"medium\"\n htmlAttributes={{ id: 'text-input-medium' }}\n />\n <TextInput\n label=\"Large Input\"\n size=\"large\"\n htmlAttributes={{ id: 'text-input-large' }}\n />\n </div>\n );\n};\n\nexport default Component;\n"]}
|
|
1
|
+
{"version":3,"file":"text-input-sizes.story.js","sourceRoot":"","sources":["../../../../src/text-input/stories/text-input-sizes.story.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,yCAAyC,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,OAAO,CACL,eAAK,SAAS,EAAC,uBAAuB,aACpC,KAAC,SAAS,IACR,KAAK,EAAC,aAAa,EACnB,IAAI,EAAC,OAAO,EACZ,WAAW,EAAC,aAAa,EACzB,QAAQ,EAAC,WAAW,EACpB,cAAc,EAAE,EAAE,EAAE,EAAE,kBAAkB,EAAE,GAC1C,EACF,KAAC,SAAS,IACR,KAAK,EAAC,cAAc,EACpB,IAAI,EAAC,QAAQ,EACb,WAAW,EAAC,cAAc,EAC1B,QAAQ,EAAC,WAAW,EACpB,cAAc,EAAE,EAAE,EAAE,EAAE,mBAAmB,EAAE,GAC3C,EACF,KAAC,SAAS,IACR,KAAK,EAAC,aAAa,EACnB,IAAI,EAAC,OAAO,EACZ,WAAW,EAAC,aAAa,EACzB,QAAQ,EAAC,WAAW,EACpB,cAAc,EAAE,EAAE,EAAE,EAAE,kBAAkB,EAAE,GAC1C,IACE,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport { TextInput } from '@neo4j-ndl/react';\n\nconst Component = () => {\n return (\n <div className=\"n-flex n-gap-token-16\">\n <TextInput\n label=\"Small Input\"\n size=\"small\"\n placeholder=\"Small Input\"\n helpText=\"Help text\"\n htmlAttributes={{ id: 'text-input-small' }}\n />\n <TextInput\n label=\"Medium Input\"\n size=\"medium\"\n placeholder=\"Medium Input\"\n helpText=\"Help text\"\n htmlAttributes={{ id: 'text-input-medium' }}\n />\n <TextInput\n label=\"Large Input\"\n size=\"large\"\n placeholder=\"Large Input\"\n helpText=\"Help text\"\n htmlAttributes={{ id: 'text-input-large' }}\n />\n </div>\n );\n};\n\nexport default Component;\n"]}
|
|
@@ -34,12 +34,11 @@ import { autoUpdate, flip, FloatingFocusManager, FloatingPortal, offset, shift,
|
|
|
34
34
|
import { tokens } from '@neo4j-ndl/base';
|
|
35
35
|
import classNames from 'classnames';
|
|
36
36
|
import { useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef, useState, } from 'react';
|
|
37
|
+
import { FormFieldLabel, FormFieldMessage, useFormField, } from '../_common/form-control';
|
|
37
38
|
import { ConditionalWrap } from '../conditional-wrap';
|
|
38
39
|
import { useIsInsideDialog } from '../dialog/dialog-context';
|
|
39
40
|
import { ClockIconOutline } from '../icons/generated/heroIcons/ClockIconOutline';
|
|
40
|
-
import { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';
|
|
41
41
|
import { useNeedleTheme } from '../theme';
|
|
42
|
-
import { Typography } from '../typography';
|
|
43
42
|
import { generateTimeOptions } from './generate-time-options';
|
|
44
43
|
import { NeedleTime } from './needle-time';
|
|
45
44
|
import { useKeyboardNavigation, useTimePickerPopover, } from './time-picker-hooks';
|
|
@@ -52,7 +51,7 @@ const INPUT_WIDTH_BY_FORMAT = {
|
|
|
52
51
|
};
|
|
53
52
|
export const TimePicker = (_a) => {
|
|
54
53
|
var _b, _c, _d;
|
|
55
|
-
var { format = 'hh:mm', isDisabled, isFluid, isReadOnly, isRequired, value, timeInterval = 15, label, onChange, className, onError, style, size = 'medium', errorText, htmlAttributes, floatingStrategy, isPortaled: isPortaledProp, ref } = _a, restProps = __rest(_a, ["format", "isDisabled", "isFluid", "isReadOnly", "isRequired", "value", "timeInterval", "label", "onChange", "className", "onError", "style", "size", "errorText", "htmlAttributes", "floatingStrategy", "isPortaled", "ref"]);
|
|
54
|
+
var { format = 'hh:mm', isDisabled, isFluid, isReadOnly, isRequired, value, timeInterval = 15, label, onChange, className, onError, style, size = 'medium', helpText, errorText, htmlAttributes, floatingStrategy, isPortaled: isPortaledProp, ref } = _a, restProps = __rest(_a, ["format", "isDisabled", "isFluid", "isReadOnly", "isRequired", "value", "timeInterval", "label", "onChange", "className", "onError", "style", "size", "helpText", "errorText", "htmlAttributes", "floatingStrategy", "isPortaled", "ref"]);
|
|
56
55
|
const [editedInput, setEditedInput] = useState(value);
|
|
57
56
|
const is24Hour = !format.includes('aa');
|
|
58
57
|
const hasSeconds = format.includes('ss');
|
|
@@ -62,13 +61,20 @@ export const TimePicker = (_a) => {
|
|
|
62
61
|
useImperativeHandle(ref, () => inputRef.current, []);
|
|
63
62
|
const [lastAction, setLastAction] = useState('type');
|
|
64
63
|
const [error, setError] = useState(undefined);
|
|
65
|
-
const errorTextId = useId();
|
|
66
64
|
const listboxId = useId();
|
|
67
65
|
const timeOptions = useMemo(() => generateTimeOptions(is24Hour, timeInterval, hasSeconds), [is24Hour, timeInterval, hasSeconds]);
|
|
68
66
|
const { themeClassName } = useNeedleTheme();
|
|
69
67
|
const { isPopoverOpen, setIsPopoverOpen } = useTimePickerPopover(false);
|
|
70
68
|
const { focusedIndex, setFocusedIndex, handleArrowNavigation } = useKeyboardNavigation(listRef, timeOptions.length);
|
|
71
69
|
const errorToShow = errorText !== undefined && errorText !== '' ? errorText : error;
|
|
70
|
+
// The shared form field resolves the ids and which message is displayed -
|
|
71
|
+
// an error, set manually or by internal validation, replaces the help text.
|
|
72
|
+
const { field, controlProps } = useFormField({
|
|
73
|
+
errorText: errorToShow,
|
|
74
|
+
helpText,
|
|
75
|
+
isRequired,
|
|
76
|
+
label,
|
|
77
|
+
});
|
|
72
78
|
const classes = {
|
|
73
79
|
'ndl-disabled': isDisabled,
|
|
74
80
|
'ndl-error': errorToShow !== undefined,
|
|
@@ -265,9 +271,9 @@ export const TimePicker = (_a) => {
|
|
|
265
271
|
const mergedRef = useMergeRefs([refs.setReference, containerRef]);
|
|
266
272
|
return (_jsxs(_Fragment, { children: [_jsxs("div", Object.assign({ className: classNames('ndl-time-picker', className, Object.assign({}, classes)), ref: mergedRef }, getReferenceProps(), { style: {
|
|
267
273
|
width: isFluid === true ? '100%' : 'fit-content',
|
|
268
|
-
}, children: [_jsxs("label", { className: "ndl-time-picker-label", children: [label !== undefined && (_jsx(
|
|
274
|
+
}, children: [_jsxs("label", { className: "ndl-time-picker-label", children: [label !== undefined && (_jsx(FormFieldLabel, { field: field, size: size, association: "implicit" })), _jsxs("div", { className: "ndl-time-picker-input-wrapper", style: Object.assign({ width: inputWidth }, style), children: [_jsx("input", Object.assign({ role: "combobox", "aria-expanded": isPopoverOpen, "aria-controls": listboxId, "aria-activedescendant": isPopoverOpen && focusedIndex >= 0
|
|
269
275
|
? `${listboxId}-option-${focusedIndex}`
|
|
270
|
-
: undefined, "aria-label": label,
|
|
276
|
+
: undefined, "aria-label": label }, controlProps, { className: "ndl-time-picker-input", type: "text", ref: inputRef, value: inputValue, disabled: isDisabled, readOnly: isReadOnly, required: isRequired, onChange: newHandleInputChange, onKeyDown: handleKeyDown, onClick: () => {
|
|
271
277
|
if (isReadOnly === true || isDisabled === true) {
|
|
272
278
|
return;
|
|
273
279
|
}
|
|
@@ -300,7 +306,7 @@ export const TimePicker = (_a) => {
|
|
|
300
306
|
}
|
|
301
307
|
}, placeholder: format,
|
|
302
308
|
// The typed value can never be longer than the format pattern.
|
|
303
|
-
maxLength: format.length }, restProps, htmlAttributes)), _jsx(ClockIconOutline, { className: "ndl-icon-svg ndl-time-picker-icon" })] })] }),
|
|
309
|
+
maxLength: format.length }, restProps, htmlAttributes)), _jsx(ClockIconOutline, { className: "ndl-icon-svg ndl-time-picker-icon" })] })] }), _jsx(FormFieldMessage, { field: field, size: size })] })), context.open && (_jsx(ConditionalWrap, { shouldWrap: isPortaled, wrap: (wrapChildren) => (_jsx(FloatingPortal, { children: wrapChildren })), children: _jsx(FloatingFocusManager, { context: context, modal: false, initialFocus: -1, children: _jsx("div", Object.assign({ ref: refs.setFloating, className: classNames(themeClassName, 'ndl-time-picker-popover', Object.assign({}, classes)), style: Object.assign(Object.assign(Object.assign({}, transitionStyles), floatingStyles), { width: isFluid === true
|
|
304
310
|
? (_d = containerRef.current) === null || _d === void 0 ? void 0 : _d.clientWidth
|
|
305
311
|
: undefined }) }, getFloatingProps(), { children: _jsx("ul", { ref: listRef, role: "listbox", id: listboxId, tabIndex: -1, children: timeOptions.map((time, index) => (_jsx("li", { id: `${listboxId}-option-${index}`, role: "option", "aria-selected": (value === null || value === void 0 ? void 0 : value.toString(is24Hour, hasSeconds)) === time ||
|
|
306
312
|
(editedInput === null || editedInput === void 0 ? void 0 : editedInput.toString(is24Hour, hasSeconds)) === time, value: time, onClick: (event) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimePicker.js","sourceRoot":"","sources":["../../../src/time-picker/TimePicker.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport {\n autoUpdate,\n type Boundary,\n flip,\n FloatingFocusManager,\n FloatingPortal,\n offset,\n shift,\n size as sizeMiddleware,\n useDismiss,\n useFloating,\n useInteractions,\n useMergeRefs,\n useTransitionStyles,\n} from '@floating-ui/react';\nimport { tokens } from '@neo4j-ndl/base';\nimport classNames from 'classnames';\nimport type React from 'react';\nimport {\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { type PolymorphicCommonProps } from '../_common/types';\nimport { ConditionalWrap } from '../conditional-wrap';\nimport { useIsInsideDialog } from '../dialog/dialog-context';\nimport { ClockIconOutline } from '../icons/generated/heroIcons/ClockIconOutline';\nimport { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';\nimport { useNeedleTheme } from '../theme';\nimport { Typography } from '../typography';\nimport { generateTimeOptions } from './generate-time-options';\nimport { NeedleTime } from './needle-time';\nimport {\n useKeyboardNavigation,\n useTimePickerPopover,\n} from './time-picker-hooks';\n\nexport type TimeFormat = 'hh:mm' | 'hh:mm aa' | 'hh:mm:ss' | 'hh:mm:ss aa';\n\n/** Fixed input width per format (only used when the picker is not fluid). */\nconst INPUT_WIDTH_BY_FORMAT: Record<TimeFormat, string> = {\n 'hh:mm': '6rem',\n 'hh:mm aa': '9rem',\n 'hh:mm:ss': '7.5rem',\n 'hh:mm:ss aa': '11rem',\n};\n\nexport type TimePickerProps = {\n /** The value of the time picker */\n value?: NeedleTime;\n /** The format of the time picker */\n format?: TimeFormat;\n /** Whether the time picker is fluid */\n isFluid?: boolean;\n /** Whether the time picker is read only */\n isReadOnly?: boolean;\n /** Whether the time picker is required */\n isRequired?: boolean;\n /** Whether the time picker is disabled */\n isDisabled?: boolean;\n /** The time interval of the time picker, in minutes */\n timeInterval?: number;\n /** The label of the time picker */\n label?: string;\n /** The size of the time picker */\n size?: 'small' | 'medium' | 'large';\n /** Manually set the error text */\n errorText?: string;\n /** Callback function triggered when the time picker value changes */\n onChange?: (time: NeedleTime) => void;\n /** Callback function triggered when the time picker encounters an error */\n onError?: (error: string, time: NeedleTime) => void;\n /**\n * Strategy for the dropdown floating element.\n * By default it is absolute, but if the component is inside of a needle Dialog, it is set to fixed.\n * If this prop is set, no auto-detection of Dialog is done.\n */\n floatingStrategy?: 'absolute' | 'fixed';\n /** Whether the dropdown element is rendered in a portal. */\n isPortaled?: boolean;\n};\n\nexport const TimePicker = <T extends React.ElementType = 'div'>({\n format = 'hh:mm',\n isDisabled,\n isFluid,\n isReadOnly,\n isRequired,\n value,\n timeInterval = 15,\n label,\n onChange,\n className,\n onError,\n style,\n size = 'medium',\n errorText,\n htmlAttributes,\n floatingStrategy,\n isPortaled: isPortaledProp,\n ref,\n ...restProps\n}: PolymorphicCommonProps<T, TimePickerProps>) => {\n const [editedInput, setEditedInput] = useState<NeedleTime | undefined>(value);\n\n const is24Hour = !format.includes('aa');\n const hasSeconds = format.includes('ss');\n const [inputValue, setInputValue] = useState<string>(\n value?.toString(is24Hour, hasSeconds) ?? '',\n );\n const listRef = useRef<HTMLUListElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(ref, () => inputRef.current as HTMLInputElement, []);\n const [lastAction, setLastAction] = useState<'type' | 'arrow'>('type');\n const [error, setError] = useState<string | undefined>(undefined);\n const errorTextId = useId();\n const listboxId = useId();\n\n const timeOptions = useMemo(\n () => generateTimeOptions(is24Hour, timeInterval, hasSeconds),\n [is24Hour, timeInterval, hasSeconds],\n );\n\n const { themeClassName } = useNeedleTheme();\n const { isPopoverOpen, setIsPopoverOpen } = useTimePickerPopover(false);\n const { focusedIndex, setFocusedIndex, handleArrowNavigation } =\n useKeyboardNavigation(listRef, timeOptions.length);\n\n const errorToShow =\n errorText !== undefined && errorText !== '' ? errorText : error;\n\n const classes = {\n 'ndl-disabled': isDisabled,\n 'ndl-error': errorToShow !== undefined,\n 'ndl-fluid': isFluid,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-read-only': isReadOnly,\n 'ndl-small': size === 'small',\n };\n\n const inputWidth = isFluid === true ? '100%' : INPUT_WIDTH_BY_FORMAT[format];\n\n const isValidTime = useCallback(\n (hours: number, minutes: number, seconds: number) => {\n if (hours > 23 || hours < 0) {\n return false;\n }\n\n if (minutes > 59 || minutes < 0) {\n return false;\n }\n\n if (seconds > 59 || seconds < 0) {\n return false;\n }\n\n return true;\n },\n [],\n );\n\n useEffect(() => {\n if (error !== undefined) {\n onError?.(error, NeedleTime.fromString(inputValue));\n }\n }, [error, inputValue, onError]);\n\n useEffect(() => {\n setEditedInput(value);\n setInputValue(value?.toString(is24Hour, hasSeconds) ?? '');\n }, [is24Hour, hasSeconds, value]);\n\n useEffect(() => {\n if (isPopoverOpen) {\n setTimeout(() => {\n listRef.current?.children[focusedIndex]?.scrollIntoView({\n block: 'center',\n inline: 'nearest',\n });\n }, 0);\n } else {\n setTimeout(() => {\n const selectedIndex =\n timeOptions.indexOf(value?.toString(is24Hour, hasSeconds) ?? '') ?? 0;\n setFocusedIndex(selectedIndex);\n }, 0);\n }\n }, [\n focusedIndex,\n is24Hour,\n hasSeconds,\n isPopoverOpen,\n value,\n setFocusedIndex,\n timeOptions,\n ]);\n\n const handleOnClick = (timeText: string) => {\n if (onChange) {\n onChange(NeedleTime.fromString(timeText));\n }\n setError(undefined);\n setInputValue(timeText);\n setEditedInput(NeedleTime.fromString(timeText));\n setIsPopoverOpen(false);\n };\n const newHandleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n scrollToTime(event.target.value);\n setInputValue(event.target.value);\n setLastAction('type');\n\n const time = NeedleTime.fromString(event.target.value);\n if (!isValidTime(time.hour, time.minute, time.second)) {\n setError('Invalid time');\n } else {\n setError(undefined);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (isReadOnly === true || isDisabled === true) {\n event.preventDefault();\n return;\n }\n\n if (event.key === 'Escape') {\n setIsPopoverOpen(false);\n }\n\n setIsPopoverOpen(true);\n\n if (event.key === 'Enter') {\n const minTypedLength = (is24Hour ? 5 : 6) + (hasSeconds ? 3 : 0);\n if (lastAction === 'type' && inputValue.length >= minTypedLength) {\n const time = NeedleTime.fromString(inputValue);\n handleOnClick(time.toString(is24Hour, hasSeconds));\n } else if (lastAction === 'type' && !inputValue.includes(':')) {\n const time = NeedleTime.fromString(inputValue);\n if (isValidTime(time.hour, time.minute, time.second)) {\n handleOnClick(time.toString(is24Hour, hasSeconds));\n }\n setIsPopoverOpen(false);\n } else {\n handleOnClick(timeOptions[focusedIndex]);\n }\n } else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {\n event.preventDefault();\n setLastAction('arrow');\n handleArrowNavigation(event.key);\n }\n };\n\n const scrollToTime = (startOfTime: string) => {\n const parsedTime = startOfTime.toLowerCase().replace(/[^0-9amp]/g, '');\n let index = -1;\n\n // Handle AM/PM input\n const isPM = parsedTime.includes('p');\n const isAM = parsedTime.includes('a');\n const timeDigits = parsedTime.replace(/[amp]/g, '');\n\n if (timeDigits.length === 1) {\n // Single digit - assume it's an hour\n const hour = `0${timeDigits}`;\n const minutes = hasSeconds ? '00:00' : '00';\n const searchTime = is24Hour\n ? `${hour}:${minutes}`\n : `${hour}:${minutes} ${isPM ? 'PM' : 'AM'}`;\n index = timeOptions.indexOf(searchTime);\n } else {\n // Find closest matching time\n const closestTime = timeOptions.find((time) => {\n const timeWithoutSpecialChars = time\n .toLowerCase()\n .replace(/[^0-9amp]/g, '');\n if (isPM || isAM) {\n // If AM/PM specified, match that specifically\n return timeWithoutSpecialChars.startsWith(parsedTime);\n } else {\n // Otherwise just match the numbers\n return timeWithoutSpecialChars\n .replace(/[amp]/g, '')\n .startsWith(timeDigits);\n }\n });\n index = closestTime !== undefined ? timeOptions.indexOf(closestTime) : -1;\n }\n\n if (index !== -1) {\n setFocusedIndex(index);\n }\n\n return index;\n };\n\n /** Custom floating ui solution */\n const isInsideDialog = useIsInsideDialog();\n const isPortaled = isPortaledProp ?? !isInsideDialog;\n // Inside a Dialog the popover is fixed and not portaled. A transformed\n // ancestor (e.g. Popover) can make Floating UI under-measure available\n // space, so use the viewport as the boundary instead.\n const floatingBoundary: Boundary = isInsideDialog ? [] : 'clippingAncestors';\n const containerRef = useRef<HTMLDivElement>(null);\n const { refs, floatingStyles, context } = useFloating({\n elements: {\n reference: containerRef.current,\n },\n middleware: [\n offset(10),\n flip({\n fallbackPlacements: ['top'],\n fallbackStrategy: 'bestFit',\n }),\n shift({ boundary: floatingBoundary, padding: 5 }),\n sizeMiddleware({\n apply({ availableHeight, elements }) {\n Object.assign(elements.floating.style, {\n maxHeight: `${availableHeight}px`,\n });\n },\n boundary: floatingBoundary,\n padding: 5,\n }),\n ],\n onOpenChange: (open) => {\n setIsPopoverOpen(open);\n },\n open: isDisabled !== true && isReadOnly !== true && isPopoverOpen,\n placement: 'bottom',\n strategy: floatingStrategy ?? (isInsideDialog ? 'fixed' : 'absolute'),\n whileElementsMounted: autoUpdate,\n });\n const dismiss = useDismiss(context);\n const { getReferenceProps, getFloatingProps } = useInteractions([dismiss]);\n const { styles: transitionStyles } = useTransitionStyles(context, {\n duration: Number.parseInt(tokens.motion.duration.quick) ?? 0,\n });\n\n const mergedRef = useMergeRefs([refs.setReference, containerRef]);\n\n return (\n <>\n <div\n className={classNames('ndl-time-picker', className, {\n ...classes,\n })}\n ref={mergedRef}\n {...getReferenceProps()}\n style={{\n width: isFluid === true ? '100%' : 'fit-content',\n }}\n >\n <label className=\"ndl-time-picker-label\">\n {label !== undefined && (\n <Typography\n variant={size === 'large' ? 'body-large' : 'body-medium'}\n >\n {label}\n </Typography>\n )}\n <div\n className=\"ndl-time-picker-input-wrapper\"\n style={{\n width: inputWidth,\n ...style,\n }}\n >\n <input\n role=\"combobox\"\n aria-expanded={isPopoverOpen}\n aria-controls={listboxId}\n aria-activedescendant={\n isPopoverOpen && focusedIndex >= 0\n ? `${listboxId}-option-${focusedIndex}`\n : undefined\n }\n aria-label={label} // TODO: handle label natively\n aria-invalid={Boolean(errorToShow)}\n aria-describedby={errorToShow ? errorTextId : undefined}\n className=\"ndl-time-picker-input\"\n type=\"text\"\n ref={inputRef}\n value={inputValue}\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n onChange={newHandleInputChange}\n onKeyDown={handleKeyDown}\n onClick={() => {\n if (isReadOnly === true || isDisabled === true) {\n return;\n }\n setIsPopoverOpen(true);\n }}\n onBlur={(event) => {\n if (isReadOnly === true || isDisabled === true) {\n return;\n }\n\n if (\n event.relatedTarget?.classList.contains(\n 'ndl-time-picker-popover-item',\n ) === true\n ) {\n return;\n }\n\n if (inputValue.length < 4) {\n setError('Invalid time');\n return;\n }\n\n const time = NeedleTime.fromString(inputValue);\n\n if (time === undefined || time === null) {\n setError('Invalid time');\n return;\n }\n\n if (!isValidTime(time.hour, time.minute, time.second)) {\n setError('Invalid time');\n } else {\n setError(undefined);\n setInputValue(time.toString(is24Hour, hasSeconds));\n setEditedInput(time);\n onChange?.(time);\n }\n }}\n placeholder={format}\n // The typed value can never be longer than the format pattern.\n maxLength={format.length}\n {...restProps}\n {...htmlAttributes}\n />\n <ClockIconOutline className=\"ndl-icon-svg ndl-time-picker-icon\" />\n </div>\n </label>\n {errorToShow !== undefined && (\n <div className=\"ndl-time-picker-error-wrapper\" role=\"status\">\n <ExclamationCircleIconSolid className=\"ndl-time-picker-error-icon\" />\n <Typography\n variant={size === 'large' ? 'body-medium' : 'body-small'}\n className=\"ndl-time-picker-error-text\"\n htmlAttributes={{ id: errorTextId }}\n >\n {errorToShow}\n </Typography>\n </div>\n )}\n </div>\n\n {context.open && (\n <ConditionalWrap\n shouldWrap={isPortaled}\n wrap={(wrapChildren) => (\n <FloatingPortal>{wrapChildren}</FloatingPortal>\n )}\n >\n <FloatingFocusManager\n context={context}\n modal={false}\n initialFocus={-1}\n >\n <div\n ref={refs.setFloating}\n className={classNames(themeClassName, 'ndl-time-picker-popover', {\n ...classes,\n })}\n style={{\n ...transitionStyles,\n ...floatingStyles,\n width:\n isFluid === true\n ? containerRef.current?.clientWidth\n : undefined,\n }}\n {...getFloatingProps()}\n >\n <ul ref={listRef} role=\"listbox\" id={listboxId} tabIndex={-1}>\n {timeOptions.map((time, index) => (\n <li\n id={`${listboxId}-option-${index}`}\n key={index}\n role=\"option\"\n aria-selected={\n value?.toString(is24Hour, hasSeconds) === time ||\n editedInput?.toString(is24Hour, hasSeconds) === time\n }\n value={time}\n onClick={(event) => {\n event.stopPropagation();\n event.preventDefault();\n handleOnClick(time);\n setIsPopoverOpen(false);\n }}\n onMouseDown={(event) => {\n event.stopPropagation();\n event.preventDefault();\n }}\n tabIndex={-1}\n className={classNames(\n focusedIndex === index ? 'focused' : '',\n 'ndl-time-picker-popover-item',\n )}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.stopPropagation();\n handleOnClick(time);\n }\n }}\n >\n {time}\n </li>\n ))}\n </ul>\n </div>\n </FloatingFocusManager>\n </ConditionalWrap>\n )}\n </>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"TimePicker.js","sourceRoot":"","sources":["../../../src/time-picker/TimePicker.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport {\n autoUpdate,\n type Boundary,\n flip,\n FloatingFocusManager,\n FloatingPortal,\n offset,\n shift,\n size as sizeMiddleware,\n useDismiss,\n useFloating,\n useInteractions,\n useMergeRefs,\n useTransitionStyles,\n} from '@floating-ui/react';\nimport { tokens } from '@neo4j-ndl/base';\nimport classNames from 'classnames';\nimport type React from 'react';\nimport {\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport {\n FormFieldLabel,\n FormFieldMessage,\n useFormField,\n} from '../_common/form-control';\nimport { type PolymorphicCommonProps } from '../_common/types';\nimport { ConditionalWrap } from '../conditional-wrap';\nimport { useIsInsideDialog } from '../dialog/dialog-context';\nimport { ClockIconOutline } from '../icons/generated/heroIcons/ClockIconOutline';\nimport { useNeedleTheme } from '../theme';\nimport { generateTimeOptions } from './generate-time-options';\nimport { NeedleTime } from './needle-time';\nimport {\n useKeyboardNavigation,\n useTimePickerPopover,\n} from './time-picker-hooks';\n\nexport type TimeFormat = 'hh:mm' | 'hh:mm aa' | 'hh:mm:ss' | 'hh:mm:ss aa';\n\n/** Fixed input width per format (only used when the picker is not fluid). */\nconst INPUT_WIDTH_BY_FORMAT: Record<TimeFormat, string> = {\n 'hh:mm': '6rem',\n 'hh:mm aa': '9rem',\n 'hh:mm:ss': '7.5rem',\n 'hh:mm:ss aa': '11rem',\n};\n\nexport type TimePickerProps = {\n /** The value of the time picker */\n value?: NeedleTime;\n /** The format of the time picker */\n format?: TimeFormat;\n /** Whether the time picker is fluid */\n isFluid?: boolean;\n /** Whether the time picker is read only */\n isReadOnly?: boolean;\n /** Whether the time picker is required */\n isRequired?: boolean;\n /** Whether the time picker is disabled */\n isDisabled?: boolean;\n /** The time interval of the time picker, in minutes */\n timeInterval?: number;\n /** The label of the time picker */\n label?: string;\n /** The size of the time picker */\n size?: 'small' | 'medium' | 'large';\n /** Assistive text displayed below the input. Replaced by `errorText` or an internal validation error while there is one */\n helpText?: React.ReactNode;\n /** Manually set the error text */\n errorText?: string;\n /** Callback function triggered when the time picker value changes */\n onChange?: (time: NeedleTime) => void;\n /** Callback function triggered when the time picker encounters an error */\n onError?: (error: string, time: NeedleTime) => void;\n /**\n * Strategy for the dropdown floating element.\n * By default it is absolute, but if the component is inside of a needle Dialog, it is set to fixed.\n * If this prop is set, no auto-detection of Dialog is done.\n */\n floatingStrategy?: 'absolute' | 'fixed';\n /** Whether the dropdown element is rendered in a portal. */\n isPortaled?: boolean;\n};\n\nexport const TimePicker = <T extends React.ElementType = 'div'>({\n format = 'hh:mm',\n isDisabled,\n isFluid,\n isReadOnly,\n isRequired,\n value,\n timeInterval = 15,\n label,\n onChange,\n className,\n onError,\n style,\n size = 'medium',\n helpText,\n errorText,\n htmlAttributes,\n floatingStrategy,\n isPortaled: isPortaledProp,\n ref,\n ...restProps\n}: PolymorphicCommonProps<T, TimePickerProps>) => {\n const [editedInput, setEditedInput] = useState<NeedleTime | undefined>(value);\n\n const is24Hour = !format.includes('aa');\n const hasSeconds = format.includes('ss');\n const [inputValue, setInputValue] = useState<string>(\n value?.toString(is24Hour, hasSeconds) ?? '',\n );\n const listRef = useRef<HTMLUListElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(ref, () => inputRef.current as HTMLInputElement, []);\n const [lastAction, setLastAction] = useState<'type' | 'arrow'>('type');\n const [error, setError] = useState<string | undefined>(undefined);\n const listboxId = useId();\n\n const timeOptions = useMemo(\n () => generateTimeOptions(is24Hour, timeInterval, hasSeconds),\n [is24Hour, timeInterval, hasSeconds],\n );\n\n const { themeClassName } = useNeedleTheme();\n const { isPopoverOpen, setIsPopoverOpen } = useTimePickerPopover(false);\n const { focusedIndex, setFocusedIndex, handleArrowNavigation } =\n useKeyboardNavigation(listRef, timeOptions.length);\n\n const errorToShow =\n errorText !== undefined && errorText !== '' ? errorText : error;\n // The shared form field resolves the ids and which message is displayed -\n // an error, set manually or by internal validation, replaces the help text.\n const { field, controlProps } = useFormField({\n errorText: errorToShow,\n helpText,\n isRequired,\n label,\n });\n\n const classes = {\n 'ndl-disabled': isDisabled,\n 'ndl-error': errorToShow !== undefined,\n 'ndl-fluid': isFluid,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-read-only': isReadOnly,\n 'ndl-small': size === 'small',\n };\n\n const inputWidth = isFluid === true ? '100%' : INPUT_WIDTH_BY_FORMAT[format];\n\n const isValidTime = useCallback(\n (hours: number, minutes: number, seconds: number) => {\n if (hours > 23 || hours < 0) {\n return false;\n }\n\n if (minutes > 59 || minutes < 0) {\n return false;\n }\n\n if (seconds > 59 || seconds < 0) {\n return false;\n }\n\n return true;\n },\n [],\n );\n\n useEffect(() => {\n if (error !== undefined) {\n onError?.(error, NeedleTime.fromString(inputValue));\n }\n }, [error, inputValue, onError]);\n\n useEffect(() => {\n setEditedInput(value);\n setInputValue(value?.toString(is24Hour, hasSeconds) ?? '');\n }, [is24Hour, hasSeconds, value]);\n\n useEffect(() => {\n if (isPopoverOpen) {\n setTimeout(() => {\n listRef.current?.children[focusedIndex]?.scrollIntoView({\n block: 'center',\n inline: 'nearest',\n });\n }, 0);\n } else {\n setTimeout(() => {\n const selectedIndex =\n timeOptions.indexOf(value?.toString(is24Hour, hasSeconds) ?? '') ?? 0;\n setFocusedIndex(selectedIndex);\n }, 0);\n }\n }, [\n focusedIndex,\n is24Hour,\n hasSeconds,\n isPopoverOpen,\n value,\n setFocusedIndex,\n timeOptions,\n ]);\n\n const handleOnClick = (timeText: string) => {\n if (onChange) {\n onChange(NeedleTime.fromString(timeText));\n }\n setError(undefined);\n setInputValue(timeText);\n setEditedInput(NeedleTime.fromString(timeText));\n setIsPopoverOpen(false);\n };\n const newHandleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n scrollToTime(event.target.value);\n setInputValue(event.target.value);\n setLastAction('type');\n\n const time = NeedleTime.fromString(event.target.value);\n if (!isValidTime(time.hour, time.minute, time.second)) {\n setError('Invalid time');\n } else {\n setError(undefined);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (isReadOnly === true || isDisabled === true) {\n event.preventDefault();\n return;\n }\n\n if (event.key === 'Escape') {\n setIsPopoverOpen(false);\n }\n\n setIsPopoverOpen(true);\n\n if (event.key === 'Enter') {\n const minTypedLength = (is24Hour ? 5 : 6) + (hasSeconds ? 3 : 0);\n if (lastAction === 'type' && inputValue.length >= minTypedLength) {\n const time = NeedleTime.fromString(inputValue);\n handleOnClick(time.toString(is24Hour, hasSeconds));\n } else if (lastAction === 'type' && !inputValue.includes(':')) {\n const time = NeedleTime.fromString(inputValue);\n if (isValidTime(time.hour, time.minute, time.second)) {\n handleOnClick(time.toString(is24Hour, hasSeconds));\n }\n setIsPopoverOpen(false);\n } else {\n handleOnClick(timeOptions[focusedIndex]);\n }\n } else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {\n event.preventDefault();\n setLastAction('arrow');\n handleArrowNavigation(event.key);\n }\n };\n\n const scrollToTime = (startOfTime: string) => {\n const parsedTime = startOfTime.toLowerCase().replace(/[^0-9amp]/g, '');\n let index = -1;\n\n // Handle AM/PM input\n const isPM = parsedTime.includes('p');\n const isAM = parsedTime.includes('a');\n const timeDigits = parsedTime.replace(/[amp]/g, '');\n\n if (timeDigits.length === 1) {\n // Single digit - assume it's an hour\n const hour = `0${timeDigits}`;\n const minutes = hasSeconds ? '00:00' : '00';\n const searchTime = is24Hour\n ? `${hour}:${minutes}`\n : `${hour}:${minutes} ${isPM ? 'PM' : 'AM'}`;\n index = timeOptions.indexOf(searchTime);\n } else {\n // Find closest matching time\n const closestTime = timeOptions.find((time) => {\n const timeWithoutSpecialChars = time\n .toLowerCase()\n .replace(/[^0-9amp]/g, '');\n if (isPM || isAM) {\n // If AM/PM specified, match that specifically\n return timeWithoutSpecialChars.startsWith(parsedTime);\n } else {\n // Otherwise just match the numbers\n return timeWithoutSpecialChars\n .replace(/[amp]/g, '')\n .startsWith(timeDigits);\n }\n });\n index = closestTime !== undefined ? timeOptions.indexOf(closestTime) : -1;\n }\n\n if (index !== -1) {\n setFocusedIndex(index);\n }\n\n return index;\n };\n\n /** Custom floating ui solution */\n const isInsideDialog = useIsInsideDialog();\n const isPortaled = isPortaledProp ?? !isInsideDialog;\n // Inside a Dialog the popover is fixed and not portaled. A transformed\n // ancestor (e.g. Popover) can make Floating UI under-measure available\n // space, so use the viewport as the boundary instead.\n const floatingBoundary: Boundary = isInsideDialog ? [] : 'clippingAncestors';\n const containerRef = useRef<HTMLDivElement>(null);\n const { refs, floatingStyles, context } = useFloating({\n elements: {\n reference: containerRef.current,\n },\n middleware: [\n offset(10),\n flip({\n fallbackPlacements: ['top'],\n fallbackStrategy: 'bestFit',\n }),\n shift({ boundary: floatingBoundary, padding: 5 }),\n sizeMiddleware({\n apply({ availableHeight, elements }) {\n Object.assign(elements.floating.style, {\n maxHeight: `${availableHeight}px`,\n });\n },\n boundary: floatingBoundary,\n padding: 5,\n }),\n ],\n onOpenChange: (open) => {\n setIsPopoverOpen(open);\n },\n open: isDisabled !== true && isReadOnly !== true && isPopoverOpen,\n placement: 'bottom',\n strategy: floatingStrategy ?? (isInsideDialog ? 'fixed' : 'absolute'),\n whileElementsMounted: autoUpdate,\n });\n const dismiss = useDismiss(context);\n const { getReferenceProps, getFloatingProps } = useInteractions([dismiss]);\n const { styles: transitionStyles } = useTransitionStyles(context, {\n duration: Number.parseInt(tokens.motion.duration.quick) ?? 0,\n });\n\n const mergedRef = useMergeRefs([refs.setReference, containerRef]);\n\n return (\n <>\n <div\n className={classNames('ndl-time-picker', className, {\n ...classes,\n })}\n ref={mergedRef}\n {...getReferenceProps()}\n style={{\n width: isFluid === true ? '100%' : 'fit-content',\n }}\n >\n <label className=\"ndl-time-picker-label\">\n {label !== undefined && (\n <FormFieldLabel field={field} size={size} association=\"implicit\" />\n )}\n <div\n className=\"ndl-time-picker-input-wrapper\"\n style={{\n width: inputWidth,\n ...style,\n }}\n >\n <input\n role=\"combobox\"\n aria-expanded={isPopoverOpen}\n aria-controls={listboxId}\n aria-activedescendant={\n isPopoverOpen && focusedIndex >= 0\n ? `${listboxId}-option-${focusedIndex}`\n : undefined\n }\n aria-label={label} // TODO: handle label natively\n {...controlProps}\n className=\"ndl-time-picker-input\"\n type=\"text\"\n ref={inputRef}\n value={inputValue}\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n onChange={newHandleInputChange}\n onKeyDown={handleKeyDown}\n onClick={() => {\n if (isReadOnly === true || isDisabled === true) {\n return;\n }\n setIsPopoverOpen(true);\n }}\n onBlur={(event) => {\n if (isReadOnly === true || isDisabled === true) {\n return;\n }\n\n if (\n event.relatedTarget?.classList.contains(\n 'ndl-time-picker-popover-item',\n ) === true\n ) {\n return;\n }\n\n if (inputValue.length < 4) {\n setError('Invalid time');\n return;\n }\n\n const time = NeedleTime.fromString(inputValue);\n\n if (time === undefined || time === null) {\n setError('Invalid time');\n return;\n }\n\n if (!isValidTime(time.hour, time.minute, time.second)) {\n setError('Invalid time');\n } else {\n setError(undefined);\n setInputValue(time.toString(is24Hour, hasSeconds));\n setEditedInput(time);\n onChange?.(time);\n }\n }}\n placeholder={format}\n // The typed value can never be longer than the format pattern.\n maxLength={format.length}\n {...restProps}\n {...htmlAttributes}\n />\n <ClockIconOutline className=\"ndl-icon-svg ndl-time-picker-icon\" />\n </div>\n </label>\n <FormFieldMessage field={field} size={size} />\n </div>\n\n {context.open && (\n <ConditionalWrap\n shouldWrap={isPortaled}\n wrap={(wrapChildren) => (\n <FloatingPortal>{wrapChildren}</FloatingPortal>\n )}\n >\n <FloatingFocusManager\n context={context}\n modal={false}\n initialFocus={-1}\n >\n <div\n ref={refs.setFloating}\n className={classNames(themeClassName, 'ndl-time-picker-popover', {\n ...classes,\n })}\n style={{\n ...transitionStyles,\n ...floatingStyles,\n width:\n isFluid === true\n ? containerRef.current?.clientWidth\n : undefined,\n }}\n {...getFloatingProps()}\n >\n <ul ref={listRef} role=\"listbox\" id={listboxId} tabIndex={-1}>\n {timeOptions.map((time, index) => (\n <li\n id={`${listboxId}-option-${index}`}\n key={index}\n role=\"option\"\n aria-selected={\n value?.toString(is24Hour, hasSeconds) === time ||\n editedInput?.toString(is24Hour, hasSeconds) === time\n }\n value={time}\n onClick={(event) => {\n event.stopPropagation();\n event.preventDefault();\n handleOnClick(time);\n setIsPopoverOpen(false);\n }}\n onMouseDown={(event) => {\n event.stopPropagation();\n event.preventDefault();\n }}\n tabIndex={-1}\n className={classNames(\n focusedIndex === index ? 'focused' : '',\n 'ndl-time-picker-popover-item',\n )}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.stopPropagation();\n handleOnClick(time);\n }\n }}\n >\n {time}\n </li>\n ))}\n </ul>\n </div>\n </FloatingFocusManager>\n </ConditionalWrap>\n )}\n </>\n );\n};\n"]}
|