@dxos/react-ui 0.1.2 → 0.1.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/dist/src/components/AlertDialog/AlertDialog.js +1 -1
- package/dist/src/components/Heading/Heading.d.ts +1 -1
- package/dist/src/components/Heading/Heading.stories.d.ts +1 -1
- package/dist/src/components/Input/BarePinInput.d.ts +310 -0
- package/dist/src/components/Input/BarePinInput.d.ts.map +1 -0
- package/dist/src/components/Input/BarePinInput.js +62 -0
- package/dist/src/components/Input/BarePinInput.js.map +1 -0
- package/dist/src/components/Input/BareTextInput.d.ts +5 -0
- package/dist/src/components/Input/BareTextInput.d.ts.map +1 -0
- package/dist/src/components/Input/BareTextInput.js +22 -0
- package/dist/src/components/Input/BareTextInput.js.map +1 -0
- package/dist/src/components/Input/Input.d.ts +3 -16
- package/dist/src/components/Input/Input.d.ts.map +1 -1
- package/dist/src/components/Input/Input.js +22 -10
- package/dist/src/components/Input/Input.js.map +1 -1
- package/dist/src/components/Input/Input.stories.d.ts +7 -3
- package/dist/src/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/src/components/Input/Input.stories.js +15 -2
- package/dist/src/components/Input/Input.stories.js.map +1 -1
- package/dist/src/components/Input/InputProps.d.ts +17 -0
- package/dist/src/components/Input/InputProps.d.ts.map +1 -0
- package/dist/src/components/Input/InputProps.js +6 -0
- package/dist/src/components/Input/InputProps.js.map +1 -0
- package/dist/src/hooks/index.d.ts +2 -0
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/hooks/index.js +2 -0
- package/dist/src/hooks/index.js.map +1 -1
- package/dist/src/hooks/useForwardedRef.d.ts +2 -0
- package/dist/src/hooks/useForwardedRef.d.ts.map +1 -0
- package/dist/src/hooks/useForwardedRef.js +24 -0
- package/dist/src/hooks/useForwardedRef.js.map +1 -0
- package/dist/src/hooks/useIsFocused.d.ts +3 -0
- package/dist/src/hooks/useIsFocused.d.ts.map +1 -0
- package/dist/src/hooks/useIsFocused.js +34 -0
- package/dist/src/hooks/useIsFocused.js.map +1 -0
- package/dist/src/plugin.d.ts.map +1 -1
- package/dist/src/plugin.js +9 -1
- package/dist/src/plugin.js.map +1 -1
- package/dist/src/styles/focus.d.ts +1 -0
- package/dist/src/styles/focus.d.ts.map +1 -1
- package/dist/src/styles/focus.js +2 -1
- package/dist/src/styles/focus.js.map +1 -1
- package/dist/src/styles/index.d.ts +1 -0
- package/dist/src/styles/index.d.ts.map +1 -1
- package/dist/src/styles/index.js +1 -0
- package/dist/src/styles/index.js.map +1 -1
- package/dist/src/styles/input.d.ts +11 -0
- package/dist/src/styles/input.d.ts.map +1 -0
- package/dist/src/styles/input.js +24 -0
- package/dist/src/styles/input.js.map +1 -0
- package/dist/src/styles/shimmer.d.ts +2 -0
- package/dist/src/styles/shimmer.d.ts.map +1 -0
- package/dist/src/styles/shimmer.js +8 -0
- package/dist/src/styles/shimmer.js.map +1 -0
- package/package.json +3 -2
- package/src/components/AlertDialog/AlertDialog.tsx +1 -1
- package/src/components/Input/BarePinInput.tsx +62 -0
- package/src/components/Input/BareTextInput.tsx +31 -0
- package/src/components/Input/Input.stories.tsx +18 -1
- package/src/components/Input/Input.tsx +33 -54
- package/src/components/Input/InputProps.ts +23 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useForwardedRef.ts +22 -0
- package/src/hooks/useIsFocused.ts +38 -0
- package/src/plugin.ts +9 -1
- package/src/styles/focus.ts +3 -0
- package/src/styles/index.ts +1 -0
- package/src/styles/input.ts +47 -0
- package/src/styles/shimmer.ts +6 -0
|
@@ -3,39 +3,15 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import cx from 'classnames';
|
|
6
|
-
import React, { ChangeEvent,
|
|
6
|
+
import React, { ChangeEvent, useCallback, useState, useTransition } from 'react';
|
|
7
7
|
|
|
8
8
|
import { useId } from '../../hooks';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
defaultFocus,
|
|
14
|
-
defaultHover,
|
|
15
|
-
defaultPlaceholder,
|
|
16
|
-
valenceColorText,
|
|
17
|
-
valenceInputBorder
|
|
18
|
-
} from '../../styles';
|
|
9
|
+
import { defaultDescription, valenceColorText } from '../../styles';
|
|
10
|
+
import { BarePinInput } from './BarePinInput';
|
|
11
|
+
import { BareTextInput } from './BareTextInput';
|
|
12
|
+
import { InputProps as NaturalInputProps } from './InputProps';
|
|
19
13
|
|
|
20
|
-
export type
|
|
21
|
-
|
|
22
|
-
export interface InputProps extends Omit<ComponentProps<'input'>, 'value' | 'onChange' | 'size'> {
|
|
23
|
-
label: ReactNode;
|
|
24
|
-
labelVisuallyHidden?: boolean;
|
|
25
|
-
description?: ReactNode;
|
|
26
|
-
descriptionVisuallyHidden?: boolean;
|
|
27
|
-
initialValue?: string;
|
|
28
|
-
onChange?: (value: string) => void;
|
|
29
|
-
disabled?: boolean;
|
|
30
|
-
size?: InputSize;
|
|
31
|
-
validationMessage?: ReactNode;
|
|
32
|
-
validationValence?: MessageValence;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const sizeMap = new Map<InputSize, string>([
|
|
36
|
-
['md', ''],
|
|
37
|
-
['lg', 'text-base']
|
|
38
|
-
]);
|
|
14
|
+
export type InputProps = NaturalInputProps;
|
|
39
15
|
|
|
40
16
|
export const Input = ({
|
|
41
17
|
label,
|
|
@@ -49,6 +25,7 @@ export const Input = ({
|
|
|
49
25
|
disabled,
|
|
50
26
|
className,
|
|
51
27
|
size,
|
|
28
|
+
length = 6,
|
|
52
29
|
validationMessage,
|
|
53
30
|
validationValence,
|
|
54
31
|
...inputProps
|
|
@@ -57,6 +34,8 @@ export const Input = ({
|
|
|
57
34
|
const descriptionId = useId('input-description');
|
|
58
35
|
const validationId = useId('input-validation');
|
|
59
36
|
|
|
37
|
+
const isInvalid = !!validationMessage && validationValence === 'error';
|
|
38
|
+
|
|
60
39
|
const [_isPending, startTransition] = useTransition();
|
|
61
40
|
|
|
62
41
|
const [internalValue, setInternalValue] = useState<string>(initialValue?.toString() || '');
|
|
@@ -73,7 +52,29 @@ export const Input = ({
|
|
|
73
52
|
[onChange]
|
|
74
53
|
);
|
|
75
54
|
|
|
76
|
-
const
|
|
55
|
+
const bareInputBaseProps = {
|
|
56
|
+
...inputProps,
|
|
57
|
+
id: inputId,
|
|
58
|
+
...(required && { required: true }),
|
|
59
|
+
...(disabled && { disabled: true }),
|
|
60
|
+
...(description && { 'aria-describedby': descriptionId }),
|
|
61
|
+
...(isInvalid && {
|
|
62
|
+
'aria-invalid': 'true' as const,
|
|
63
|
+
'aria-errormessage': validationId
|
|
64
|
+
}),
|
|
65
|
+
...(placeholder && { placeholder }),
|
|
66
|
+
value: internalValue,
|
|
67
|
+
onChange: onInternalChange,
|
|
68
|
+
validationMessage,
|
|
69
|
+
validationValence
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const bareInput =
|
|
73
|
+
size === 'pin' ? (
|
|
74
|
+
<BarePinInput {...bareInputBaseProps} length={length} />
|
|
75
|
+
) : (
|
|
76
|
+
<BareTextInput {...bareInputBaseProps} size={size} />
|
|
77
|
+
);
|
|
77
78
|
|
|
78
79
|
return (
|
|
79
80
|
<div className={cx('my-4', className)} role='none'>
|
|
@@ -86,29 +87,7 @@ export const Input = ({
|
|
|
86
87
|
>
|
|
87
88
|
{label}
|
|
88
89
|
</label>
|
|
89
|
-
|
|
90
|
-
id={inputId}
|
|
91
|
-
{...inputProps}
|
|
92
|
-
className={cx(
|
|
93
|
-
defaultFocus,
|
|
94
|
-
defaultPlaceholder,
|
|
95
|
-
defaultHover({ disabled }),
|
|
96
|
-
sizeMap.get(size ?? 'md'),
|
|
97
|
-
'bg-white/50 border text-neutral-900 text-sm rounded-lg block w-full px-2.5 py-2 dark:bg-neutral-700/50 dark:text-white',
|
|
98
|
-
valenceInputBorder(validationMessage ? validationValence : undefined),
|
|
99
|
-
disabled && defaultDisabled
|
|
100
|
-
)}
|
|
101
|
-
{...(required && { required: true })}
|
|
102
|
-
{...(disabled && { disabled: true })}
|
|
103
|
-
{...(placeholder && { placeholder })}
|
|
104
|
-
{...(description && { 'aria-describedby': descriptionId })}
|
|
105
|
-
{...(isInvalid && {
|
|
106
|
-
'aria-invalid': 'true',
|
|
107
|
-
'aria-errormessage': validationId
|
|
108
|
-
})}
|
|
109
|
-
value={internalValue}
|
|
110
|
-
onChange={onInternalChange}
|
|
111
|
-
/>
|
|
90
|
+
{bareInput}
|
|
112
91
|
{(description || validationMessage) && (
|
|
113
92
|
<p
|
|
114
93
|
{...(!isInvalid && { id: descriptionId })}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
6
|
+
|
|
7
|
+
import { MessageValence } from '../../props';
|
|
8
|
+
|
|
9
|
+
export type InputSize = 'md' | 'lg' | 'pin';
|
|
10
|
+
|
|
11
|
+
export interface InputProps extends Omit<ComponentProps<'input'>, 'value' | 'onChange' | 'size' | 'ref'> {
|
|
12
|
+
label: ReactNode;
|
|
13
|
+
labelVisuallyHidden?: boolean;
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
descriptionVisuallyHidden?: boolean;
|
|
16
|
+
initialValue?: string;
|
|
17
|
+
onChange?: (value: string) => void;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
size?: InputSize;
|
|
20
|
+
validationMessage?: ReactNode;
|
|
21
|
+
validationValence?: MessageValence;
|
|
22
|
+
length?: number;
|
|
23
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useRef, useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
export const useForwardedRef = <T>(ref: React.ForwardedRef<T>) => {
|
|
8
|
+
const innerRef = useRef<T>(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!ref) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (typeof ref === 'function') {
|
|
15
|
+
ref(innerRef.current);
|
|
16
|
+
} else {
|
|
17
|
+
ref.current = innerRef.current;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return innerRef;
|
|
22
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// Based upon the useIsFocused hook which is part of the `rci` project:
|
|
6
|
+
/// https://github.com/leonardodino/rci/blob/main/packages/use-is-focused
|
|
7
|
+
|
|
8
|
+
import { useEffect, useRef, useState, RefObject } from 'react';
|
|
9
|
+
|
|
10
|
+
export const useIsFocused = (inputRef: RefObject<HTMLInputElement>) => {
|
|
11
|
+
const [isFocused, setIsFocused] = useState<boolean | undefined>(undefined);
|
|
12
|
+
const isFocusedRef = useRef<boolean | undefined>(isFocused);
|
|
13
|
+
|
|
14
|
+
isFocusedRef.current = isFocused;
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const input = inputRef.current;
|
|
18
|
+
if (!input) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const onFocus = () => setIsFocused(true);
|
|
23
|
+
const onBlur = () => setIsFocused(false);
|
|
24
|
+
input.addEventListener('focus', onFocus);
|
|
25
|
+
input.addEventListener('blur', onBlur);
|
|
26
|
+
|
|
27
|
+
if (isFocusedRef.current === undefined) {
|
|
28
|
+
setIsFocused(document.activeElement === input);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return () => {
|
|
32
|
+
input.removeEventListener('focus', onFocus);
|
|
33
|
+
input.removeEventListener('blur', onBlur);
|
|
34
|
+
};
|
|
35
|
+
}, [inputRef, setIsFocused]);
|
|
36
|
+
|
|
37
|
+
return isFocused;
|
|
38
|
+
};
|
package/src/plugin.ts
CHANGED
|
@@ -223,6 +223,12 @@ export const themePlugin = (options: VitePluginTailwindOptions) => {
|
|
|
223
223
|
'100%': {
|
|
224
224
|
transform: 'translateX(calc(100% + 1rem))'
|
|
225
225
|
}
|
|
226
|
+
},
|
|
227
|
+
// Shimmer
|
|
228
|
+
'shimmer-loop': {
|
|
229
|
+
'100%': {
|
|
230
|
+
transform: 'translateX(100%)'
|
|
231
|
+
}
|
|
226
232
|
}
|
|
227
233
|
},
|
|
228
234
|
animation: {
|
|
@@ -248,7 +254,9 @@ export const themePlugin = (options: VitePluginTailwindOptions) => {
|
|
|
248
254
|
'toast-hide': 'toast-hide 100ms ease-in forwards',
|
|
249
255
|
'toast-slide-in-right': 'toast-slide-in-right 150ms cubic-bezier(0.16, 1, 0.3, 1)',
|
|
250
256
|
'toast-slide-in-bottom': 'toast-slide-in-bottom 150ms cubic-bezier(0.16, 1, 0.3, 1)',
|
|
251
|
-
'toast-swipe-out': 'toast-swipe-out 100ms ease-out forwards'
|
|
257
|
+
'toast-swipe-out': 'toast-swipe-out 100ms ease-out forwards',
|
|
258
|
+
// Shimmer
|
|
259
|
+
shimmer: 'shimmer-loop 2s infinite'
|
|
252
260
|
}
|
|
253
261
|
}
|
|
254
262
|
},
|
package/src/styles/focus.ts
CHANGED
|
@@ -4,3 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
export const defaultFocus =
|
|
6
6
|
'focus:outline-none focus-visible:hover:outline-none dark:focus-visible:hover:outline-none focus-visible:ring focus-visible:ring-offset-1 focus-visible:ring-primary-500 focus-visible:ring-offset-white dark:focus-visible:ring-primary-200 dark:focus-visible:ring-offset-black';
|
|
7
|
+
|
|
8
|
+
export const staticFocus =
|
|
9
|
+
'ring ring-offset-1 ring-primary-500 ring-offset-white dark:ring-primary-200 dark:ring-offset-black';
|
package/src/styles/index.ts
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import cx from 'classnames';
|
|
6
|
+
|
|
7
|
+
import { MessageValence } from '../props';
|
|
8
|
+
import { defaultDisabled } from './disabled';
|
|
9
|
+
import { defaultFocus, staticFocus } from './focus';
|
|
10
|
+
import { defaultHover } from './hover';
|
|
11
|
+
import { defaultPlaceholder } from './text';
|
|
12
|
+
import { valenceInputBorder } from './valence';
|
|
13
|
+
|
|
14
|
+
export const defaultInput = ({
|
|
15
|
+
disabled,
|
|
16
|
+
validationValence
|
|
17
|
+
}: {
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
validationValence?: MessageValence;
|
|
20
|
+
}) => {
|
|
21
|
+
return cx(
|
|
22
|
+
defaultFocus,
|
|
23
|
+
defaultPlaceholder,
|
|
24
|
+
defaultHover({ disabled }),
|
|
25
|
+
'bg-white/50 border text-neutral-900 text-sm rounded-lg dark:bg-neutral-700/50 dark:text-white',
|
|
26
|
+
valenceInputBorder(validationValence),
|
|
27
|
+
disabled && defaultDisabled
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const staticInput = ({
|
|
32
|
+
disabled,
|
|
33
|
+
focused,
|
|
34
|
+
validationValence
|
|
35
|
+
}: {
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
focused?: boolean;
|
|
38
|
+
validationValence?: MessageValence;
|
|
39
|
+
}) => {
|
|
40
|
+
return cx(
|
|
41
|
+
defaultPlaceholder,
|
|
42
|
+
'bg-white/50 border text-neutral-900 text-sm rounded-lg dark:bg-neutral-700/50 dark:text-white',
|
|
43
|
+
valenceInputBorder(validationValence),
|
|
44
|
+
disabled && defaultDisabled,
|
|
45
|
+
focused && staticFocus
|
|
46
|
+
);
|
|
47
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
export const defaultShimmer =
|
|
6
|
+
'relative before:absolute before:inset-0 before:-translate-x-full before:animate-shimmer before:bg-gradient-to-r before:from-transparent before:via-neutral-100/20 before:to-transparent isolate overflow-hidden before:border-t before:border-neutral-100/20';
|