@uxf/ui 10.0.12 → 10.4.0

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,10 +1,18 @@
1
- import React, { ReactNode } from "react";
1
+ import React, { MouseEventHandler, ReactNode } from "react";
2
2
  import { FileInputBaseProps } from "../_file-input-base";
3
+ import { IconName } from "../icon/types";
3
4
  import { AvatarFileInputVariant } from "./theme";
4
5
  export interface AvatarFileInputProps extends FileInputBaseProps {
6
+ customControls?: (args: {
7
+ onSelectFile: MouseEventHandler;
8
+ onRemoveFile: MouseEventHandler;
9
+ }) => ReactNode;
5
10
  helperText?: ReactNode;
11
+ hiddenLabel?: boolean;
12
+ icon?: IconName;
6
13
  label?: ReactNode;
7
- changeFileLabel?: ReactNode;
14
+ removeFileLabel?: ReactNode;
15
+ selectFileLabel?: ReactNode;
8
16
  variant?: AvatarFileInputVariant;
9
17
  }
10
18
  export declare const AvatarFileInput: React.ForwardRefExoticComponent<AvatarFileInputProps & React.RefAttributes<HTMLInputElement>>;
@@ -26,28 +26,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.AvatarFileInput = void 0;
27
27
  const classes_1 = require("@uxf/core/constants/classes");
28
28
  const useInputFocus_1 = require("@uxf/core/hooks/useInputFocus");
29
+ const composeRefs_1 = require("@uxf/core/utils/composeRefs");
29
30
  const cx_1 = require("@uxf/core/utils/cx");
30
31
  const file_1 = require("@uxf/core/utils/file");
31
32
  const react_1 = __importStar(require("react"));
32
33
  const _file_input_base_1 = require("../_file-input-base");
33
34
  const avatar_1 = require("../avatar");
35
+ const button_1 = require("../button");
36
+ const form_component_1 = require("../form-component");
34
37
  const icon_1 = require("../icon");
