@uva-glass/component-library 3.34.7 → 3.34.9
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/assets/TextArea.css +1 -1
- package/dist/components/MultiSelectBox/MultiSelectBox.js +24 -24
- package/dist/components/MultiSelectBox/MultiSelectBox.js.map +1 -1
- package/dist/components/TextArea/TextArea.js +17 -17
- package/dist/components/hooks/usePositionedFloaters.d.ts +1 -0
- package/dist/components/hooks/usePositionedFloaters.js +18 -17
- package/dist/components/hooks/usePositionedFloaters.js.map +1 -1
- package/package.json +3 -3
package/dist/assets/TextArea.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
._text-
|
|
1
|
+
._text-area__wrapper_2mhm2_1{display:flex;flex-direction:column;gap:.5rem}._text-area__header_2mhm2_7{align-items:flex-end;display:flex;justify-content:space-between}._text-area__label-wrapper_2mhm2_13{display:flex;flex-direction:column;gap:.5rem}._text-area__label_2mhm2_13{font-family:inherit;font-size:inherit;font-weight:var(--semibold)}._text-area__sub-label_2mhm2_25{color:var(--new-color-grey-700);font-size:var(--font-size-text-non-essential)}._text-area__word-count_2mhm2_30{color:var(--new-color-grey-600);font-size:var(--font-size-text-non-essential)}._text-area__word-count--alert_2mhm2_35{color:var(--new-color-red-600);font-weight:700}._text-area_2mhm2_1{border-radius:.5rem;font-family:inherit;font-size:inherit;min-height:5.25rem;overflow:hidden;padding:.5rem;resize:none;white-space:pre-wrap;width:100%;word-wrap:break-word}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsxs as f, jsx as u } from "react/jsx-runtime";
|
|
2
|
-
import { useId as
|
|
2
|
+
import { useId as q, useState as d, useRef as O, useCallback as g, useEffect as w } from "react";
|
|
3
3
|
import { c as v } from "../../clsx-OuTLNxxd.js";
|
|
4
|
-
import { Icon as
|
|
5
|
-
import { Checkbox as
|
|
6
|
-
import { usePositionedFloaters as
|
|
4
|
+
import { Icon as G } from "../Icon/Icon.js";
|
|
5
|
+
import { Checkbox as J } from "../Checkbox/Checkbox.js";
|
|
6
|
+
import { usePositionedFloaters as Q } from "../hooks/usePositionedFloaters.js";
|
|
7
7
|
import '../../assets/MultiSelectBox.css';const r = {
|
|
8
8
|
"multi-select-box-wrapper": "_multi-select-box-wrapper_ltxrv_1",
|
|
9
9
|
"multi-select-box-trigger": "_multi-select-box-trigger_ltxrv_5",
|
|
@@ -17,9 +17,9 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
17
17
|
"multi-select-box-listbox-option--active": "_multi-select-box-listbox-option--active_ltxrv_97",
|
|
18
18
|
"multi-select-box-listbox-option-content": "_multi-select-box-listbox-option-content_ltxrv_108",
|
|
19
19
|
"multi-select-box-listbox-option--disabled": "_multi-select-box-listbox-option--disabled_ltxrv_122"
|
|
20
|
-
},
|
|
20
|
+
}, te = ({
|
|
21
21
|
selectData: c,
|
|
22
|
-
onChange:
|
|
22
|
+
onChange: m,
|
|
23
23
|
defaultSelectedItems: y,
|
|
24
24
|
labelSuffix: E = "geselecteerd",
|
|
25
25
|
disabled: A = !1,
|
|
@@ -28,7 +28,7 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
28
28
|
maxOptionHeight: C,
|
|
29
29
|
optionPositionRight: L
|
|
30
30
|
}) => {
|
|
31
|
-
const _ =
|
|
31
|
+
const _ = q(), [n, h] = d(y || []), [S, k] = d(y?.length || 0), [s, a] = d(!1), [b, x] = d(-1), I = O(null), N = O(null), [F, K] = d(null), [R, $] = d(null), { style: D, updatePosition: M } = Q(F, R, {
|
|
32
32
|
mouseEvent: "click",
|
|
33
33
|
offset: 4,
|
|
34
34
|
maxFixedHeight: C,
|
|
@@ -40,7 +40,7 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
40
40
|
!e || !I.current || I.current.contains(e) || a(!1);
|
|
41
41
|
},
|
|
42
42
|
[a]
|
|
43
|
-
),
|
|
43
|
+
), T = g(
|
|
44
44
|
(e) => {
|
|
45
45
|
switch (e.key) {
|
|
46
46
|
case "Enter":
|
|
@@ -52,7 +52,7 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
[s]
|
|
55
|
-
),
|
|
55
|
+
), j = g(
|
|
56
56
|
(e) => {
|
|
57
57
|
if (s)
|
|
58
58
|
switch (e.key) {
|
|
@@ -79,7 +79,7 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
79
79
|
const t = c[b];
|
|
80
80
|
if (!t || t.disabled) break;
|
|
81
81
|
const o = n.some((i) => i.value === t.value) ? n.filter((i) => i.value !== t.value) : [...n, t];
|
|
82
|
-
h(o), k(o.length),
|
|
82
|
+
h(o), k(o.length), m(o);
|
|
83
83
|
break;
|
|
84
84
|
}
|
|
85
85
|
case "Tab":
|
|
@@ -90,23 +90,23 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
90
90
|
break;
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
|
-
[b, s, c, n,
|
|
94
|
-
),
|
|
93
|
+
[b, s, c, n, m]
|
|
94
|
+
), z = (e, t) => {
|
|
95
95
|
if (t.disabled || e.target.tagName === "INPUT") return;
|
|
96
96
|
const o = n.some((i) => i.value === t.value) ? n.filter((i) => i.value !== t.value) : [...n, t];
|
|
97
|
-
h(o), k(o.length),
|
|
98
|
-
},
|
|
97
|
+
h(o), k(o.length), m(o), M();
|
|
98
|
+
}, U = g(
|
|
99
99
|
(e) => {
|
|
100
100
|
const { checked: t, value: l } = e.target;
|
|
101
101
|
let o = [...n];
|
|
102
102
|
if (t) {
|
|
103
|
-
const i = c.find((
|
|
103
|
+
const i = c.find((H) => H.value === l);
|
|
104
104
|
i && o.push(i);
|
|
105
105
|
} else
|
|
106
106
|
o = o.filter((i) => i.value !== l);
|
|
107
|
-
h(o), k(o.length),
|
|
107
|
+
h(o), k(o.length), m(o);
|
|
108
108
|
},
|
|
109
|
-
[c, n,
|
|
109
|
+
[c, n, m]
|
|
110
110
|
);
|
|
111
111
|
return w(() => {
|
|
112
112
|
s && x(0);
|
|
@@ -128,7 +128,7 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
128
128
|
onClick: () => {
|
|
129
129
|
a(!s);
|
|
130
130
|
},
|
|
131
|
-
onKeyDown:
|
|
131
|
+
onKeyDown: T,
|
|
132
132
|
"aria-expanded": s,
|
|
133
133
|
"aria-haspopup": "listbox",
|
|
134
134
|
"aria-label": `${S} ${E}`,
|
|
@@ -142,7 +142,7 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
142
142
|
E
|
|
143
143
|
] }),
|
|
144
144
|
/* @__PURE__ */ u(
|
|
145
|
-
|
|
145
|
+
G,
|
|
146
146
|
{
|
|
147
147
|
className: v(r["multi-select-box-trigger-icon"], {
|
|
148
148
|
[r["multi-select-box-trigger-icon--open"]]: s
|
|
@@ -170,18 +170,18 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
170
170
|
[r["multi-select-box-listbox-option--disabled"]]: l
|
|
171
171
|
}),
|
|
172
172
|
role: "option",
|
|
173
|
-
onKeyDown:
|
|
174
|
-
onClick: (i) =>
|
|
173
|
+
onKeyDown: j,
|
|
174
|
+
onClick: (i) => z(i, { label: e, value: t, disabled: l }),
|
|
175
175
|
onMouseOver: () => x(o),
|
|
176
176
|
onFocus: () => x(o),
|
|
177
177
|
tabIndex: 0,
|
|
178
178
|
"aria-selected": n.some((i) => i.value === t),
|
|
179
179
|
children: /* @__PURE__ */ f("label", { htmlFor: e, className: r["multi-select-box-listbox-option-content"], tabIndex: -1, children: [
|
|
180
180
|
/* @__PURE__ */ u(
|
|
181
|
-
|
|
181
|
+
J,
|
|
182
182
|
{
|
|
183
183
|
id: `${e}-${_}`,
|
|
184
|
-
onChange:
|
|
184
|
+
onChange: U,
|
|
185
185
|
value: t,
|
|
186
186
|
tabIndex: -1,
|
|
187
187
|
disabled: l,
|
|
@@ -198,6 +198,6 @@ import '../../assets/MultiSelectBox.css';const r = {
|
|
|
198
198
|
] });
|
|
199
199
|
};
|
|
200
200
|
export {
|
|
201
|
-
|
|
201
|
+
te as MultiSelectBox
|
|
202
202
|
};
|
|
203
203
|
//# sourceMappingURL=MultiSelectBox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelectBox.js","sources":["../../../src/components/MultiSelectBox/MultiSelectBox.tsx"],"sourcesContent":["import { useRef, useState, useId, useEffect, useCallback } from 'react';\nimport { clsx } from 'clsx';\n\nimport type { KeyboardEvent, ChangeEvent, MouseEvent } from 'react';\n\nimport styles from './MultiSelectBox.module.css';\n\nimport { Icon } from 'components/Icon';\nimport { Checkbox } from 'components/Checkbox';\nimport { usePositionedFloaters } from 'components/hooks/usePositionedFloaters';\n\nexport type MultiSelectData = {\n label: string;\n value: string | number;\n disabled?: boolean;\n};\n\nexport interface MultiSelectBoxProps {\n /** Array of label, values pairs */\n selectData: MultiSelectData[];\n /** Retuns selected label, values */\n onChange: (values: MultiSelectData[]) => void;\n /** Array of label, value pairs that should be check by default */\n defaultSelectedItems?: MultiSelectData[];\n /** Suffix label in the selectbutton '[count] selected' */\n labelSuffix?: string;\n /** Disables the multiselect */\n disabled?: boolean;\n /** If true sets the option dropdown min-width to the width of the select button. */\n fullWidth?: boolean;\n /** Dark border. */\n darkBorder?: boolean;\n /** The max height of the options. */\n maxOptionHeight?: `${number}${'px' | 'rem'}`;\n /** `true` to align the right side of the options with the select box; otherwise, `false` to align on the left side. */\n optionPositionRight?: boolean;\n}\n\nexport const MultiSelectBox = ({\n selectData,\n onChange,\n defaultSelectedItems,\n labelSuffix = 'geselecteerd',\n disabled = false,\n fullWidth = false,\n darkBorder = false,\n maxOptionHeight,\n optionPositionRight,\n}: MultiSelectBoxProps) => {\n const multiselectboxId = useId();\n const [selectedItems, setSelectedItems] = useState<MultiSelectData[]>(defaultSelectedItems || []);\n const [selectedItemsCount, setSelectedItemsCount] = useState(defaultSelectedItems?.length || 0);\n const [isOpen, setIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const optionListRef = useRef<HTMLUListElement>(null);\n\n const [positionElement, setPositionElement] = useState<HTMLElement | null>(null);\n const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);\n const { style: positionStyle } = usePositionedFloaters(positionElement, referenceElement, {\n mouseEvent: 'click',\n position: 'bottomLeft',\n offset: 4,\n maxFixedHeight: maxOptionHeight,\n horizontalPosition: optionPositionRight ? 'right' : 'left',\n mobileBreakpoint: '28rem',\n fullWidth,\n });\n\n const onMouseEventOutside = useCallback(\n ({ target }: Event | MouseEvent) => {\n if (!target || !wrapperRef.current) return;\n\n if (!wrapperRef.current.contains(target as Node)) {\n setIsOpen(false);\n }\n },\n [setIsOpen]\n );\n\n const onTriggerKeyDown = useCallback(\n (event: KeyboardEvent<HTMLButtonElement>) => {\n switch (event.key) {\n case 'Enter':\n event.preventDefault();\n setIsOpen(true);\n break;\n case 'Escape':\n if (isOpen) {\n event.stopPropagation();\n setIsOpen(false);\n }\n break;\n default:\n break;\n }\n },\n [isOpen]\n );\n\n const onOptionKeyDown = useCallback(\n (event: KeyboardEvent<HTMLLIElement>) => {\n if (!isOpen) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActiveIndex((prev) => {\n let nextIndex = prev;\n do {\n nextIndex = nextIndex < selectData.length - 1 ? nextIndex + 1 : 0;\n } while (selectData[nextIndex]?.disabled);\n return nextIndex;\n });\n break;\n case 'ArrowUp':\n event.preventDefault();\n setActiveIndex((prev) => {\n let nextIndex = prev;\n do {\n nextIndex = nextIndex <= 0 ? selectData.length - 1 : nextIndex - 1;\n } while (selectData[nextIndex]?.disabled);\n return nextIndex;\n });\n break;\n case 'Enter': {\n event.preventDefault();\n const selectedItem = selectData[activeIndex];\n if (!selectedItem || selectedItem.disabled) break;\n const isAlreadySelected = selectedItems.some((item) => item.value === selectedItem.value);\n const updatedSelectedItems = isAlreadySelected\n ? selectedItems.filter((item) => item.value !== selectedItem.value)\n : [...selectedItems, selectedItem];\n\n setSelectedItems(updatedSelectedItems);\n setSelectedItemsCount(updatedSelectedItems.length);\n onChange(updatedSelectedItems);\n break;\n }\n case 'Tab':\n event.preventDefault();\n setIsOpen(false);\n break;\n case 'Escape':\n event.stopPropagation();\n setIsOpen(false);\n break;\n default:\n break;\n }\n },\n [activeIndex, isOpen, selectData, selectedItems, onChange]\n );\n\n const onOptionClick = (event: MouseEvent<HTMLLIElement>, option: MultiSelectData) => {\n if (option.disabled) return;\n\n // Prevent toggle if click originated from the checkbox\n if ((event.target as HTMLElement).tagName === 'INPUT') return;\n\n const isAlreadySelected = selectedItems.some((item) => item.value === option.value);\n const updatedSelectedItems = isAlreadySelected\n ? selectedItems.filter((item) => item.value !== option.value)\n : [...selectedItems, option];\n\n setSelectedItems(updatedSelectedItems);\n setSelectedItemsCount(updatedSelectedItems.length);\n onChange(updatedSelectedItems);\n };\n\n const handleSelect = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const { checked, value } = event.target;\n let updatedSelectedItems = [...selectedItems];\n\n if (checked) {\n const selectedItem = selectData.find((item) => item.value === value);\n if (selectedItem) {\n updatedSelectedItems.push(selectedItem);\n }\n } else {\n updatedSelectedItems = updatedSelectedItems.filter((item) => item.value !== value);\n }\n\n setSelectedItems(updatedSelectedItems);\n setSelectedItemsCount(updatedSelectedItems.length);\n onChange(updatedSelectedItems);\n },\n [selectData, selectedItems, onChange]\n );\n\n useEffect(() => {\n if (isOpen) {\n setActiveIndex(0);\n }\n }, [isOpen]);\n\n useEffect(() => {\n const activeOption = optionListRef.current?.children[activeIndex] as HTMLElement;\n activeOption?.focus();\n }, [activeIndex]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n document.addEventListener('click', onMouseEventOutside, true);\n document.addEventListener('scroll', onMouseEventOutside, true);\n\n return () => {\n document.removeEventListener('click', onMouseEventOutside, true);\n document.removeEventListener('scroll', onMouseEventOutside, true);\n };\n }, [onMouseEventOutside, isOpen]);\n\n return (\n <div className={styles['multi-select-box-wrapper']} ref={wrapperRef}>\n <button\n className={clsx(styles['multi-select-box-trigger'], {\n [styles['multi-select-box-trigger--darkBorder']]: darkBorder,\n })}\n type=\"button\"\n onClick={() => {\n setIsOpen(!isOpen);\n }}\n onKeyDown={onTriggerKeyDown}\n aria-expanded={isOpen}\n aria-haspopup=\"listbox\"\n aria-label={`${selectedItemsCount} ${labelSuffix}`}\n disabled={disabled}\n {...(isOpen && { 'aria-controls': multiselectboxId })}\n ref={setReferenceElement}\n >\n <span className={styles['multi-select-box-trigger-label']}>\n {selectedItemsCount} {labelSuffix}\n </span>\n <Icon\n className={clsx(styles['multi-select-box-trigger-icon'], {\n [styles['multi-select-box-trigger-icon--open']]: isOpen,\n })}\n name=\"CheveronDown\"\n size={16}\n />\n </button>\n\n <div\n id={multiselectboxId}\n className={clsx(styles['multi-select-box-listbox--wrapper'])}\n style={{ ...positionStyle.style, visibility: isOpen ? 'visible' : 'hidden' }}\n role=\"listbox\"\n ref={setPositionElement}\n >\n <ul className={styles['multi-select-box-listbox']} ref={optionListRef}>\n {selectData.map(({ label, value, disabled }, index) => (\n <li\n className={clsx(styles['multi-select-box-listbox-option'], {\n [styles['multi-select-box-listbox-option--active']]: index === activeIndex,\n [styles['multi-select-box-listbox-option--disabled']]: disabled,\n })}\n key={value}\n role=\"option\"\n onKeyDown={onOptionKeyDown}\n onClick={(event) => onOptionClick(event, { label, value, disabled })}\n onMouseOver={() => setActiveIndex(index)}\n onFocus={() => setActiveIndex(index)}\n tabIndex={0}\n aria-selected={selectedItems.some((item) => item.value === value)}\n >\n <label htmlFor={label} className={styles['multi-select-box-listbox-option-content']} tabIndex={-1}>\n <Checkbox\n id={`${label}-${multiselectboxId}`}\n onChange={handleSelect}\n value={value}\n tabIndex={-1}\n disabled={disabled}\n checked={selectedItems.some((item) => item.value === value)}\n />\n <span>{label}</span>\n </label>\n </li>\n ))}\n </ul>\n </div>\n </div>\n );\n};\n"],"names":["MultiSelectBox","selectData","onChange","defaultSelectedItems","labelSuffix","disabled","fullWidth","darkBorder","maxOptionHeight","optionPositionRight","multiselectboxId","useId","selectedItems","setSelectedItems","useState","selectedItemsCount","setSelectedItemsCount","isOpen","setIsOpen","activeIndex","setActiveIndex","wrapperRef","useRef","optionListRef","positionElement","setPositionElement","referenceElement","setReferenceElement","positionStyle","usePositionedFloaters","onMouseEventOutside","useCallback","target","onTriggerKeyDown","event","onOptionKeyDown","prev","nextIndex","selectedItem","updatedSelectedItems","item","onOptionClick","option","handleSelect","checked","value","useEffect","styles","jsxs","clsx","jsx","Icon","label","index","Checkbox"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MultiSelectBox.js","sources":["../../../src/components/MultiSelectBox/MultiSelectBox.tsx"],"sourcesContent":["import { useRef, useState, useId, useEffect, useCallback } from 'react';\nimport { clsx } from 'clsx';\n\nimport type { KeyboardEvent, ChangeEvent, MouseEvent } from 'react';\n\nimport styles from './MultiSelectBox.module.css';\n\nimport { Icon } from 'components/Icon';\nimport { Checkbox } from 'components/Checkbox';\nimport { usePositionedFloaters } from 'components/hooks/usePositionedFloaters';\n\nexport type MultiSelectData = {\n label: string;\n value: string | number;\n disabled?: boolean;\n};\n\nexport interface MultiSelectBoxProps {\n /** Array of label, values pairs */\n selectData: MultiSelectData[];\n /** Retuns selected label, values */\n onChange: (values: MultiSelectData[]) => void;\n /** Array of label, value pairs that should be check by default */\n defaultSelectedItems?: MultiSelectData[];\n /** Suffix label in the selectbutton '[count] selected' */\n labelSuffix?: string;\n /** Disables the multiselect */\n disabled?: boolean;\n /** If true sets the option dropdown min-width to the width of the select button. */\n fullWidth?: boolean;\n /** Dark border. */\n darkBorder?: boolean;\n /** The max height of the options. */\n maxOptionHeight?: `${number}${'px' | 'rem'}`;\n /** `true` to align the right side of the options with the select box; otherwise, `false` to align on the left side. */\n optionPositionRight?: boolean;\n}\n\nexport const MultiSelectBox = ({\n selectData,\n onChange,\n defaultSelectedItems,\n labelSuffix = 'geselecteerd',\n disabled = false,\n fullWidth = false,\n darkBorder = false,\n maxOptionHeight,\n optionPositionRight,\n}: MultiSelectBoxProps) => {\n const multiselectboxId = useId();\n const [selectedItems, setSelectedItems] = useState<MultiSelectData[]>(defaultSelectedItems || []);\n const [selectedItemsCount, setSelectedItemsCount] = useState(defaultSelectedItems?.length || 0);\n const [isOpen, setIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const optionListRef = useRef<HTMLUListElement>(null);\n\n const [positionElement, setPositionElement] = useState<HTMLElement | null>(null);\n const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);\n const { style: positionStyle, updatePosition } = usePositionedFloaters(positionElement, referenceElement, {\n mouseEvent: 'click',\n position: 'bottomLeft',\n offset: 4,\n maxFixedHeight: maxOptionHeight,\n horizontalPosition: optionPositionRight ? 'right' : 'left',\n mobileBreakpoint: '28rem',\n fullWidth,\n });\n\n const onMouseEventOutside = useCallback(\n ({ target }: Event | MouseEvent) => {\n if (!target || !wrapperRef.current) return;\n\n if (!wrapperRef.current.contains(target as Node)) {\n setIsOpen(false);\n }\n },\n [setIsOpen]\n );\n\n const onTriggerKeyDown = useCallback(\n (event: KeyboardEvent<HTMLButtonElement>) => {\n switch (event.key) {\n case 'Enter':\n event.preventDefault();\n setIsOpen(true);\n break;\n case 'Escape':\n if (isOpen) {\n event.stopPropagation();\n setIsOpen(false);\n }\n break;\n default:\n break;\n }\n },\n [isOpen]\n );\n\n const onOptionKeyDown = useCallback(\n (event: KeyboardEvent<HTMLLIElement>) => {\n if (!isOpen) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActiveIndex((prev) => {\n let nextIndex = prev;\n do {\n nextIndex = nextIndex < selectData.length - 1 ? nextIndex + 1 : 0;\n } while (selectData[nextIndex]?.disabled);\n return nextIndex;\n });\n break;\n case 'ArrowUp':\n event.preventDefault();\n setActiveIndex((prev) => {\n let nextIndex = prev;\n do {\n nextIndex = nextIndex <= 0 ? selectData.length - 1 : nextIndex - 1;\n } while (selectData[nextIndex]?.disabled);\n return nextIndex;\n });\n break;\n case 'Enter': {\n event.preventDefault();\n const selectedItem = selectData[activeIndex];\n if (!selectedItem || selectedItem.disabled) break;\n const isAlreadySelected = selectedItems.some((item) => item.value === selectedItem.value);\n const updatedSelectedItems = isAlreadySelected\n ? selectedItems.filter((item) => item.value !== selectedItem.value)\n : [...selectedItems, selectedItem];\n\n setSelectedItems(updatedSelectedItems);\n setSelectedItemsCount(updatedSelectedItems.length);\n onChange(updatedSelectedItems);\n break;\n }\n case 'Tab':\n event.preventDefault();\n setIsOpen(false);\n break;\n case 'Escape':\n event.stopPropagation();\n setIsOpen(false);\n break;\n default:\n break;\n }\n },\n [activeIndex, isOpen, selectData, selectedItems, onChange]\n );\n\n const onOptionClick = (event: MouseEvent<HTMLLIElement>, option: MultiSelectData) => {\n if (option.disabled) return;\n\n // Prevent toggle if click originated from the checkbox\n if ((event.target as HTMLElement).tagName === 'INPUT') return;\n\n const isAlreadySelected = selectedItems.some((item) => item.value === option.value);\n const updatedSelectedItems = isAlreadySelected\n ? selectedItems.filter((item) => item.value !== option.value)\n : [...selectedItems, option];\n\n setSelectedItems(updatedSelectedItems);\n setSelectedItemsCount(updatedSelectedItems.length);\n onChange(updatedSelectedItems);\n updatePosition();\n };\n\n const handleSelect = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const { checked, value } = event.target;\n let updatedSelectedItems = [...selectedItems];\n\n if (checked) {\n const selectedItem = selectData.find((item) => item.value === value);\n if (selectedItem) {\n updatedSelectedItems.push(selectedItem);\n }\n } else {\n updatedSelectedItems = updatedSelectedItems.filter((item) => item.value !== value);\n }\n\n setSelectedItems(updatedSelectedItems);\n setSelectedItemsCount(updatedSelectedItems.length);\n onChange(updatedSelectedItems);\n },\n [selectData, selectedItems, onChange]\n );\n\n useEffect(() => {\n if (isOpen) {\n setActiveIndex(0);\n }\n }, [isOpen]);\n\n useEffect(() => {\n const activeOption = optionListRef.current?.children[activeIndex] as HTMLElement;\n activeOption?.focus();\n }, [activeIndex]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n document.addEventListener('click', onMouseEventOutside, true);\n document.addEventListener('scroll', onMouseEventOutside, true);\n\n return () => {\n document.removeEventListener('click', onMouseEventOutside, true);\n document.removeEventListener('scroll', onMouseEventOutside, true);\n };\n }, [onMouseEventOutside, isOpen]);\n\n return (\n <div className={styles['multi-select-box-wrapper']} ref={wrapperRef}>\n <button\n className={clsx(styles['multi-select-box-trigger'], {\n [styles['multi-select-box-trigger--darkBorder']]: darkBorder,\n })}\n type=\"button\"\n onClick={() => {\n setIsOpen(!isOpen);\n }}\n onKeyDown={onTriggerKeyDown}\n aria-expanded={isOpen}\n aria-haspopup=\"listbox\"\n aria-label={`${selectedItemsCount} ${labelSuffix}`}\n disabled={disabled}\n {...(isOpen && { 'aria-controls': multiselectboxId })}\n ref={setReferenceElement}\n >\n <span className={styles['multi-select-box-trigger-label']}>\n {selectedItemsCount} {labelSuffix}\n </span>\n <Icon\n className={clsx(styles['multi-select-box-trigger-icon'], {\n [styles['multi-select-box-trigger-icon--open']]: isOpen,\n })}\n name=\"CheveronDown\"\n size={16}\n />\n </button>\n\n <div\n id={multiselectboxId}\n className={clsx(styles['multi-select-box-listbox--wrapper'])}\n style={{ ...positionStyle.style, visibility: isOpen ? 'visible' : 'hidden' }}\n role=\"listbox\"\n ref={setPositionElement}\n >\n <ul className={styles['multi-select-box-listbox']} ref={optionListRef}>\n {selectData.map(({ label, value, disabled }, index) => (\n <li\n className={clsx(styles['multi-select-box-listbox-option'], {\n [styles['multi-select-box-listbox-option--active']]: index === activeIndex,\n [styles['multi-select-box-listbox-option--disabled']]: disabled,\n })}\n key={value}\n role=\"option\"\n onKeyDown={onOptionKeyDown}\n onClick={(event) => onOptionClick(event, { label, value, disabled })}\n onMouseOver={() => setActiveIndex(index)}\n onFocus={() => setActiveIndex(index)}\n tabIndex={0}\n aria-selected={selectedItems.some((item) => item.value === value)}\n >\n <label htmlFor={label} className={styles['multi-select-box-listbox-option-content']} tabIndex={-1}>\n <Checkbox\n id={`${label}-${multiselectboxId}`}\n onChange={handleSelect}\n value={value}\n tabIndex={-1}\n disabled={disabled}\n checked={selectedItems.some((item) => item.value === value)}\n />\n <span>{label}</span>\n </label>\n </li>\n ))}\n </ul>\n </div>\n </div>\n );\n};\n"],"names":["MultiSelectBox","selectData","onChange","defaultSelectedItems","labelSuffix","disabled","fullWidth","darkBorder","maxOptionHeight","optionPositionRight","multiselectboxId","useId","selectedItems","setSelectedItems","useState","selectedItemsCount","setSelectedItemsCount","isOpen","setIsOpen","activeIndex","setActiveIndex","wrapperRef","useRef","optionListRef","positionElement","setPositionElement","referenceElement","setReferenceElement","positionStyle","updatePosition","usePositionedFloaters","onMouseEventOutside","useCallback","target","onTriggerKeyDown","event","onOptionKeyDown","prev","nextIndex","selectedItem","updatedSelectedItems","item","onOptionClick","option","handleSelect","checked","value","useEffect","styles","jsxs","clsx","jsx","Icon","label","index","Checkbox"],"mappings":";;;;;;;;;;;;;;;;;;;GAsCaA,KAAiB,CAAC;AAAA,EAC7B,YAAAC;AAAA,EACA,UAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,UAAAC,IAAW;AAAA,EACX,WAAAC,IAAY;AAAA,EACZ,YAAAC,IAAa;AAAA,EACb,iBAAAC;AAAA,EACA,qBAAAC;AACF,MAA2B;AACzB,QAAMC,IAAmBC,EAAA,GACnB,CAACC,GAAeC,CAAgB,IAAIC,EAA4BX,KAAwB,CAAA,CAAE,GAC1F,CAACY,GAAoBC,CAAqB,IAAIF,EAASX,GAAsB,UAAU,CAAC,GACxF,CAACc,GAAQC,CAAS,IAAIJ,EAAS,EAAK,GACpC,CAACK,GAAaC,CAAc,IAAIN,EAAS,EAAE,GAC3CO,IAAaC,EAAuB,IAAI,GACxCC,IAAgBD,EAAyB,IAAI,GAE7C,CAACE,GAAiBC,CAAkB,IAAIX,EAA6B,IAAI,GACzE,CAACY,GAAkBC,CAAmB,IAAIb,EAAmC,IAAI,GACjF,EAAE,OAAOc,GAAe,gBAAAC,MAAmBC,EAAsBN,GAAiBE,GAAkB;AAAA,IACxG,YAAY;AAAA,IAEZ,QAAQ;AAAA,IACR,gBAAgBlB;AAAA,IAChB,oBAAoBC,IAAsB,UAAU;AAAA,IACpD,kBAAkB;AAAA,IAClB,WAAAH;AAAA,EAAA,CACD,GAEKyB,IAAsBC;AAAA,IAC1B,CAAC,EAAE,QAAAC,EAAA,MAAiC;AAClC,MAAI,CAACA,KAAU,CAACZ,EAAW,WAEtBA,EAAW,QAAQ,SAASY,CAAc,KAC7Cf,EAAU,EAAK;AAAA,IACjB;AAAA,IAEF,CAACA,CAAS;AAAA,EAAA,GAGNgB,IAAmBF;AAAA,IACvB,CAACG,MAA4C;AAC3C,cAAQA,EAAM,KAAA;AAAA,QACZ,KAAK;AACH,UAAAA,EAAM,eAAA,GACNjB,EAAU,EAAI;AACd;AAAA,QACF,KAAK;AACH,UAAID,MACFkB,EAAM,gBAAA,GACNjB,EAAU,EAAK;AAEjB;AAAA,MAEA;AAAA,IACJ;AAAA,IAEF,CAACD,CAAM;AAAA,EAAA,GAGHmB,IAAkBJ;AAAA,IACtB,CAACG,MAAwC;AACvC,UAAKlB;AAEL,gBAAQkB,EAAM,KAAA;AAAA,UACZ,KAAK;AACH,YAAAA,EAAM,eAAA,GACNf,EAAe,CAACiB,MAAS;AACvB,kBAAIC,IAAYD;AAChB;AACE,gBAAAC,IAAYA,IAAYrC,EAAW,SAAS,IAAIqC,IAAY,IAAI;AAAA,qBACzDrC,EAAWqC,CAAS,GAAG;AAChC,qBAAOA;AAAA,YAAA,CACR;AACD;AAAA,UACF,KAAK;AACH,YAAAH,EAAM,eAAA,GACNf,EAAe,CAACiB,MAAS;AACvB,kBAAIC,IAAYD;AAChB;AACE,gBAAAC,IAAYA,KAAa,IAAIrC,EAAW,SAAS,IAAIqC,IAAY;AAAA,qBAC1DrC,EAAWqC,CAAS,GAAG;AAChC,qBAAOA;AAAA,YAAA,CACR;AACD;AAAA,UACF,KAAK,SAAS;AACZ,YAAAH,EAAM,eAAA;AACN,kBAAMI,IAAetC,EAAWkB,CAAW;AAC3C,gBAAI,CAACoB,KAAgBA,EAAa,SAAU;AAE5C,kBAAMC,IADoB5B,EAAc,KAAK,CAAC6B,MAASA,EAAK,UAAUF,EAAa,KAAK,IAEpF3B,EAAc,OAAO,CAAC6B,MAASA,EAAK,UAAUF,EAAa,KAAK,IAChE,CAAC,GAAG3B,GAAe2B,CAAY;AAEnC,YAAA1B,EAAiB2B,CAAoB,GACrCxB,EAAsBwB,EAAqB,MAAM,GACjDtC,EAASsC,CAAoB;AAC7B;AAAA,UAAA;AAAA,UAEF,KAAK;AACH,YAAAL,EAAM,eAAA,GACNjB,EAAU,EAAK;AACf;AAAA,UACF,KAAK;AACH,YAAAiB,EAAM,gBAAA,GACNjB,EAAU,EAAK;AACf;AAAA,QAEA;AAAA,IACJ;AAAA,IAEF,CAACC,GAAaF,GAAQhB,GAAYW,GAAeV,CAAQ;AAAA,EAAA,GAGrDwC,IAAgB,CAACP,GAAkCQ,MAA4B;AAInF,QAHIA,EAAO,YAGNR,EAAM,OAAuB,YAAY,QAAS;AAGvD,UAAMK,IADoB5B,EAAc,KAAK,CAAC6B,MAASA,EAAK,UAAUE,EAAO,KAAK,IAE9E/B,EAAc,OAAO,CAAC6B,MAASA,EAAK,UAAUE,EAAO,KAAK,IAC1D,CAAC,GAAG/B,GAAe+B,CAAM;AAE7B,IAAA9B,EAAiB2B,CAAoB,GACrCxB,EAAsBwB,EAAqB,MAAM,GACjDtC,EAASsC,CAAoB,GAC7BX,EAAA;AAAA,EAAe,GAGXe,IAAeZ;AAAA,IACnB,CAACG,MAAyC;AACxC,YAAM,EAAE,SAAAU,GAAS,OAAAC,EAAA,IAAUX,EAAM;AACjC,UAAIK,IAAuB,CAAC,GAAG5B,CAAa;AAE5C,UAAIiC,GAAS;AACX,cAAMN,IAAetC,EAAW,KAAK,CAACwC,MAASA,EAAK,UAAUK,CAAK;AACnE,QAAIP,KACFC,EAAqB,KAAKD,CAAY;AAAA,MACxC;AAEA,QAAAC,IAAuBA,EAAqB,OAAO,CAACC,MAASA,EAAK,UAAUK,CAAK;AAGnF,MAAAjC,EAAiB2B,CAAoB,GACrCxB,EAAsBwB,EAAqB,MAAM,GACjDtC,EAASsC,CAAoB;AAAA,IAAA;AAAA,IAE/B,CAACvC,GAAYW,GAAeV,CAAQ;AAAA,EAAA;AAGtC,SAAA6C,EAAU,MAAM;AACd,IAAI9B,KACFG,EAAe,CAAC;AAAA,EAClB,GACC,CAACH,CAAM,CAAC,GAEX8B,EAAU,MAAM;AAEd,IADqBxB,EAAc,SAAS,SAASJ,CAAW,GAClD,MAAA;AAAA,EAAM,GACnB,CAACA,CAAW,CAAC,GAEhB4B,EAAU,MAAM;AACd,QAAK9B;AAEL,sBAAS,iBAAiB,SAASc,GAAqB,EAAI,GAC5D,SAAS,iBAAiB,UAAUA,GAAqB,EAAI,GAEtD,MAAM;AACX,iBAAS,oBAAoB,SAASA,GAAqB,EAAI,GAC/D,SAAS,oBAAoB,UAAUA,GAAqB,EAAI;AAAA,MAAA;AAAA,EAClE,GACC,CAACA,GAAqBd,CAAM,CAAC,qBAG7B,OAAA,EAAI,WAAW+B,EAAO,0BAA0B,GAAG,KAAK3B,GACvD,UAAA;AAAA,IAAA,gBAAA4B;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWC,EAAKF,EAAO,0BAA0B,GAAG;AAAA,UAClD,CAACA,EAAO,sCAAsC,CAAC,GAAGzC;AAAA,QAAA,CACnD;AAAA,QACD,MAAK;AAAA,QACL,SAAS,MAAM;AACb,UAAAW,EAAU,CAACD,CAAM;AAAA,QAAA;AAAA,QAEnB,WAAWiB;AAAA,QACX,iBAAejB;AAAA,QACf,iBAAc;AAAA,QACd,cAAY,GAAGF,CAAkB,IAAIX,CAAW;AAAA,QAChD,UAAAC;AAAA,QACC,GAAIY,KAAU,EAAE,iBAAiBP,EAAA;AAAA,QAClC,KAAKiB;AAAA,QAEL,UAAA;AAAA,UAAA,gBAAAsB,EAAC,QAAA,EAAK,WAAWD,EAAO,gCAAgC,GACrD,UAAA;AAAA,YAAAjC;AAAA,YAAmB;AAAA,YAAEX;AAAA,UAAA,GACxB;AAAA,UACA,gBAAA+C;AAAA,YAACC;AAAA,YAAA;AAAA,cACC,WAAWF,EAAKF,EAAO,+BAA+B,GAAG;AAAA,gBACvD,CAACA,EAAO,qCAAqC,CAAC,GAAG/B;AAAA,cAAA,CAClD;AAAA,cACD,MAAK;AAAA,cACL,MAAM;AAAA,YAAA;AAAA,UAAA;AAAA,QACR;AAAA,MAAA;AAAA,IAAA;AAAA,IAGF,gBAAAkC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,IAAIzC;AAAA,QACJ,WAAWwC,EAAKF,EAAO,mCAAmC,CAAC;AAAA,QAC3D,OAAO,EAAE,GAAGpB,EAAc,OAAO,YAAYX,IAAS,YAAY,SAAA;AAAA,QAClE,MAAK;AAAA,QACL,KAAKQ;AAAA,QAEL,4BAAC,MAAA,EAAG,WAAWuB,EAAO,0BAA0B,GAAG,KAAKzB,GACrD,UAAAtB,EAAW,IAAI,CAAC,EAAE,OAAAoD,GAAO,OAAAP,GAAO,UAAAzC,KAAYiD,MAC3C,gBAAAH;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWD,EAAKF,EAAO,iCAAiC,GAAG;AAAA,cACzD,CAACA,EAAO,yCAAyC,CAAC,GAAGM,MAAUnC;AAAA,cAC/D,CAAC6B,EAAO,2CAA2C,CAAC,GAAG3C;AAAAA,YAAA,CACxD;AAAA,YAED,MAAK;AAAA,YACL,WAAW+B;AAAA,YACX,SAAS,CAACD,MAAUO,EAAcP,GAAO,EAAE,OAAAkB,GAAO,OAAAP,GAAO,UAAAzC,GAAU;AAAA,YACnE,aAAa,MAAMe,EAAekC,CAAK;AAAA,YACvC,SAAS,MAAMlC,EAAekC,CAAK;AAAA,YACnC,UAAU;AAAA,YACV,iBAAe1C,EAAc,KAAK,CAAC6B,MAASA,EAAK,UAAUK,CAAK;AAAA,YAEhE,UAAA,gBAAAG,EAAC,WAAM,SAASI,GAAO,WAAWL,EAAO,yCAAyC,GAAG,UAAU,IAC7F,UAAA;AAAA,cAAA,gBAAAG;AAAA,gBAACI;AAAA,gBAAA;AAAA,kBACC,IAAI,GAAGF,CAAK,IAAI3C,CAAgB;AAAA,kBAChC,UAAUkC;AAAA,kBACV,OAAAE;AAAA,kBACA,UAAU;AAAA,kBACV,UAAUzC;AAAAA,kBACV,SAASO,EAAc,KAAK,CAAC6B,MAASA,EAAK,UAAUK,CAAK;AAAA,gBAAA;AAAA,cAAA;AAAA,cAE5D,gBAAAK,EAAC,UAAM,UAAAE,EAAA,CAAM;AAAA,YAAA,EAAA,CACf;AAAA,UAAA;AAAA,UAnBKP;AAAA,QAAA,CAqBR,EAAA,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EACF,GACF;AAEJ;"}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import { jsxs as r, jsx as _ } from "react/jsx-runtime";
|
|
2
|
-
import { useRef as
|
|
3
|
-
import { c as
|
|
2
|
+
import { useRef as h, useState as u } from "react";
|
|
3
|
+
import { c as p } from "../../clsx-OuTLNxxd.js";
|
|
4
4
|
import '../../assets/TextArea.css';const e = {
|
|
5
|
-
"text-area__wrapper": "_text-
|
|
6
|
-
"text-area__header": "_text-
|
|
7
|
-
"text-area__label-wrapper": "_text-area__label-
|
|
8
|
-
"text-area__label": "_text-
|
|
9
|
-
"text-area__sub-label": "_text-area__sub-
|
|
10
|
-
"text-area__word-count": "_text-area__word-
|
|
11
|
-
"text-area__word-count--alert": "_text-area__word-count--
|
|
12
|
-
"text-area": "_text-
|
|
5
|
+
"text-area__wrapper": "_text-area__wrapper_2mhm2_1",
|
|
6
|
+
"text-area__header": "_text-area__header_2mhm2_7",
|
|
7
|
+
"text-area__label-wrapper": "_text-area__label-wrapper_2mhm2_13",
|
|
8
|
+
"text-area__label": "_text-area__label_2mhm2_13",
|
|
9
|
+
"text-area__sub-label": "_text-area__sub-label_2mhm2_25",
|
|
10
|
+
"text-area__word-count": "_text-area__word-count_2mhm2_30",
|
|
11
|
+
"text-area__word-count--alert": "_text-area__word-count--alert_2mhm2_35",
|
|
12
|
+
"text-area": "_text-area_2mhm2_1"
|
|
13
13
|
};
|
|
14
|
-
function b({ onChange:
|
|
15
|
-
const t =
|
|
16
|
-
t.current && (t.current.style.height = "auto", t.current.style.height = `${t.current.scrollHeight}px`,
|
|
14
|
+
function b({ onChange: o, label: l, subLabel: n, maxCharacters: a = 0, defaultValue: s = "" }) {
|
|
15
|
+
const t = h(null), [c, x] = u(s.length), m = () => {
|
|
16
|
+
t.current && (t.current.style.height = "auto", t.current.style.height = `${t.current.scrollHeight}px`, x(t.current.value.length), o(t.current.value.trim()));
|
|
17
17
|
};
|
|
18
18
|
return /* @__PURE__ */ r("div", { className: e["text-area__wrapper"], children: [
|
|
19
19
|
(l || a > 0) && /* @__PURE__ */ r("div", { className: e["text-area__header"], children: [
|
|
20
20
|
/* @__PURE__ */ r("span", { className: e["text-area__label-wrapper"], children: [
|
|
21
21
|
l && /* @__PURE__ */ _("span", { className: e["text-area__label"], children: l }),
|
|
22
|
-
|
|
22
|
+
n && /* @__PURE__ */ _("span", { className: e["text-area__sub-label"], children: n })
|
|
23
23
|
] }),
|
|
24
24
|
a > 0 && /* @__PURE__ */ r("div", { className: e["text-area__word-count"], children: [
|
|
25
|
-
/* @__PURE__ */ _("span", { className:
|
|
25
|
+
/* @__PURE__ */ _("span", { className: p({ [e["text-area__word-count--alert"]]: c === a }), children: c }),
|
|
26
26
|
" / ",
|
|
27
27
|
a
|
|
28
28
|
] })
|
|
@@ -33,8 +33,8 @@ function b({ onChange: u, label: l, subLabel: s, maxCharacters: a = 0, defaultVa
|
|
|
33
33
|
ref: t,
|
|
34
34
|
className: e["text-area"],
|
|
35
35
|
maxLength: a > 0 ? a : void 0,
|
|
36
|
-
onInput:
|
|
37
|
-
defaultValue:
|
|
36
|
+
onInput: m,
|
|
37
|
+
defaultValue: s
|
|
38
38
|
}
|
|
39
39
|
)
|
|
40
40
|
] });
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { useState as
|
|
1
|
+
import { useState as H, useEffect as P } from "react";
|
|
2
2
|
import { useDebounce as $ } from "./useDebounce.js";
|
|
3
3
|
const a = 10, F = 90, r = 300, y = 0, B = 768, k = 2;
|
|
4
4
|
function M(c, n, i) {
|
|
5
|
-
const [m,
|
|
5
|
+
const [m, p] = H(!1), w = {
|
|
6
6
|
inset: "0 auto auto 0",
|
|
7
7
|
opacity: 0,
|
|
8
8
|
maxHeight: "100%",
|
|
@@ -11,30 +11,30 @@ function M(c, n, i) {
|
|
|
11
11
|
overflowX: "hidden",
|
|
12
12
|
overflowY: "auto",
|
|
13
13
|
margin: "0rem"
|
|
14
|
-
}, [l, v] =
|
|
14
|
+
}, [l, v] = H(w), h = (t) => {
|
|
15
15
|
const e = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
16
16
|
return t.indexOf("rem") !== -1 ? parseFloat(t) * e : parseFloat(t);
|
|
17
|
-
},
|
|
17
|
+
}, b = (t, e) => {
|
|
18
18
|
if (!t) return 0;
|
|
19
19
|
const o = e === "bottom" ? window.innerHeight - t.bottom - i.offset - a : t.top - i.offset - a;
|
|
20
20
|
return !i.maxFixedHeight || h(i.maxFixedHeight) > o ? o : h(i.maxFixedHeight);
|
|
21
|
-
},
|
|
21
|
+
}, E = (t, e) => {
|
|
22
22
|
if (!t) return 0;
|
|
23
23
|
const o = e === "left" ? window.innerWidth - t.left - a : t.right - a;
|
|
24
24
|
return o <= r ? r : o;
|
|
25
|
-
},
|
|
25
|
+
}, W = (t, e, o) => o ? `${t.left - Math.abs(e.width - t.width) / k}px` : `${t.left}px`, f = () => {
|
|
26
26
|
const t = c?.getBoundingClientRect(), e = n?.getBoundingClientRect();
|
|
27
27
|
let o = "bottom", d = "left";
|
|
28
|
-
const
|
|
28
|
+
const L = window.matchMedia(
|
|
29
29
|
`(max-width: ${i.mobileBreakpoint ? h(i.mobileBreakpoint) : B}px)`
|
|
30
30
|
).matches;
|
|
31
|
-
return !e || !t ? w : (window.innerHeight - e.bottom - a < F && (o = "top"), (window.innerWidth - e.left - a < r || i.horizontalPosition === "right") && !
|
|
31
|
+
return !e || !t ? w : (window.innerHeight - e.bottom - a < F && (o = "top"), (window.innerWidth - e.left - a < r || i.horizontalPosition === "right") && !L && (d = "right"), {
|
|
32
32
|
inset: `${o === "bottom" ? e[o] + "px" : "auto"}
|
|
33
33
|
${d === "right" ? window.innerWidth - e[d] + "px" : "auto"}
|
|
34
34
|
${o === "top" ? window.innerHeight - e[o] + "px" : "auto"}
|
|
35
|
-
${d === "left" ?
|
|
36
|
-
maxHeight: `${
|
|
37
|
-
maxWidth: `${
|
|
35
|
+
${d === "left" ? W(e, t, L) : "auto"}`,
|
|
36
|
+
maxHeight: `${b(e, o)}px`,
|
|
37
|
+
maxWidth: `${E(e, d)}px`,
|
|
38
38
|
minWidth: i.fullWidth ? e.width : r,
|
|
39
39
|
overflowX: "hidden",
|
|
40
40
|
overflowY: "auto",
|
|
@@ -45,22 +45,23 @@ function M(c, n, i) {
|
|
|
45
45
|
v({
|
|
46
46
|
...l,
|
|
47
47
|
...f()
|
|
48
|
-
}),
|
|
49
|
-
},
|
|
48
|
+
}), p(!0);
|
|
49
|
+
}, x = () => {
|
|
50
50
|
m && v({
|
|
51
51
|
...l,
|
|
52
52
|
...f()
|
|
53
53
|
});
|
|
54
54
|
}, s = (t) => {
|
|
55
55
|
!n || n.contains(t.target) || !c || c.contains(t.target);
|
|
56
|
-
},
|
|
57
|
-
return P(() => (n !== null && (i.mouseEvent === "click" ? n.addEventListener("click", u) : (n.addEventListener("mouseenter", u), n.addEventListener("mouseleave", s)), document.addEventListener("mousedown", s), document.addEventListener("touchstart", s), window.addEventListener("resize",
|
|
58
|
-
n !== null && (i.mouseEvent === "click" ? n.removeEventListener("click", u) : (n.removeEventListener("mouseenter", u), n.removeEventListener("mouseleave", s)), document.removeEventListener("mousedown", s), document.removeEventListener("touchstart", s), window.removeEventListener("resize",
|
|
56
|
+
}, g = $(x, y);
|
|
57
|
+
return P(() => (n !== null && (i.mouseEvent === "click" ? n.addEventListener("click", u) : (n.addEventListener("mouseenter", u), n.addEventListener("mouseleave", s)), document.addEventListener("mousedown", s), document.addEventListener("touchstart", s), window.addEventListener("resize", g)), () => {
|
|
58
|
+
n !== null && (i.mouseEvent === "click" ? n.removeEventListener("click", u) : (n.removeEventListener("mouseenter", u), n.removeEventListener("mouseleave", s)), document.removeEventListener("mousedown", s), document.removeEventListener("touchstart", s), window.removeEventListener("resize", g));
|
|
59
59
|
})), {
|
|
60
60
|
style: {
|
|
61
61
|
style: l
|
|
62
62
|
},
|
|
63
|
-
status: m
|
|
63
|
+
status: m,
|
|
64
|
+
updatePosition: x
|
|
64
65
|
};
|
|
65
66
|
}
|
|
66
67
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePositionedFloaters.js","sources":["../../../src/components/hooks/usePositionedFloaters.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nimport { useDebounce } from './useDebounce';\n\ninterface positionProps {\n style: {\n style: {\n inset: string;\n };\n };\n status: boolean;\n}\n\ninterface optionProps {\n mouseEvent: 'click' | 'hover';\n position: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';\n offset: number;\n maxFixedHeight?: `${number}${'px' | 'rem'}`;\n horizontalPosition?: 'left' | 'right';\n mobileBreakpoint?: `${number}${'px' | 'rem'}`;\n fullWidth: boolean;\n}\n\nconst BODY_PADDING = 10;\nconst MIN_HEIGHT = 90;\nconst MIN_WIDTH = 300;\nconst DEBOUNCE_DELAY = 0;\nconst MOBILE_BREAKPOINT = 768;\nconst HALF = 2;\n\nexport function usePositionedFloaters<T extends HTMLElement = HTMLElement>(\n positionedElement: T | null,\n referenceElement: T | null,\n options: optionProps\n): positionProps {\n const [status, setStatus] = useState(false);\n const defaultStyle = {\n inset: '0 auto auto 0',\n opacity: 0,\n maxHeight: '100%',\n maxWidth: '100%',\n minWidth: MIN_WIDTH,\n overflowX: 'hidden',\n overflowY: 'auto',\n margin: '0rem',\n };\n\n const [style, setStyle] = useState(defaultStyle);\n\n const sizeToPx = (size: `${number}${'px' | 'rem'}`): number => {\n const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return size.indexOf('rem') !== -1 ? parseFloat(size) * rootFontSize : parseFloat(size);\n };\n\n const setHeight = (refRect: DOMRect, pos: string): number => {\n if (!refRect) return 0;\n\n const _maxHeight =\n pos === 'bottom'\n ? window.innerHeight - refRect.bottom - options.offset - BODY_PADDING\n : refRect.top - options.offset - BODY_PADDING;\n\n return !options.maxFixedHeight || sizeToPx(options.maxFixedHeight) > _maxHeight\n ? _maxHeight\n : sizeToPx(options.maxFixedHeight);\n };\n\n const setWidth = (refRect: DOMRect, pos: string): number => {\n if (!refRect) return 0;\n\n const _availableWidth =\n pos === 'left' ? window.innerWidth - refRect.left - BODY_PADDING : refRect.right - BODY_PADDING;\n\n return _availableWidth <= MIN_WIDTH ? MIN_WIDTH : _availableWidth;\n };\n\n const setLeft = (refRect: DOMRect, posRect: DOMRect, isMobile: boolean) => {\n if (isMobile) {\n return `${refRect.left - Math.abs(posRect.width - refRect.width) / HALF}px`;\n } else {\n return `${refRect.left}px`;\n }\n };\n\n const calcPosition = (): typeof defaultStyle => {\n const positionedRect = (positionedElement as HTMLElement | null)?.getBoundingClientRect();\n const referenceRect = (referenceElement as HTMLElement | null)?.getBoundingClientRect();\n let yPos = 'bottom';\n let xPos = 'left';\n\n const isMobile = window.matchMedia(\n `(max-width: ${options.mobileBreakpoint ? sizeToPx(options.mobileBreakpoint) : MOBILE_BREAKPOINT}px)`\n ).matches;\n\n if (!referenceRect || !positionedRect) {\n return defaultStyle;\n }\n\n if (window.innerHeight - referenceRect.bottom - BODY_PADDING < MIN_HEIGHT) {\n yPos = 'top';\n }\n\n if (\n (window.innerWidth - referenceRect.left - BODY_PADDING < MIN_WIDTH || options.horizontalPosition === 'right') &&\n !isMobile\n ) {\n xPos = 'right';\n }\n\n return {\n inset: `${yPos === 'bottom' ? referenceRect[yPos] + 'px' : 'auto'}\n ${xPos === 'right' ? window.innerWidth - referenceRect[xPos] + 'px' : 'auto'}\n ${yPos === 'top' ? window.innerHeight - referenceRect[yPos] + 'px' : 'auto'}\n ${xPos === 'left' ? setLeft(referenceRect, positionedRect, isMobile) : 'auto'}`,\n maxHeight: `${setHeight(referenceRect, yPos)}px`,\n maxWidth: `${setWidth(referenceRect, xPos)}px`,\n minWidth: options.fullWidth ? referenceRect.width : MIN_WIDTH,\n overflowX: 'hidden',\n overflowY: 'auto',\n opacity: 1,\n margin: `${options.offset}px 0`,\n };\n };\n\n const handleMouseEvent = (): void => {\n setStyle({\n ...style,\n ...calcPosition(),\n });\n setStatus(true);\n };\n\n const updatePosition = (): void => {\n if (status) {\n setStyle({\n ...style,\n ...calcPosition(),\n });\n }\n };\n\n const handleClickOutside = (evt: Event): void => {\n if (\n !referenceElement ||\n (referenceElement as unknown as HTMLElement).contains(evt.target as Node) ||\n !positionedElement ||\n (positionedElement as unknown as HTMLElement).contains(evt.target as Node)\n ) {\n return;\n }\n };\n\n const debouncedUpdatePosition = useDebounce(updatePosition, DEBOUNCE_DELAY);\n\n useEffect(() => {\n if (referenceElement !== null) {\n if (options.mouseEvent === 'click') {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).addEventListener('click', handleMouseEvent);\n } else {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).addEventListener('mouseenter', handleMouseEvent);\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).addEventListener('mouseleave', handleClickOutside);\n }\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('touchstart', handleClickOutside);\n window.addEventListener('resize', debouncedUpdatePosition);\n }\n\n return () => {\n if (referenceElement !== null) {\n if (options.mouseEvent === 'click') {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).removeEventListener('click', handleMouseEvent);\n } else {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).removeEventListener('mouseenter', handleMouseEvent);\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).removeEventListener('mouseleave', handleClickOutside);\n }\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('touchstart', handleClickOutside);\n window.removeEventListener('resize', debouncedUpdatePosition);\n }\n };\n });\n\n return {\n style: {\n style,\n },\n status,\n };\n}\n"],"names":["BODY_PADDING","MIN_HEIGHT","MIN_WIDTH","DEBOUNCE_DELAY","MOBILE_BREAKPOINT","HALF","usePositionedFloaters","positionedElement","referenceElement","options","status","setStatus","useState","defaultStyle","style","setStyle","sizeToPx","size","rootFontSize","setHeight","refRect","pos","_maxHeight","setWidth","_availableWidth","setLeft","posRect","isMobile","calcPosition","positionedRect","referenceRect","yPos","xPos","handleMouseEvent","updatePosition","handleClickOutside","evt","debouncedUpdatePosition","useDebounce","useEffect"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"usePositionedFloaters.js","sources":["../../../src/components/hooks/usePositionedFloaters.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nimport { useDebounce } from './useDebounce';\n\ninterface positionProps {\n style: {\n style: {\n inset: string;\n };\n };\n status: boolean;\n updatePosition: () => void;\n}\n\ninterface optionProps {\n mouseEvent: 'click' | 'hover';\n position: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';\n offset: number;\n maxFixedHeight?: `${number}${'px' | 'rem'}`;\n horizontalPosition?: 'left' | 'right';\n mobileBreakpoint?: `${number}${'px' | 'rem'}`;\n fullWidth: boolean;\n}\n\nconst BODY_PADDING = 10;\nconst MIN_HEIGHT = 90;\nconst MIN_WIDTH = 300;\nconst DEBOUNCE_DELAY = 0;\nconst MOBILE_BREAKPOINT = 768;\nconst HALF = 2;\n\nexport function usePositionedFloaters<T extends HTMLElement = HTMLElement>(\n positionedElement: T | null,\n referenceElement: T | null,\n options: optionProps\n): positionProps {\n const [status, setStatus] = useState(false);\n const defaultStyle = {\n inset: '0 auto auto 0',\n opacity: 0,\n maxHeight: '100%',\n maxWidth: '100%',\n minWidth: MIN_WIDTH,\n overflowX: 'hidden',\n overflowY: 'auto',\n margin: '0rem',\n };\n\n const [style, setStyle] = useState(defaultStyle);\n\n const sizeToPx = (size: `${number}${'px' | 'rem'}`): number => {\n const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return size.indexOf('rem') !== -1 ? parseFloat(size) * rootFontSize : parseFloat(size);\n };\n\n const setHeight = (refRect: DOMRect, pos: string): number => {\n if (!refRect) return 0;\n\n const _maxHeight =\n pos === 'bottom'\n ? window.innerHeight - refRect.bottom - options.offset - BODY_PADDING\n : refRect.top - options.offset - BODY_PADDING;\n\n return !options.maxFixedHeight || sizeToPx(options.maxFixedHeight) > _maxHeight\n ? _maxHeight\n : sizeToPx(options.maxFixedHeight);\n };\n\n const setWidth = (refRect: DOMRect, pos: string): number => {\n if (!refRect) return 0;\n\n const _availableWidth =\n pos === 'left' ? window.innerWidth - refRect.left - BODY_PADDING : refRect.right - BODY_PADDING;\n\n return _availableWidth <= MIN_WIDTH ? MIN_WIDTH : _availableWidth;\n };\n\n const setLeft = (refRect: DOMRect, posRect: DOMRect, isMobile: boolean) => {\n if (isMobile) {\n return `${refRect.left - Math.abs(posRect.width - refRect.width) / HALF}px`;\n } else {\n return `${refRect.left}px`;\n }\n };\n\n const calcPosition = (): typeof defaultStyle => {\n const positionedRect = (positionedElement as HTMLElement | null)?.getBoundingClientRect();\n const referenceRect = (referenceElement as HTMLElement | null)?.getBoundingClientRect();\n let yPos = 'bottom';\n let xPos = 'left';\n\n const isMobile = window.matchMedia(\n `(max-width: ${options.mobileBreakpoint ? sizeToPx(options.mobileBreakpoint) : MOBILE_BREAKPOINT}px)`\n ).matches;\n\n if (!referenceRect || !positionedRect) {\n return defaultStyle;\n }\n\n if (window.innerHeight - referenceRect.bottom - BODY_PADDING < MIN_HEIGHT) {\n yPos = 'top';\n }\n\n if (\n (window.innerWidth - referenceRect.left - BODY_PADDING < MIN_WIDTH || options.horizontalPosition === 'right') &&\n !isMobile\n ) {\n xPos = 'right';\n }\n\n return {\n inset: `${yPos === 'bottom' ? referenceRect[yPos] + 'px' : 'auto'}\n ${xPos === 'right' ? window.innerWidth - referenceRect[xPos] + 'px' : 'auto'}\n ${yPos === 'top' ? window.innerHeight - referenceRect[yPos] + 'px' : 'auto'}\n ${xPos === 'left' ? setLeft(referenceRect, positionedRect, isMobile) : 'auto'}`,\n maxHeight: `${setHeight(referenceRect, yPos)}px`,\n maxWidth: `${setWidth(referenceRect, xPos)}px`,\n minWidth: options.fullWidth ? referenceRect.width : MIN_WIDTH,\n overflowX: 'hidden',\n overflowY: 'auto',\n opacity: 1,\n margin: `${options.offset}px 0`,\n };\n };\n\n const handleMouseEvent = (): void => {\n setStyle({\n ...style,\n ...calcPosition(),\n });\n setStatus(true);\n };\n\n const updatePosition = (): void => {\n if (status) {\n setStyle({\n ...style,\n ...calcPosition(),\n });\n }\n };\n\n const handleClickOutside = (evt: Event): void => {\n if (\n !referenceElement ||\n (referenceElement as unknown as HTMLElement).contains(evt.target as Node) ||\n !positionedElement ||\n (positionedElement as unknown as HTMLElement).contains(evt.target as Node)\n ) {\n return;\n }\n };\n\n const debouncedUpdatePosition = useDebounce(updatePosition, DEBOUNCE_DELAY);\n\n useEffect(() => {\n if (referenceElement !== null) {\n if (options.mouseEvent === 'click') {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).addEventListener('click', handleMouseEvent);\n } else {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).addEventListener('mouseenter', handleMouseEvent);\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).addEventListener('mouseleave', handleClickOutside);\n }\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('touchstart', handleClickOutside);\n window.addEventListener('resize', debouncedUpdatePosition);\n }\n\n return () => {\n if (referenceElement !== null) {\n if (options.mouseEvent === 'click') {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).removeEventListener('click', handleMouseEvent);\n } else {\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).removeEventListener('mouseenter', handleMouseEvent);\n // eslint-disable-next-line no-extra-semi\n (referenceElement as unknown as HTMLElement).removeEventListener('mouseleave', handleClickOutside);\n }\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('touchstart', handleClickOutside);\n window.removeEventListener('resize', debouncedUpdatePosition);\n }\n };\n });\n\n return {\n style: {\n style,\n },\n status,\n updatePosition,\n };\n}\n"],"names":["BODY_PADDING","MIN_HEIGHT","MIN_WIDTH","DEBOUNCE_DELAY","MOBILE_BREAKPOINT","HALF","usePositionedFloaters","positionedElement","referenceElement","options","status","setStatus","useState","defaultStyle","style","setStyle","sizeToPx","size","rootFontSize","setHeight","refRect","pos","_maxHeight","setWidth","_availableWidth","setLeft","posRect","isMobile","calcPosition","positionedRect","referenceRect","yPos","xPos","handleMouseEvent","updatePosition","handleClickOutside","evt","debouncedUpdatePosition","useDebounce","useEffect"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@uva-glass/component-library",
|
|
3
3
|
"author": "Team Glass - Frontend vrienden",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "3.34.
|
|
5
|
+
"version": "3.34.9",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"npm-run-all2": "^8.0.4",
|
|
81
81
|
"react": "^19.1.0",
|
|
82
82
|
"react-dom": "^19.1.0",
|
|
83
|
-
"react-router": "^7.
|
|
83
|
+
"react-router": "^7.7.0",
|
|
84
84
|
"semantic-release": "^24.2.7",
|
|
85
85
|
"storybook": "^9.0.17",
|
|
86
86
|
"style-dictionary": "^5.0.1",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"stylelint-order": "^7.0.0",
|
|
91
91
|
"ts-node": "^10.9.2",
|
|
92
92
|
"typescript": "^5.8.3",
|
|
93
|
-
"vite": "^7.0.
|
|
93
|
+
"vite": "^7.0.5",
|
|
94
94
|
"vite-plugin-dts": "^4.5.4",
|
|
95
95
|
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
96
96
|
"vite-plugin-static-copy": "^3.1.1",
|