@dxos/react-ui 0.1.2 → 0.1.4
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/Avatar/Avatar.d.ts +1 -1
- package/dist/src/components/Avatar/Avatar.d.ts.map +1 -1
- package/dist/src/components/Avatar/Avatar.stories.d.ts +1 -1
- package/dist/src/components/Button/Button.d.ts +1 -1
- package/dist/src/components/Button/Button.d.ts.map +1 -1
- package/dist/src/components/Button/Button.stories.d.ts +1 -1
- package/dist/src/components/Heading/Heading.d.ts +4 -1
- package/dist/src/components/Heading/Heading.d.ts.map +1 -1
- package/dist/src/components/Heading/Heading.stories.d.ts +4 -1
- package/dist/src/components/Heading/Heading.stories.d.ts.map +1 -1
- package/dist/src/components/Input/BarePinInput.d.ts +313 -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
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2022 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.staticInput = exports.defaultInput = void 0;
|
|
10
|
+
const classnames_1 = __importDefault(require("classnames"));
|
|
11
|
+
const disabled_1 = require("./disabled");
|
|
12
|
+
const focus_1 = require("./focus");
|
|
13
|
+
const hover_1 = require("./hover");
|
|
14
|
+
const text_1 = require("./text");
|
|
15
|
+
const valence_1 = require("./valence");
|
|
16
|
+
const defaultInput = ({ disabled, validationValence }) => {
|
|
17
|
+
return (0, classnames_1.default)(focus_1.defaultFocus, text_1.defaultPlaceholder, (0, hover_1.defaultHover)({ disabled }), 'bg-white/50 border text-neutral-900 text-sm rounded-lg dark:bg-neutral-700/50 dark:text-white', (0, valence_1.valenceInputBorder)(validationValence), disabled && disabled_1.defaultDisabled);
|
|
18
|
+
};
|
|
19
|
+
exports.defaultInput = defaultInput;
|
|
20
|
+
const staticInput = ({ disabled, focused, validationValence }) => {
|
|
21
|
+
return (0, classnames_1.default)(text_1.defaultPlaceholder, 'bg-white/50 border text-neutral-900 text-sm rounded-lg dark:bg-neutral-700/50 dark:text-white', (0, valence_1.valenceInputBorder)(validationValence), disabled && disabled_1.defaultDisabled, focused && focus_1.staticFocus);
|
|
22
|
+
};
|
|
23
|
+
exports.staticInput = staticInput;
|
|
24
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/styles/input.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;AAEF,4DAA4B;AAG5B,yCAA6C;AAC7C,mCAAoD;AACpD,mCAAuC;AACvC,iCAA4C;AAC5C,uCAA+C;AAExC,MAAM,YAAY,GAAG,CAAC,EAC3B,QAAQ,EACR,iBAAiB,EAIlB,EAAE,EAAE;IACH,OAAO,IAAA,oBAAE,EACP,oBAAY,EACZ,yBAAkB,EAClB,IAAA,oBAAY,EAAC,EAAE,QAAQ,EAAE,CAAC,EAC1B,+FAA+F,EAC/F,IAAA,4BAAkB,EAAC,iBAAiB,CAAC,EACrC,QAAQ,IAAI,0BAAe,CAC5B,CAAC;AACJ,CAAC,CAAC;AAfW,QAAA,YAAY,gBAevB;AAEK,MAAM,WAAW,GAAG,CAAC,EAC1B,QAAQ,EACR,OAAO,EACP,iBAAiB,EAKlB,EAAE,EAAE;IACH,OAAO,IAAA,oBAAE,EACP,yBAAkB,EAClB,+FAA+F,EAC/F,IAAA,4BAAkB,EAAC,iBAAiB,CAAC,EACrC,QAAQ,IAAI,0BAAe,EAC3B,OAAO,IAAI,mBAAW,CACvB,CAAC;AACJ,CAAC,CAAC;AAhBW,QAAA,WAAW,eAgBtB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const defaultShimmer = "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";
|
|
2
|
+
//# sourceMappingURL=shimmer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shimmer.d.ts","sourceRoot":"","sources":["../../../src/styles/shimmer.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,iQACqO,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2022 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.defaultShimmer = void 0;
|
|
7
|
+
exports.defaultShimmer = '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';
|
|
8
|
+
//# sourceMappingURL=shimmer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shimmer.js","sourceRoot":"","sources":["../../../src/styles/shimmer.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEW,QAAA,cAAc,GACzB,8PAA8P,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Vite plugin which configures a low-level design system for DXOS.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -31,12 +31,13 @@
|
|
|
31
31
|
"jdenticon": "^3.2.0",
|
|
32
32
|
"postcss": "^8.4.17",
|
|
33
33
|
"qrcode.react": "^3.1.0",
|
|
34
|
+
"rci": "^0.0.3",
|
|
34
35
|
"tailwindcss": "^3.1.8",
|
|
35
36
|
"tailwindcss-logical": "^3.0.0",
|
|
36
37
|
"tailwindcss-radix": "^2.6.0"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
|
-
"@dxos/vite-plugin": "0.1.
|
|
40
|
+
"@dxos/vite-plugin": "0.1.4",
|
|
40
41
|
"@types/react": "^18.0.21",
|
|
41
42
|
"@types/react-dom": "^18.0.6",
|
|
42
43
|
"@vitejs/plugin-react": "^2.0.1",
|
|
@@ -90,7 +90,7 @@ export const AlertDialog = ({
|
|
|
90
90
|
{title}
|
|
91
91
|
</AlertDialogPrimitive.Title>
|
|
92
92
|
{description && (
|
|
93
|
-
<AlertDialogPrimitive.Description className={cx('
|
|
93
|
+
<AlertDialogPrimitive.Description className={cx('my-2', defaultDescription)}>
|
|
94
94
|
{description}
|
|
95
95
|
</AlertDialogPrimitive.Description>
|
|
96
96
|
)}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import cx from 'classnames';
|
|
6
|
+
import { CodeInput, getSegmentCssWidth } from 'rci';
|
|
7
|
+
import React, { forwardRef, useCallback, ComponentProps } from 'react';
|
|
8
|
+
|
|
9
|
+
import { useForwardedRef, useIsFocused } from '../../hooks';
|
|
10
|
+
import { staticInput } from '../../styles/input';
|
|
11
|
+
import { InputProps } from './InputProps';
|
|
12
|
+
|
|
13
|
+
const bareInputStyleProps = {
|
|
14
|
+
padding: '8px',
|
|
15
|
+
spacing: '8px',
|
|
16
|
+
fontFamily: ''
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type BarePinInputProps = Omit<InputProps, 'ref' | 'label' | 'onChange'> &
|
|
20
|
+
Pick<ComponentProps<typeof CodeInput>, 'onChange' | 'value' | 'length'>;
|
|
21
|
+
|
|
22
|
+
// TODO(thure): supplying a `value` prop to CodeInput does not yield correct controlled input interactivity; this may be an issue with RCI (filed as https://github.com/leonardodino/rci/issues/25).
|
|
23
|
+
export const BarePinInput = forwardRef<HTMLInputElement, BarePinInputProps>(
|
|
24
|
+
({ initialValue, size, validationMessage, validationValence, value, ...inputProps }, ref) => {
|
|
25
|
+
const width = getSegmentCssWidth('13px');
|
|
26
|
+
const inputRef = useForwardedRef(ref);
|
|
27
|
+
const inputFocused = useIsFocused(inputRef);
|
|
28
|
+
|
|
29
|
+
const renderSegment = useCallback<ComponentProps<typeof CodeInput>['renderSegment']>(
|
|
30
|
+
({ state, index }) => (
|
|
31
|
+
<div
|
|
32
|
+
key={index}
|
|
33
|
+
className={staticInput({
|
|
34
|
+
focused: inputFocused && !!state,
|
|
35
|
+
disabled: inputProps.disabled,
|
|
36
|
+
...(validationMessage && { validationValence })
|
|
37
|
+
})}
|
|
38
|
+
data-state={state}
|
|
39
|
+
style={{ width, height: '100%' }}
|
|
40
|
+
/>
|
|
41
|
+
),
|
|
42
|
+
[inputFocused, validationValence, validationMessage, inputProps.disabled]
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<CodeInput
|
|
47
|
+
{...{
|
|
48
|
+
spellCheck: false,
|
|
49
|
+
...inputProps,
|
|
50
|
+
...bareInputStyleProps,
|
|
51
|
+
inputRef,
|
|
52
|
+
className: cx(
|
|
53
|
+
'font-mono selection:bg-transparent',
|
|
54
|
+
inputProps.disabled && 'cursor-not-allowed',
|
|
55
|
+
inputProps.className
|
|
56
|
+
),
|
|
57
|
+
renderSegment
|
|
58
|
+
}}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import cx from 'classnames';
|
|
6
|
+
import React, { ComponentProps } from 'react';
|
|
7
|
+
|
|
8
|
+
import { defaultInput } from '../../styles/input';
|
|
9
|
+
import { InputProps, InputSize } from './InputProps';
|
|
10
|
+
|
|
11
|
+
const sizeMap: Record<InputSize, string> = {
|
|
12
|
+
md: 'text-sm',
|
|
13
|
+
lg: 'text-base',
|
|
14
|
+
pin: ''
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type BareTextInputProps = Omit<InputProps, 'label' | 'initialValue' | 'onChange'> &
|
|
18
|
+
Pick<ComponentProps<'input'>, 'onChange'>;
|
|
19
|
+
|
|
20
|
+
export const BareTextInput = ({ validationValence, validationMessage, size, ...inputProps }: BareTextInputProps) => {
|
|
21
|
+
return (
|
|
22
|
+
<input
|
|
23
|
+
{...inputProps}
|
|
24
|
+
className={cx(
|
|
25
|
+
defaultInput({ disabled: inputProps.disabled, ...(validationMessage && { validationValence }) }),
|
|
26
|
+
'block w-full px-2.5 py-2',
|
|
27
|
+
sizeMap[size ?? 'md']
|
|
28
|
+
)}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -16,6 +16,10 @@ export default {
|
|
|
16
16
|
validationValence: {
|
|
17
17
|
control: 'select',
|
|
18
18
|
options: ['success', 'info', 'warning', 'error']
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
control: 'select',
|
|
22
|
+
options: ['md', 'lg', 'pin']
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
25
|
};
|
|
@@ -33,7 +37,8 @@ Default.args = {
|
|
|
33
37
|
labelVisuallyHidden: false,
|
|
34
38
|
descriptionVisuallyHidden: false,
|
|
35
39
|
validationMessage: '',
|
|
36
|
-
validationValence: undefined
|
|
40
|
+
validationValence: undefined,
|
|
41
|
+
length: 6
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
export const Disabled = () => (
|
|
@@ -89,3 +94,15 @@ export const InputWithValidationAndDescription = () => (
|
|
|
89
94
|
}}
|
|
90
95
|
/>
|
|
91
96
|
);
|
|
97
|
+
|
|
98
|
+
export const PinInput = () => (
|
|
99
|
+
<Template
|
|
100
|
+
{...{
|
|
101
|
+
label: 'This input is a PIN-style input',
|
|
102
|
+
size: 'pin',
|
|
103
|
+
length: 6,
|
|
104
|
+
description: 'Type in secret you received',
|
|
105
|
+
placeholder: '••••••'
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
@@ -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';
|