@mindlogic-ai/logician-ui 3.0.0-alpha.32 → 3.0.0-alpha.34
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/components/Code/shikiAdapter.d.ts.map +1 -1
- package/dist/components/Code/shikiAdapter.js +1 -0
- package/dist/components/Code/shikiAdapter.js.map +1 -1
- package/dist/components/Code/shikiAdapter.mjs +1 -0
- package/dist/components/Code/shikiAdapter.mjs.map +1 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +44 -8
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/Select.mjs +44 -8
- package/dist/components/Select/Select.mjs.map +1 -1
- package/dist/components/Select/Select.styles.d.ts +20 -5
- package/dist/components/Select/Select.styles.d.ts.map +1 -1
- package/dist/components/Select/Select.styles.js +23 -9
- package/dist/components/Select/Select.styles.js.map +1 -1
- package/dist/components/Select/Select.styles.mjs +23 -9
- package/dist/components/Select/Select.styles.mjs.map +1 -1
- package/dist/components/Textarea/Textarea.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.js +29 -5
- package/dist/components/Textarea/Textarea.js.map +1 -1
- package/dist/components/Textarea/Textarea.mjs +29 -5
- package/dist/components/Textarea/Textarea.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Code/shikiAdapter.ts +1 -0
- package/src/components/Select/Comparison.stories.tsx +346 -0
- package/src/components/Select/Select.styles.ts +23 -9
- package/src/components/Select/Select.tsx +48 -4
- package/src/components/Textarea/Textarea.tsx +38 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shikiAdapter.d.ts","sourceRoot":"","sources":["../../../src/components/Code/shikiAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAoC,MAAM,OAAO,CAAC;AAE/E,eAAO,MAAM,iBAAiB,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"shikiAdapter.d.ts","sourceRoot":"","sources":["../../../src/components/Code/shikiAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAoC,MAAM,OAAO,CAAC;AAE/E,eAAO,MAAM,iBAAiB,EAAE,eAAe,EA8B9C,CAAC;AAEF,eAAO,MAAM,YAAY,6CAWvB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shikiAdapter.js","sources":["../../../src/components/Code/shikiAdapter.ts"],"sourcesContent":[null],"names":["createShikiAdapter"],"mappings":";;;;;AAGO,MAAM,iBAAiB,GAAsB;IAClD,MAAM;IACN,GAAG;IACH,QAAQ;IACR,KAAK;IACL,MAAM;IACN,YAAY;IACZ,IAAI;IACJ,MAAM;IACN,MAAM;IACN,YAAY;IACZ,MAAM;IACN,KAAK;IACL,QAAQ;IACR,KAAK;IACL,UAAU;IACV,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,GAAG;IACH,MAAM;IACN,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,KAAK;IACL,YAAY;IACZ,KAAK;IACL,MAAM;;AAGD,MAAM,YAAY,GAAGA,wBAAkB,CAE5C;AACA,IAAA,MAAM,IAAI,GAAA;QACR,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,oDAAO,wCAAO,KAAC;AACnD,QAAA,OAAO,iBAAiB,CAAC;AACvB,YAAA,KAAK,EAAE,iBAAiB;YACxB,MAAM,EAAE,CAAC,aAAa,CAAC;AACxB,SAAA,CAAC;IACJ,CAAC;AACD,IAAA,KAAK,EAAE,aAAa;AACrB,CAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"shikiAdapter.js","sources":["../../../src/components/Code/shikiAdapter.ts"],"sourcesContent":[null],"names":["createShikiAdapter"],"mappings":";;;;;AAGO,MAAM,iBAAiB,GAAsB;IAClD,MAAM;IACN,GAAG;IACH,QAAQ;IACR,KAAK;IACL,MAAM;IACN,YAAY;IACZ,IAAI;IACJ,MAAM;IACN,MAAM;IACN,YAAY;IACZ,MAAM;IACN,KAAK;IACL,QAAQ;IACR,KAAK;IACL,UAAU;IACV,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,GAAG;IACH,MAAM;IACN,MAAM;IACN,OAAO;IACP,KAAK;IACL,OAAO;IACP,MAAM;IACN,KAAK;IACL,YAAY;IACZ,KAAK;IACL,MAAM;;AAGD,MAAM,YAAY,GAAGA,wBAAkB,CAE5C;AACA,IAAA,MAAM,IAAI,GAAA;QACR,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,oDAAO,wCAAO,KAAC;AACnD,QAAA,OAAO,iBAAiB,CAAC;AACvB,YAAA,KAAK,EAAE,iBAAiB;YACxB,MAAM,EAAE,CAAC,aAAa,CAAC;AACxB,SAAA,CAAC;IACJ,CAAC;AACD,IAAA,KAAK,EAAE,aAAa;AACrB,CAAA;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shikiAdapter.mjs","sources":["../../../src/components/Code/shikiAdapter.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAGO,MAAM,iBAAiB,GAAsB;IAClD,MAAM;IACN,GAAG;IACH,QAAQ;IACR,KAAK;IACL,MAAM;IACN,YAAY;IACZ,IAAI;IACJ,MAAM;IACN,MAAM;IACN,YAAY;IACZ,MAAM;IACN,KAAK;IACL,QAAQ;IACR,KAAK;IACL,UAAU;IACV,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,GAAG;IACH,MAAM;IACN,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,KAAK;IACL,YAAY;IACZ,KAAK;IACL,MAAM;;AAGD,MAAM,YAAY,GAAG,kBAAkB,CAE5C;AACA,IAAA,MAAM,IAAI,GAAA;QACR,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,OAAO,yCAAO,CAAC;AACnD,QAAA,OAAO,iBAAiB,CAAC;AACvB,YAAA,KAAK,EAAE,iBAAiB;YACxB,MAAM,EAAE,CAAC,aAAa,CAAC;AACxB,SAAA,CAAC;IACJ,CAAC;AACD,IAAA,KAAK,EAAE,aAAa;AACrB,CAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"shikiAdapter.mjs","sources":["../../../src/components/Code/shikiAdapter.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAGO,MAAM,iBAAiB,GAAsB;IAClD,MAAM;IACN,GAAG;IACH,QAAQ;IACR,KAAK;IACL,MAAM;IACN,YAAY;IACZ,IAAI;IACJ,MAAM;IACN,MAAM;IACN,YAAY;IACZ,MAAM;IACN,KAAK;IACL,QAAQ;IACR,KAAK;IACL,UAAU;IACV,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,GAAG;IACH,MAAM;IACN,MAAM;IACN,OAAO;IACP,KAAK;IACL,OAAO;IACP,MAAM;IACN,KAAK;IACL,YAAY;IACZ,KAAK;IACL,MAAM;;AAGD,MAAM,YAAY,GAAG,kBAAkB,CAE5C;AACA,IAAA,MAAM,IAAI,GAAA;QACR,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,OAAO,yCAAO,CAAC;AACnD,QAAA,OAAO,iBAAiB,CAAC;AACvB,YAAA,KAAK,EAAE,iBAAiB;YACxB,MAAM,EAAE,CAAC,aAAa,CAAC;AACxB,SAAA,CAAC;IACJ,CAAC;AACD,IAAA,KAAK,EAAE,aAAa;AACrB,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/Select/Select.tsx"],"names":[],"mappings":"AAAA,OAAoB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAUtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,eAAO,MAAM,MAAM,GACjB,MAAM,EACN,OAAO,SAAS,OAAO,GAAG,KAAK,EAC/B,KAAK,SAAS,SAAS,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,EACnD,uCAKC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/Select/Select.tsx"],"names":[],"mappings":"AAAA,OAAoB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAUtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,eAAO,MAAM,MAAM,GACjB,MAAM,EACN,OAAO,SAAS,OAAO,GAAG,KAAK,EAC/B,KAAK,SAAS,SAAS,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,EACnD,uCAKC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,4CA4LrC,CAAC"}
|
|
@@ -7,8 +7,9 @@ var react = require('@chakra-ui/react');
|
|
|
7
7
|
var Select_styles = require('./Select.styles.js');
|
|
8
8
|
|
|
9
9
|
const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
10
|
-
const [primaryColor, primaryLightest, primaryDark, dangerColor, gray50, gray300, gray400, gray500, gray600, gray1200,] = react.useToken('colors', [
|
|
10
|
+
const [primaryColor, primaryLighter, primaryLightest, primaryDark, dangerColor, gray50, gray300, gray400, gray500, gray600, gray1000, gray1200, gray1300,] = react.useToken('colors', [
|
|
11
11
|
'primary.main',
|
|
12
|
+
'primary.lighter',
|
|
12
13
|
'primary.extralight',
|
|
13
14
|
'primary.dark',
|
|
14
15
|
'danger.main',
|
|
@@ -17,7 +18,9 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
17
18
|
'gray.400',
|
|
18
19
|
'gray.500',
|
|
19
20
|
'gray.600',
|
|
21
|
+
'gray.1000',
|
|
20
22
|
'gray.1200',
|
|
23
|
+
'gray.1300',
|
|
21
24
|
]);
|
|
22
25
|
const colors = {
|
|
23
26
|
primaryLightest,
|
|
@@ -26,9 +29,7 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
26
29
|
gray50,
|
|
27
30
|
gray300,
|
|
28
31
|
gray500,
|
|
29
|
-
|
|
30
|
-
gray1200,
|
|
31
|
-
};
|
|
32
|
+
gray1200};
|
|
32
33
|
// invalid prop이 true이면 variant를 'danger'로 오버라이드
|
|
33
34
|
const effectiveVariant = invalid ? 'danger' : variant;
|
|
34
35
|
return (jsxRuntime.jsx(ReactSelect, { closeMenuOnSelect: true, closeMenuOnScroll: true, isSearchable: false, ...rest,
|
|
@@ -40,19 +41,40 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
40
41
|
return styles?.container ? styles.container(merged, state) : merged;
|
|
41
42
|
},
|
|
42
43
|
control: (base, state) => {
|
|
44
|
+
// Mirror Input.tsx: borderColor gray.400, _hover primary.lighter,
|
|
45
|
+
// _focus primary.main + 1px outline (Chakra Input recipe's
|
|
46
|
+
// `focusVisibleRing: "inside"`), _invalid danger.main,
|
|
47
|
+
// _disabled bg gray.50 / color gray.1000 / fontWeight semibold.
|
|
48
|
+
const focusOutlineColor = invalid ? dangerColor : primaryColor;
|
|
43
49
|
const merged = {
|
|
44
50
|
...base,
|
|
45
51
|
...Select_styles.getControlStyles(effectiveVariant, colors),
|
|
46
52
|
width: '100%',
|
|
47
|
-
border: `1px solid ${invalid ? dangerColor : state.isFocused ? primaryColor :
|
|
53
|
+
border: `1px solid ${invalid ? dangerColor : state.isFocused ? primaryColor : gray400}`,
|
|
48
54
|
boxShadow: 'none',
|
|
55
|
+
outline: state.isFocused
|
|
56
|
+
? `1px solid ${focusOutlineColor}`
|
|
57
|
+
: 'none',
|
|
58
|
+
outlineOffset: 0,
|
|
59
|
+
// react-select sets a 0.1s `transition: all` on the control,
|
|
60
|
+
// which causes the border-color and outline (none -> solid +
|
|
61
|
+
// transparent -> primary) to interpolate awkwardly — a brief
|
|
62
|
+
// dark blink during focus. Disable to match Input, which
|
|
63
|
+
// toggles its focus ring instantly via :focus-visible.
|
|
64
|
+
transition: 'none',
|
|
49
65
|
'&:hover': {
|
|
50
66
|
borderColor: invalid
|
|
51
67
|
? dangerColor
|
|
52
68
|
: state.isFocused
|
|
53
69
|
? primaryColor
|
|
54
|
-
:
|
|
70
|
+
: primaryLighter,
|
|
55
71
|
},
|
|
72
|
+
...(state.isDisabled && {
|
|
73
|
+
backgroundColor: gray50,
|
|
74
|
+
color: gray1000,
|
|
75
|
+
fontWeight: 600,
|
|
76
|
+
cursor: 'not-allowed',
|
|
77
|
+
}),
|
|
56
78
|
};
|
|
57
79
|
return styles?.control ? styles.control(merged, state) : merged;
|
|
58
80
|
},
|
|
@@ -82,17 +104,28 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
82
104
|
return styles?.option ? styles.option(merged, state) : merged;
|
|
83
105
|
},
|
|
84
106
|
singleValue: (base, state) => {
|
|
85
|
-
|
|
107
|
+
// Match Input text color (gray.1300, inherited from body in Input).
|
|
108
|
+
// When disabled, mirror Input's _disabled color (gray.1000).
|
|
109
|
+
const merged = {
|
|
110
|
+
...base,
|
|
111
|
+
margin: 0,
|
|
112
|
+
color: state.isDisabled ? gray1000 : gray1300,
|
|
113
|
+
};
|
|
86
114
|
return styles?.singleValue
|
|
87
115
|
? styles.singleValue(merged, state)
|
|
88
116
|
: merged;
|
|
89
117
|
},
|
|
90
118
|
valueContainer: (base, state) => {
|
|
119
|
+
// Zero internal padding so the visible text starts after the
|
|
120
|
+
// control's own 12px paddingLeft (matches Input's `px: 3` =
|
|
121
|
+
// 12px). react-select's default valueContainer padding is
|
|
122
|
+
// `2px 8px`, which would otherwise stack on top.
|
|
91
123
|
const merged = {
|
|
92
124
|
...base,
|
|
93
125
|
display: 'flex',
|
|
94
126
|
alignItems: 'center',
|
|
95
127
|
textAlign: 'left',
|
|
128
|
+
padding: 0,
|
|
96
129
|
};
|
|
97
130
|
return styles?.valueContainer
|
|
98
131
|
? styles.valueContainer(merged, state)
|
|
@@ -105,7 +138,10 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
105
138
|
: merged;
|
|
106
139
|
},
|
|
107
140
|
dropdownIndicator: (base, state) => {
|
|
108
|
-
|
|
141
|
+
// Lighter than the body text color so the chevron doesn't
|
|
142
|
+
// visually outweigh Input's right-side icons (which are
|
|
143
|
+
// typically outline-style and read as gray.600-ish).
|
|
144
|
+
const merged = { ...base, color: gray600 };
|
|
109
145
|
return styles?.dropdownIndicator
|
|
110
146
|
? styles.dropdownIndicator(merged, state)
|
|
111
147
|
: merged;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.js","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":[null],"names":["useToken","_jsx","getControlStyles","getPlaceholderStyles","getMenuStyles","getOptionStyles"],"mappings":";;;;;;;;MAYa,MAAM,GAAG,CAIpB,EACA,OAAO,GAAG,SAAS,EACnB,OAAO,GAAG,KAAK,EACf,MAAM,EACN,GAAG,IAAI,EAC6B,KAAI;
|
|
1
|
+
{"version":3,"file":"Select.js","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":[null],"names":["useToken","_jsx","getControlStyles","getPlaceholderStyles","getMenuStyles","getOptionStyles"],"mappings":";;;;;;;;MAYa,MAAM,GAAG,CAIpB,EACA,OAAO,GAAG,SAAS,EACnB,OAAO,GAAG,KAAK,EACf,MAAM,EACN,GAAG,IAAI,EAC6B,KAAI;AACxC,IAAA,MAAM,CACJ,YAAY,EACZ,cAAc,EACd,eAAe,EACf,WAAW,EACX,WAAW,EACX,MAAM,EACN,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,QAAQ,EACT,GAAGA,cAAQ,CAAC,QAAQ,EAAE;QACrB,cAAc;QACd,iBAAiB;QACjB,oBAAoB;QACpB,cAAc;QACd,aAAa;QACb,SAAS;QACT,UAAU;QACV,UAAU;QACV,UAAU;QACV,UAAU;QACV,WAAW;QACX,WAAW;QACX,WAAW;AACZ,KAAA,CAAC;AAEF,IAAA,MAAM,MAAM,GAAiB;QAG3B,eAAe;QACf,WAAW;QACX,WAAW;QACX,MAAM;QACN,OAAO;QAEP,OAAO;QAGP,SAED;;IAGD,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO;AAErD,IAAA,QACEC,cAAA,CAAC,WAAW,EAAA,EACV,iBAAiB,EAAA,IAAA,EACjB,iBAAiB,EAAA,IAAA,EACjB,YAAY,EAAE,KAAK,EAAA,GACf,IAAI;;;AAGR,QAAA,MAAM,EAAE;AACN,YAAA,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;gBACzB,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;AACzC,gBAAA,OAAO,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;YACrE,CAAC;AACD,YAAA,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;;;;;gBAKvB,MAAM,iBAAiB,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY;AAC9D,gBAAA,MAAM,MAAM,GAAG;AACb,oBAAA,GAAG,IAAI;AACP,oBAAA,GAAGC,8BAAgB,CAAC,gBAAgB,EAAE,MAAM,CAAC;AAC7C,oBAAA,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,aACN,OAAO,GAAG,WAAW,GAAG,KAAK,CAAC,SAAS,GAAG,YAAY,GAAG,OAC3D,CAAA,CAAE;AACF,oBAAA,SAAS,EAAE,MAAM;oBACjB,OAAO,EAAE,KAAK,CAAC;0BACX,CAAA,UAAA,EAAa,iBAAiB,CAAA;AAChC,0BAAE,MAAM;AACV,oBAAA,aAAa,EAAE,CAAC;;;;;;AAMhB,oBAAA,UAAU,EAAE,MAAM;AAClB,oBAAA,SAAS,EAAE;AACT,wBAAA,WAAW,EAAE;AACX,8BAAE;8BACA,KAAK,CAAC;AACN,kCAAE;AACF,kCAAE,cAAc;AACrB,qBAAA;AACD,oBAAA,IAAI,KAAK,CAAC,UAAU,IAAI;AACtB,wBAAA,eAAe,EAAE,MAAM;AACvB,wBAAA,KAAK,EAAE,QAAQ;AACf,wBAAA,UAAU,EAAE,GAAG;AACf,wBAAA,MAAM,EAAE,aAAa;qBACtB,CAAC;iBACH;AACD,gBAAA,OAAO,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;YACjE,CAAC;AACD,YAAA,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;AAC3B,gBAAA,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,GAAGC,kCAAoB,CAAC,MAAM,CAAC,EAAE;gBAC3D,OAAO,MAAM,EAAE;sBACX,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK;sBAChC,MAAM;YACZ,CAAC;AACD,YAAA,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;AACpB,gBAAA,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,GAAGC,2BAAa,CAAC,MAAM,CAAC,EAAE;AACpD,gBAAA,OAAO,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;YAC3D,CAAC;AACD,YAAA,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;gBACxB,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE;AAC9C,gBAAA,OAAO,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;YACnE,CAAC;AACD,YAAA,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;AACtB,gBAAA,MAAM,MAAM,GAAG;AACb,oBAAA,GAAG,IAAI;AACP,oBAAA,GAAGC,6BAAe,CAAC;wBACjB,UAAU,EAAE,KAAK,CAAC,UAAU;wBAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;wBAC5B,MAAM;qBACP,CAAC;iBACH;AACD,gBAAA,OAAO,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;YAC/D,CAAC;AACD,YAAA,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;;;AAG3B,gBAAA,MAAM,MAAM,GAAG;AACb,oBAAA,GAAG,IAAI;AACP,oBAAA,MAAM,EAAE,CAAC;oBACT,KAAK,EAAE,KAAK,CAAC,UAAU,GAAG,QAAQ,GAAG,QAAQ;iBAC9C;gBACD,OAAO,MAAM,EAAE;sBACX,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK;sBAChC,MAAM;YACZ,CAAC;AACD,YAAA,cAAc,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;;;;;AAK9B,gBAAA,MAAM,MAAM,GAAG;AACb,oBAAA,GAAG,IAAI;AACP,oBAAA,OAAO,EAAE,MAAM;AACf,oBAAA,UAAU,EAAE,QAAQ;AACpB,oBAAA,SAAS,EAAE,MAAe;AAC1B,oBAAA,OAAO,EAAE,CAAC;iBACX;gBACD,OAAO,MAAM,EAAE;sBACX,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK;sBACnC,MAAM;YACZ,CAAC;AACD,YAAA,kBAAkB,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;gBAClC,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE;gBAC3C,OAAO,MAAM,EAAE;sBACX,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK;sBACvC,MAAM;YACZ,CAAC;AACD,YAAA,iBAAiB,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;;;;gBAIjC,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE;gBAC1C,OAAO,MAAM,EAAE;sBACX,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK;sBACtC,MAAM;YACZ,CAAC;AACD,YAAA,mBAAmB,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;AACnC,gBAAA,MAAM,MAAM,GAAG;AACb,oBAAA,GAAG,IAAI;AACP,oBAAA,OAAO,EAAE,MAAM;AACf,oBAAA,UAAU,EAAE,QAAQ;iBACrB;gBACD,OAAO,MAAM,EAAE;sBACX,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,KAAK;sBACxC,MAAM;YACZ,CAAC;AACD,YAAA,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,KAAI;gBAC1B,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;AACxC,gBAAA,OAAO,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;YACvE,CAAC;AACF,SAAA,EAAA,CACD;AAEN;;;;"}
|
|
@@ -5,8 +5,9 @@ import { useToken } from '@chakra-ui/react';
|
|
|
5
5
|
import { getOptionStyles, getMenuStyles, getPlaceholderStyles, getControlStyles } from './Select.styles.mjs';
|
|
6
6
|
|
|
7
7
|
const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
8
|
-
const [primaryColor, primaryLightest, primaryDark, dangerColor, gray50, gray300, gray400, gray500, gray600, gray1200,] = useToken('colors', [
|
|
8
|
+
const [primaryColor, primaryLighter, primaryLightest, primaryDark, dangerColor, gray50, gray300, gray400, gray500, gray600, gray1000, gray1200, gray1300,] = useToken('colors', [
|
|
9
9
|
'primary.main',
|
|
10
|
+
'primary.lighter',
|
|
10
11
|
'primary.extralight',
|
|
11
12
|
'primary.dark',
|
|
12
13
|
'danger.main',
|
|
@@ -15,7 +16,9 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
15
16
|
'gray.400',
|
|
16
17
|
'gray.500',
|
|
17
18
|
'gray.600',
|
|
19
|
+
'gray.1000',
|
|
18
20
|
'gray.1200',
|
|
21
|
+
'gray.1300',
|
|
19
22
|
]);
|
|
20
23
|
const colors = {
|
|
21
24
|
primaryLightest,
|
|
@@ -24,9 +27,7 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
24
27
|
gray50,
|
|
25
28
|
gray300,
|
|
26
29
|
gray500,
|
|
27
|
-
|
|
28
|
-
gray1200,
|
|
29
|
-
};
|
|
30
|
+
gray1200};
|
|
30
31
|
// invalid prop이 true이면 variant를 'danger'로 오버라이드
|
|
31
32
|
const effectiveVariant = invalid ? 'danger' : variant;
|
|
32
33
|
return (jsx(ReactSelect, { closeMenuOnSelect: true, closeMenuOnScroll: true, isSearchable: false, ...rest,
|
|
@@ -38,19 +39,40 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
38
39
|
return styles?.container ? styles.container(merged, state) : merged;
|
|
39
40
|
},
|
|
40
41
|
control: (base, state) => {
|
|
42
|
+
// Mirror Input.tsx: borderColor gray.400, _hover primary.lighter,
|
|
43
|
+
// _focus primary.main + 1px outline (Chakra Input recipe's
|
|
44
|
+
// `focusVisibleRing: "inside"`), _invalid danger.main,
|
|
45
|
+
// _disabled bg gray.50 / color gray.1000 / fontWeight semibold.
|
|
46
|
+
const focusOutlineColor = invalid ? dangerColor : primaryColor;
|
|
41
47
|
const merged = {
|
|
42
48
|
...base,
|
|
43
49
|
...getControlStyles(effectiveVariant, colors),
|
|
44
50
|
width: '100%',
|
|
45
|
-
border: `1px solid ${invalid ? dangerColor : state.isFocused ? primaryColor :
|
|
51
|
+
border: `1px solid ${invalid ? dangerColor : state.isFocused ? primaryColor : gray400}`,
|
|
46
52
|
boxShadow: 'none',
|
|
53
|
+
outline: state.isFocused
|
|
54
|
+
? `1px solid ${focusOutlineColor}`
|
|
55
|
+
: 'none',
|
|
56
|
+
outlineOffset: 0,
|
|
57
|
+
// react-select sets a 0.1s `transition: all` on the control,
|
|
58
|
+
// which causes the border-color and outline (none -> solid +
|
|
59
|
+
// transparent -> primary) to interpolate awkwardly — a brief
|
|
60
|
+
// dark blink during focus. Disable to match Input, which
|
|
61
|
+
// toggles its focus ring instantly via :focus-visible.
|
|
62
|
+
transition: 'none',
|
|
47
63
|
'&:hover': {
|
|
48
64
|
borderColor: invalid
|
|
49
65
|
? dangerColor
|
|
50
66
|
: state.isFocused
|
|
51
67
|
? primaryColor
|
|
52
|
-
:
|
|
68
|
+
: primaryLighter,
|
|
53
69
|
},
|
|
70
|
+
...(state.isDisabled && {
|
|
71
|
+
backgroundColor: gray50,
|
|
72
|
+
color: gray1000,
|
|
73
|
+
fontWeight: 600,
|
|
74
|
+
cursor: 'not-allowed',
|
|
75
|
+
}),
|
|
54
76
|
};
|
|
55
77
|
return styles?.control ? styles.control(merged, state) : merged;
|
|
56
78
|
},
|
|
@@ -80,17 +102,28 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
80
102
|
return styles?.option ? styles.option(merged, state) : merged;
|
|
81
103
|
},
|
|
82
104
|
singleValue: (base, state) => {
|
|
83
|
-
|
|
105
|
+
// Match Input text color (gray.1300, inherited from body in Input).
|
|
106
|
+
// When disabled, mirror Input's _disabled color (gray.1000).
|
|
107
|
+
const merged = {
|
|
108
|
+
...base,
|
|
109
|
+
margin: 0,
|
|
110
|
+
color: state.isDisabled ? gray1000 : gray1300,
|
|
111
|
+
};
|
|
84
112
|
return styles?.singleValue
|
|
85
113
|
? styles.singleValue(merged, state)
|
|
86
114
|
: merged;
|
|
87
115
|
},
|
|
88
116
|
valueContainer: (base, state) => {
|
|
117
|
+
// Zero internal padding so the visible text starts after the
|
|
118
|
+
// control's own 12px paddingLeft (matches Input's `px: 3` =
|
|
119
|
+
// 12px). react-select's default valueContainer padding is
|
|
120
|
+
// `2px 8px`, which would otherwise stack on top.
|
|
89
121
|
const merged = {
|
|
90
122
|
...base,
|
|
91
123
|
display: 'flex',
|
|
92
124
|
alignItems: 'center',
|
|
93
125
|
textAlign: 'left',
|
|
126
|
+
padding: 0,
|
|
94
127
|
};
|
|
95
128
|
return styles?.valueContainer
|
|
96
129
|
? styles.valueContainer(merged, state)
|
|
@@ -103,7 +136,10 @@ const Select = ({ variant = 'default', invalid = false, styles, ...rest }) => {
|
|
|
103
136
|
: merged;
|
|
104
137
|
},
|
|
105
138
|
dropdownIndicator: (base, state) => {
|
|
106
|
-
|
|
139
|
+
// Lighter than the body text color so the chevron doesn't
|
|
140
|
+
// visually outweigh Input's right-side icons (which are
|
|
141
|
+
// typically outline-style and read as gray.600-ish).
|
|
142
|
+
const merged = { ...base, color: gray600 };
|
|
107
143
|
return styles?.dropdownIndicator
|
|
108
144
|
? styles.dropdownIndicator(merged, state)
|
|
109
145
|
: merged;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.mjs","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;;;MAYa,MAAM,GAAG,CAIpB,EACA,OAAO,GAAG,SAAS,EACnB,OAAO,GAAG,KAAK,EACf,MAAM,EACN,GAAG,IAAI,EAC6B,KAAI;
|
|
1
|
+
{"version":3,"file":"Select.mjs","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":"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"}
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Select component styles (Chakra v3 compatible)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Defaults mirror the Input component (Chakra v3 `Input` recipe + Logician
|
|
5
|
+
* Input.tsx overrides) so the two controls share the same border, hover,
|
|
6
|
+
* focus, font, and disabled/readOnly behavior. When the Input component
|
|
7
|
+
* changes, update these values to match.
|
|
8
|
+
*
|
|
9
|
+
* Reference (kept in sync with Input.tsx):
|
|
10
|
+
* borderColor: gray.400
|
|
11
|
+
* _hover : primary.lighter
|
|
12
|
+
* _focus : primary.main
|
|
13
|
+
* _invalid : danger.main
|
|
14
|
+
* borderRadius: 6 (Chakra `l2` -> Logician `radii.sm`)
|
|
15
|
+
* minHeight : 40 (Chakra md, `sizes.10`)
|
|
16
|
+
* fontSize : 1em (Chakra textStyle `sm`, inherits responsively)
|
|
17
|
+
* fontWeight : 500 (Chakra textStyle `sm` -> `subtitleAndP.medium`)
|
|
18
|
+
* paddingX : 12px (Chakra md, `px: 3`)
|
|
6
19
|
*/
|
|
7
20
|
export type SelectColors = Record<string, string>;
|
|
8
21
|
export declare const getPlaceholderStyles: (colors: SelectColors) => {
|
|
9
22
|
color: string;
|
|
10
23
|
fontSize: string;
|
|
11
|
-
fontWeight:
|
|
24
|
+
fontWeight: number;
|
|
12
25
|
};
|
|
13
26
|
export declare const getMenuStyles: (colors: SelectColors) => {
|
|
14
27
|
width: string;
|
|
@@ -41,19 +54,21 @@ export declare const getControlStyles: (variant: string, colors: SelectColors) =
|
|
|
41
54
|
borderRadius: number;
|
|
42
55
|
cursor: string;
|
|
43
56
|
minHeight: number;
|
|
44
|
-
fontSize:
|
|
57
|
+
fontSize: string;
|
|
45
58
|
fontWeight: number;
|
|
46
59
|
paddingLeft: number;
|
|
47
60
|
paddingRight: number;
|
|
61
|
+
backgroundColor: string;
|
|
48
62
|
} | {
|
|
49
63
|
border: string;
|
|
50
64
|
boxShadow: string;
|
|
51
65
|
borderRadius: number;
|
|
52
66
|
cursor: string;
|
|
53
67
|
minHeight: number;
|
|
54
|
-
fontSize:
|
|
68
|
+
fontSize: string;
|
|
55
69
|
fontWeight: number;
|
|
56
70
|
paddingLeft: number;
|
|
57
71
|
paddingRight: number;
|
|
72
|
+
backgroundColor: string;
|
|
58
73
|
};
|
|
59
74
|
//# sourceMappingURL=Select.styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.styles.d.ts","sourceRoot":"","sources":["../../../src/components/Select/Select.styles.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"Select.styles.d.ts","sourceRoot":"","sources":["../../../src/components/Select/Select.styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD,eAAO,MAAM,oBAAoB,GAAI,QAAQ,YAAY;;;;CAIvD,CAAC;AAEH,eAAO,MAAM,aAAa,GAAI,QAAQ,YAAY;;;;;;;;;CAShD,CAAC;AAEH,eAAO,MAAM,eAAe,GAAI,qCAI7B;IACD,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;;;;;;;;;;;;CAgBC,CAAC;AAEH,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,QAAQ,YAAY;;;;;;;;;;;;;;;;;;;;CAqBrE,CAAC"}
|
|
@@ -4,13 +4,26 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* Select component styles (Chakra v3 compatible)
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Defaults mirror the Input component (Chakra v3 `Input` recipe + Logician
|
|
8
|
+
* Input.tsx overrides) so the two controls share the same border, hover,
|
|
9
|
+
* focus, font, and disabled/readOnly behavior. When the Input component
|
|
10
|
+
* changes, update these values to match.
|
|
11
|
+
*
|
|
12
|
+
* Reference (kept in sync with Input.tsx):
|
|
13
|
+
* borderColor: gray.400
|
|
14
|
+
* _hover : primary.lighter
|
|
15
|
+
* _focus : primary.main
|
|
16
|
+
* _invalid : danger.main
|
|
17
|
+
* borderRadius: 6 (Chakra `l2` -> Logician `radii.sm`)
|
|
18
|
+
* minHeight : 40 (Chakra md, `sizes.10`)
|
|
19
|
+
* fontSize : 1em (Chakra textStyle `sm`, inherits responsively)
|
|
20
|
+
* fontWeight : 500 (Chakra textStyle `sm` -> `subtitleAndP.medium`)
|
|
21
|
+
* paddingX : 12px (Chakra md, `px: 3`)
|
|
9
22
|
*/
|
|
10
23
|
const getPlaceholderStyles = (colors) => ({
|
|
11
|
-
color: colors.
|
|
12
|
-
fontSize: '
|
|
13
|
-
fontWeight:
|
|
24
|
+
color: colors.gray500,
|
|
25
|
+
fontSize: '1em',
|
|
26
|
+
fontWeight: 500,
|
|
14
27
|
});
|
|
15
28
|
const getMenuStyles = (colors) => ({
|
|
16
29
|
width: 'max-content',
|
|
@@ -44,10 +57,11 @@ const getControlStyles = (variant, colors) => {
|
|
|
44
57
|
borderRadius: 6,
|
|
45
58
|
cursor: 'pointer',
|
|
46
59
|
minHeight: 40,
|
|
47
|
-
fontSize:
|
|
48
|
-
fontWeight:
|
|
49
|
-
paddingLeft:
|
|
50
|
-
paddingRight:
|
|
60
|
+
fontSize: '1em',
|
|
61
|
+
fontWeight: 500,
|
|
62
|
+
paddingLeft: 12,
|
|
63
|
+
paddingRight: 8,
|
|
64
|
+
backgroundColor: 'white',
|
|
51
65
|
};
|
|
52
66
|
if (variant === 'danger') {
|
|
53
67
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.styles.js","sources":["../../../src/components/Select/Select.styles.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAAA
|
|
1
|
+
{"version":3,"file":"Select.styles.js","sources":["../../../src/components/Select/Select.styles.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;AAkBG;MAIU,oBAAoB,GAAG,CAAC,MAAoB,MAAM;IAC7D,KAAK,EAAE,MAAM,CAAC,OAAO;AACrB,IAAA,QAAQ,EAAE,KAAK;AACf,IAAA,UAAU,EAAE,GAAG;AAChB,CAAA;MAEY,aAAa,GAAG,CAAC,MAAoB,MAAM;AACtD,IAAA,KAAK,EAAE,aAAa;AACpB,IAAA,QAAQ,EAAE,MAAM;AAChB,IAAA,eAAe,EAAE,OAAO;AACxB,IAAA,YAAY,EAAE,CAAC;AACf,IAAA,MAAM,EAAE,CAAA,UAAA,EAAa,MAAM,CAAC,OAAO,CAAA,CAAE;AACrC,IAAA,SAAS,EAAE,EAAE;AACb,IAAA,SAAS,EAAE,sCAAsC;AACjD,IAAA,MAAM,EAAE,CAAC;AACV,CAAA;AAEM,MAAM,eAAe,GAAG,CAAC,EAC9B,UAAU,EACV,UAAU,EACV,MAAM,GAKP,MAAM;IACL,MAAM,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS;AAC9C,IAAA,SAAS,EAAE,EAAE;AACb,IAAA,MAAM,EAAE,OAAO;AACf,IAAA,YAAY,EAAE,CAAC;AACf,IAAA,QAAQ,EAAE,EAAE;IACZ,eAAe,EAAE,UAAU,GAAG,MAAM,CAAC,eAAe,GAAG,OAAO;AAC9D,IAAA,KAAK,EAAE;UACH,MAAM,CAAC;AACT,UAAE;cACE,MAAM,CAAC;cACP,MAAM,CAAC,QAAQ;IACrB,UAAU,EAAE,UAAU,GAAG,GAAG,GAAG,GAAG;AAClC,IAAA,SAAS,EAAE;AACT,QAAA,eAAe,EAAE,UAAU,GAAG,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM;AACrE,KAAA;AACF,CAAA;MAEY,gBAAgB,GAAG,CAAC,OAAe,EAAE,MAAoB,KAAI;AACxE,IAAA,MAAM,UAAU,GAAG;AACjB,QAAA,YAAY,EAAE,CAAC;AACf,QAAA,MAAM,EAAE,SAAS;AACjB,QAAA,SAAS,EAAE,EAAE;AACb,QAAA,QAAQ,EAAE,KAAK;AACf,QAAA,UAAU,EAAE,GAAG;AACf,QAAA,WAAW,EAAE,EAAE;AACf,QAAA,YAAY,EAAE,CAAC;AACf,QAAA,eAAe,EAAE,OAAO;KACzB;AAED,IAAA,IAAI,OAAO,KAAK,QAAQ,EAAE;QACxB,OAAO;AACL,YAAA,GAAG,UAAU;AACb,YAAA,MAAM,EAAE,CAAA,UAAA,EAAa,MAAM,CAAC,WAAW,CAAA,CAAE;AACzC,YAAA,SAAS,EAAE,CAAA,UAAA,EAAa,MAAM,CAAC,WAAW,CAAA,CAAE;SAC7C;IACH;AAEA,IAAA,OAAO,UAAU;AACnB;;;;;;;"}
|
|
@@ -2,13 +2,26 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Select component styles (Chakra v3 compatible)
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Defaults mirror the Input component (Chakra v3 `Input` recipe + Logician
|
|
6
|
+
* Input.tsx overrides) so the two controls share the same border, hover,
|
|
7
|
+
* focus, font, and disabled/readOnly behavior. When the Input component
|
|
8
|
+
* changes, update these values to match.
|
|
9
|
+
*
|
|
10
|
+
* Reference (kept in sync with Input.tsx):
|
|
11
|
+
* borderColor: gray.400
|
|
12
|
+
* _hover : primary.lighter
|
|
13
|
+
* _focus : primary.main
|
|
14
|
+
* _invalid : danger.main
|
|
15
|
+
* borderRadius: 6 (Chakra `l2` -> Logician `radii.sm`)
|
|
16
|
+
* minHeight : 40 (Chakra md, `sizes.10`)
|
|
17
|
+
* fontSize : 1em (Chakra textStyle `sm`, inherits responsively)
|
|
18
|
+
* fontWeight : 500 (Chakra textStyle `sm` -> `subtitleAndP.medium`)
|
|
19
|
+
* paddingX : 12px (Chakra md, `px: 3`)
|
|
7
20
|
*/
|
|
8
21
|
const getPlaceholderStyles = (colors) => ({
|
|
9
|
-
color: colors.
|
|
10
|
-
fontSize: '
|
|
11
|
-
fontWeight:
|
|
22
|
+
color: colors.gray500,
|
|
23
|
+
fontSize: '1em',
|
|
24
|
+
fontWeight: 500,
|
|
12
25
|
});
|
|
13
26
|
const getMenuStyles = (colors) => ({
|
|
14
27
|
width: 'max-content',
|
|
@@ -42,10 +55,11 @@ const getControlStyles = (variant, colors) => {
|
|
|
42
55
|
borderRadius: 6,
|
|
43
56
|
cursor: 'pointer',
|
|
44
57
|
minHeight: 40,
|
|
45
|
-
fontSize:
|
|
46
|
-
fontWeight:
|
|
47
|
-
paddingLeft:
|
|
48
|
-
paddingRight:
|
|
58
|
+
fontSize: '1em',
|
|
59
|
+
fontWeight: 500,
|
|
60
|
+
paddingLeft: 12,
|
|
61
|
+
paddingRight: 8,
|
|
62
|
+
backgroundColor: 'white',
|
|
49
63
|
};
|
|
50
64
|
if (variant === 'danger') {
|
|
51
65
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.styles.mjs","sources":["../../../src/components/Select/Select.styles.ts"],"sourcesContent":[null],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"Select.styles.mjs","sources":["../../../src/components/Select/Select.styles.ts"],"sourcesContent":[null],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;AAkBG;MAIU,oBAAoB,GAAG,CAAC,MAAoB,MAAM;IAC7D,KAAK,EAAE,MAAM,CAAC,OAAO;AACrB,IAAA,QAAQ,EAAE,KAAK;AACf,IAAA,UAAU,EAAE,GAAG;AAChB,CAAA;MAEY,aAAa,GAAG,CAAC,MAAoB,MAAM;AACtD,IAAA,KAAK,EAAE,aAAa;AACpB,IAAA,QAAQ,EAAE,MAAM;AAChB,IAAA,eAAe,EAAE,OAAO;AACxB,IAAA,YAAY,EAAE,CAAC;AACf,IAAA,MAAM,EAAE,CAAA,UAAA,EAAa,MAAM,CAAC,OAAO,CAAA,CAAE;AACrC,IAAA,SAAS,EAAE,EAAE;AACb,IAAA,SAAS,EAAE,sCAAsC;AACjD,IAAA,MAAM,EAAE,CAAC;AACV,CAAA;AAEM,MAAM,eAAe,GAAG,CAAC,EAC9B,UAAU,EACV,UAAU,EACV,MAAM,GAKP,MAAM;IACL,MAAM,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS;AAC9C,IAAA,SAAS,EAAE,EAAE;AACb,IAAA,MAAM,EAAE,OAAO;AACf,IAAA,YAAY,EAAE,CAAC;AACf,IAAA,QAAQ,EAAE,EAAE;IACZ,eAAe,EAAE,UAAU,GAAG,MAAM,CAAC,eAAe,GAAG,OAAO;AAC9D,IAAA,KAAK,EAAE;UACH,MAAM,CAAC;AACT,UAAE;cACE,MAAM,CAAC;cACP,MAAM,CAAC,QAAQ;IACrB,UAAU,EAAE,UAAU,GAAG,GAAG,GAAG,GAAG;AAClC,IAAA,SAAS,EAAE;AACT,QAAA,eAAe,EAAE,UAAU,GAAG,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM;AACrE,KAAA;AACF,CAAA;MAEY,gBAAgB,GAAG,CAAC,OAAe,EAAE,MAAoB,KAAI;AACxE,IAAA,MAAM,UAAU,GAAG;AACjB,QAAA,YAAY,EAAE,CAAC;AACf,QAAA,MAAM,EAAE,SAAS;AACjB,QAAA,SAAS,EAAE,EAAE;AACb,QAAA,QAAQ,EAAE,KAAK;AACf,QAAA,UAAU,EAAE,GAAG;AACf,QAAA,WAAW,EAAE,EAAE;AACf,QAAA,YAAY,EAAE,CAAC;AACf,QAAA,eAAe,EAAE,OAAO;KACzB;AAED,IAAA,IAAI,OAAO,KAAK,QAAQ,EAAE;QACxB,OAAO;AACL,YAAA,GAAG,UAAU;AACb,YAAA,MAAM,EAAE,CAAA,UAAA,EAAa,MAAM,CAAC,WAAW,CAAA,CAAE;AACzC,YAAA,SAAS,EAAE,CAAA,UAAA,EAAa,MAAM,CAAC,WAAW,CAAA,CAAE;SAC7C;IACH;AAEA,IAAA,OAAO,UAAU;AACnB;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../../../src/components/Textarea/Textarea.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../../../src/components/Textarea/Textarea.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,eAAO,MAAM,QAAQ,+GA6FpB,CAAC"}
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var react = require('@chakra-ui/react');
|
|
7
|
+
var mergeCss = require('../../utils/mergeCss.js');
|
|
7
8
|
|
|
8
|
-
const Textarea = React.forwardRef(({ placeholder, onChange, value: propValue, _focusVisible, disabled, invalid, readOnly, ...props }, ref) => {
|
|
9
|
+
const Textarea = React.forwardRef(({ placeholder, onChange, value: propValue, _focusVisible, _hover, _focus, disabled, invalid, readOnly, css, ...props }, ref) => {
|
|
9
10
|
const [currentValue, setCurrentValue] = React.useState(propValue);
|
|
10
11
|
React.useEffect(() => {
|
|
11
12
|
setCurrentValue(propValue);
|
|
@@ -16,10 +17,18 @@ const Textarea = React.forwardRef(({ placeholder, onChange, value: propValue, _f
|
|
|
16
17
|
onChange(e);
|
|
17
18
|
}
|
|
18
19
|
};
|
|
19
|
-
return (jsxRuntime.jsx(react.Textarea, { ref: ref, placeholder: placeholder, value: currentValue, onChange: handleChange, disabled: disabled, readOnly: readOnly, "data-invalid": invalid || undefined, resize: "none",
|
|
20
|
+
return (jsxRuntime.jsx(react.Textarea, { ref: ref, placeholder: placeholder, value: currentValue, onChange: handleChange, disabled: disabled, readOnly: readOnly, "data-invalid": invalid || undefined, resize: "none", bg: "white",
|
|
21
|
+
// Chakra v3 `Input` outline variant declares
|
|
22
|
+
// `focusRingColor: var(--focus-color)`, but the matching
|
|
23
|
+
// `Textarea` recipe does not — so the focus ring defaults to
|
|
24
|
+
// `colorPalette.focusRing` (gray.400) and ends up visibly
|
|
25
|
+
// different from Input/Select. Mirror Input's chain explicitly.
|
|
26
|
+
focusRingColor: invalid ? 'danger.main' : 'primary.main', borderColor: invalid ? 'danger.main' : 'gray.400', _hover: {
|
|
27
|
+
borderColor: invalid ? 'danger.main' : 'primary.lighter',
|
|
28
|
+
..._hover,
|
|
29
|
+
}, _focus: {
|
|
20
30
|
borderColor: invalid ? 'danger.main' : 'primary.main',
|
|
21
|
-
|
|
22
|
-
borderColor: invalid ? 'danger.main' : 'gray.600',
|
|
31
|
+
..._focus,
|
|
23
32
|
}, _invalid: {
|
|
24
33
|
borderColor: 'danger.main',
|
|
25
34
|
_hover: {
|
|
@@ -28,7 +37,22 @@ const Textarea = React.forwardRef(({ placeholder, onChange, value: propValue, _f
|
|
|
28
37
|
_focus: {
|
|
29
38
|
borderColor: 'danger.main',
|
|
30
39
|
},
|
|
31
|
-
},
|
|
40
|
+
}, _readOnly: {
|
|
41
|
+
opacity: 1,
|
|
42
|
+
cursor: 'not-allowed',
|
|
43
|
+
bg: 'gray.50',
|
|
44
|
+
color: 'gray.600',
|
|
45
|
+
borderColor: 'gray.200',
|
|
46
|
+
}, _disabled: {
|
|
47
|
+
opacity: 1,
|
|
48
|
+
cursor: 'not-allowed',
|
|
49
|
+
bg: 'gray.50',
|
|
50
|
+
color: 'gray.1000',
|
|
51
|
+
fontWeight: 'semibold',
|
|
52
|
+
}, ...props, css: mergeCss.mergeCss({
|
|
53
|
+
'--focus-color': 'var(--chakra-colors-primary-main)',
|
|
54
|
+
'--error-color': 'var(--chakra-colors-danger-main)',
|
|
55
|
+
}, css) }));
|
|
32
56
|
});
|
|
33
57
|
Textarea.displayName = 'Textarea';
|
|
34
58
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.js","sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":[null],"names":["forwardRef","useState","useEffect","_jsx","ChakraTextarea"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Textarea.js","sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":[null],"names":["forwardRef","useState","useEffect","_jsx","ChakraTextarea","mergeCss"],"mappings":";;;;;;;;AAOO,MAAM,QAAQ,GAAGA,gBAAU,CAChC,CACE,EACE,WAAW,EACX,QAAQ,EACR,KAAK,EAAE,SAAS,EAChB,aAAa,EACb,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,GAAG,EACH,GAAG,KAAK,EACT,EACD,GAAG,KACD;IACF,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAGC,cAAQ,CAE9C,SAAS,CAAC;IAEZC,eAAS,CAAC,MAAK;QACb,eAAe,CAAC,SAAS,CAAC;AAC5B,IAAA,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;AAEf,IAAA,MAAM,YAAY,GAAG,CAAC,CAAmC,KAAI;AAC3D,QAAA,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAE/B,IAAI,QAAQ,EAAE;YACZ,QAAQ,CAAC,CAAC,CAAC;QACb;AACF,IAAA,CAAC;AAED,IAAA,QACEC,cAAA,CAACC,cAAc,EAAA,EACb,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAAA,cAAA,EACJ,OAAO,IAAI,SAAS,EAClC,MAAM,EAAC,MAAM,EACb,EAAE,EAAC,OAAO;;;;;;QAMV,cAAc,EAAE,OAAO,GAAG,aAAa,GAAG,cAAc,EACxD,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,UAAU,EACjD,MAAM,EAAE;YACN,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,iBAAiB;AACxD,YAAA,GAAG,MAAM;AACV,SAAA,EACD,MAAM,EAAE;YACN,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,cAAc;AACrD,YAAA,GAAG,MAAM;AACV,SAAA,EACD,QAAQ,EAAE;AACR,YAAA,WAAW,EAAE,aAAa;AAC1B,YAAA,MAAM,EAAE;AACN,gBAAA,WAAW,EAAE,aAAa;AAC3B,aAAA;AACD,YAAA,MAAM,EAAE;AACN,gBAAA,WAAW,EAAE,aAAa;AAC3B,aAAA;AACF,SAAA,EACD,SAAS,EAAE;AACT,YAAA,OAAO,EAAE,CAAC;AACV,YAAA,MAAM,EAAE,aAAa;AACrB,YAAA,EAAE,EAAE,SAAS;AACb,YAAA,KAAK,EAAE,UAAU;AACjB,YAAA,WAAW,EAAE,UAAU;AACxB,SAAA,EACD,SAAS,EAAE;AACT,YAAA,OAAO,EAAE,CAAC;AACV,YAAA,MAAM,EAAE,aAAa;AACrB,YAAA,EAAE,EAAE,SAAS;AACb,YAAA,KAAK,EAAE,WAAW;AAClB,YAAA,UAAU,EAAE,UAAU;AACvB,SAAA,EAAA,GACG,KAAK,EACT,GAAG,EAAEC,iBAAQ,CACX;AACE,YAAA,eAAe,EAAE,mCAAmC;AACpD,YAAA,eAAe,EAAE,kCAAkC;AACpD,SAAA,EACD,GAAG,CACJ,EAAA,CACD;AAEN,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { forwardRef, useState, useEffect } from 'react';
|
|
4
4
|
import { Textarea as Textarea$1 } from '@chakra-ui/react';
|
|
5
|
+
import { mergeCss } from '../../utils/mergeCss.mjs';
|
|
5
6
|
|
|
6
|
-
const Textarea = forwardRef(({ placeholder, onChange, value: propValue, _focusVisible, disabled, invalid, readOnly, ...props }, ref) => {
|
|
7
|
+
const Textarea = forwardRef(({ placeholder, onChange, value: propValue, _focusVisible, _hover, _focus, disabled, invalid, readOnly, css, ...props }, ref) => {
|
|
7
8
|
const [currentValue, setCurrentValue] = useState(propValue);
|
|
8
9
|
useEffect(() => {
|
|
9
10
|
setCurrentValue(propValue);
|
|
@@ -14,10 +15,18 @@ const Textarea = forwardRef(({ placeholder, onChange, value: propValue, _focusVi
|
|
|
14
15
|
onChange(e);
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
|
-
return (jsx(Textarea$1, { ref: ref, placeholder: placeholder, value: currentValue, onChange: handleChange, disabled: disabled, readOnly: readOnly, "data-invalid": invalid || undefined, resize: "none",
|
|
18
|
+
return (jsx(Textarea$1, { ref: ref, placeholder: placeholder, value: currentValue, onChange: handleChange, disabled: disabled, readOnly: readOnly, "data-invalid": invalid || undefined, resize: "none", bg: "white",
|
|
19
|
+
// Chakra v3 `Input` outline variant declares
|
|
20
|
+
// `focusRingColor: var(--focus-color)`, but the matching
|
|
21
|
+
// `Textarea` recipe does not — so the focus ring defaults to
|
|
22
|
+
// `colorPalette.focusRing` (gray.400) and ends up visibly
|
|
23
|
+
// different from Input/Select. Mirror Input's chain explicitly.
|
|
24
|
+
focusRingColor: invalid ? 'danger.main' : 'primary.main', borderColor: invalid ? 'danger.main' : 'gray.400', _hover: {
|
|
25
|
+
borderColor: invalid ? 'danger.main' : 'primary.lighter',
|
|
26
|
+
..._hover,
|
|
27
|
+
}, _focus: {
|
|
18
28
|
borderColor: invalid ? 'danger.main' : 'primary.main',
|
|
19
|
-
|
|
20
|
-
borderColor: invalid ? 'danger.main' : 'gray.600',
|
|
29
|
+
..._focus,
|
|
21
30
|
}, _invalid: {
|
|
22
31
|
borderColor: 'danger.main',
|
|
23
32
|
_hover: {
|
|
@@ -26,7 +35,22 @@ const Textarea = forwardRef(({ placeholder, onChange, value: propValue, _focusVi
|
|
|
26
35
|
_focus: {
|
|
27
36
|
borderColor: 'danger.main',
|
|
28
37
|
},
|
|
29
|
-
},
|
|
38
|
+
}, _readOnly: {
|
|
39
|
+
opacity: 1,
|
|
40
|
+
cursor: 'not-allowed',
|
|
41
|
+
bg: 'gray.50',
|
|
42
|
+
color: 'gray.600',
|
|
43
|
+
borderColor: 'gray.200',
|
|
44
|
+
}, _disabled: {
|
|
45
|
+
opacity: 1,
|
|
46
|
+
cursor: 'not-allowed',
|
|
47
|
+
bg: 'gray.50',
|
|
48
|
+
color: 'gray.1000',
|
|
49
|
+
fontWeight: 'semibold',
|
|
50
|
+
}, ...props, css: mergeCss({
|
|
51
|
+
'--focus-color': 'var(--chakra-colors-primary-main)',
|
|
52
|
+
'--error-color': 'var(--chakra-colors-danger-main)',
|
|
53
|
+
}, css) }));
|
|
30
54
|
});
|
|
31
55
|
Textarea.displayName = 'Textarea';
|
|
32
56
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.mjs","sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":[null],"names":["_jsx","ChakraTextarea"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Textarea.mjs","sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":[null],"names":["_jsx","ChakraTextarea"],"mappings":";;;;;;AAOO,MAAM,QAAQ,GAAG,UAAU,CAChC,CACE,EACE,WAAW,EACX,QAAQ,EACR,KAAK,EAAE,SAAS,EAChB,aAAa,EACb,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,GAAG,EACH,GAAG,KAAK,EACT,EACD,GAAG,KACD;IACF,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAE9C,SAAS,CAAC;IAEZ,SAAS,CAAC,MAAK;QACb,eAAe,CAAC,SAAS,CAAC;AAC5B,IAAA,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;AAEf,IAAA,MAAM,YAAY,GAAG,CAAC,CAAmC,KAAI;AAC3D,QAAA,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAE/B,IAAI,QAAQ,EAAE;YACZ,QAAQ,CAAC,CAAC,CAAC;QACb;AACF,IAAA,CAAC;AAED,IAAA,QACEA,GAAA,CAACC,UAAc,EAAA,EACb,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAAA,cAAA,EACJ,OAAO,IAAI,SAAS,EAClC,MAAM,EAAC,MAAM,EACb,EAAE,EAAC,OAAO;;;;;;QAMV,cAAc,EAAE,OAAO,GAAG,aAAa,GAAG,cAAc,EACxD,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,UAAU,EACjD,MAAM,EAAE;YACN,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,iBAAiB;AACxD,YAAA,GAAG,MAAM;AACV,SAAA,EACD,MAAM,EAAE;YACN,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,cAAc;AACrD,YAAA,GAAG,MAAM;AACV,SAAA,EACD,QAAQ,EAAE;AACR,YAAA,WAAW,EAAE,aAAa;AAC1B,YAAA,MAAM,EAAE;AACN,gBAAA,WAAW,EAAE,aAAa;AAC3B,aAAA;AACD,YAAA,MAAM,EAAE;AACN,gBAAA,WAAW,EAAE,aAAa;AAC3B,aAAA;AACF,SAAA,EACD,SAAS,EAAE;AACT,YAAA,OAAO,EAAE,CAAC;AACV,YAAA,MAAM,EAAE,aAAa;AACrB,YAAA,EAAE,EAAE,SAAS;AACb,YAAA,KAAK,EAAE,UAAU;AACjB,YAAA,WAAW,EAAE,UAAU;AACxB,SAAA,EACD,SAAS,EAAE;AACT,YAAA,OAAO,EAAE,CAAC;AACV,YAAA,MAAM,EAAE,aAAa;AACrB,YAAA,EAAE,EAAE,SAAS;AACb,YAAA,KAAK,EAAE,WAAW;AAClB,YAAA,UAAU,EAAE,UAAU;AACvB,SAAA,EAAA,GACG,KAAK,EACT,GAAG,EAAE,QAAQ,CACX;AACE,YAAA,eAAe,EAAE,mCAAmC;AACpD,YAAA,eAAe,EAAE,kCAAkC;AACpD,SAAA,EACD,GAAG,CACJ,EAAA,CACD;AAEN,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { Box, Flex, HStack, Stack, Text } from '@chakra-ui/react';
|
|
2
|
+
import { Meta } from '@storybook/react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { Button } from '../Button';
|
|
6
|
+
import { FormControl } from '../FormControl';
|
|
7
|
+
import { FormLabel } from '../FormLabel';
|
|
8
|
+
import { IoAddOutline, IoIosMail, IoSearch } from '../Icon';
|
|
9
|
+
import { Input } from '../Input';
|
|
10
|
+
import { PasswordInput } from '../PasswordInput';
|
|
11
|
+
import { Textarea } from '../Textarea';
|
|
12
|
+
|
|
13
|
+
import { Select } from '.';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Temporary visual comparison between Input, Select and Textarea.
|
|
17
|
+
* Used to verify the three controls share the same default look
|
|
18
|
+
* (border, hover, focus, font, padding, disabled/invalid states)
|
|
19
|
+
* and look coherent inside real form layouts.
|
|
20
|
+
*
|
|
21
|
+
* Safe to delete once the unified style is no longer being iterated on.
|
|
22
|
+
*/
|
|
23
|
+
const meta = {
|
|
24
|
+
title: 'Components/Select/Comparison',
|
|
25
|
+
} satisfies Meta;
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
|
|
29
|
+
const sortOptions = [
|
|
30
|
+
{ label: '최신순', value: 'recent' },
|
|
31
|
+
{ label: '오래된순', value: 'oldest' },
|
|
32
|
+
{ label: '이름순', value: 'name' },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const categoryOptions = [
|
|
36
|
+
{ label: '전체', value: 'all' },
|
|
37
|
+
{ label: '비즈니스', value: 'business' },
|
|
38
|
+
{ label: '교육', value: 'education' },
|
|
39
|
+
{ label: '엔터테인먼트', value: 'entertainment' },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const roleOptions = [
|
|
43
|
+
{ label: '관리자', value: 'admin' },
|
|
44
|
+
{ label: '편집자', value: 'editor' },
|
|
45
|
+
{ label: '뷰어', value: 'viewer' },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const countryOptions = [
|
|
49
|
+
{ label: '대한민국', value: 'KR' },
|
|
50
|
+
{ label: '미국', value: 'US' },
|
|
51
|
+
{ label: '일본', value: 'JP' },
|
|
52
|
+
{ label: '독일', value: 'DE' },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Component-level diff: every Input / Select / Textarea state side-by-side.
|
|
57
|
+
*/
|
|
58
|
+
export const SideBySide = () => {
|
|
59
|
+
const [text, setText] = useState('');
|
|
60
|
+
const [note, setNote] = useState('');
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Stack gap={6} width="400px">
|
|
64
|
+
<Box>
|
|
65
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
66
|
+
Input — placeholder
|
|
67
|
+
</Text>
|
|
68
|
+
<Input
|
|
69
|
+
placeholder="Placeholder text"
|
|
70
|
+
value={text}
|
|
71
|
+
onChange={e => setText(e.target.value)}
|
|
72
|
+
/>
|
|
73
|
+
</Box>
|
|
74
|
+
<Box>
|
|
75
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
76
|
+
Select — placeholder
|
|
77
|
+
</Text>
|
|
78
|
+
<Select options={categoryOptions} placeholder="Placeholder text" />
|
|
79
|
+
</Box>
|
|
80
|
+
<Box>
|
|
81
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
82
|
+
Textarea — placeholder
|
|
83
|
+
</Text>
|
|
84
|
+
<Textarea
|
|
85
|
+
placeholder="Placeholder text"
|
|
86
|
+
value={note}
|
|
87
|
+
onChange={e => setNote(e.target.value)}
|
|
88
|
+
/>
|
|
89
|
+
</Box>
|
|
90
|
+
|
|
91
|
+
<Box>
|
|
92
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
93
|
+
Input — with value
|
|
94
|
+
</Text>
|
|
95
|
+
<Input defaultValue="Some value" />
|
|
96
|
+
</Box>
|
|
97
|
+
<Box>
|
|
98
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
99
|
+
Select — with value
|
|
100
|
+
</Text>
|
|
101
|
+
<Select options={categoryOptions} defaultValue={categoryOptions[0]} />
|
|
102
|
+
</Box>
|
|
103
|
+
<Box>
|
|
104
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
105
|
+
Textarea — with value
|
|
106
|
+
</Text>
|
|
107
|
+
<Textarea defaultValue="Some value" />
|
|
108
|
+
</Box>
|
|
109
|
+
|
|
110
|
+
<Box>
|
|
111
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
112
|
+
Input — invalid
|
|
113
|
+
</Text>
|
|
114
|
+
<Input placeholder="Invalid input" invalid />
|
|
115
|
+
</Box>
|
|
116
|
+
<Box>
|
|
117
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
118
|
+
Select — invalid
|
|
119
|
+
</Text>
|
|
120
|
+
<Select options={categoryOptions} placeholder="Invalid select" invalid />
|
|
121
|
+
</Box>
|
|
122
|
+
<Box>
|
|
123
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
124
|
+
Textarea — invalid
|
|
125
|
+
</Text>
|
|
126
|
+
<Textarea placeholder="Invalid textarea" invalid />
|
|
127
|
+
</Box>
|
|
128
|
+
|
|
129
|
+
<Box>
|
|
130
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
131
|
+
Input — disabled
|
|
132
|
+
</Text>
|
|
133
|
+
<Input disabled defaultValue="Disabled" />
|
|
134
|
+
</Box>
|
|
135
|
+
<Box>
|
|
136
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
137
|
+
Select — disabled
|
|
138
|
+
</Text>
|
|
139
|
+
<Select
|
|
140
|
+
options={categoryOptions}
|
|
141
|
+
defaultValue={categoryOptions[0]}
|
|
142
|
+
isDisabled
|
|
143
|
+
/>
|
|
144
|
+
</Box>
|
|
145
|
+
<Box>
|
|
146
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
147
|
+
Textarea — disabled
|
|
148
|
+
</Text>
|
|
149
|
+
<Textarea disabled defaultValue="Disabled" />
|
|
150
|
+
</Box>
|
|
151
|
+
|
|
152
|
+
<Box>
|
|
153
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
154
|
+
Input — readOnly
|
|
155
|
+
</Text>
|
|
156
|
+
<Input readOnly defaultValue="Read only" />
|
|
157
|
+
</Box>
|
|
158
|
+
<Box>
|
|
159
|
+
<Text mb={1} fontSize="sm" fontWeight="medium">
|
|
160
|
+
Textarea — readOnly
|
|
161
|
+
</Text>
|
|
162
|
+
<Textarea readOnly defaultValue="Read only" />
|
|
163
|
+
</Box>
|
|
164
|
+
</Stack>
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* factchat 챗봇 목록 페이지의 상단 toolbar 패턴.
|
|
170
|
+
* 검색 Input + 카테고리 Select + 정렬 Select + 새 챗봇 Button 이 가로로
|
|
171
|
+
* 한 줄에 배치되는 케이스 — 높이와 border 두께가 어긋나면 가장 눈에
|
|
172
|
+
* 잘 띄는 레이아웃입니다.
|
|
173
|
+
*/
|
|
174
|
+
export const ChatbotListToolbar = () => {
|
|
175
|
+
const [query, setQuery] = useState('');
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<Box width="100%" maxW="1200px">
|
|
179
|
+
<HStack gap={3}>
|
|
180
|
+
<Box flex={1}>
|
|
181
|
+
<Input
|
|
182
|
+
leftIcon={<IoSearch color="gray.500" />}
|
|
183
|
+
placeholder="챗봇 검색..."
|
|
184
|
+
value={query}
|
|
185
|
+
onChange={e => setQuery(e.target.value)}
|
|
186
|
+
/>
|
|
187
|
+
</Box>
|
|
188
|
+
<Box w="160px">
|
|
189
|
+
<Select options={categoryOptions} defaultValue={categoryOptions[0]} />
|
|
190
|
+
</Box>
|
|
191
|
+
<Box w="160px">
|
|
192
|
+
<Select options={sortOptions} defaultValue={sortOptions[0]} />
|
|
193
|
+
</Box>
|
|
194
|
+
<Button colorPalette="primary" variant="solid">
|
|
195
|
+
<IoAddOutline />새 챗봇
|
|
196
|
+
</Button>
|
|
197
|
+
</HStack>
|
|
198
|
+
</Box>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 회원가입 폼 — Input, Select, Textarea 가 라벨과 함께 세로로 쌓이는
|
|
204
|
+
* 케이스. 라벨/필드 정렬, 좌측 padding, 폰트 두께가 모두 일관되어야
|
|
205
|
+
* 합니다.
|
|
206
|
+
*/
|
|
207
|
+
export const SignUpForm = () => {
|
|
208
|
+
const [email, setEmail] = useState('');
|
|
209
|
+
const [name, setName] = useState('');
|
|
210
|
+
const [bio, setBio] = useState('');
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<Box width="400px">
|
|
214
|
+
<Text fontSize="xl" fontWeight="bold" mb={6}>
|
|
215
|
+
회원가입
|
|
216
|
+
</Text>
|
|
217
|
+
<Stack gap={4}>
|
|
218
|
+
<FormControl>
|
|
219
|
+
<FormLabel>이메일</FormLabel>
|
|
220
|
+
<Input
|
|
221
|
+
leftIcon={<IoIosMail color="gray.500" />}
|
|
222
|
+
placeholder="name@example.com"
|
|
223
|
+
type="email"
|
|
224
|
+
value={email}
|
|
225
|
+
onChange={e => setEmail(e.target.value)}
|
|
226
|
+
/>
|
|
227
|
+
</FormControl>
|
|
228
|
+
<FormControl>
|
|
229
|
+
<FormLabel>이름</FormLabel>
|
|
230
|
+
<Input
|
|
231
|
+
placeholder="홍길동"
|
|
232
|
+
value={name}
|
|
233
|
+
onChange={e => setName(e.target.value)}
|
|
234
|
+
/>
|
|
235
|
+
</FormControl>
|
|
236
|
+
<FormControl>
|
|
237
|
+
<FormLabel>비밀번호</FormLabel>
|
|
238
|
+
<PasswordInput placeholder="8자 이상 입력해주세요" />
|
|
239
|
+
</FormControl>
|
|
240
|
+
<FormControl>
|
|
241
|
+
<FormLabel>역할</FormLabel>
|
|
242
|
+
<Select options={roleOptions} placeholder="역할을 선택하세요" />
|
|
243
|
+
</FormControl>
|
|
244
|
+
<FormControl>
|
|
245
|
+
<FormLabel>국가</FormLabel>
|
|
246
|
+
<Select options={countryOptions} placeholder="국가를 선택하세요" />
|
|
247
|
+
</FormControl>
|
|
248
|
+
<FormControl>
|
|
249
|
+
<FormLabel>자기소개</FormLabel>
|
|
250
|
+
<Textarea
|
|
251
|
+
placeholder="간단한 자기소개를 입력해주세요"
|
|
252
|
+
rows={3}
|
|
253
|
+
value={bio}
|
|
254
|
+
onChange={e => setBio(e.target.value)}
|
|
255
|
+
/>
|
|
256
|
+
</FormControl>
|
|
257
|
+
<Button colorPalette="primary" variant="solid" mt={2}>
|
|
258
|
+
가입하기
|
|
259
|
+
</Button>
|
|
260
|
+
</Stack>
|
|
261
|
+
</Box>
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* factchat audit-logs 페이지 풍의 필터바.
|
|
267
|
+
* Select 3개가 가로로 늘어서 있고, 그 옆에 검색 Input 이 함께 있는
|
|
268
|
+
* 패턴 — 모든 컨트롤이 같은 baseline / 높이로 떨어져야 합니다.
|
|
269
|
+
*/
|
|
270
|
+
export const AdminFilterBar = () => {
|
|
271
|
+
const statusOptions = [
|
|
272
|
+
{ label: '전체 상태', value: 'all' },
|
|
273
|
+
{ label: '성공', value: 'success' },
|
|
274
|
+
{ label: '실패', value: 'failed' },
|
|
275
|
+
];
|
|
276
|
+
const actorOptions = [
|
|
277
|
+
{ label: '전체 사용자', value: 'all' },
|
|
278
|
+
{ label: '관리자', value: 'admin' },
|
|
279
|
+
{ label: '일반 사용자', value: 'user' },
|
|
280
|
+
];
|
|
281
|
+
const periodOptions = [
|
|
282
|
+
{ label: '최근 7일', value: '7d' },
|
|
283
|
+
{ label: '최근 30일', value: '30d' },
|
|
284
|
+
{ label: '최근 90일', value: '90d' },
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<Box width="100%" maxW="1100px">
|
|
289
|
+
<Flex gap={3} flexWrap="wrap" align="center">
|
|
290
|
+
<Box w="180px">
|
|
291
|
+
<Select options={periodOptions} defaultValue={periodOptions[0]} />
|
|
292
|
+
</Box>
|
|
293
|
+
<Box w="180px">
|
|
294
|
+
<Select options={statusOptions} defaultValue={statusOptions[0]} />
|
|
295
|
+
</Box>
|
|
296
|
+
<Box w="180px">
|
|
297
|
+
<Select options={actorOptions} defaultValue={actorOptions[0]} />
|
|
298
|
+
</Box>
|
|
299
|
+
<Box flex={1} minW="240px">
|
|
300
|
+
<Input
|
|
301
|
+
leftIcon={<IoSearch color="gray.500" />}
|
|
302
|
+
placeholder="로그 메시지 검색"
|
|
303
|
+
/>
|
|
304
|
+
</Box>
|
|
305
|
+
<Button colorPalette="neutral" variant="outline">
|
|
306
|
+
내보내기
|
|
307
|
+
</Button>
|
|
308
|
+
</Flex>
|
|
309
|
+
</Box>
|
|
310
|
+
);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* 한 row 안에 Input 과 Select 가 인라인으로 섞이는 케이스 — 예를 들어
|
|
315
|
+
* 파라미터 편집 폼에서 "필드명" + "타입" + "기본값" 처럼 늘어서는
|
|
316
|
+
* 케이스. baseline 정렬 검증용.
|
|
317
|
+
*/
|
|
318
|
+
export const InlineFieldRow = () => {
|
|
319
|
+
const typeOptions = [
|
|
320
|
+
{ label: 'String', value: 'string' },
|
|
321
|
+
{ label: 'Number', value: 'number' },
|
|
322
|
+
{ label: 'Boolean', value: 'boolean' },
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<Box width="100%" maxW="900px">
|
|
327
|
+
<Text fontSize="sm" fontWeight="medium" mb={2}>
|
|
328
|
+
파라미터 추가
|
|
329
|
+
</Text>
|
|
330
|
+
<HStack gap={3} align="flex-start">
|
|
331
|
+
<Box flex={2}>
|
|
332
|
+
<Input placeholder="필드명" />
|
|
333
|
+
</Box>
|
|
334
|
+
<Box flex={1}>
|
|
335
|
+
<Select options={typeOptions} defaultValue={typeOptions[0]} />
|
|
336
|
+
</Box>
|
|
337
|
+
<Box flex={2}>
|
|
338
|
+
<Input placeholder="기본값" />
|
|
339
|
+
</Box>
|
|
340
|
+
<Button colorPalette="primary" variant="solid">
|
|
341
|
+
추가
|
|
342
|
+
</Button>
|
|
343
|
+
</HStack>
|
|
344
|
+
</Box>
|
|
345
|
+
);
|
|
346
|
+
};
|
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Select component styles (Chakra v3 compatible)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Defaults mirror the Input component (Chakra v3 `Input` recipe + Logician
|
|
5
|
+
* Input.tsx overrides) so the two controls share the same border, hover,
|
|
6
|
+
* focus, font, and disabled/readOnly behavior. When the Input component
|
|
7
|
+
* changes, update these values to match.
|
|
8
|
+
*
|
|
9
|
+
* Reference (kept in sync with Input.tsx):
|
|
10
|
+
* borderColor: gray.400
|
|
11
|
+
* _hover : primary.lighter
|
|
12
|
+
* _focus : primary.main
|
|
13
|
+
* _invalid : danger.main
|
|
14
|
+
* borderRadius: 6 (Chakra `l2` -> Logician `radii.sm`)
|
|
15
|
+
* minHeight : 40 (Chakra md, `sizes.10`)
|
|
16
|
+
* fontSize : 1em (Chakra textStyle `sm`, inherits responsively)
|
|
17
|
+
* fontWeight : 500 (Chakra textStyle `sm` -> `subtitleAndP.medium`)
|
|
18
|
+
* paddingX : 12px (Chakra md, `px: 3`)
|
|
6
19
|
*/
|
|
7
20
|
|
|
8
21
|
export type SelectColors = Record<string, string>;
|
|
9
22
|
|
|
10
23
|
export const getPlaceholderStyles = (colors: SelectColors) => ({
|
|
11
|
-
color: colors.
|
|
12
|
-
fontSize: '
|
|
13
|
-
fontWeight:
|
|
24
|
+
color: colors.gray500,
|
|
25
|
+
fontSize: '1em',
|
|
26
|
+
fontWeight: 500,
|
|
14
27
|
});
|
|
15
28
|
|
|
16
29
|
export const getMenuStyles = (colors: SelectColors) => ({
|
|
@@ -55,10 +68,11 @@ export const getControlStyles = (variant: string, colors: SelectColors) => {
|
|
|
55
68
|
borderRadius: 6,
|
|
56
69
|
cursor: 'pointer',
|
|
57
70
|
minHeight: 40,
|
|
58
|
-
fontSize:
|
|
59
|
-
fontWeight:
|
|
60
|
-
paddingLeft:
|
|
61
|
-
paddingRight:
|
|
71
|
+
fontSize: '1em',
|
|
72
|
+
fontWeight: 500,
|
|
73
|
+
paddingLeft: 12,
|
|
74
|
+
paddingRight: 8,
|
|
75
|
+
backgroundColor: 'white',
|
|
62
76
|
};
|
|
63
77
|
|
|
64
78
|
if (variant === 'danger') {
|
|
@@ -22,6 +22,7 @@ export const Select = <
|
|
|
22
22
|
}: SelectProps<Option, IsMulti, Group>) => {
|
|
23
23
|
const [
|
|
24
24
|
primaryColor,
|
|
25
|
+
primaryLighter,
|
|
25
26
|
primaryLightest,
|
|
26
27
|
primaryDark,
|
|
27
28
|
dangerColor,
|
|
@@ -30,9 +31,12 @@ export const Select = <
|
|
|
30
31
|
gray400,
|
|
31
32
|
gray500,
|
|
32
33
|
gray600,
|
|
34
|
+
gray1000,
|
|
33
35
|
gray1200,
|
|
36
|
+
gray1300,
|
|
34
37
|
] = useToken('colors', [
|
|
35
38
|
'primary.main',
|
|
39
|
+
'primary.lighter',
|
|
36
40
|
'primary.extralight',
|
|
37
41
|
'primary.dark',
|
|
38
42
|
'danger.main',
|
|
@@ -41,11 +45,14 @@ export const Select = <
|
|
|
41
45
|
'gray.400',
|
|
42
46
|
'gray.500',
|
|
43
47
|
'gray.600',
|
|
48
|
+
'gray.1000',
|
|
44
49
|
'gray.1200',
|
|
50
|
+
'gray.1300',
|
|
45
51
|
]);
|
|
46
52
|
|
|
47
53
|
const colors: SelectColors = {
|
|
48
54
|
primaryColor,
|
|
55
|
+
primaryLighter,
|
|
49
56
|
primaryLightest,
|
|
50
57
|
primaryDark,
|
|
51
58
|
dangerColor,
|
|
@@ -54,7 +61,9 @@ export const Select = <
|
|
|
54
61
|
gray400,
|
|
55
62
|
gray500,
|
|
56
63
|
gray600,
|
|
64
|
+
gray1000,
|
|
57
65
|
gray1200,
|
|
66
|
+
gray1300,
|
|
58
67
|
};
|
|
59
68
|
|
|
60
69
|
// invalid prop이 true이면 variant를 'danger'로 오버라이드
|
|
@@ -74,21 +83,42 @@ export const Select = <
|
|
|
74
83
|
return styles?.container ? styles.container(merged, state) : merged;
|
|
75
84
|
},
|
|
76
85
|
control: (base, state) => {
|
|
86
|
+
// Mirror Input.tsx: borderColor gray.400, _hover primary.lighter,
|
|
87
|
+
// _focus primary.main + 1px outline (Chakra Input recipe's
|
|
88
|
+
// `focusVisibleRing: "inside"`), _invalid danger.main,
|
|
89
|
+
// _disabled bg gray.50 / color gray.1000 / fontWeight semibold.
|
|
90
|
+
const focusOutlineColor = invalid ? dangerColor : primaryColor;
|
|
77
91
|
const merged = {
|
|
78
92
|
...base,
|
|
79
93
|
...getControlStyles(effectiveVariant, colors),
|
|
80
94
|
width: '100%',
|
|
81
95
|
border: `1px solid ${
|
|
82
|
-
invalid ? dangerColor : state.isFocused ? primaryColor :
|
|
96
|
+
invalid ? dangerColor : state.isFocused ? primaryColor : gray400
|
|
83
97
|
}`,
|
|
84
98
|
boxShadow: 'none',
|
|
99
|
+
outline: state.isFocused
|
|
100
|
+
? `1px solid ${focusOutlineColor}`
|
|
101
|
+
: 'none',
|
|
102
|
+
outlineOffset: 0,
|
|
103
|
+
// react-select sets a 0.1s `transition: all` on the control,
|
|
104
|
+
// which causes the border-color and outline (none -> solid +
|
|
105
|
+
// transparent -> primary) to interpolate awkwardly — a brief
|
|
106
|
+
// dark blink during focus. Disable to match Input, which
|
|
107
|
+
// toggles its focus ring instantly via :focus-visible.
|
|
108
|
+
transition: 'none',
|
|
85
109
|
'&:hover': {
|
|
86
110
|
borderColor: invalid
|
|
87
111
|
? dangerColor
|
|
88
112
|
: state.isFocused
|
|
89
113
|
? primaryColor
|
|
90
|
-
:
|
|
114
|
+
: primaryLighter,
|
|
91
115
|
},
|
|
116
|
+
...(state.isDisabled && {
|
|
117
|
+
backgroundColor: gray50,
|
|
118
|
+
color: gray1000,
|
|
119
|
+
fontWeight: 600,
|
|
120
|
+
cursor: 'not-allowed',
|
|
121
|
+
}),
|
|
92
122
|
};
|
|
93
123
|
return styles?.control ? styles.control(merged, state) : merged;
|
|
94
124
|
},
|
|
@@ -118,17 +148,28 @@ export const Select = <
|
|
|
118
148
|
return styles?.option ? styles.option(merged, state) : merged;
|
|
119
149
|
},
|
|
120
150
|
singleValue: (base, state) => {
|
|
121
|
-
|
|
151
|
+
// Match Input text color (gray.1300, inherited from body in Input).
|
|
152
|
+
// When disabled, mirror Input's _disabled color (gray.1000).
|
|
153
|
+
const merged = {
|
|
154
|
+
...base,
|
|
155
|
+
margin: 0,
|
|
156
|
+
color: state.isDisabled ? gray1000 : gray1300,
|
|
157
|
+
};
|
|
122
158
|
return styles?.singleValue
|
|
123
159
|
? styles.singleValue(merged, state)
|
|
124
160
|
: merged;
|
|
125
161
|
},
|
|
126
162
|
valueContainer: (base, state) => {
|
|
163
|
+
// Zero internal padding so the visible text starts after the
|
|
164
|
+
// control's own 12px paddingLeft (matches Input's `px: 3` =
|
|
165
|
+
// 12px). react-select's default valueContainer padding is
|
|
166
|
+
// `2px 8px`, which would otherwise stack on top.
|
|
127
167
|
const merged = {
|
|
128
168
|
...base,
|
|
129
169
|
display: 'flex',
|
|
130
170
|
alignItems: 'center',
|
|
131
171
|
textAlign: 'left' as const,
|
|
172
|
+
padding: 0,
|
|
132
173
|
};
|
|
133
174
|
return styles?.valueContainer
|
|
134
175
|
? styles.valueContainer(merged, state)
|
|
@@ -141,7 +182,10 @@ export const Select = <
|
|
|
141
182
|
: merged;
|
|
142
183
|
},
|
|
143
184
|
dropdownIndicator: (base, state) => {
|
|
144
|
-
|
|
185
|
+
// Lighter than the body text color so the chevron doesn't
|
|
186
|
+
// visually outweigh Input's right-side icons (which are
|
|
187
|
+
// typically outline-style and read as gray.600-ish).
|
|
188
|
+
const merged = { ...base, color: gray600 };
|
|
145
189
|
return styles?.dropdownIndicator
|
|
146
190
|
? styles.dropdownIndicator(merged, state)
|
|
147
191
|
: merged;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ChangeEvent, forwardRef, useEffect, useState } from 'react';
|
|
2
2
|
import { Textarea as ChakraTextarea } from '@chakra-ui/react';
|
|
3
3
|
|
|
4
|
+
import { mergeCss } from '@/utils/mergeCss';
|
|
5
|
+
|
|
4
6
|
import { TextareaProps } from './Textarea.types';
|
|
5
7
|
|
|
6
8
|
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
@@ -10,9 +12,12 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
10
12
|
onChange,
|
|
11
13
|
value: propValue,
|
|
12
14
|
_focusVisible,
|
|
15
|
+
_hover,
|
|
16
|
+
_focus,
|
|
13
17
|
disabled,
|
|
14
18
|
invalid,
|
|
15
19
|
readOnly,
|
|
20
|
+
css,
|
|
16
21
|
...props
|
|
17
22
|
},
|
|
18
23
|
ref
|
|
@@ -43,12 +48,21 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
43
48
|
readOnly={readOnly}
|
|
44
49
|
data-invalid={invalid || undefined}
|
|
45
50
|
resize="none"
|
|
51
|
+
bg="white"
|
|
52
|
+
// Chakra v3 `Input` outline variant declares
|
|
53
|
+
// `focusRingColor: var(--focus-color)`, but the matching
|
|
54
|
+
// `Textarea` recipe does not — so the focus ring defaults to
|
|
55
|
+
// `colorPalette.focusRing` (gray.400) and ends up visibly
|
|
56
|
+
// different from Input/Select. Mirror Input's chain explicitly.
|
|
57
|
+
focusRingColor={invalid ? 'danger.main' : 'primary.main'}
|
|
46
58
|
borderColor={invalid ? 'danger.main' : 'gray.400'}
|
|
59
|
+
_hover={{
|
|
60
|
+
borderColor: invalid ? 'danger.main' : 'primary.lighter',
|
|
61
|
+
..._hover,
|
|
62
|
+
}}
|
|
47
63
|
_focus={{
|
|
48
64
|
borderColor: invalid ? 'danger.main' : 'primary.main',
|
|
49
|
-
|
|
50
|
-
_hover={{
|
|
51
|
-
borderColor: invalid ? 'danger.main' : 'gray.600',
|
|
65
|
+
..._focus,
|
|
52
66
|
}}
|
|
53
67
|
_invalid={{
|
|
54
68
|
borderColor: 'danger.main',
|
|
@@ -59,7 +73,28 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
59
73
|
borderColor: 'danger.main',
|
|
60
74
|
},
|
|
61
75
|
}}
|
|
76
|
+
_readOnly={{
|
|
77
|
+
opacity: 1,
|
|
78
|
+
cursor: 'not-allowed',
|
|
79
|
+
bg: 'gray.50',
|
|
80
|
+
color: 'gray.600',
|
|
81
|
+
borderColor: 'gray.200',
|
|
82
|
+
}}
|
|
83
|
+
_disabled={{
|
|
84
|
+
opacity: 1,
|
|
85
|
+
cursor: 'not-allowed',
|
|
86
|
+
bg: 'gray.50',
|
|
87
|
+
color: 'gray.1000',
|
|
88
|
+
fontWeight: 'semibold',
|
|
89
|
+
}}
|
|
62
90
|
{...props}
|
|
91
|
+
css={mergeCss(
|
|
92
|
+
{
|
|
93
|
+
'--focus-color': 'var(--chakra-colors-primary-main)',
|
|
94
|
+
'--error-color': 'var(--chakra-colors-danger-main)',
|
|
95
|
+
},
|
|
96
|
+
css
|
|
97
|
+
)}
|
|
63
98
|
/>
|
|
64
99
|
);
|
|
65
100
|
}
|