@vygruppen/spor-react 11.1.3 → 11.1.5
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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +74 -12
- package/dist/index.mjs +75 -13
- package/package.json +1 -1
- package/src/input/Input.tsx +26 -1
- package/src/input/Textarea.tsx +42 -2
- package/src/theme/components/textarea.ts +3 -3
package/.turbo/turbo-build.log
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
> @vygruppen/spor-react@11.1.
|
2
|
+
> @vygruppen/spor-react@11.1.5 build
|
3
3
|
> tsup src/index.tsx --dts --treeshake --format cjs,esm
|
4
4
|
|
5
5
|
[34mCLI[39m Building entry: src/index.tsx
|
@@ -9,10 +9,10 @@
|
|
9
9
|
[34mCJS[39m Build start
|
10
10
|
[34mESM[39m Build start
|
11
11
|
[34mDTS[39m Build start
|
12
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
13
|
-
[32mCJS[39m ⚡️ Build success in
|
14
|
-
[32mESM[39m [1mdist/index.mjs [22m[
|
15
|
-
[32mESM[39m ⚡️ Build success in
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
17
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m343.
|
18
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m343.
|
12
|
+
[32mCJS[39m [1mdist/index.js [22m[32m450.58 KB[39m
|
13
|
+
[32mCJS[39m ⚡️ Build success in 2008ms
|
14
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m431.05 KB[39m
|
15
|
+
[32mESM[39m ⚡️ Build success in 2008ms
|
16
|
+
[32mDTS[39m ⚡️ Build success in 16836ms
|
17
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m343.30 KB[39m
|
18
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m343.30 KB[39m
|
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# @vygruppen/spor-react
|
2
2
|
|
3
|
+
## 11.1.5
|
4
|
+
|
5
|
+
### Patch Changes
|
6
|
+
|
7
|
+
- 7c47e93: Fix(TextArea): Overlapping of label and text
|
8
|
+
|
9
|
+
## 11.1.4
|
10
|
+
|
11
|
+
### Patch Changes
|
12
|
+
|
13
|
+
- cd49b43: Set correct position of label for input elements that caused the dance during hydration step
|
14
|
+
|
3
15
|
## 11.1.3
|
4
16
|
|
5
17
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
@@ -6822,10 +6822,10 @@ declare const theme: {
|
|
6822
6822
|
minHeight: string;
|
6823
6823
|
verticalAlign: string;
|
6824
6824
|
appearance: string;
|
6825
|
-
|
6825
|
+
borderTop: string;
|
6826
6826
|
"&:not(:placeholder-shown)": {
|
6827
6827
|
"&:has(+ label)": {
|
6828
|
-
|
6828
|
+
borderTop: string;
|
6829
6829
|
};
|
6830
6830
|
"& + label": {
|
6831
6831
|
transform: string;
|
package/dist/index.d.ts
CHANGED
@@ -6822,10 +6822,10 @@ declare const theme: {
|
|
6822
6822
|
minHeight: string;
|
6823
6823
|
verticalAlign: string;
|
6824
6824
|
appearance: string;
|
6825
|
-
|
6825
|
+
borderTop: string;
|
6826
6826
|
"&:not(:placeholder-shown)": {
|
6827
6827
|
"&:has(+ label)": {
|
6828
|
-
|
6828
|
+
borderTop: string;
|
6829
6829
|
};
|
6830
6830
|
"& + label": {
|
6831
6831
|
transform: string;
|
package/dist/index.js
CHANGED
@@ -1503,9 +1503,37 @@ var Input = react.forwardRef(
|
|
1503
1503
|
"aria-labelledby": labelId,
|
1504
1504
|
ref,
|
1505
1505
|
overflow: "hidden",
|
1506
|
-
placeholder: " "
|
1506
|
+
placeholder: " ",
|
1507
|
+
css: {
|
1508
|
+
"&::-webkit-search-cancel-button": {
|
1509
|
+
WebkitAppearance: "none"
|
1510
|
+
}
|
1511
|
+
}
|
1507
1512
|
}
|
1508
|
-
), /* @__PURE__ */ React86__namespace.default.createElement(
|
1513
|
+
), /* @__PURE__ */ React86__namespace.default.createElement(
|
1514
|
+
react.FormLabel,
|
1515
|
+
{
|
1516
|
+
htmlFor: inputId,
|
1517
|
+
id: labelId,
|
1518
|
+
pointerEvents: "none",
|
1519
|
+
sx: {
|
1520
|
+
position: "absolute",
|
1521
|
+
left: "2.6rem",
|
1522
|
+
top: "26.9%",
|
1523
|
+
fontSize: "1.13rem",
|
1524
|
+
pointerEvents: "none",
|
1525
|
+
margin: 0,
|
1526
|
+
zIndex: 2,
|
1527
|
+
"input:focus + &, input[data-has-value] + &": {
|
1528
|
+
color: "var(--chakra-colors-gray-600)"
|
1529
|
+
},
|
1530
|
+
"input[data-has-value] + &": {
|
1531
|
+
transform: "translateY(-40%) scale(0.9)"
|
1532
|
+
}
|
1533
|
+
}
|
1534
|
+
},
|
1535
|
+
label
|
1536
|
+
), rightIcon && /* @__PURE__ */ React86__namespace.default.createElement(react.InputRightElement, { pointerEvents: "none" }, rightIcon));
|
1509
1537
|
}
|
1510
1538
|
);
|
1511
1539
|
var InputLeftElement2 = react.forwardRef(
|
@@ -1984,6 +2012,28 @@ var Switch = react.forwardRef(
|
|
1984
2012
|
return /* @__PURE__ */ React86__namespace.default.createElement(react.Switch, { as, size: size2, ...props, ref });
|
1985
2013
|
}
|
1986
2014
|
);
|
2015
|
+
var useLabelHeight = (label) => {
|
2016
|
+
const labelRef = React86.useRef(null);
|
2017
|
+
const [labelHeight, setLabelHeight] = React86.useState(0);
|
2018
|
+
React86.useLayoutEffect(() => {
|
2019
|
+
const updateLabelHeight = () => {
|
2020
|
+
if (labelRef.current) {
|
2021
|
+
setLabelHeight(labelRef.current.offsetHeight);
|
2022
|
+
}
|
2023
|
+
};
|
2024
|
+
const observer = new ResizeObserver(updateLabelHeight);
|
2025
|
+
if (labelRef.current) {
|
2026
|
+
observer.observe(labelRef.current);
|
2027
|
+
}
|
2028
|
+
setTimeout(updateLabelHeight, 0);
|
2029
|
+
return () => {
|
2030
|
+
if (labelRef.current) {
|
2031
|
+
observer.unobserve(labelRef.current);
|
2032
|
+
}
|
2033
|
+
};
|
2034
|
+
}, [label]);
|
2035
|
+
return { labelRef, labelHeight };
|
2036
|
+
};
|
1987
2037
|
var Textarea = react.forwardRef((props, ref) => {
|
1988
2038
|
const {
|
1989
2039
|
spacingProps,
|
@@ -1992,15 +2042,26 @@ var Textarea = react.forwardRef((props, ref) => {
|
|
1992
2042
|
const formControlProps = react.useFormControlContext();
|
1993
2043
|
const fallbackId = `textarea-${React86.useId()}`;
|
1994
2044
|
const inputId = props.id ?? (formControlProps == null ? void 0 : formControlProps.id) ?? fallbackId;
|
1995
|
-
|
1996
|
-
|
2045
|
+
const { labelRef, labelHeight } = useLabelHeight(label);
|
2046
|
+
return /* @__PURE__ */ React86__namespace.default.createElement(
|
2047
|
+
react.InputGroup,
|
1997
2048
|
{
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2049
|
+
position: "relative",
|
2050
|
+
...spacingProps,
|
2051
|
+
style: { "--label-height": `${labelHeight}px` }
|
2001
2052
|
},
|
2002
|
-
|
2003
|
-
|
2053
|
+
/* @__PURE__ */ React86__namespace.default.createElement(react.Textarea, { ...rest, id: inputId, ref, placeholder: " " }),
|
2054
|
+
label && /* @__PURE__ */ React86__namespace.default.createElement(
|
2055
|
+
react.FormLabel,
|
2056
|
+
{
|
2057
|
+
ref: labelRef,
|
2058
|
+
htmlFor: inputId,
|
2059
|
+
id: `${inputId}-label`,
|
2060
|
+
pointerEvents: "none"
|
2061
|
+
},
|
2062
|
+
label
|
2063
|
+
)
|
2064
|
+
);
|
2004
2065
|
});
|
2005
2066
|
function getSpacingProps(props) {
|
2006
2067
|
const {
|
@@ -14463,13 +14524,14 @@ var tabs_default = config40;
|
|
14463
14524
|
var config41 = react.defineStyleConfig({
|
14464
14525
|
baseStyle: (props) => ({
|
14465
14526
|
...inputBaseStyle(props).field,
|
14466
|
-
minHeight: "
|
14527
|
+
minHeight: "calc(var(--label-height) + 4rem)",
|
14467
14528
|
verticalAlign: "top",
|
14468
14529
|
appearance: "none",
|
14469
|
-
|
14530
|
+
borderTop: "0.8rem solid transparent",
|
14470
14531
|
"&:not(:placeholder-shown)": {
|
14471
14532
|
"&:has(+ label)": {
|
14472
|
-
|
14533
|
+
borderTop: "var(--label-height) solid transparent"
|
14534
|
+
// use border in stead of padding to avoid problems with scrolling
|
14473
14535
|
},
|
14474
14536
|
"& + label": {
|
14475
14537
|
transform: "scale(0.825) translateY(-10px)"
|
package/dist/index.mjs
CHANGED
@@ -4,7 +4,7 @@ export { tokens12 as tokens };
|
|
4
4
|
import { forwardRef, Divider as Divider$1, Stack as Stack$1, Box, useMultiStyleConfig, chakra, Flex, Checkbox as Checkbox$1, useCheckbox, FormControl as FormControl$1, FormLabel as FormLabel$1, useFormControlContext, InputGroup, InputLeftElement, Input as Input$1, InputRightElement, Select, useDisclosure, Button, useControllableState, Radio as Radio$1, RadioGroup as RadioGroup$1, IconButton as IconButton$1, Switch as Switch$1, Textarea as Textarea$1, useStyleConfig, Accordion as Accordion$1, Skeleton as Skeleton$1, useButtonGroup, Center, ButtonGroup as ButtonGroup$1, Badge as Badge$1, Code as Code$1, Text, PopoverAnchor, PopoverContent, PopoverArrow, PopoverBody, FocusLock, Popover as Popover$1, PopoverTrigger, Portal, Link, ModalHeader as ModalHeader$1, useModalContext, DrawerContent as DrawerContent$1, Tabs as Tabs$1, Table as Table$1, defineStyleConfig as defineStyleConfig$1, createMultiStyleConfigHelpers as createMultiStyleConfigHelpers$1, Heading, CheckboxGroup as CheckboxGroup$1, List, ListItem, useColorModeValue, useFormControlProps, useFormControl, AccordionItem, AccordionButton, AccordionIcon, AccordionPanel, useColorMode, SkeletonCircle as SkeletonCircle$1, SkeletonText as SkeletonText$1, Breadcrumb as Breadcrumb$1, BreadcrumbItem as BreadcrumbItem$1, BreadcrumbLink as BreadcrumbLink$1, Drawer as Drawer$1, DrawerOverlay, DrawerBody, DrawerHeader, useMediaQuery, DrawerCloseButton, DarkMode, PopoverCloseButton, usePopoverContext, UnorderedList, ChakraProvider, useToast as useToast$1, useInterval } from '@chakra-ui/react';
|
5
5
|
export { AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, Box, Center, Collapse, Container, DarkMode, DrawerBody, DrawerCloseButton, DrawerFooter, DrawerOverlay, Fade, Flex, FormHelperText, Grid, GridItem, HStack, Image, Img, InputGroup, LightMode, ListItem, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalOverlay, OrderedList, Portal, ScaleFade, SimpleGrid, Slide, SlideFade, Spacer, Tab, TabList, TabPanel, TabPanels, TableCaption, Tbody, Td, Tfoot, Th, Thead, Tr, UnorderedList, VStack, Wrap, WrapItem, defineStyleConfig, extendTheme, useBreakpointValue, useClipboard, useColorMode, useColorModePreference, useColorModeValue, useControllableProp, useDisclosure, useMergeRefs, useOutsideClick, usePrefersReducedMotion, useTheme, useToken } from '@chakra-ui/react';
|
6
6
|
import * as React86 from 'react';
|
7
|
-
import React86__default, { forwardRef as forwardRef$1, useRef, useState, useEffect, useId, useContext, createContext, useCallback, useMemo
|
7
|
+
import React86__default, { forwardRef as forwardRef$1, useRef, useState, useEffect, useId, useContext, createContext, useLayoutEffect, useCallback, useMemo } from 'react';
|
8
8
|
import { CloseOutline24Icon, SearchOutline24Icon, CloseFill30Icon, CloseFill24Icon, CloseFill18Icon, CalendarOutline24Icon, InformationFill24Icon, InformationFill18Icon, WarningFill24Icon, WarningFill18Icon, ErrorFill24Icon, ErrorFill18Icon, LinkOutOutline24Icon, DropdownDownFill18Icon, DropdownDownFill24Icon, DropdownUpFill24Icon, DropdownRightFill18Icon, DropdownLeftFill18Icon, Forward15MediaControllerFill30Icon, Backward15MediaControllerFill30Icon, PauseMediaControllerFill24Icon, PlayMediaControllerFill24Icon, NextMediaControllerFill30Icon, PreviousMediaControllerFill30Icon, ArrowLeftFill24Icon, ArrowLeftFill30Icon, ArrowRightFill18Icon, ArrowLeftOutline24Icon, ArrowRightOutline24Icon, ServiceFill24Icon, ErrorOutline24Icon, AltTransportOutline24Icon, WarningOutline24Icon, SuccessOutline24Icon, InformationOutline24Icon, TrainFill18Icon, TrainFill24Icon, TrainFill30Icon, ExpressBusFill18Icon, ExpressBusFill24Icon, ExpressBusFill30Icon, BusFill18Icon, BusFill24Icon, BusFill30Icon, FerryFill18Icon, FerryFill24Icon, FerryFill30Icon, SubwayFill18Icon, SubwayFill24Icon, SubwayFill30Icon, TramFill18Icon, TramFill24Icon, TramFill30Icon, AltTransportFill18Icon, AltTransportFill24Icon, AltTransportFill30Icon, WalkFill18Icon, WalkFill24Icon, WalkFill30Icon } from '@vygruppen/spor-icon-react';
|
9
9
|
import { usePopover, DismissButton, Overlay, useOverlayTrigger, useButton, useDateSegment, useDateField, useDatePicker, I18nProvider, useDialog, useFilter, useComboBox, useListBox, useOption, useListBoxSection, useSelect, HiddenSelect, useProgressBar, useCalendar, useDateRangePicker, useCalendarGrid, useRangeCalendar, useTimeField, useCalendarCell } from 'react-aria';
|
10
10
|
import { useOverlayTriggerState, useDateFieldState, useDatePickerState, useComboBoxState, useSelectState, Item, useCalendarState, useDateRangePickerState, useTimeFieldState, useRangeCalendarState } from 'react-stately';
|
@@ -1483,9 +1483,37 @@ var Input = forwardRef(
|
|
1483
1483
|
"aria-labelledby": labelId,
|
1484
1484
|
ref,
|
1485
1485
|
overflow: "hidden",
|
1486
|
-
placeholder: " "
|
1486
|
+
placeholder: " ",
|
1487
|
+
css: {
|
1488
|
+
"&::-webkit-search-cancel-button": {
|
1489
|
+
WebkitAppearance: "none"
|
1490
|
+
}
|
1491
|
+
}
|
1487
1492
|
}
|
1488
|
-
), /* @__PURE__ */ React86__default.createElement(
|
1493
|
+
), /* @__PURE__ */ React86__default.createElement(
|
1494
|
+
FormLabel$1,
|
1495
|
+
{
|
1496
|
+
htmlFor: inputId,
|
1497
|
+
id: labelId,
|
1498
|
+
pointerEvents: "none",
|
1499
|
+
sx: {
|
1500
|
+
position: "absolute",
|
1501
|
+
left: "2.6rem",
|
1502
|
+
top: "26.9%",
|
1503
|
+
fontSize: "1.13rem",
|
1504
|
+
pointerEvents: "none",
|
1505
|
+
margin: 0,
|
1506
|
+
zIndex: 2,
|
1507
|
+
"input:focus + &, input[data-has-value] + &": {
|
1508
|
+
color: "var(--chakra-colors-gray-600)"
|
1509
|
+
},
|
1510
|
+
"input[data-has-value] + &": {
|
1511
|
+
transform: "translateY(-40%) scale(0.9)"
|
1512
|
+
}
|
1513
|
+
}
|
1514
|
+
},
|
1515
|
+
label
|
1516
|
+
), rightIcon && /* @__PURE__ */ React86__default.createElement(InputRightElement, { pointerEvents: "none" }, rightIcon));
|
1489
1517
|
}
|
1490
1518
|
);
|
1491
1519
|
var InputLeftElement2 = forwardRef(
|
@@ -1964,6 +1992,28 @@ var Switch = forwardRef(
|
|
1964
1992
|
return /* @__PURE__ */ React86__default.createElement(Switch$1, { as, size: size2, ...props, ref });
|
1965
1993
|
}
|
1966
1994
|
);
|
1995
|
+
var useLabelHeight = (label) => {
|
1996
|
+
const labelRef = useRef(null);
|
1997
|
+
const [labelHeight, setLabelHeight] = useState(0);
|
1998
|
+
useLayoutEffect(() => {
|
1999
|
+
const updateLabelHeight = () => {
|
2000
|
+
if (labelRef.current) {
|
2001
|
+
setLabelHeight(labelRef.current.offsetHeight);
|
2002
|
+
}
|
2003
|
+
};
|
2004
|
+
const observer = new ResizeObserver(updateLabelHeight);
|
2005
|
+
if (labelRef.current) {
|
2006
|
+
observer.observe(labelRef.current);
|
2007
|
+
}
|
2008
|
+
setTimeout(updateLabelHeight, 0);
|
2009
|
+
return () => {
|
2010
|
+
if (labelRef.current) {
|
2011
|
+
observer.unobserve(labelRef.current);
|
2012
|
+
}
|
2013
|
+
};
|
2014
|
+
}, [label]);
|
2015
|
+
return { labelRef, labelHeight };
|
2016
|
+
};
|
1967
2017
|
var Textarea = forwardRef((props, ref) => {
|
1968
2018
|
const {
|
1969
2019
|
spacingProps,
|
@@ -1972,15 +2022,26 @@ var Textarea = forwardRef((props, ref) => {
|
|
1972
2022
|
const formControlProps = useFormControlContext();
|
1973
2023
|
const fallbackId = `textarea-${useId()}`;
|
1974
2024
|
const inputId = props.id ?? (formControlProps == null ? void 0 : formControlProps.id) ?? fallbackId;
|
1975
|
-
|
1976
|
-
|
2025
|
+
const { labelRef, labelHeight } = useLabelHeight(label);
|
2026
|
+
return /* @__PURE__ */ React86__default.createElement(
|
2027
|
+
InputGroup,
|
1977
2028
|
{
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
2029
|
+
position: "relative",
|
2030
|
+
...spacingProps,
|
2031
|
+
style: { "--label-height": `${labelHeight}px` }
|
1981
2032
|
},
|
1982
|
-
|
1983
|
-
|
2033
|
+
/* @__PURE__ */ React86__default.createElement(Textarea$1, { ...rest, id: inputId, ref, placeholder: " " }),
|
2034
|
+
label && /* @__PURE__ */ React86__default.createElement(
|
2035
|
+
FormLabel$1,
|
2036
|
+
{
|
2037
|
+
ref: labelRef,
|
2038
|
+
htmlFor: inputId,
|
2039
|
+
id: `${inputId}-label`,
|
2040
|
+
pointerEvents: "none"
|
2041
|
+
},
|
2042
|
+
label
|
2043
|
+
)
|
2044
|
+
);
|
1984
2045
|
});
|
1985
2046
|
function getSpacingProps(props) {
|
1986
2047
|
const {
|
@@ -14443,13 +14504,14 @@ var tabs_default = config40;
|
|
14443
14504
|
var config41 = defineStyleConfig$1({
|
14444
14505
|
baseStyle: (props) => ({
|
14445
14506
|
...inputBaseStyle(props).field,
|
14446
|
-
minHeight: "
|
14507
|
+
minHeight: "calc(var(--label-height) + 4rem)",
|
14447
14508
|
verticalAlign: "top",
|
14448
14509
|
appearance: "none",
|
14449
|
-
|
14510
|
+
borderTop: "0.8rem solid transparent",
|
14450
14511
|
"&:not(:placeholder-shown)": {
|
14451
14512
|
"&:has(+ label)": {
|
14452
|
-
|
14513
|
+
borderTop: "var(--label-height) solid transparent"
|
14514
|
+
// use border in stead of padding to avoid problems with scrolling
|
14453
14515
|
},
|
14454
14516
|
"& + label": {
|
14455
14517
|
transform: "scale(0.825) translateY(-10px)"
|
package/package.json
CHANGED
package/src/input/Input.tsx
CHANGED
@@ -60,8 +60,33 @@ export const Input = forwardRef<InputProps, "input">(
|
|
60
60
|
ref={ref}
|
61
61
|
overflow="hidden"
|
62
62
|
placeholder=" " // This is needed to make the label work as expected
|
63
|
+
css={{
|
64
|
+
"&::-webkit-search-cancel-button": {
|
65
|
+
WebkitAppearance: "none",
|
66
|
+
},
|
67
|
+
}}
|
63
68
|
/>
|
64
|
-
|
69
|
+
|
70
|
+
<FormLabel
|
71
|
+
htmlFor={inputId}
|
72
|
+
id={labelId}
|
73
|
+
pointerEvents="none"
|
74
|
+
sx={{
|
75
|
+
position: "absolute",
|
76
|
+
left: "2.6rem",
|
77
|
+
top: "26.9%",
|
78
|
+
fontSize: "1.13rem",
|
79
|
+
pointerEvents: "none",
|
80
|
+
margin: 0,
|
81
|
+
zIndex: 2,
|
82
|
+
"input:focus + &, input[data-has-value] + &": {
|
83
|
+
color: "var(--chakra-colors-gray-600)",
|
84
|
+
},
|
85
|
+
"input[data-has-value] + &": {
|
86
|
+
transform: "translateY(-40%) scale(0.9)",
|
87
|
+
},
|
88
|
+
}}
|
89
|
+
>
|
65
90
|
{label}
|
66
91
|
</FormLabel>
|
67
92
|
{rightIcon && (
|
package/src/input/Textarea.tsx
CHANGED
@@ -6,11 +6,44 @@ import {
|
|
6
6
|
useFormControlContext,
|
7
7
|
InputGroup,
|
8
8
|
} from "@chakra-ui/react";
|
9
|
-
import React, { useId } from "react";
|
9
|
+
import React, { useId, useLayoutEffect, useRef, useState } from "react";
|
10
10
|
|
11
11
|
export type TextareaProps = Exclude<ChakraTextareaProps, "size"> & {
|
12
12
|
label?: string;
|
13
13
|
};
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Hook to calculate the height of the label element to adjust spacing for the input for floating label.
|
17
|
+
*/
|
18
|
+
const useLabelHeight = (label: string | undefined) => {
|
19
|
+
const labelRef = useRef<HTMLLabelElement>(null);
|
20
|
+
const [labelHeight, setLabelHeight] = useState(0);
|
21
|
+
|
22
|
+
useLayoutEffect(() => {
|
23
|
+
const updateLabelHeight = () => {
|
24
|
+
if (labelRef.current) {
|
25
|
+
setLabelHeight(labelRef.current.offsetHeight);
|
26
|
+
}
|
27
|
+
};
|
28
|
+
|
29
|
+
const observer = new ResizeObserver(updateLabelHeight);
|
30
|
+
if (labelRef.current) {
|
31
|
+
observer.observe(labelRef.current);
|
32
|
+
}
|
33
|
+
|
34
|
+
// Initial calculation with a slight delay to ensure CSS is applied
|
35
|
+
setTimeout(updateLabelHeight, 0);
|
36
|
+
|
37
|
+
return () => {
|
38
|
+
if (labelRef.current) {
|
39
|
+
observer.unobserve(labelRef.current);
|
40
|
+
}
|
41
|
+
};
|
42
|
+
}, [label]);
|
43
|
+
|
44
|
+
return { labelRef, labelHeight };
|
45
|
+
};
|
46
|
+
|
14
47
|
/**
|
15
48
|
* Text area that works with the `FormControl` component.
|
16
49
|
*
|
@@ -31,11 +64,18 @@ export const Textarea = forwardRef<TextareaProps, "textarea">((props, ref) => {
|
|
31
64
|
const fallbackId = `textarea-${useId()}`;
|
32
65
|
const inputId = props.id ?? formControlProps?.id ?? fallbackId;
|
33
66
|
|
67
|
+
const { labelRef, labelHeight } = useLabelHeight(label);
|
68
|
+
|
34
69
|
return (
|
35
|
-
<InputGroup
|
70
|
+
<InputGroup
|
71
|
+
position="relative"
|
72
|
+
{...spacingProps}
|
73
|
+
style={{ "--label-height": `${labelHeight}px` } as React.CSSProperties}
|
74
|
+
>
|
36
75
|
<ChakraTextarea {...rest} id={inputId} ref={ref} placeholder=" " />
|
37
76
|
{label && (
|
38
77
|
<FormLabel
|
78
|
+
ref={labelRef}
|
39
79
|
htmlFor={inputId}
|
40
80
|
id={`${inputId}-label`}
|
41
81
|
pointerEvents="none"
|
@@ -4,13 +4,13 @@ import { inputBaseStyle, inputVariant } from "../utils/input-utils";
|
|
4
4
|
const config = defineStyleConfig({
|
5
5
|
baseStyle: (props) => ({
|
6
6
|
...inputBaseStyle(props).field,
|
7
|
-
minHeight: "
|
7
|
+
minHeight: "calc(var(--label-height) + 4rem)",
|
8
8
|
verticalAlign: "top",
|
9
9
|
appearance: "none",
|
10
|
-
|
10
|
+
borderTop: "0.8rem solid transparent",
|
11
11
|
"&:not(:placeholder-shown)": {
|
12
12
|
"&:has(+ label)": {
|
13
|
-
|
13
|
+
borderTop: "var(--label-height) solid transparent", // use border in stead of padding to avoid problems with scrolling
|
14
14
|
},
|
15
15
|
"& + label": {
|
16
16
|
transform: "scale(0.825) translateY(-10px)",
|