@box/blueprint-web 7.4.0 → 7.4.3

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.
@@ -1,5 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import { type SelectRendererProps } from '@ariakit/react-core/select/select-renderer';
3
+ import { type SelectItemProps } from '@ariakit/react-core/select/select-item';
3
4
  import { type TextAreaProps } from '../text-area/types';
4
5
  export type OptionValue = {
5
6
  value: string;
@@ -182,7 +183,7 @@ export type ConditionalComboboxProps = ComboboxTextArea | {
182
183
  as: 'input';
183
184
  };
184
185
  export type ComboboxProps<Multiple extends boolean, FreeInput extends boolean, T extends OptionValue> = ComboboxBaseProps<Multiple, FreeInput, T> & ConditionalComboboxProps;
185
- export interface ComboboxOptionProps {
186
+ export interface ComboboxOptionProps extends Pick<SelectItemProps, 'hideOnClick'> {
186
187
  /**
187
188
  * The content to render for the combobox option.
188
189
  */
package/lib-esm/index.css CHANGED
@@ -3697,6 +3697,109 @@ table.bp_inline_table_module_inlineTable--b023b tr:not(:last-child) td{
3697
3697
  .bp_page_section_module_pageSectionDivider--30452{
3698
3698
  width:100%;
3699
3699
  }
3700
+
3701
+ .bp_password_input_module_passwordInput--e892b input[type=password],.bp_password_input_module_passwordInput--e892b input[type=text]{
3702
+ padding-inline-end:2.375rem;
3703
+ }
3704
+ .bp_password_input_module_passwordInput--e892b .bp_password_input_module_iconButton--e892b{
3705
+ inset-inline-end:.5rem;
3706
+ }
3707
+ .bp_password_input_module_passwordInput--e892b .bp_password_input_module_iconButton--e892b:active,.bp_password_input_module_passwordInput--e892b .bp_password_input_module_iconButton--e892b:hover{
3708
+ background:none;
3709
+ }
3710
+
3711
+ .bp_base_text_input_module_textInputContainer--6a02b{
3712
+ display:flex;
3713
+ flex-direction:column;
3714
+ font-weight:400;
3715
+ position:relative;
3716
+ }
3717
+ .bp_base_text_input_module_textInputContainer--6a02b,.bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_label--6a02b{
3718
+ font-family:Lato, -apple-system, BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
3719
+ font-size:.875rem;
3720
+ letter-spacing:.01875rem;
3721
+ line-height:1.25rem;
3722
+ text-decoration:none;
3723
+ text-transform:none;
3724
+ }
3725
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_label--6a02b{
3726
+ color:#222;
3727
+ flex:0 0 fit-content;
3728
+ font-weight:700;
3729
+ width:-moz-fit-content;
3730
+ width:fit-content;
3731
+ }
3732
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_label--6a02b:not(.bp_base_text_input_module_hidden--6a02b){
3733
+ margin-block-end:var(--space-2);
3734
+ }
3735
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b{
3736
+ background:#fff;
3737
+ border:.0625rem solid #909090;
3738
+ border-radius:.375rem;
3739
+ box-shadow:inset 0 .125rem .25rem 0 #0000001a;
3740
+ box-sizing:border-box;
3741
+ color:var(--text-text-on-light);
3742
+ font-family:Lato, -apple-system, BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
3743
+ font-size:.875rem;
3744
+ font-weight:400;
3745
+ height:2.5rem;
3746
+ letter-spacing:.01875rem;
3747
+ line-height:1.25rem;
3748
+ padding-block:0;
3749
+ padding-inline:.75rem;
3750
+ text-decoration:none;
3751
+ text-transform:none;
3752
+ width:unset;
3753
+ }
3754
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b:hover{
3755
+ box-shadow:var(--innershadow-1);
3756
+ }
3757
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b::placeholder{
3758
+ color:#6f6f6f;
3759
+ opacity:1;
3760
+ }
3761
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b.bp_base_text_input_module_error--6a02b{
3762
+ background:#fff;
3763
+ border:.125rem solid #ed3757;
3764
+ outline:0;
3765
+ padding-inline-start:.6875rem;
3766
+ }
3767
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b:disabled{
3768
+ background:var(--surface-input-surface);
3769
+ border-color:var(--border-input-border);
3770
+ box-shadow:var(--innershadow-1);
3771
+ color:var(--text-text-on-light);
3772
+ }
3773
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b:disabled:hover{
3774
+ border-color:var(--border-input-border);
3775
+ }
3776
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b:focus-visible{
3777
+ background:#fff;
3778
+ border:.125rem solid #2486fc;
3779
+ outline:0;
3780
+ padding-inline-start:.6875rem;
3781
+ }
3782
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b:focus-visible:has(+ :not(.bp_base_text_input_module_iconShared--6a02b)){
3783
+ padding-inline:.6875rem;
3784
+ }
3785
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_textInput--6a02b:not(:disabled):not(:focus-visible):not(.bp_base_text_input_module_error--6a02b):hover{
3786
+ background:#fff;
3787
+ border:.0625rem solid #6f6f6f;
3788
+ }
3789
+ .bp_base_text_input_module_textInputContainer--6a02b .bp_base_text_input_module_iconShared--6a02b{
3790
+ height:1.5rem;
3791
+ inset-block-end:.375rem;
3792
+ inset-inline-start:unset;
3793
+ position:absolute;
3794
+ width:1.5rem;
3795
+ }
3796
+ .bp_base_text_input_module_textInputContainer--6a02b.bp_base_text_input_module_disabled--6a02b{
3797
+ opacity:60%;
3798
+ }
3799
+
3800
+ .bp_base_text_input_module_inlineError--6a02b{
3801
+ margin-block-start:var(--space-2);
3802
+ }
3700
3803
  .bp_chip_module_chip--34343{
3701
3804
  align-items:center;
3702
3805
  border:none;
@@ -5088,103 +5191,9 @@ table.bp_inline_table_module_inlineTable--b023b tr:not(:last-child) td{
5088
5191
  color:var(--text-cta-link-pressed);
5089
5192
  }
5090
5193
 
5091
- .bp_text_input_module_textInputContainer--d93d3{
5092
- display:flex;
5093
- flex-direction:column;
5094
- font-weight:400;
5095
- position:relative;
5096
- }
5097
- .bp_text_input_module_textInputContainer--d93d3,.bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_label--d93d3{
5098
- font-family:Lato, -apple-system, BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
5099
- font-size:.875rem;
5100
- letter-spacing:.01875rem;
5101
- line-height:1.25rem;
5102
- text-decoration:none;
5103
- text-transform:none;
5104
- }
5105
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_label--d93d3{
5106
- color:#222;
5107
- flex:0 0 fit-content;
5108
- font-weight:700;
5109
- width:-moz-fit-content;
5110
- width:fit-content;
5111
- }
5112
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_label--d93d3:not(.bp_text_input_module_hidden--d93d3){
5113
- margin-block-end:var(--space-2);
5114
- }
5115
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3{
5116
- background:#fff;
5117
- border:.0625rem solid #909090;
5118
- border-radius:.375rem;
5119
- box-shadow:inset 0 .125rem .25rem 0 #0000001a;
5120
- box-sizing:border-box;
5121
- color:var(--text-text-on-light);
5122
- font-family:Lato, -apple-system, BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
5123
- font-size:.875rem;
5124
- font-weight:400;
5125
- height:2.5rem;
5126
- letter-spacing:.01875rem;
5127
- line-height:1.25rem;
5128
- padding-block:0;
5129
- padding-inline:.75rem;
5130
- text-decoration:none;
5131
- text-transform:none;
5132
- width:unset;
5133
- }
5134
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3:hover{
5135
- box-shadow:var(--innershadow-1);
5136
- }
5137
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3::placeholder{
5138
- color:#6f6f6f;
5139
- opacity:1;
5140
- }
5141
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3.bp_text_input_module_error--d93d3{
5142
- background:#fff;
5143
- border:.125rem solid #ed3757;
5144
- outline:0;
5145
- padding-inline-start:.6875rem;
5146
- }
5147
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3:disabled{
5148
- background:var(--surface-input-surface);
5149
- border-color:var(--border-input-border);
5150
- box-shadow:var(--innershadow-1);
5151
- color:var(--text-text-on-light);
5152
- }
5153
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3:disabled:hover{
5154
- border-color:var(--border-input-border);
5155
- }
5156
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3:focus-visible{
5157
- background:#fff;
5158
- border:.125rem solid #2486fc;
5159
- outline:0;
5160
- padding-inline-start:.6875rem;
5161
- }
5162
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3:focus-visible:not(.bp_text_input_module_loading--d93d3){
5163
- padding-inline:.6875rem;
5164
- }
5165
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3:not(:disabled):not(:focus-visible):not(.bp_text_input_module_error--d93d3):hover{
5166
- background:#fff;
5167
- border:.0625rem solid #6f6f6f;
5168
- }
5169
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_textInput--d93d3.bp_text_input_module_loading--d93d3{
5194
+ .bp_text_input_module_textInput--3c0cc input:has(+ .bp_text_input_module_iconLoading--3c0cc){
5170
5195
  padding-inline-end:1.875rem;
5171
5196
  }
5172
- .bp_text_input_module_textInputContainer--d93d3 .bp_text_input_module_loadingIndicator--d93d3{
5173
- display:inline-block;
5174
- height:1.5rem;
5175
- inset-block-end:.375rem;
5176
- inset-inline-end:0;
5177
- inset-inline-start:unset;
5178
- position:absolute;
5179
- width:1.5rem;
5180
- }
5181
- .bp_text_input_module_textInputContainer--d93d3.bp_text_input_module_disabled--d93d3{
5182
- opacity:60%;
5183
- }
5184
-
5185
- .bp_text_input_module_inlineError--d93d3{
5186
- margin-block-start:var(--space-2);
5187
- }
5188
5197
  :root{
5189
5198
  --notification-default-paragraph-indent:0rem;
5190
5199
  --notification-default-paragraph-spacing:0;
@@ -26,6 +26,7 @@ export * from './loading-indicator/loading-indicator';
26
26
  export * from './modal';
27
27
  export * from './navigation-menu';
28
28
  export * from './page-section';
29
+ export * from './password-input';
29
30
  export * from './primitives/calendar';
30
31
  export * from './primitives/chips/filter-chip';
31
32
  export * from './primitives/context-menu';
package/lib-esm/index.js CHANGED
@@ -28,6 +28,7 @@ export { LoadingIndicator } from './loading-indicator/loading-indicator.js';
28
28
  export { Modal } from './modal/modal.js';
29
29
  export { NavigationMenu } from './navigation-menu/index.js';
30
30
  export { PageSection } from './page-section/index.js';
31
+ export { PasswordInput } from './password-input/password-input.js';
31
32
  export { Calendar } from './primitives/calendar/calendar.js';
32
33
  export { CalendarDate, CalendarDateTime, DateFormatter, Time, ZonedDateTime } from './primitives/calendar/classes.util.js';
33
34
  export { fromAbsolute } from './primitives/calendar/from-absolute.util.js';
@@ -0,0 +1,2 @@
1
+ export { PasswordInput } from './password-input';
2
+ export { type PasswordInputProps } from './types';
@@ -0,0 +1,10 @@
1
+ /// <reference types="react" />
2
+ export declare const PasswordInput: import("react").ForwardRefExoticComponent<(Omit<Omit<import("../text-input").TextInputProps, "type" | "icon" | "loading" | "loadingAriaLabel"> & {
3
+ showPasswordAriaLabel: string;
4
+ hidePasswordAriaLabel: string;
5
+ autoComplete: "current-password" | "new-password";
6
+ } & Required<Pick<import("./types").ControlledComponentProps, keyof import("./types").ControlledComponentProps>> & Omit<import("./types").ControlledComponentProps, keyof import("./types").ControlledComponentProps>, "ref"> | Omit<Omit<import("../text-input").TextInputProps, "type" | "icon" | "loading" | "loadingAriaLabel"> & {
7
+ showPasswordAriaLabel: string;
8
+ hidePasswordAriaLabel: string;
9
+ autoComplete: "current-password" | "new-password";
10
+ } & Partial<Record<keyof import("./types").ControlledComponentProps, never>> & Omit<import("./types").ControlledComponentProps, keyof import("./types").ControlledComponentProps>, "ref">) & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,55 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Hidden, Visible } from '@box/blueprint-web-assets/icons/Line';
3
+ import clsx from 'clsx';
4
+ import { forwardRef, useRef, useState, useCallback } from 'react';
5
+ import { IconButton } from '../primitives/icon-button/icon-button.js';
6
+ import { useForkRef } from '../utils/useForkRef.js';
7
+ import { useUniqueId } from '../utils/useUniqueId.js';
8
+ import styles from './password-input.module.js';
9
+ import { BaseTextInput } from '../primitives/base-text-input/base-text-input.js';
10
+
11
+ const PasswordInput = /*#__PURE__*/forwardRef((props, forwardedRef) => {
12
+ const {
13
+ onPasswordVisibleChange,
14
+ passwordVisible,
15
+ showPasswordAriaLabel,
16
+ hidePasswordAriaLabel,
17
+ autoComplete: autocomplete,
18
+ ...rest
19
+ } = props;
20
+ const inputRef = useRef(null);
21
+ const inputId = useUniqueId('input-');
22
+ const isControlled = typeof passwordVisible === 'boolean';
23
+ const [passwordVisibleInternal, setPasswordVisibleInternal] = useState(isControlled ? passwordVisible : false);
24
+ const passwordVisibleFinal = isControlled ? passwordVisible : passwordVisibleInternal;
25
+ const toggleVisibility = useCallback(() => {
26
+ if (isControlled) {
27
+ onPasswordVisibleChange?.(!passwordVisibleFinal);
28
+ } else {
29
+ setPasswordVisibleInternal(!passwordVisibleFinal);
30
+ }
31
+ }, [isControlled, onPasswordVisibleChange, passwordVisibleFinal]);
32
+ const inputType = passwordVisibleFinal ? 'text' : 'password';
33
+ const iconButtonAriaLabel = passwordVisibleFinal ? hidePasswordAriaLabel : showPasswordAriaLabel;
34
+ return jsx(BaseTextInput, {
35
+ ...rest,
36
+ ref: useForkRef(inputRef, forwardedRef),
37
+ autoComplete: autocomplete,
38
+ className: clsx(styles.passwordInput, props.className),
39
+ icon: jsx(IconButton, {
40
+ "aria-controls": inputId,
41
+ "aria-label": iconButtonAriaLabel,
42
+ className: styles.iconButton,
43
+ disabled: props.disabled,
44
+ icon: passwordVisibleFinal ? Hidden : Visible,
45
+ onClick: toggleVisibility,
46
+ size: "small"
47
+ }),
48
+ id: inputId,
49
+ spellCheck: false,
50
+ type: inputType
51
+ });
52
+ });
53
+ PasswordInput.displayName = 'PasswordInput';
54
+
55
+ export { PasswordInput };
@@ -0,0 +1,4 @@
1
+ import '../index.css';
2
+ var styles = {"passwordInput":"bp_password_input_module_passwordInput--e892b","iconButton":"bp_password_input_module_iconButton--e892b"};
3
+
4
+ export { styles as default };
@@ -0,0 +1,16 @@
1
+ import { type RequireAllOrNone } from 'type-fest';
2
+ import { type TextInputProps } from '../text-input';
3
+ export interface ControlledComponentProps {
4
+ /** visibility state for the input */
5
+ passwordVisible: boolean;
6
+ /** callback for when visibility changes */
7
+ onPasswordVisibleChange: (isPasswordVisible: boolean) => void;
8
+ }
9
+ export type PasswordInputProps = Omit<TextInputProps, 'type' | 'icon' | 'loading' | 'loadingAriaLabel'> & {
10
+ /** label communicating that, when pressed button reveals the password */
11
+ showPasswordAriaLabel: string;
12
+ /** label communicating that, when pressed button hides the password */
13
+ hidePasswordAriaLabel: string;
14
+ /** autocompletion hint to the browser */
15
+ autoComplete: 'current-password' | 'new-password';
16
+ } & RequireAllOrNone<ControlledComponentProps, keyof ControlledComponentProps>;
@@ -0,0 +1,19 @@
1
+ /// <reference types="react" />
2
+ /**
3
+ * This extends a default HTML &lt;input/&gt; and accepts the same props as well as some custom ones listed below.<br/>
4
+ *
5
+ * **IMPORTANT **: Since input uses tooltip to display error message, it must be placed inside a single <b>TooltipProvider</b> component provided by the app, see [issue on github](https://github.com/radix-ui/primitives/issues/1712) and [radix docs](https://www.radix-ui.com/docs/primitives/components/tooltip#provider).
6
+ *
7
+ */
8
+ export declare const BaseTextInput: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & {
9
+ ref?: ((instance: HTMLInputElement | null) => void) | import("react").RefObject<HTMLInputElement> | null | undefined;
10
+ } & {
11
+ label: string;
12
+ type?: "text" | "password" | undefined;
13
+ hideLabel?: boolean | undefined;
14
+ invalid?: boolean | undefined;
15
+ disabled?: boolean | undefined;
16
+ required?: boolean | undefined;
17
+ error?: import("react").ReactNode;
18
+ icon?: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | undefined;
19
+ }, "ref"> & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,75 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { VisuallyHidden } from '@radix-ui/react-visually-hidden';
3
+ import clsx from 'clsx';
4
+ import { forwardRef, useMemo, cloneElement } from 'react';
5
+ import { useUniqueId } from '../../utils/useUniqueId.js';
6
+ import styles from './base-text-input.module.js';
7
+ import { InlineError } from '../inline-error/inline-error.js';
8
+
9
+ /**
10
+ * This extends a default HTML &lt;input/&gt; and accepts the same props as well as some custom ones listed below.<br/>
11
+ *
12
+ * **IMPORTANT **: Since input uses tooltip to display error message, it must be placed inside a single <b>TooltipProvider</b> component provided by the app, see [issue on github](https://github.com/radix-ui/primitives/issues/1712) and [radix docs](https://www.radix-ui.com/docs/primitives/components/tooltip#provider).
13
+ *
14
+ */
15
+ const BaseTextInput = /*#__PURE__*/forwardRef((props, forwardedRef) => {
16
+ const {
17
+ className,
18
+ label,
19
+ type = 'text',
20
+ disabled,
21
+ invalid = false,
22
+ hideLabel,
23
+ error,
24
+ required = false,
25
+ icon,
26
+ id,
27
+ ...rest
28
+ } = props;
29
+ const uniqueId = useUniqueId('input-');
30
+ const inputId = id || uniqueId;
31
+ const inlineErrorId = useUniqueId('inline-error-');
32
+ const hasError = !!error && !disabled;
33
+ const shouldMarkError = (!!error || invalid) && !disabled;
34
+ const IconComponent = useMemo(() => icon && /*#__PURE__*/cloneElement(icon, {
35
+ className: clsx(icon.props?.className, styles.iconShared)
36
+ }), [icon]);
37
+ return jsxs(Fragment, {
38
+ children: [jsxs("div", {
39
+ className: clsx([styles.textInputContainer], {
40
+ [styles.disabled]: disabled,
41
+ [styles.error]: shouldMarkError
42
+ }, className),
43
+ children: [jsx("label", {
44
+ className: clsx([styles.label], {
45
+ [styles.hidden]: hideLabel
46
+ }),
47
+ htmlFor: inputId,
48
+ children: hideLabel ? jsx(VisuallyHidden, {
49
+ children: label
50
+ }) : label
51
+ }), jsx("input", {
52
+ ...rest,
53
+ ...(hasError && {
54
+ 'aria-describedby': inlineErrorId
55
+ }),
56
+ ref: forwardedRef,
57
+ "aria-invalid": shouldMarkError,
58
+ "aria-required": required,
59
+ className: clsx([styles.textInput], {
60
+ [styles.error]: shouldMarkError
61
+ }),
62
+ disabled: disabled,
63
+ id: inputId,
64
+ required: required,
65
+ type: type
66
+ }), IconComponent]
67
+ }), jsx(InlineError, {
68
+ className: styles.inlineError,
69
+ id: inlineErrorId,
70
+ children: error
71
+ })]
72
+ });
73
+ });
74
+
75
+ export { BaseTextInput };
@@ -0,0 +1,4 @@
1
+ import '../../index.css';
2
+ var styles = {"textInputContainer":"bp_base_text_input_module_textInputContainer--6a02b","label":"bp_base_text_input_module_label--6a02b","hidden":"bp_base_text_input_module_hidden--6a02b","textInput":"bp_base_text_input_module_textInput--6a02b","error":"bp_base_text_input_module_error--6a02b","iconShared":"bp_base_text_input_module_iconShared--6a02b","disabled":"bp_base_text_input_module_disabled--6a02b","inlineError":"bp_base_text_input_module_inlineError--6a02b"};
3
+
4
+ export { styles as default };
@@ -0,0 +1,2 @@
1
+ export { BaseTextInput } from './base-text-input';
2
+ export { type BaseTextInputProps } from './types';
@@ -0,0 +1,26 @@
1
+ /// <reference types="react" />
2
+ export type BaseTextInputProps = React.ComponentPropsWithRef<'input'> & {
3
+ /** The label for text input */
4
+ label: string;
5
+ /** Input type, defaults to 'text' */
6
+ type?: 'text' | 'password';
7
+ /** When true label text is hidden */
8
+ hideLabel?: boolean;
9
+ /**
10
+ * When true it enforces the error state, without error message.
11
+ * Developer is responsible for connecting the error message with TextInput using aria-describedby.
12
+ * This prop should not be used in conjunction with error prop.
13
+ * */
14
+ invalid?: boolean;
15
+ /** When true prevents user interaction with input */
16
+ disabled?: boolean;
17
+ /** When true it indicates input field must be filled out */
18
+ required?: boolean;
19
+ /** Content of error message */
20
+ error?: React.ReactNode;
21
+ /**
22
+ * Custom icon to be rendered after input
23
+ * When loading is true and input is not disabled prop value will be ignored
24
+ * */
25
+ icon?: React.ReactElement;
26
+ };
@@ -1,28 +1,2 @@
1
1
  /// <reference types="react" />
2
- /**
3
- * This extends a default HTML &lt;input/&gt; and accepts the same props as well as some custom ones listed below.<br/>
4
- *
5
- * **IMPORTANT **: Since input uses tooltip to display error message, it must be placed inside a single <b>TooltipProvider</b> component provided by the app, see [issue on github](https://github.com/radix-ui/primitives/issues/1712) and [radix docs](https://www.radix-ui.com/docs/primitives/components/tooltip#provider).
6
- *
7
- */
8
- export declare const TextInput: import("react").ForwardRefExoticComponent<(Omit<Omit<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & {
9
- ref?: ((instance: HTMLInputElement | null) => void) | import("react").RefObject<HTMLInputElement> | null | undefined;
10
- } & {
11
- label: string;
12
- type?: "text" | undefined;
13
- hideLabel?: boolean | undefined;
14
- invalid?: boolean | undefined;
15
- disabled?: boolean | undefined;
16
- required?: boolean | undefined;
17
- error?: import("react").ReactNode;
18
- } & Required<Pick<import("./types").Loading, keyof import("./types").Loading>> & Omit<import("./types").Loading, keyof import("./types").Loading>, "ref"> | Omit<Omit<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & {
19
- ref?: ((instance: HTMLInputElement | null) => void) | import("react").RefObject<HTMLInputElement> | null | undefined;
20
- } & {
21
- label: string;
22
- type?: "text" | undefined;
23
- hideLabel?: boolean | undefined;
24
- invalid?: boolean | undefined;
25
- disabled?: boolean | undefined;
26
- required?: boolean | undefined;
27
- error?: import("react").ReactNode;
28
- } & Partial<Record<keyof import("./types").Loading, never>> & Omit<import("./types").Loading, keyof import("./types").Loading>, "ref">) & import("react").RefAttributes<HTMLInputElement>>;
2
+ export declare const TextInput: import("react").ForwardRefExoticComponent<(Omit<Omit<import("../primitives/base-text-input").BaseTextInputProps, "icon"> & Required<Pick<import("./types").Loading, keyof import("./types").Loading>> & Omit<import("./types").Loading, keyof import("./types").Loading>, "ref"> | Omit<Omit<import("../primitives/base-text-input").BaseTextInputProps, "icon"> & Partial<Record<keyof import("./types").Loading, never>> & Omit<import("./types").Loading, keyof import("./types").Loading>, "ref">) & import("react").RefAttributes<HTMLInputElement>>;
@@ -1,82 +1,34 @@
1
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
- import { VisuallyHidden } from '@radix-ui/react-visually-hidden';
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { forwardRef, useRef, useCallback, useMemo } from 'react';
3
3
  import clsx from 'clsx';
4
- import { forwardRef, useRef, useCallback } from 'react';
5
4
  import { LoadingIndicator } from '../loading-indicator/loading-indicator.js';
6
- import { InlineError } from '../primitives/inline-error/inline-error.js';
7
- import { useForkRef } from '../utils/useForkRef.js';
8
- import { useUniqueId } from '../utils/useUniqueId.js';
9
5
  import styles from './text-input.module.js';
6
+ import { BaseTextInput } from '../primitives/base-text-input/base-text-input.js';
7
+ import { useForkRef } from '../utils/useForkRef.js';
10
8
 
11
- /**
12
- * This extends a default HTML &lt;input/&gt; and accepts the same props as well as some custom ones listed below.<br/>
13
- *
14
- * **IMPORTANT **: Since input uses tooltip to display error message, it must be placed inside a single <b>TooltipProvider</b> component provided by the app, see [issue on github](https://github.com/radix-ui/primitives/issues/1712) and [radix docs](https://www.radix-ui.com/docs/primitives/components/tooltip#provider).
15
- *
16
- */
17
9
  const TextInput = /*#__PURE__*/forwardRef((props, forwardedRef) => {
18
10
  const {
19
- className,
20
- label,
21
- type = 'text',
22
- disabled,
23
- invalid = false,
24
- hideLabel,
25
- error,
26
11
  loading = false,
27
12
  loadingAriaLabel,
28
- required = false,
29
13
  ...rest
30
14
  } = props;
31
15
  const inputRef = useRef(null);
32
- const inputId = useUniqueId('input-');
33
- const inlineErrorId = useUniqueId('inline-error-');
34
16
  const focusInput = useCallback(() => {
35
17
  inputRef.current?.focus();
36
18
  }, []);
37
- const hasError = !!error && !disabled;
38
- const shouldMarkError = (!!error || invalid) && !disabled;
39
- const isLoading = !disabled && loading && loadingAriaLabel;
40
- return jsxs(Fragment, {
41
- children: [jsxs("div", {
42
- className: clsx([styles.textInputContainer], {
43
- [styles.disabled]: disabled,
44
- [styles.error]: shouldMarkError
45
- }, className),
46
- children: [jsx("label", {
47
- className: clsx([styles.label], {
48
- [styles.hidden]: hideLabel
49
- }),
50
- htmlFor: inputId,
51
- children: hideLabel ? jsx(VisuallyHidden, {
52
- children: label
53
- }) : label
54
- }), jsx("input", {
55
- ...rest,
56
- ...(hasError && {
57
- 'aria-describedby': inlineErrorId
58
- }),
59
- ref: useForkRef(inputRef, forwardedRef),
60
- "aria-invalid": shouldMarkError,
61
- "aria-required": required,
62
- className: clsx([styles.textInput], {
63
- [styles.error]: shouldMarkError,
64
- [styles.loading]: isLoading
65
- }),
66
- disabled: disabled,
67
- id: inputId,
68
- required: required,
69
- type: type
70
- }), isLoading && jsx(LoadingIndicator, {
71
- "aria-label": loadingAriaLabel,
72
- className: styles.loadingIndicator,
73
- onClick: focusInput
74
- })]
75
- }), jsx(InlineError, {
76
- className: styles.inlineError,
77
- id: inlineErrorId,
78
- children: error
79
- })]
19
+ const isLoading = !props.disabled && loading && loadingAriaLabel;
20
+ const icon = useMemo(() => isLoading && jsx(LoadingIndicator, {
21
+ "aria-label": loadingAriaLabel,
22
+ className: styles.iconLoading,
23
+ onClick: focusInput
24
+ }), [isLoading, loadingAriaLabel, focusInput]);
25
+ return jsx(BaseTextInput, {
26
+ ...rest,
27
+ ref: useForkRef(inputRef, forwardedRef),
28
+ className: clsx(styles.textInput, props.className),
29
+ ...(icon ? {
30
+ icon
31
+ } : {})
80
32
  });
81
33
  });
82
34
  TextInput.displayName = 'TextInput';
@@ -1,4 +1,4 @@
1
1
  import '../index.css';
2
- var styles = {"textInputContainer":"bp_text_input_module_textInputContainer--d93d3","label":"bp_text_input_module_label--d93d3","hidden":"bp_text_input_module_hidden--d93d3","textInput":"bp_text_input_module_textInput--d93d3","error":"bp_text_input_module_error--d93d3","loading":"bp_text_input_module_loading--d93d3","loadingIndicator":"bp_text_input_module_loadingIndicator--d93d3","disabled":"bp_text_input_module_disabled--d93d3","inlineError":"bp_text_input_module_inlineError--d93d3"};
2
+ var styles = {"textInput":"bp_text_input_module_textInput--3c0cc","iconLoading":"bp_text_input_module_iconLoading--3c0cc"};
3
3
 
4
4
  export { styles as default };
@@ -1,28 +1,9 @@
1
- /// <reference types="react" />
2
1
  import { type RequireAllOrNone } from 'type-fest';
2
+ import { type BaseTextInputProps } from '../primitives/base-text-input';
3
3
  export interface Loading {
4
4
  /** When true input is renedered with loading indicator. When this is true `loadingAriaLabel` must also be provided. */
5
5
  loading?: boolean;
6
6
  /** The aria-label for the loading indicator. */
7
7
  loadingAriaLabel?: string;
8
8
  }
9
- export type TextInputProps = React.ComponentPropsWithRef<'input'> & {
10
- /** The label for text input */
11
- label: string;
12
- /** Input type, defaults to 'text' */
13
- type?: 'text';
14
- /** When true label text is hidden */
15
- hideLabel?: boolean;
16
- /**
17
- * When true it enforces the error state, without error message.
18
- * Developer is responsible for connecting the error message with TextInput using aria-describedby.
19
- * This prop should not be used in conjunction with error prop.
20
- * */
21
- invalid?: boolean;
22
- /** When true prevents user interaction with input */
23
- disabled?: boolean;
24
- /** When true it indicates input field must be filled out */
25
- required?: boolean;
26
- /** Content of error message */
27
- error?: React.ReactNode;
28
- } & RequireAllOrNone<Loading, keyof Loading>;
9
+ export type TextInputProps = Omit<BaseTextInputProps, 'icon'> & RequireAllOrNone<Loading, keyof Loading>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box/blueprint-web",
3
- "version": "7.4.0",
3
+ "version": "7.4.3",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -55,10 +55,10 @@
55
55
  "type-fest": "^3.2.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@box/storybook-utils": "^0.2.0",
58
+ "@box/storybook-utils": "^0.2.1",
59
59
  "react-stately": "^3.31.1"
60
60
  },
61
- "gitHead": "b47b6c859b0acae07254d87a87f916a26656367d",
61
+ "gitHead": "44cc28c706872e74392472870b4e7584d3a783e3",
62
62
  "module": "lib-esm/index.js",
63
63
  "main": "lib-esm/index.js",
64
64
  "exports": {