@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.
- package/lib-esm/combobox/types.d.ts +2 -1
- package/lib-esm/index.css +104 -95
- package/lib-esm/index.d.ts +1 -0
- package/lib-esm/index.js +1 -0
- package/lib-esm/password-input/index.d.ts +2 -0
- package/lib-esm/password-input/password-input.d.ts +10 -0
- package/lib-esm/password-input/password-input.js +55 -0
- package/lib-esm/password-input/password-input.module.js +4 -0
- package/lib-esm/password-input/types.d.ts +16 -0
- package/lib-esm/primitives/base-text-input/base-text-input.d.ts +19 -0
- package/lib-esm/primitives/base-text-input/base-text-input.js +75 -0
- package/lib-esm/primitives/base-text-input/base-text-input.module.js +4 -0
- package/lib-esm/primitives/base-text-input/index.d.ts +2 -0
- package/lib-esm/primitives/base-text-input/types.d.ts +26 -0
- package/lib-esm/text-input/text-input.d.ts +1 -27
- package/lib-esm/text-input/text-input.js +17 -65
- package/lib-esm/text-input/text-input.module.js +1 -1
- package/lib-esm/text-input/types.d.ts +2 -21
- package/package.json +3 -3
|
@@ -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
|
-
.
|
|
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;
|
package/lib-esm/index.d.ts
CHANGED
|
@@ -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,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,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 <input/> 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 <input/> 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,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 <input/> 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 {
|
|
2
|
-
import {
|
|
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 <input/> 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
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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 = {"
|
|
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 =
|
|
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.
|
|
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.
|
|
58
|
+
"@box/storybook-utils": "^0.2.1",
|
|
59
59
|
"react-stately": "^3.31.1"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "44cc28c706872e74392472870b4e7584d3a783e3",
|
|
62
62
|
"module": "lib-esm/index.js",
|
|
63
63
|
"main": "lib-esm/index.js",
|
|
64
64
|
"exports": {
|