@eccenca/gui-elements 23.7.0-rc.1 → 23.7.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -1
- package/dist/cjs/cmem/markdown/Markdown.js +1 -1
- package/dist/cjs/cmem/markdown/Markdown.js.map +1 -1
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +3 -3
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/cjs/components/Breadcrumb/BreadcrumbList.js +1 -1
- package/dist/cjs/components/Breadcrumb/BreadcrumbList.js.map +1 -1
- package/dist/cjs/components/Card/Card.js +3 -1
- package/dist/cjs/components/Card/Card.js.map +1 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js +8 -34
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/cjs/components/Sticky/StickyTarget.js +46 -5
- package/dist/cjs/components/Sticky/StickyTarget.js.map +1 -1
- package/dist/cjs/components/TextField/TextArea.js +85 -8
- package/dist/cjs/components/TextField/TextArea.js.map +1 -1
- package/dist/esm/cmem/markdown/Markdown.js +1 -1
- package/dist/esm/cmem/markdown/Markdown.js.map +1 -1
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js +3 -3
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/esm/components/Breadcrumb/BreadcrumbList.js +1 -1
- package/dist/esm/components/Breadcrumb/BreadcrumbList.js.map +1 -1
- package/dist/esm/components/Card/Card.js +4 -2
- package/dist/esm/components/Card/Card.js.map +1 -1
- package/dist/esm/components/MultiSelect/MultiSelect.js +8 -34
- package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/Sticky/StickyTarget.js +46 -5
- package/dist/esm/components/Sticky/StickyTarget.js.map +1 -1
- package/dist/esm/components/TextField/TextArea.js +86 -9
- package/dist/esm/components/TextField/TextArea.js.map +1 -1
- package/dist/types/cmem/ActivityControl/ActivityControlTypes.d.ts +1 -0
- package/dist/types/components/AutocompleteField/AutoCompleteField.d.ts +1 -1
- package/dist/types/components/Breadcrumb/BreadcrumbList.d.ts +2 -1
- package/dist/types/components/Card/Card.d.ts +8 -2
- package/dist/types/components/MultiSelect/MultiSelect.d.ts +14 -9
- package/dist/types/components/Sticky/StickyTarget.d.ts +14 -3
- package/dist/types/components/TextField/TextArea.d.ts +28 -3
- package/package.json +1 -1
- package/src/cmem/ActivityControl/ActivityControlTypes.ts +2 -0
- package/src/cmem/markdown/Markdown.tsx +1 -1
- package/src/components/Application/application.scss +0 -1
- package/src/components/AutocompleteField/AutoCompleteField.tsx +4 -4
- package/src/components/Breadcrumb/BreadcrumbList.tsx +3 -3
- package/src/components/Card/Card.tsx +15 -3
- package/src/components/Card/card.scss +6 -1
- package/src/components/Icon/stories/Icon.stories.tsx +1 -1
- package/src/components/MultiSelect/MultiSelect.tsx +30 -43
- package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +1 -2
- package/src/components/MultiSuggestField/tests/MultiSuggestField.test.tsx +90 -6
- package/src/components/Sticky/StickyTarget.tsx +63 -7
- package/src/components/Sticky/sticky.scss +71 -12
- package/src/components/TextField/TextArea.tsx +174 -12
- package/src/components/TextField/stories/TextArea.stories.tsx +39 -12
- package/src/components/TextField/textfield.scss +81 -11
- package/src/includes/blueprintjs/_requisits.scss +1 -1
- package/src/includes/blueprintjs/_variables.scss +3 -172
- package/src/includes/carbon-components/_requisits.scss +1 -0
|
@@ -13,15 +13,26 @@ export interface StickyTargetProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
13
13
|
* The application header is not taken into offset calculation
|
|
14
14
|
*/
|
|
15
15
|
local?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Set additional distance to original sticky position.
|
|
18
|
+
*/
|
|
19
|
+
offset?: `${number}${string}`;
|
|
16
20
|
/**
|
|
17
21
|
* Set the background color used for the sticky area.
|
|
18
22
|
* As it can overlay other content readability could be harmed if the overlayed content is shining through.
|
|
19
23
|
*/
|
|
20
24
|
background?: "card" | "application" | "transparent";
|
|
21
25
|
/**
|
|
22
|
-
*
|
|
26
|
+
* In some situations there could be a gap between sticky target area and the border of the related scroll area.
|
|
27
|
+
* The main gap is the gap towards the direction of the sticky behaviour, specified by `to`.
|
|
28
|
+
* You can fill this gap with a gradient or full background color.
|
|
23
29
|
*/
|
|
24
|
-
|
|
30
|
+
fillMainGap?: "full" | "gradient";
|
|
31
|
+
/**
|
|
32
|
+
* The secondary gap is the gap against the direction of the sticky behaviour.
|
|
33
|
+
* So in case of `to="top"` this is rendered on the bottom of the sticky area.
|
|
34
|
+
*/
|
|
35
|
+
fillSecondaryGap?: "full" | "gradient";
|
|
25
36
|
/**
|
|
26
37
|
* Callback that returns an DOM element.
|
|
27
38
|
* The position of `StickyTarget` is then calculated relative to that element.
|
|
@@ -37,8 +48,10 @@ export const StickyTarget = ({
|
|
|
37
48
|
className,
|
|
38
49
|
to = "top",
|
|
39
50
|
local = false,
|
|
40
|
-
background = "transparent",
|
|
41
51
|
offset,
|
|
52
|
+
background = "transparent",
|
|
53
|
+
fillMainGap,
|
|
54
|
+
fillSecondaryGap,
|
|
42
55
|
style,
|
|
43
56
|
getConnectedElement,
|
|
44
57
|
...otherDivProps
|
|
@@ -50,8 +63,13 @@ export const StickyTarget = ({
|
|
|
50
63
|
offsetStyle = { ...style, "--eccgui-sticky-target-localoffset": offset } as CSSProperties;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
|
-
let connectedOffset = 0;
|
|
54
66
|
React.useEffect(() => {
|
|
67
|
+
let removeEventForConnectedOffset = () => {
|
|
68
|
+
/* no event need to be removed */
|
|
69
|
+
};
|
|
70
|
+
let removeEventForStickynessCheck = () => {
|
|
71
|
+
/* no event need to be removed */
|
|
72
|
+
};
|
|
55
73
|
/**
|
|
56
74
|
* If the target should be sticky to a defined element then:
|
|
57
75
|
* * check for the element and its scroll parent
|
|
@@ -64,6 +82,7 @@ export const StickyTarget = ({
|
|
|
64
82
|
const scrollParentFallback = !scrollParent ? document.documentElement : false;
|
|
65
83
|
if (scrollParent || scrollParentFallback) {
|
|
66
84
|
const updateTargetOffset = () => {
|
|
85
|
+
let connectedOffset = 0;
|
|
67
86
|
const scrollParentPosition = (
|
|
68
87
|
(scrollParent || scrollParentFallback) as HTMLElement
|
|
69
88
|
).getBoundingClientRect();
|
|
@@ -85,20 +104,55 @@ export const StickyTarget = ({
|
|
|
85
104
|
`${connectedOffset}px`
|
|
86
105
|
);
|
|
87
106
|
};
|
|
107
|
+
|
|
88
108
|
updateTargetOffset();
|
|
89
109
|
const eventListeningTarget = scrollParent || window;
|
|
90
110
|
const eventListeningMethod = (_event: Event) => {
|
|
91
111
|
updateTargetOffset();
|
|
92
112
|
};
|
|
93
113
|
eventListeningTarget.addEventListener("scroll", eventListeningMethod);
|
|
94
|
-
|
|
114
|
+
removeEventForConnectedOffset = () => {
|
|
95
115
|
eventListeningTarget.removeEventListener("scroll", eventListeningMethod);
|
|
96
116
|
};
|
|
97
117
|
}
|
|
98
118
|
}
|
|
99
119
|
}
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Check if sticky target element is currently in sticky mode.
|
|
122
|
+
* sticky mode = current position === defined sticky position
|
|
123
|
+
*/
|
|
124
|
+
if (stickyTargetRef && (fillMainGap || fillSecondaryGap)) {
|
|
125
|
+
const stickyTarget = stickyTargetRef.current as Element;
|
|
126
|
+
const scrollParent = utils.getScrollParent(stickyTarget);
|
|
127
|
+
const checkStickyness = () => {
|
|
128
|
+
const definedPosition = parseInt(window.getComputedStyle(stickyTarget)[to], 10);
|
|
129
|
+
const scrollParentPosition = scrollParent ? scrollParent.getBoundingClientRect()[to] : 0;
|
|
130
|
+
const currentPosition =
|
|
131
|
+
(to === "top" ? 1 : -1) * (stickyTarget.getBoundingClientRect()[to] - scrollParentPosition);
|
|
132
|
+
// check stickyness in a small position range (not exact value) because of float values
|
|
133
|
+
const isSticky = currentPosition <= definedPosition + 1 && currentPosition >= definedPosition - 1;
|
|
134
|
+
if (isSticky && !stickyTarget.classList.contains(`${eccgui}-sticky__target--issticky`)) {
|
|
135
|
+
stickyTarget.classList.add(`${eccgui}-sticky__target--issticky`);
|
|
136
|
+
}
|
|
137
|
+
if (!isSticky && stickyTarget.classList.contains(`${eccgui}-sticky__target--issticky`)) {
|
|
138
|
+
stickyTarget.classList.remove(`${eccgui}-sticky__target--issticky`);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
checkStickyness();
|
|
142
|
+
const eventListeningTarget = scrollParent || window;
|
|
143
|
+
const eventListeningMethod = (_event: Event) => {
|
|
144
|
+
checkStickyness();
|
|
145
|
+
};
|
|
146
|
+
eventListeningTarget.addEventListener("scroll", eventListeningMethod);
|
|
147
|
+
removeEventForStickynessCheck = () => {
|
|
148
|
+
eventListeningTarget.removeEventListener("scroll", eventListeningMethod);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return () => {
|
|
152
|
+
removeEventForConnectedOffset();
|
|
153
|
+
removeEventForStickynessCheck();
|
|
154
|
+
};
|
|
155
|
+
}, [getConnectedElement, stickyTargetRef, to, fillMainGap, fillSecondaryGap]);
|
|
102
156
|
|
|
103
157
|
return (
|
|
104
158
|
<div
|
|
@@ -108,6 +162,8 @@ export const StickyTarget = ({
|
|
|
108
162
|
(to ? ` ${eccgui}-sticky__target--${to}` : "") +
|
|
109
163
|
(local ? ` ${eccgui}-sticky__target--localscrollarea` : "") +
|
|
110
164
|
(background ? ` ${eccgui}-sticky__target--bg-${background}` : "") +
|
|
165
|
+
(fillMainGap ? ` ${eccgui}-sticky__target--maingapfill-${fillMainGap}` : "") +
|
|
166
|
+
(fillSecondaryGap ? ` ${eccgui}-sticky__target--secondarygapfill-${fillSecondaryGap}` : "") +
|
|
111
167
|
(className ? ` ${className}` : "")
|
|
112
168
|
}
|
|
113
169
|
style={offset ? offsetStyle : style}
|
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
.#{$eccgui}-sticky__target {
|
|
6
6
|
position: sticky;
|
|
7
7
|
z-index: 1;
|
|
8
|
+
background-color: var(--eccgui-sticky-target-bgcolor, transparent);
|
|
8
9
|
|
|
9
10
|
--eccgui-sticky-target-applicationoffset: 0px;
|
|
11
|
+
--eccgui-sticky-target-maingap: 0px;
|
|
10
12
|
|
|
11
13
|
.#{$eccgui}-application__content &:not(.#{$eccgui}-sticky__target--localscrollarea) {
|
|
12
|
-
--eccgui-sticky-target-applicationoffset: $eccgui-size-block-whitespace;
|
|
14
|
+
--eccgui-sticky-target-applicationoffset: #{$eccgui-size-block-whitespace};
|
|
15
|
+
--eccgui-sticky-target-maingap: #{$eccgui-size-block-whitespace};
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
.#{$eccgui}-application__header
|
|
@@ -17,53 +20,109 @@
|
|
|
17
20
|
&:not(.#{$eccgui}-sticky__target--localscrollarea) {
|
|
18
21
|
--eccgui-sticky-target-applicationoffset: calc(#{mini-units(8)} + #{$eccgui-size-block-whitespace});
|
|
19
22
|
}
|
|
23
|
+
|
|
24
|
+
&[class*="#{$eccgui}-sticky__target--maingapfill"]:before,
|
|
25
|
+
&[class*="#{$eccgui}-sticky__target--secondarygapfill"]:after {
|
|
26
|
+
position: absolute;
|
|
27
|
+
left: 0;
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: calc(var(--eccgui-sticky-target-maingap) + var(--eccgui-sticky-target-localoffset, 0px));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&[class*="#{$eccgui}-sticky__target--secondarygapfill"]:after {
|
|
33
|
+
height: $eccgui-size-block-whitespace * 0.5;
|
|
34
|
+
}
|
|
20
35
|
}
|
|
21
36
|
|
|
22
37
|
.#{$eccgui}-sticky__target--top {
|
|
23
38
|
top: calc(var(--eccgui-sticky-target-applicationoffset) + var(--eccgui-sticky-target-localoffset, 0px));
|
|
39
|
+
|
|
40
|
+
&[class*="#{$eccgui}-sticky__target--maingapfill"]:before {
|
|
41
|
+
bottom: 100%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&[class*="#{$eccgui}-sticky__target--secondarygapfill"]:after {
|
|
45
|
+
top: 100%;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.#{$eccgui}-sticky__target--maingapfill-gradient:before {
|
|
49
|
+
background: linear-gradient(transparent, 10%, var(--eccgui-sticky-target-bgcolor, transparent));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&.#{$eccgui}-sticky__target--secondarygapfill-gradient:after {
|
|
53
|
+
background: linear-gradient(var(--eccgui-sticky-target-bgcolor, transparent), transparent);
|
|
54
|
+
}
|
|
24
55
|
}
|
|
25
56
|
|
|
26
57
|
.#{$eccgui}-sticky__target--bottom {
|
|
27
58
|
--eccgui-sticky-target-applicationoffset: 0px;
|
|
28
59
|
|
|
29
60
|
bottom: calc(var(--eccgui-sticky-target-applicationoffset) + var(--eccgui-sticky-target-localoffset, 0px));
|
|
61
|
+
|
|
62
|
+
&[class*="#{$eccgui}-sticky__target--maingapfill"]:before {
|
|
63
|
+
top: 100%;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&[class*="#{$eccgui}-sticky__target--secondarygapfill"]:after {
|
|
67
|
+
bottom: 100%;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
&.#{$eccgui}-sticky__target--maingapfill-gradient:before {
|
|
71
|
+
background: linear-gradient(var(--eccgui-sticky-target-bgcolor, 90%, transparent), transparent);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&.#{$eccgui}-sticky__target--secondarygapfill-gradient:after {
|
|
75
|
+
background: linear-gradient(transparent, var(--eccgui-sticky-target-bgcolor, transparent));
|
|
76
|
+
}
|
|
30
77
|
}
|
|
31
78
|
|
|
32
79
|
.#{$eccgui}-sticky__target--bg-card {
|
|
33
|
-
|
|
80
|
+
--eccgui-sticky-target-bgcolor: #{$card-background-color};
|
|
34
81
|
|
|
35
82
|
.#{$eccgui}-card.#{$eccgui}-intent--primary & {
|
|
36
|
-
|
|
83
|
+
--eccgui-sticky-target-bgcolor: #{color.mix($eccgui-color-primary, $card-background-color, 5%)};
|
|
37
84
|
}
|
|
38
85
|
.#{$eccgui}-card.#{$eccgui}-intent--accent & {
|
|
39
|
-
|
|
86
|
+
--eccgui-sticky-target-bgcolor: #{color.mix($eccgui-color-accent, $card-background-color, 10%)};
|
|
40
87
|
}
|
|
41
88
|
.#{$eccgui}-card.#{$eccgui}-intent--success & {
|
|
42
|
-
|
|
89
|
+
--eccgui-sticky-target-bgcolor: #{$eccgui-color-success-background};
|
|
43
90
|
}
|
|
44
91
|
.#{$eccgui}-card.#{$eccgui}-intent--info & {
|
|
45
|
-
|
|
92
|
+
--eccgui-sticky-target-bgcolor: #{$eccgui-color-info-background};
|
|
46
93
|
}
|
|
47
94
|
.#{$eccgui}-card.#{$eccgui}-intent--warning & {
|
|
48
|
-
|
|
95
|
+
--eccgui-sticky-target-bgcolor: #{$eccgui-color-warning-background};
|
|
49
96
|
}
|
|
50
97
|
.#{$eccgui}-card.#{$eccgui}-intent--danger & {
|
|
51
|
-
|
|
98
|
+
--eccgui-sticky-target-bgcolor: #{$eccgui-color-danger-background};
|
|
52
99
|
}
|
|
53
100
|
|
|
54
101
|
.#{$eccgui}-card.#{$ns}-interactive:hover & {
|
|
55
|
-
|
|
102
|
+
--eccgui-sticky-target-bgcolor: #{$button-background-color-hover};
|
|
56
103
|
}
|
|
57
104
|
|
|
58
105
|
.#{$eccgui}-card.#{$ns}-selected & {
|
|
59
|
-
|
|
106
|
+
--eccgui-sticky-target-bgcolor: #{$card-selected-background-color};
|
|
60
107
|
}
|
|
61
108
|
|
|
62
109
|
.#{$eccgui}-card--elevated & {
|
|
63
|
-
|
|
110
|
+
--eccgui-sticky-target-bgcolor: #{$button-background-color-active};
|
|
64
111
|
}
|
|
65
112
|
}
|
|
66
113
|
|
|
67
114
|
.#{$eccgui}-sticky__target--bg-application {
|
|
68
|
-
|
|
115
|
+
--eccgui-sticky-target-bgcolor: #{$eccgui-color-application-background};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.#{$eccgui}-sticky__target--issticky {
|
|
119
|
+
&[class*="#{$eccgui}-sticky__target--maingapfill"]:before,
|
|
120
|
+
&[class*="#{$eccgui}-sticky__target--secondarygapfill"]:after {
|
|
121
|
+
content: "";
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.#{$eccgui}-sticky__target--maingapfill-full:before,
|
|
126
|
+
.#{$eccgui}-sticky__target--secondarygapfill-full:after {
|
|
127
|
+
background: var(--eccgui-sticky-target-bgcolor, transparent);
|
|
69
128
|
}
|
|
@@ -1,35 +1,63 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {
|
|
3
|
+
Classes as BlueprintClassNames,
|
|
3
4
|
Intent as BlueprintIntent,
|
|
5
|
+
MaybeElement,
|
|
4
6
|
TextArea as BlueprintTextArea,
|
|
5
7
|
TextAreaProps as BlueprintTextAreaProps,
|
|
6
8
|
} from "@blueprintjs/core";
|
|
7
9
|
|
|
10
|
+
import { Definitions as IntentDefinitions, IntentTypes } from "../../common/Intent";
|
|
8
11
|
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
|
|
12
|
+
import { Icon } from "../Icon";
|
|
13
|
+
import { ValidIconName } from "../Icon/canonicalIconNames";
|
|
9
14
|
|
|
10
15
|
import { InvisibleCharacterWarningProps, useTextValidation } from "./useTextValidation";
|
|
11
16
|
|
|
12
|
-
export interface TextAreaProps extends
|
|
17
|
+
export interface TextAreaProps extends Omit<BlueprintTextAreaProps, "intent"> {
|
|
13
18
|
/**
|
|
14
19
|
* when set to true the input takes a blue border color
|
|
20
|
+
* @deprecated Use the `intent` property.
|
|
15
21
|
*/
|
|
16
22
|
hasStatePrimary?: boolean;
|
|
17
23
|
/**
|
|
18
24
|
* when set to true the input takes a green border color
|
|
25
|
+
* @deprecated Use the `intent` property.
|
|
19
26
|
*/
|
|
20
27
|
hasStateSuccess?: boolean;
|
|
21
28
|
/**
|
|
22
29
|
* when set to true the input takes an orange border color
|
|
30
|
+
* @deprecated Use the `intent` property.
|
|
23
31
|
*/
|
|
24
32
|
hasStateWarning?: boolean;
|
|
25
33
|
/**
|
|
26
34
|
* when set to true the input takes a red border color
|
|
35
|
+
* @deprecated Use the `intent` property.
|
|
27
36
|
*/
|
|
28
37
|
hasStateDanger?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Intent state of the text area.
|
|
40
|
+
*/
|
|
41
|
+
intent?: IntentTypes | "edited" | "removed";
|
|
29
42
|
/**
|
|
30
43
|
* If set, allows to be informed of invisible, hard to spot characters in the string value.
|
|
31
44
|
*/
|
|
32
45
|
invisibleCharacterWarning?: InvisibleCharacterWarningProps;
|
|
46
|
+
/**
|
|
47
|
+
* Left aligned icon, can be a canonical icon name or an `Icon` element.
|
|
48
|
+
* This will update left padding on the text area.
|
|
49
|
+
*/
|
|
50
|
+
leftIcon?: ValidIconName | MaybeElement;
|
|
51
|
+
/**
|
|
52
|
+
* Element to render on right side of text area. Should be not too large.
|
|
53
|
+
* This will update right padding on the text area.
|
|
54
|
+
*/
|
|
55
|
+
rightElement?: JSX.Element;
|
|
56
|
+
/**
|
|
57
|
+
* Add HTML properties to the wrapper element.
|
|
58
|
+
* The element wraps `TextArea` in case of a given `wrapperDivProps`, `leftIcon` or `rightElement` property.
|
|
59
|
+
*/
|
|
60
|
+
wrapperDivProps?: Omit<React.HTMLAttributes<HTMLDivElement>, "children">;
|
|
33
61
|
}
|
|
34
62
|
|
|
35
63
|
export const TextArea = ({
|
|
@@ -40,38 +68,172 @@ export const TextArea = ({
|
|
|
40
68
|
hasStateDanger = false,
|
|
41
69
|
rows = 5,
|
|
42
70
|
invisibleCharacterWarning,
|
|
71
|
+
leftIcon,
|
|
72
|
+
rightElement,
|
|
73
|
+
wrapperDivProps,
|
|
43
74
|
...otherProps
|
|
44
75
|
}: TextAreaProps) => {
|
|
45
|
-
|
|
76
|
+
const textAreaCallback = React.useCallback(
|
|
77
|
+
(textAreaElement: HTMLTextAreaElement) => {
|
|
78
|
+
if (textAreaElement && typeof textAreaElement === "object") {
|
|
79
|
+
let textAreaStyle: CSSStyleDeclaration;
|
|
80
|
+
if (!textAreaElement.dataset.processed) {
|
|
81
|
+
textAreaStyle = getComputedStyle(textAreaElement);
|
|
82
|
+
textAreaElement.dataset.processed = "yes";
|
|
83
|
+
textAreaElement.dataset.paddingtop = textAreaStyle.paddingTop ?? "0px";
|
|
84
|
+
textAreaElement.dataset.paddingleft = textAreaStyle.paddingLeft ?? "0px";
|
|
85
|
+
textAreaElement.dataset.paddingright = textAreaStyle.paddingRight ?? "0px";
|
|
86
|
+
} else {
|
|
87
|
+
textAreaStyle = {
|
|
88
|
+
paddingTop: textAreaElement.dataset.paddingtop ?? "0px",
|
|
89
|
+
paddingLeft: textAreaElement.dataset.paddingleft ?? "0px",
|
|
90
|
+
paddingRight: textAreaElement.dataset.paddingright ?? "0px",
|
|
91
|
+
} as CSSStyleDeclaration;
|
|
92
|
+
}
|
|
93
|
+
const textAreaElementRect = textAreaElement.getBoundingClientRect();
|
|
94
|
+
const wrapperElement = textAreaElement.parentElement;
|
|
95
|
+
|
|
96
|
+
if (leftIcon && wrapperElement) {
|
|
97
|
+
const leftIconElement = wrapperElement.querySelector(`.${eccgui}-textarea__icon`) as HTMLElement;
|
|
98
|
+
const leftIconElementRect = leftIconElement.getBoundingClientRect();
|
|
99
|
+
if (
|
|
100
|
+
parseInt(textAreaStyle.paddingTop, 10) * 2 + (leftIconElementRect.height ?? 0) <=
|
|
101
|
+
(textAreaElementRect.height ?? 0)
|
|
102
|
+
) {
|
|
103
|
+
leftIconElement.style.setProperty("top", textAreaStyle.paddingTop);
|
|
104
|
+
} else {
|
|
105
|
+
leftIconElement.style.setProperty(
|
|
106
|
+
"top",
|
|
107
|
+
`${((textAreaElementRect.height ?? 0) - (leftIconElementRect.height ?? 0)) * 0.5}px`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
leftIconElement.style.setProperty("left", textAreaStyle.paddingLeft);
|
|
111
|
+
textAreaElement.style.setProperty(
|
|
112
|
+
"padding-left",
|
|
113
|
+
`calc(${leftIconElementRect.width ? 2 : 1} * ${textAreaStyle.paddingLeft} + ${
|
|
114
|
+
leftIconElementRect.width ?? 0
|
|
115
|
+
}px)`
|
|
116
|
+
);
|
|
117
|
+
leftIconElement.addEventListener("click", (_event: MouseEvent) => {
|
|
118
|
+
textAreaElement.focus();
|
|
119
|
+
}); //onclick((_event: MouseEvent) => {textAreaElement.dispatchEvent("click")})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (rightElement && wrapperElement) {
|
|
123
|
+
const rightElementElement = wrapperElement.querySelector(
|
|
124
|
+
`.${eccgui}-textarea__options`
|
|
125
|
+
) as HTMLElement;
|
|
126
|
+
const rightElementElementRect = rightElementElement.getBoundingClientRect();
|
|
127
|
+
if (
|
|
128
|
+
parseInt(textAreaStyle.paddingTop, 10) * 2 + (rightElementElementRect.height ?? 0) <=
|
|
129
|
+
(textAreaElementRect.height ?? 0)
|
|
130
|
+
) {
|
|
131
|
+
rightElementElement.style.setProperty("top", textAreaStyle.paddingTop);
|
|
132
|
+
} else {
|
|
133
|
+
rightElementElement.style.setProperty(
|
|
134
|
+
"top",
|
|
135
|
+
`${((textAreaElementRect.height ?? 0) - (rightElementElementRect.height ?? 0)) * 0.5}px`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
rightElementElement.style.setProperty("right", textAreaStyle.paddingRight);
|
|
139
|
+
textAreaElement.style.setProperty(
|
|
140
|
+
"padding-right",
|
|
141
|
+
`calc(${rightElementElementRect.width ? 2 : 1} * ${textAreaStyle.paddingRight} + ${
|
|
142
|
+
rightElementElementRect.width ?? 0
|
|
143
|
+
}px)`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
[leftIcon, rightElement]
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
let deprecatedIntent;
|
|
46
152
|
switch (true) {
|
|
47
153
|
case hasStatePrimary:
|
|
48
|
-
|
|
154
|
+
deprecatedIntent = IntentDefinitions.PRIMARY;
|
|
49
155
|
break;
|
|
50
156
|
case hasStateSuccess:
|
|
51
|
-
|
|
157
|
+
deprecatedIntent = IntentDefinitions.SUCCESS;
|
|
52
158
|
break;
|
|
53
159
|
case hasStateWarning:
|
|
54
|
-
|
|
160
|
+
deprecatedIntent = IntentDefinitions.WARNING;
|
|
55
161
|
break;
|
|
56
162
|
case hasStateDanger:
|
|
57
|
-
|
|
163
|
+
deprecatedIntent = IntentDefinitions.DANGER;
|
|
58
164
|
break;
|
|
59
165
|
default:
|
|
60
166
|
break;
|
|
61
167
|
}
|
|
62
168
|
|
|
63
|
-
const
|
|
169
|
+
const { intent = deprecatedIntent, ...otherBlueprintTextAreaProps } = otherProps;
|
|
64
170
|
|
|
65
|
-
|
|
171
|
+
let iconIntent;
|
|
172
|
+
switch (intent) {
|
|
173
|
+
case "edited":
|
|
174
|
+
iconIntent = IntentDefinitions.INFO;
|
|
175
|
+
break;
|
|
176
|
+
case "removed":
|
|
177
|
+
iconIntent = IntentDefinitions.DANGER;
|
|
178
|
+
break;
|
|
179
|
+
default:
|
|
180
|
+
iconIntent = intent as IntentTypes;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const maybeWrappedOnChange = useTextValidation({ ...otherBlueprintTextAreaProps, invisibleCharacterWarning });
|
|
185
|
+
|
|
186
|
+
const textarea = (
|
|
66
187
|
<BlueprintTextArea
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
188
|
+
inputRef={textAreaCallback}
|
|
189
|
+
className={
|
|
190
|
+
`${eccgui}-textarea` +
|
|
191
|
+
(intent ? ` ${eccgui}-intent--${intent}` : "") +
|
|
192
|
+
(className ? ` ${className}` : "")
|
|
193
|
+
}
|
|
194
|
+
intent={
|
|
195
|
+
intent && !["info", "edited", "removed", "neutral"].includes(intent)
|
|
196
|
+
? (intent as BlueprintIntent)
|
|
197
|
+
: undefined
|
|
198
|
+
}
|
|
199
|
+
spellCheck={intent === "removed" ? false : undefined}
|
|
200
|
+
rows={
|
|
201
|
+
rows && !otherBlueprintTextAreaProps.autoResize && !otherBlueprintTextAreaProps.growVertically
|
|
202
|
+
? rows
|
|
203
|
+
: 1
|
|
204
|
+
}
|
|
205
|
+
{...otherBlueprintTextAreaProps}
|
|
71
206
|
dir={"auto"}
|
|
72
207
|
onChange={maybeWrappedOnChange}
|
|
73
208
|
/>
|
|
74
209
|
);
|
|
210
|
+
|
|
211
|
+
const { className: wrapperClassName, ...otherWrapperDivProps } = wrapperDivProps ?? {};
|
|
212
|
+
|
|
213
|
+
return wrapperDivProps || leftIcon || rightElement ? (
|
|
214
|
+
<div
|
|
215
|
+
className={`${eccgui}-textarea__wrapper` + (wrapperClassName ? ` ${wrapperClassName}` : "")}
|
|
216
|
+
{...otherWrapperDivProps}
|
|
217
|
+
>
|
|
218
|
+
{textarea}
|
|
219
|
+
{leftIcon && (
|
|
220
|
+
<div className={`${eccgui}-textarea__icon`}>
|
|
221
|
+
{typeof leftIcon === "string" ? (
|
|
222
|
+
<Icon
|
|
223
|
+
name={leftIcon as ValidIconName}
|
|
224
|
+
className={BlueprintClassNames.ICON}
|
|
225
|
+
intent={iconIntent as IntentTypes | undefined}
|
|
226
|
+
/>
|
|
227
|
+
) : (
|
|
228
|
+
<span className={BlueprintClassNames.ICON}>{leftIcon}</span>
|
|
229
|
+
)}
|
|
230
|
+
</div>
|
|
231
|
+
)}
|
|
232
|
+
{rightElement && <div className={`${eccgui}-textarea__options`}>{rightElement}</div>}
|
|
233
|
+
</div>
|
|
234
|
+
) : (
|
|
235
|
+
textarea
|
|
236
|
+
);
|
|
75
237
|
};
|
|
76
238
|
|
|
77
239
|
export default TextArea;
|
|
@@ -1,22 +1,49 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { Meta, StoryFn } from "@storybook/react";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { helpersArgTypes } from "../../../../.storybook/helpers";
|
|
5
|
+
|
|
6
|
+
import { Button, IconButton, TextArea } from "./../../../../index";
|
|
7
|
+
type TextAreaType = typeof TextArea;
|
|
6
8
|
|
|
7
9
|
export default {
|
|
8
10
|
title: "Forms/TextArea",
|
|
9
|
-
component:
|
|
10
|
-
argTypes: {
|
|
11
|
-
|
|
11
|
+
component: TextArea,
|
|
12
|
+
argTypes: {
|
|
13
|
+
leftIcon: {
|
|
14
|
+
...helpersArgTypes.exampleIcon,
|
|
15
|
+
},
|
|
16
|
+
rightElement: {
|
|
17
|
+
control: helpersArgTypes.exampleIcon.control,
|
|
18
|
+
options: [...helpersArgTypes.exampleIcon.options, "Button element", "2 Icon buttons"],
|
|
19
|
+
mapping: {
|
|
20
|
+
...helpersArgTypes.exampleIcon.mapping,
|
|
21
|
+
"Button element": (
|
|
22
|
+
<Button small onClick={() => alert("clicked")}>
|
|
23
|
+
Button label
|
|
24
|
+
</Button>
|
|
25
|
+
),
|
|
26
|
+
"2 Icon buttons": (
|
|
27
|
+
<>
|
|
28
|
+
<IconButton name={"item-comment"} onClick={() => alert("1 clicked")} text="Button 1" />
|
|
29
|
+
<IconButton name={"item-edit"} onClick={() => alert("2 clicked")} text="Button 2" />
|
|
30
|
+
</>
|
|
31
|
+
),
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
intent: {
|
|
35
|
+
...helpersArgTypes.exampleIntent,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
} as Meta<TextAreaType>;
|
|
12
39
|
|
|
13
|
-
const Template:
|
|
40
|
+
const Template: StoryFn<TextAreaType> = (args) => <TextArea {...args}></TextArea>;
|
|
14
41
|
|
|
15
42
|
export const Default = Template.bind({});
|
|
16
43
|
Default.args = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
rows: 10,
|
|
45
|
+
wrapperDivProps: {
|
|
46
|
+
"data-test-id": "textarea-test-id",
|
|
47
|
+
"data-testid": "textarea-testid",
|
|
48
|
+
},
|
|
22
49
|
};
|