35
38
  exports.AvatarFileInput = (0, react_1.forwardRef)((props, ref) => {
36
- var _a, _b;
39
+ var _a, _b, _c, _d, _e;
37
40
  const generatedId = (0, react_1.useId)();
38
41
  const id = props.id || generatedId;
39
42
  const innerRef = (0, react_1.useRef)(null);
40
43
  const input = (0, useInputFocus_1.useInputFocus)(innerRef, props.onBlur, props.onFocus);
41
44
  const errorId = props.isInvalid && props.id ? `${props.id}--errormessage` : undefined;
42
- const stateClassNames = (0, cx_1.cx)(input.focused && classes_1.CLASSES.IS_FOCUSED, (props.isDisabled || props.isReadOnly) && classes_1.CLASSES.IS_DISABLED, props.isInvalid && classes_1.CLASSES.IS_INVALID);
43
- const label = props.value && props.changeFileLabel ? props.changeFileLabel : props.label;
44
- return (react_1.default.createElement("div", { className: `uxf-avatar-file-input uxf-avatar-file-input--variant-${(_a = props.variant) !== null && _a !== void 0 ? _a : "default"} ${(_b = props.className) !== null && _b !== void 0 ? _b : ""}` },
45
- react_1.default.createElement("div", { className: "uxf-avatar-file-input__label-wrapper" },
46
- props.value ? (react_1.default.createElement(avatar_1.Avatar, { className: (0, cx_1.cx)("uxf-avatar-file-input__image", stateClassNames), src: (0, file_1.getFileUrl)(props.value) })) : (react_1.default.createElement("label", { className: (0, cx_1.cx)("uxf-avatar-file-input__label", stateClassNames), htmlFor: id, tabIndex: 0 },
47
- react_1.default.createElement(icon_1.Icon, { className: (0, cx_1.cx)("uxf-avatar-file-input__label-icon", stateClassNames), name: "cloud", size: 28 }))),
48
- (props.label && typeof props.label === "string") ||
49
- (props.value && props.changeFileLabel && typeof props.changeFileLabel === "string") ? (react_1.default.createElement("label", { className: (0, cx_1.cx)("uxf-avatar-file-input__label-text", stateClassNames), htmlFor: id, tabIndex: 0 }, label)) : (label)),
50
- react_1.default.createElement(_file_input_base_1._FileInputBase, { accept: props.accept, "aria-describedby": errorId, "aria-invalid": props.isInvalid, className: "uxf-avatar-file-input__input", form: props.form, id: id, isDisabled: props.isDisabled, isFocused: props.isFocused, isInvalid: props.isInvalid, isReadOnly: props.isReadOnly, isRequired: props.isRequired, name: props.name, onBlur: input.onBlur, onChange: props.onChange, onFocus: input.onFocus, onUploadError: props.onUploadError, onUploadFile: props.onUploadFile, ref: ref, value: props.value }),
51
- props.helperText && (react_1.default.createElement("div", { className: (0, cx_1.cx)("uxf-helper-text", errorId && classes_1.CLASSES.IS_INVALID), id: errorId }, props.helperText))));
45
+ const stateClassName = (0, cx_1.cx)(((_a = props.isFocused) !== null && _a !== void 0 ? _a : input.focused) && classes_1.CLASSES.IS_FOCUSED, props.isDisabled && classes_1.CLASSES.IS_DISABLED, props.isInvalid && classes_1.CLASSES.IS_INVALID, props.isReadOnly && classes_1.CLASSES.IS_READONLY, props.isRequired && classes_1.CLASSES.IS_REQUIRED);
46
+ const rootClassName = (0, cx_1.cx)(`uxf-avatar-file-input uxf-avatar-file-input--variant-${(_b = props.variant) !== null && _b !== void 0 ? _b : "default"}`, stateClassName, props.className);
47
+ const onSelectFile = () => { var _a; return (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.click(); };
48
+ const onRemoveFile = () => props.onChange(null);
49
+ return (react_1.default.createElement(form_component_1.FormComponent, { className: rootClassName, errorId: props.id, helperText: props.helperText, hiddenLabel: props.hiddenLabel, inputId: id, label: props.label },
50
+ react_1.default.createElement("div", { className: "uxf-avatar-file-input__inner-wrapper" },
51
+ react_1.default.createElement("div", { className: (0, cx_1.cx)("uxf-avatar-file-input__input", stateClassName), onClick: onSelectFile },
52
+ react_1.default.createElement(_file_input_base_1._FileInputBase, { accept: props.accept, "aria-describedby": errorId, "aria-invalid": props.isInvalid, className: "uxf-avatar-file-input__input-element", form: props.form, id: id, isDisabled: props.isDisabled, isFocused: props.isFocused, isInvalid: props.isInvalid, isReadOnly: props.isReadOnly, isRequired: props.isRequired, name: props.name, onBlur: input.onBlur, onFocus: input.onFocus, onChange: props.onChange, onUploadError: props.onUploadError, onUploadFile: props.onUploadFile, ref: (0, composeRefs_1.composeRefs)(innerRef, ref), value: props.value }),
53
+ props.value ? (react_1.default.createElement(avatar_1.Avatar, { className: "uxf-avatar-file-input__input-avatar", src: (0, file_1.getFileUrl)(props.value) })) : (react_1.default.createElement("div", { className: "uxf-avatar-file-input__input-empty" },
54
+ react_1.default.createElement(icon_1.Icon, { className: "uxf-avatar-file-input__input-empty-icon", name: (_c = props.icon) !== null && _c !== void 0 ? _c : "cloud" })))),
55
+ react_1.default.createElement("div", { className: "uxf-avatar-file-input__controls" }, props.customControls ? (props.customControls({
56
+ onSelectFile,
57
+ onRemoveFile,
58
+ })) : (react_1.default.createElement("div", { className: "uxf-avatar-file-input__controls-buttons" },
59
+ react_1.default.createElement(button_1.Button, { className: "uxf-avatar-file-input__controls-button uxf-avatar-file-input__controls-button--select", disabled: props.isDisabled, onClick: onSelectFile, size: "sm", variant: "white" }, (_d = props.selectFileLabel) !== null && _d !== void 0 ? _d : "Upload image"),
60
+ !!props.value && !props.isDisabled && (react_1.default.createElement(button_1.Button, { className: "uxf-avatar-file-input__controls-button uxf-avatar-file-input__controls-button--remove", color: "error", disabled: props.isDisabled, onClick: onRemoveFile, size: "sm", variant: "white" }, (_e = props.removeFileLabel) !== null && _e !== void 0 ? _e : "Remove avatar"))))))));
52
61
  });
53
62
  exports.AvatarFileInput.displayName = "UxfUiAvatarFileInput";
@@ -1,116 +1,146 @@
1
1
  .uxf-avatar-file-input {
2
- align-items: center;
3
- display: flex;
4
- gap: theme("spacing.4");
5
-
6
- &__input {
7
- display: none;
2
+ &.is-disabled .uxf-avatar-file-input__inner-wrapper {
3
+ cursor: not-allowed;
8
4
  }
9
5
 
10
- &--variant-default {
11
- .uxf-avatar-file-input__label {
12
- border-radius: theme("borderRadius.full");
13
- }
6
+ &__inner-wrapper {
7
+ align-items: center;
8
+ display: flex;
9
+ gap: theme("spacing.4");
10
+ margin-top: theme("spacing.2");
14
11
  }
15
12
 
16
- &__label {
17
- @apply transition-all duration-75;
18
-
19
- align-items: center;
20
- border-style: dashed;
21
- border-width: theme("borderWidth.2");
13
+ &__input {
22
14
  cursor: pointer;
23
- display: flex;
15
+ flex-shrink: 0;
24
16
  height: theme("height.20");
25
- justify-content: center;
17
+ position: relative;
26
18
  width: theme("width.20");
27
19
 
28
- :root .light & {
29
- border-color: theme("colors.lightBorder");
30
- }
31
-
32
- :root .dark & {
33
- border-color: theme("colors.darkBorder");
34
- }
20
+ &:hover .uxf-avatar-file-input__input-empty {
21
+ :root .light & {
22
+ --bg-color: theme("colors.lightBorder/.25");
23
+ }
35
24
 
36
- &-wrapper {
37
- align-items: center;
38
- display: flex;
39
- gap: theme("spacing.4");
25
+ :root .dark & {
26
+ --bg-color: theme("colors.darkBorder/.25");
27
+ }
40
28
  }
41
29
 
42
- &-icon {
30
+ &.is-invalid .uxf-avatar-file-input__input-empty {
43
31
  :root .light & {
44
- color: theme("colors.lightLow");
32
+ --bg-color: theme("colors.error.DEFAULT/.05");
33
+ --border-color: var(--color);
34
+ --color: theme("colors.error.DEFAULT");
45
35
  }
46
36
 
47
37
  :root .dark & {
48
- color: theme("colors.lightBorder");
38
+ --bg-color: theme("colors.error.DEFAULT/.05");
39
+ --border-color: var(--color);
40
+ --color: theme("colors.error.DEFAULT");
49
41
  }
42
+ }
50
43
 
51
- &.is-invalid {
44
+ &.is-disabled {
45
+ pointer-events: none;
46
+
47
+ .uxf-avatar-file-input__input-empty {
52
48
  :root .light & {
53
- color: theme("colors.error.DEFAULT");
49
+ --border-color: var(--color);
50
+ --color: theme("colors.lightBorder");
54
51
  }
55
52
 
56
53
  :root .dark & {
57
- color: theme("colors.error.DEFAULT");
54
+ --border-color: var(--color);
55
+ --color: theme("colors.darkBorder");
58
56
  }
59
57
  }
58
+
59
+ .uxf-avatar-file-input__input-avatar {
60
+ opacity: 0.5;
61
+ }
60
62
  }
63
+ }
64
+
65
+ &__input-element {
66
+ @apply sr-only;
61
67
 
62
- &:hover {
68
+ &:focus-visible + .uxf-avatar-file-input__input-empty {
63
69
  border-width: theme("borderWidth.4");
64
- }
65
70
 
66
- &.is-invalid {
67
- :root .light & {
68
- border-color: theme("colors.error.DEFAULT");
71
+ /* :root .light & {
72
+ --bg-color: theme("colors.primary.DEFAULT/.05");
73
+ --border-color: var(--color);
74
+ --color: theme("colors.primary.DEFAULT");
69
75
  }
70
76
 
71
77
  :root .dark & {
72
- border-color: theme("colors.error.DEFAULT");
73
- }
78
+ --bg-color: theme("colors.primary.DEFAULT/.05");
79
+ --border-color: var(--color);
80
+ --color: theme("colors.primary.DEFAULT");
81
+ */
74
82
  }
83
+ }
75
84
 
76
- &.is-disabled {
77
- background-color: theme("colors.lightLow/.20");
78
- cursor: not-allowed;
79
-
80
- &:hover {
81
- border-width: theme("borderWidth.2");
82
- }
83
- }
85
+ &__input-avatar {
86
+ border-radius: inherit;
87
+ display: flex;
88
+ height: 100%;
89
+ width: 100%;
84
90
  }
85
91
 
86
- &__label-text {
87
- @apply text-sm shadow-sm;
92
+ &__input-empty {
93
+ --bg-color: transparent;
88
94
 
89
- border: theme("borderWidth.DEFAULT") solid theme("colors.gray.300");
90
- padding: theme("spacing[1.5]") theme("spacing.3");
91
- text-align: center;
95
+ @apply transition-all duration-75;
96
+
97
+ align-items: center;
98
+ background-color: var(--bg-color);
99
+ border: theme("borderWidth.2") dashed var(--border-color);
100
+ border-radius: inherit;
101
+ display: flex;
102
+ height: 100%;
103
+ justify-content: center;
104
+ width: 100%;
92
105
 
93
106
  :root .light & {
94
- color: theme("colors.lightHigh");
107
+ --color: theme("colors.lightMedium");
108
+ --border-color: theme("colors.lightBorder");
95
109
  }
96
110
 
97
111
  :root .dark & {
98
- color: theme("colors.lightBorder");
112
+ --color: theme("colors.darkMedium");
113
+ --border-color: theme("colors.darkBorder");
99
114
  }
115
+ }
100
116
 
101
- &.is-invalid {
102
- :root .light & {
103
- color: theme("colors.error.DEFAULT");
104
- }
117
+ &__input-empty-icon {
118
+ color: var(--color);
119
+ height: theme("width.6");
120
+ width: theme("width.6");
121
+ }
105
122
 
106
- :root .dark & {
107
- color: theme("colors.error.DEFAULT");
108
- }
123
+ &__controls-buttons {
124
+ align-items: flex-start;
125
+ display: flex;
126
+ flex-direction: column;
127
+ gap: theme("spacing.2");
128
+ justify-content: center;
129
+ }
130
+
131
+ &__controls-button--remove .uxf-button__text {
132
+ color: theme("colors.error.DEFAULT");
133
+ }
134
+
135
+ &--variant-default {
136
+ .uxf-avatar-file-input__input {
137
+ border-radius: theme("borderRadius.full");
109
138
  }
110
139
  }
111
140
 
112
- &__image {
113
- height: theme("height.20");
114
- width: theme("width.20");
141
+ &--variant-square {
142
+ .uxf-avatar-file-input__input {
143
+ border-radius: 0;
144
+ }
115
145
  }
116
146
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxf/ui",
3
- "version": "10.0.12",
3
+ "version": "10.4.0",
4
4
  "description": "",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -17,9 +17,9 @@
17
17
  "dependencies": {
18
18
  "@floating-ui/react": "0.26.0",
19
19
  "@headlessui/react": "1.7.14",
20
- "@uxf/core": "10.0.0",
20
+ "@uxf/core": "10.4.0",
21
21
  "@uxf/datepicker": "10.0.0",
22
- "@uxf/styles": "10.0.0",
22
+ "@uxf/styles": "10.4.0",
23
23
  "color2k": "2.0.2",
24
24
  "dayjs": "1.11.10",
25
25
  "jump.js": "1.0.2",