@heliosgraphics/ui 2.0.0-alpha.95 → 2.0.0-alpha.97
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/components/Alert/Alert.tsx +2 -0
- package/components/Breadcrumb/Breadcrumb.tsx +17 -1
- package/components/Browser/Browser.tsx +2 -0
- package/components/Button/Button.tsx +7 -3
- package/components/ButtonGroup/ButtonGroup.tsx +2 -0
- package/components/Checkbox/Checkbox.tsx +66 -55
- package/components/Clock/Clock.tsx +23 -19
- package/components/Column/Column.tsx +2 -0
- package/components/Confirm/Confirm.tsx +2 -0
- package/components/DatePicker/DatePicker.meta.ts +12 -5
- package/components/DatePicker/DatePicker.module.css +70 -1
- package/components/DatePicker/DatePicker.tsx +116 -4
- package/components/DatePicker/DatePicker.types.ts +6 -1
- package/components/DatePicker/DatePicker.utils.ts +53 -0
- package/components/Debug/Debug.tsx +2 -0
- package/components/Details/Details.tsx +2 -0
- package/components/Dialog/Dialog.module.css +4 -6
- package/components/Dialog/Dialog.tsx +33 -24
- package/components/Donut/Donut.tsx +2 -0
- package/components/Dot/Dot.tsx +2 -0
- package/components/Dropdown/Dropdown.module.css +5 -0
- package/components/Dropdown/Dropdown.tsx +21 -26
- package/components/Fieldset/Fieldset.tsx +2 -0
- package/components/Flex/Flex.meta.ts +1 -0
- package/components/Flex/Flex.tsx +22 -2
- package/components/Flex/Flex.types.ts +1 -0
- package/components/Flex/Flex.utils.spec.ts +4 -1
- package/components/Flex/Flex.utils.ts +4 -1
- package/components/Grid/Grid.tsx +2 -0
- package/components/Heading/Heading.meta.ts +5 -0
- package/components/Heading/Heading.tsx +15 -9
- package/components/Heading/Heading.types.ts +1 -0
- package/components/Heading/components/H0/H0.tsx +2 -0
- package/components/Heading/components/H1/H1.tsx +2 -0
- package/components/Heading/components/H2/H2.tsx +2 -0
- package/components/Heading/components/H3/H3.tsx +2 -0
- package/components/Heading/components/H4/H4.tsx +2 -0
- package/components/Heading/components/H5/H5.tsx +2 -0
- package/components/Heading/components/H6/H6.tsx +2 -0
- package/components/Icon/Icon.tsx +2 -0
- package/components/Input/Input.tsx +103 -95
- package/components/Layout/Layout.tsx +2 -0
- package/components/Layout/components/LayoutAside/LayoutAside.tsx +2 -0
- package/components/Layout/components/LayoutAside/components/LayoutAsideContent/LayoutAsideContent.tsx +2 -0
- package/components/Layout/components/LayoutAside/components/LayoutAsideFooter/LayoutAsideFooter.tsx +2 -0
- package/components/Layout/components/LayoutAside/components/LayoutAsideToggle/LayoutAsideToggle.tsx +2 -0
- package/components/Layout/components/LayoutMain/LayoutMain.tsx +2 -0
- package/components/Layout/components/LayoutMain/components/LayoutMainContent/LayoutMainContent.tsx +2 -0
- package/components/Layout/components/LayoutNavigation/LayoutNavigation.tsx +2 -0
- package/components/Layout/components/LayoutSubNavigation/LayoutSubNavigation.tsx +2 -0
- package/components/Loading/Loading.tsx +2 -0
- package/components/Markdown/Markdown.tsx +2 -0
- package/components/Masonry/Masonry.tsx +5 -1
- package/components/Menu/Menu.tsx +2 -0
- package/components/Menu/components/MenuCategory/MenuCategory.tsx +2 -0
- package/components/Menu/components/MenuFilter/MenuFilter.tsx +2 -0
- package/components/Menu/components/MenuItem/MenuItem.tsx +2 -0
- package/components/Overlay/Overlay.tsx +18 -2
- package/components/Pie/Pie.tsx +2 -0
- package/components/Pill/Pill.meta.ts +9 -1
- package/components/Pill/Pill.module.css +11 -0
- package/components/Pill/Pill.tsx +28 -3
- package/components/Pill/Pill.types.ts +2 -0
- package/components/Placeholder/Placeholder.tsx +2 -0
- package/components/Progress/Progress.tsx +2 -0
- package/components/Radio/Radio.tsx +2 -0
- package/components/Range/Range.tsx +2 -0
- package/components/Segments/Segments.context.ts +19 -0
- package/components/Segments/Segments.meta.ts +4 -0
- package/components/Segments/Segments.tsx +34 -42
- package/components/Segments/Segments.types.ts +1 -0
- package/components/Segments/components/SegmentButton/SegmentButton.meta.ts +0 -4
- package/components/Segments/components/SegmentButton/SegmentButton.tsx +28 -3
- package/components/Segments/components/SegmentButton/SegmentButton.types.ts +0 -2
- package/components/Select/Select.tsx +40 -43
- package/components/Separator/Separator.tsx +2 -0
- package/components/Separator/components/HRMarkup/HRMarkup.tsx +2 -0
- package/components/Separator/components/HorizontalSeparator/HorizontalSeparator.tsx +2 -0
- package/components/Separator/components/VerticalSeparator/VerticalSeparator.tsx +2 -0
- package/components/Setup/Setup.tsx +3 -0
- package/components/Shimmer/Shimmer.tsx +2 -0
- package/components/Slider/Slider.tsx +2 -0
- package/components/Spacer/Spacer.tsx +2 -0
- package/components/Table/Table.tsx +2 -0
- package/components/Tabs/Tabs.meta.ts +12 -12
- package/components/Tabs/Tabs.module.css +25 -9
- package/components/Tabs/Tabs.tsx +49 -53
- package/components/Tabs/Tabs.types.ts +10 -3
- package/components/Text/Text.tsx +2 -0
- package/components/Text/components/Div/Div.tsx +2 -0
- package/components/Text/components/Micro/Micro.tsx +2 -0
- package/components/Text/components/P/P.tsx +2 -0
- package/components/Text/components/Small/Small.tsx +2 -0
- package/components/Text/components/Tiny/Tiny.tsx +2 -0
- package/components/Textarea/Textarea.tsx +14 -13
- package/components/Tile/Tile.tsx +2 -0
- package/components/Timestamp/Timestamp.tsx +2 -0
- package/components/Toggle/Toggle.tsx +2 -0
- package/components/Tooltip/Tooltip.tsx +17 -9
- package/components/Tooltip/Tooltip.types.ts +0 -1
- package/components/Tooltip/components/TooltipContent/TooltipContent.tsx +2 -0
- package/components/Tooltip/components/TooltipTrigger/TooltipTrigger.tsx +4 -2
- package/components/shared/InputLabel/InputLabel.tsx +2 -0
- package/components/shared/ResultList/ResultList.tsx +6 -4
- package/contexts/LayoutContext/LayoutContext.tsx +15 -34
- package/contexts/LayoutContext/LayoutContext.types.ts +0 -1
- package/hooks/useLayoutContext.tsx +0 -1
- package/hooks/useResizeObserver.tsx +2 -2
- package/index.ts +5 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { useId,
|
|
3
|
+
import { useId, forwardRef } from "react"
|
|
4
4
|
import { getClasses } from "@heliosgraphics/utils"
|
|
5
5
|
import { Button } from "../Button"
|
|
6
6
|
import { ButtonGroup } from "../ButtonGroup"
|
|
@@ -13,104 +13,112 @@ import styles from "./Input.module.css"
|
|
|
13
13
|
import type { InputProps } from "./Input.types"
|
|
14
14
|
import type { ResultItem } from "../shared/ResultList"
|
|
15
15
|
|
|
16
|
-
export const Input
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
16
|
+
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
17
|
+
(
|
|
18
|
+
{
|
|
19
|
+
className,
|
|
20
|
+
helperText,
|
|
21
|
+
id,
|
|
22
|
+
isDisabled,
|
|
23
|
+
autoComplete,
|
|
24
|
+
autoFocus,
|
|
25
|
+
isLabelHidden,
|
|
26
|
+
isLoading,
|
|
27
|
+
isRequired,
|
|
28
|
+
label,
|
|
29
|
+
maxLength,
|
|
30
|
+
name,
|
|
31
|
+
onBlur,
|
|
32
|
+
onChange,
|
|
33
|
+
onClear,
|
|
34
|
+
onFocus,
|
|
35
|
+
onKeyDown,
|
|
36
|
+
onKeyUp,
|
|
37
|
+
placeholder,
|
|
38
|
+
results,
|
|
39
|
+
showResults,
|
|
40
|
+
type = "text",
|
|
41
|
+
value,
|
|
42
|
+
},
|
|
43
|
+
ref,
|
|
44
|
+
) => {
|
|
45
|
+
const generatedId: string = useId()
|
|
46
|
+
const htmlFor: string = id || generatedId
|
|
47
|
+
const helperId: string = `${htmlFor}-helper`
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
const filteredItems: Array<ResultItem> =
|
|
50
|
+
results
|
|
51
|
+
?.filter((item) => {
|
|
52
|
+
const lowerCaseItem: string = item.name.toLowerCase()
|
|
53
|
+
const lowerCaseFilter: string | undefined = value?.toLowerCase()
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
return lowerCaseFilter && lowerCaseItem.includes(lowerCaseFilter)
|
|
56
|
+
})
|
|
57
|
+
.filter(Boolean) || []
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
const showingResults: boolean = Boolean(!!filteredItems?.length && showResults)
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
const inputClasses: string = getClasses(styles.input, "relative flex flex-column", className, {
|
|
62
|
+
[styles.inputDisabled]: isDisabled,
|
|
63
|
+
[styles.inputShowingResults]: showingResults,
|
|
64
|
+
})
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<
|
|
66
|
+
return (
|
|
67
|
+
<div className={inputClasses} data-ui-component="Input">
|
|
68
|
+
<InputLabel id={htmlFor} label={label} isDisabled={!!isDisabled} isHidden={!!isLabelHidden} />
|
|
69
|
+
<Flex className="grow-1">
|
|
70
|
+
{onClear && !!value && (
|
|
71
|
+
<ButtonGroup className={styles.input__clear}>
|
|
72
|
+
<Button
|
|
73
|
+
value="Clear"
|
|
74
|
+
size="tiny"
|
|
75
|
+
intent="neutral"
|
|
76
|
+
icon="x"
|
|
77
|
+
onClick={onClear}
|
|
78
|
+
isIconOnly={true}
|
|
79
|
+
isRounded={true}
|
|
80
|
+
/>
|
|
81
|
+
</ButtonGroup>
|
|
82
|
+
)}
|
|
83
|
+
<input
|
|
84
|
+
ref={ref}
|
|
85
|
+
className={styles.input__input}
|
|
86
|
+
disabled={isDisabled}
|
|
87
|
+
autoComplete={autoComplete}
|
|
88
|
+
autoFocus={autoFocus}
|
|
89
|
+
id={htmlFor}
|
|
90
|
+
maxLength={maxLength}
|
|
91
|
+
name={name}
|
|
92
|
+
onBlur={onBlur}
|
|
93
|
+
type={type}
|
|
94
|
+
onChange={onChange}
|
|
95
|
+
onFocus={onFocus}
|
|
96
|
+
onKeyDown={onKeyDown}
|
|
97
|
+
onKeyUp={onKeyUp}
|
|
98
|
+
placeholder={placeholder}
|
|
99
|
+
required={isRequired}
|
|
100
|
+
value={value}
|
|
101
|
+
aria-describedby={helperText ? helperId : undefined}
|
|
102
|
+
/>
|
|
103
|
+
{isLoading && (
|
|
104
|
+
<div className={styles.input__loading}>
|
|
105
|
+
<Loading size={20} />
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
</Flex>
|
|
109
|
+
{showingResults && (
|
|
110
|
+
<div className={styles.input__results}>
|
|
111
|
+
<ResultList items={filteredItems} />
|
|
101
112
|
</div>
|
|
102
113
|
)}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
</div>
|
|
115
|
-
)
|
|
116
|
-
}
|
|
114
|
+
{!!helperText && (
|
|
115
|
+
<Text type="tiny" emphasis="tertiary" className={styles.input__helper} id={helperId}>
|
|
116
|
+
{helperText}
|
|
117
|
+
</Text>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
)
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
Input.displayName = "Input"
|
|
@@ -31,7 +31,11 @@ export const Masonry: FC<MasonryProps> = ({
|
|
|
31
31
|
return (
|
|
32
32
|
<>
|
|
33
33
|
<style dangerouslySetInnerHTML={{ __html: mediaStyles }} />
|
|
34
|
-
<div className={id}>
|
|
34
|
+
<div className={id} data-ui-component="Masonry">
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
35
37
|
</>
|
|
36
38
|
)
|
|
37
39
|
}
|
|
40
|
+
|
|
41
|
+
Masonry.displayName = "Masonry"
|
package/components/Menu/Menu.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import styles from "./Overlay.module.css"
|
|
2
|
-
import type { FC, MouseEvent } from "react"
|
|
2
|
+
import type { FC, MouseEvent, KeyboardEvent } from "react"
|
|
3
3
|
import type { OverlayProps } from "./Overlay.types"
|
|
4
4
|
import { getClasses } from "@heliosgraphics/utils"
|
|
5
5
|
|
|
@@ -11,6 +11,13 @@ export const Overlay: FC<OverlayProps> = ({ onClose, isCentered, children, isOpe
|
|
|
11
11
|
return onClose?.()
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {
|
|
15
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
16
|
+
event.preventDefault()
|
|
17
|
+
onClose?.()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
const contentClasses: string = getClasses(styles.overlay__content, {
|
|
15
22
|
[styles.overlay__contentCentered]: isCentered,
|
|
16
23
|
})
|
|
@@ -25,7 +32,16 @@ export const Overlay: FC<OverlayProps> = ({ onClose, isCentered, children, isOpe
|
|
|
25
32
|
data-open={isOpen}
|
|
26
33
|
>
|
|
27
34
|
<div className={contentClasses}>{children}</div>
|
|
28
|
-
<div
|
|
35
|
+
<div
|
|
36
|
+
className={styles.overlay__layer}
|
|
37
|
+
onClick={hideFunction}
|
|
38
|
+
onKeyDown={handleKeyDown}
|
|
39
|
+
role="button"
|
|
40
|
+
tabIndex={0}
|
|
41
|
+
aria-label="Close overlay"
|
|
42
|
+
/>
|
|
29
43
|
</section>
|
|
30
44
|
)
|
|
31
45
|
}
|
|
46
|
+
|
|
47
|
+
Overlay.displayName = "Overlay"
|
package/components/Pie/Pie.tsx
CHANGED
|
@@ -28,8 +28,16 @@ export const meta: HeliosAttributeMeta<PillProps> = {
|
|
|
28
28
|
type: "HeliosIconType",
|
|
29
29
|
isOptional: true,
|
|
30
30
|
},
|
|
31
|
+
isEllipsis: {
|
|
32
|
+
type: "boolean",
|
|
33
|
+
isOptional: true,
|
|
34
|
+
},
|
|
31
35
|
isLabelHidden: {
|
|
32
|
-
type: "
|
|
36
|
+
type: "boolean",
|
|
37
|
+
isOptional: true,
|
|
38
|
+
},
|
|
39
|
+
isLoading: {
|
|
40
|
+
type: "boolean",
|
|
33
41
|
isOptional: true,
|
|
34
42
|
},
|
|
35
43
|
isMono: {
|
|
@@ -51,3 +51,14 @@
|
|
|
51
51
|
.pillTiny.pillRounded:not(.pillIconOnly) {
|
|
52
52
|
padding: 0 8px;
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
.pillEllipsis {
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
max-width: 100%;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.pillEllipsis :global(.text) {
|
|
61
|
+
overflow: hidden;
|
|
62
|
+
text-overflow: ellipsis;
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
}
|
package/components/Pill/Pill.tsx
CHANGED
|
@@ -3,8 +3,9 @@ import { getColorClasses } from "../../utils/colors"
|
|
|
3
3
|
import { Flex } from "../Flex"
|
|
4
4
|
import { Text } from "../Text"
|
|
5
5
|
import { Icon } from "../Icon"
|
|
6
|
+
import { Loading } from "../Loading"
|
|
6
7
|
import styles from "./Pill.module.css"
|
|
7
|
-
import { memo, type FC } from "react"
|
|
8
|
+
import { memo, type FC, type KeyboardEvent } from "react"
|
|
8
9
|
import type { PillProps } from "./Pill.types"
|
|
9
10
|
|
|
10
11
|
const PILL_ICON_SIZE = {
|
|
@@ -13,13 +14,21 @@ const PILL_ICON_SIZE = {
|
|
|
13
14
|
normal: 24,
|
|
14
15
|
} as const satisfies Record<string, number>
|
|
15
16
|
|
|
17
|
+
const PILL_LOADING_SIZE = {
|
|
18
|
+
tiny: 10,
|
|
19
|
+
small: 10,
|
|
20
|
+
normal: 20,
|
|
21
|
+
} as const satisfies Record<string, 10 | 20 | 40>
|
|
22
|
+
|
|
16
23
|
export const Pill: FC<PillProps> = memo(
|
|
17
24
|
({
|
|
18
25
|
appearance = "light",
|
|
19
26
|
color = "gray",
|
|
20
27
|
className,
|
|
21
28
|
icon,
|
|
29
|
+
isEllipsis,
|
|
22
30
|
isLabelHidden,
|
|
31
|
+
isLoading,
|
|
23
32
|
isMono,
|
|
24
33
|
isRounded,
|
|
25
34
|
label,
|
|
@@ -38,21 +47,35 @@ export const Pill: FC<PillProps> = memo(
|
|
|
38
47
|
[styles.pillTiny]: size === "tiny",
|
|
39
48
|
|
|
40
49
|
[styles.pillIconOnly]: !!icon && isLabelHidden,
|
|
50
|
+
[styles.pillEllipsis]: isEllipsis,
|
|
41
51
|
})
|
|
42
52
|
|
|
43
53
|
const isSmall: boolean = size !== "normal"
|
|
44
54
|
const pillTextSize = isSmall ? "tiny" : "small"
|
|
45
55
|
|
|
56
|
+
const onKeyDown = onClick
|
|
57
|
+
? (event: KeyboardEvent<HTMLDivElement>): void => {
|
|
58
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
59
|
+
event.preventDefault()
|
|
60
|
+
onClick(event as unknown as React.MouseEvent<HTMLDivElement>)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
: undefined
|
|
64
|
+
|
|
65
|
+
const isInteractive: boolean = !!onClick && !isLoading
|
|
66
|
+
|
|
46
67
|
return (
|
|
47
68
|
<Flex
|
|
48
|
-
{...(
|
|
69
|
+
{...(isInteractive && { onClick, role: "button", tabIndex: 0 })}
|
|
70
|
+
{...(isInteractive && onKeyDown && { onKeyDown })}
|
|
49
71
|
className={pillClasses}
|
|
50
72
|
isCentered={true}
|
|
51
73
|
gap={2}
|
|
52
74
|
aria-label={isLabelHidden ? label : undefined}
|
|
53
75
|
data-ui-component="Pill"
|
|
54
76
|
>
|
|
55
|
-
{
|
|
77
|
+
{isLoading && <Loading size={PILL_LOADING_SIZE[size] || 20} />}
|
|
78
|
+
{!isLoading && icon && <Icon size={PILL_ICON_SIZE[size] || 16} icon={icon} />}
|
|
56
79
|
{!isLabelHidden && (
|
|
57
80
|
<Text type={pillTextSize} whiteSpace="nowrap" {...(isMono && { fontFamily: "mono" })} fontWeight="medium">
|
|
58
81
|
{label}
|
|
@@ -62,3 +85,5 @@ export const Pill: FC<PillProps> = memo(
|
|
|
62
85
|
)
|
|
63
86
|
},
|
|
64
87
|
)
|
|
88
|
+
|
|
89
|
+
Pill.displayName = "Pill"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext } from "react"
|
|
4
|
+
|
|
5
|
+
export interface SegmentsContextValue {
|
|
6
|
+
activeValue: string
|
|
7
|
+
onSelect: (value: string) => void
|
|
8
|
+
registerRef: (value: string, el: HTMLButtonElement | null) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const SegmentsContext = createContext<SegmentsContextValue | null>(null)
|
|
12
|
+
|
|
13
|
+
export const useSegments = (): SegmentsContextValue => {
|
|
14
|
+
const context = useContext(SegmentsContext)
|
|
15
|
+
|
|
16
|
+
if (!context) throw new Error("SegmentButton must be used within Segments")
|
|
17
|
+
|
|
18
|
+
return context
|
|
19
|
+
}
|