@dt-dds/react-dropdown 1.0.0-beta.31

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/index.mjs ADDED
@@ -0,0 +1,413 @@
1
+ // src/components/detail/DropdownDetail.tsx
2
+ import { Typography } from "@dt-dds/react-typography";
3
+
4
+ // src/components/detail/DropdownDetail.styled.ts
5
+ import styled from "@emotion/styled";
6
+ var DropdownDetailStyled = styled.div`
7
+ display: flex;
8
+ align-items: center;
9
+ padding-left: 15px;
10
+ margin-top: 4px;
11
+ `;
12
+
13
+ // src/components/detail/DropdownDetail.tsx
14
+ import { jsx } from "react/jsx-runtime";
15
+ var DropdownDetail = ({
16
+ dataTestId,
17
+ isDisabled = false,
18
+ hasError = false,
19
+ children = ""
20
+ }) => {
21
+ const messageColor = isDisabled ? "content.light" : "content.medium";
22
+ return /* @__PURE__ */ jsx(DropdownDetailStyled, { "data-testid": dataTestId != null ? dataTestId : "dropdown-text", children: /* @__PURE__ */ jsx(
23
+ Typography,
24
+ {
25
+ color: hasError ? "error.default" : messageColor,
26
+ element: "span",
27
+ fontStyles: "body3",
28
+ children
29
+ }
30
+ ) });
31
+ };
32
+
33
+ // src/context/DropdownProvider.tsx
34
+ import {
35
+ createContext,
36
+ useContext,
37
+ useEffect,
38
+ useState
39
+ } from "react";
40
+ import { jsx as jsx2 } from "react/jsx-runtime";
41
+ var DEFAULT_VALUE = {
42
+ state: {
43
+ text: "",
44
+ value: ""
45
+ },
46
+ isOpen: false,
47
+ setState: () => null,
48
+ setIsOpen: () => null
49
+ };
50
+ var DropdownContext = createContext(DEFAULT_VALUE);
51
+ var DropdownContextProvider = ({
52
+ children,
53
+ defaultValue,
54
+ name
55
+ }) => {
56
+ const [state, setState] = useState(defaultValue != null ? defaultValue : DEFAULT_VALUE.state);
57
+ const [isOpen, setIsOpen] = useState(DEFAULT_VALUE.isOpen);
58
+ useEffect(() => defaultValue && setState(defaultValue), [defaultValue]);
59
+ return /* @__PURE__ */ jsx2(
60
+ DropdownContext.Provider,
61
+ {
62
+ value: {
63
+ state,
64
+ setState,
65
+ isOpen,
66
+ setIsOpen,
67
+ name
68
+ },
69
+ children
70
+ }
71
+ );
72
+ };
73
+ var useDropdownContext = () => {
74
+ const context = useContext(DropdownContext);
75
+ if (!context) {
76
+ throw new Error(
77
+ "Dropdown compound components cannot be rendered outside the Dropdown component"
78
+ );
79
+ }
80
+ return context;
81
+ };
82
+
83
+ // src/components/option/DropdownOption.styled.ts
84
+ import styled2 from "@emotion/styled";
85
+ var DropdownOptionStyled = styled2.li`
86
+ ${({ theme, disabled, isSelected }) => `
87
+ ${theme.fontStyles[isSelected ? "body2Bold" : "body2"]};
88
+ color: ${theme.palette.content.default};
89
+ list-style: none;
90
+ padding: ${theme.spacing["4xs"]} ${theme.spacing["2xs"]};
91
+ text-overflow: ellipsis;
92
+ overflow-x: hidden;
93
+
94
+ &:hover {
95
+ background: ${disabled ? theme.palette.surface.light : theme.palette.primary.light};
96
+ cursor: ${disabled ? "not-allowed" : "pointer"};
97
+ }
98
+
99
+ ${disabled && `
100
+ color: ${theme.palette.content.light};
101
+ background: ${theme.palette.surface.light};
102
+ `}
103
+ `}
104
+ `;
105
+
106
+ // src/components/option/DropdownOption.tsx
107
+ import { jsx as jsx3 } from "react/jsx-runtime";
108
+ var DropdownOption = ({
109
+ dataTestId,
110
+ option,
111
+ children,
112
+ style,
113
+ isDisabled,
114
+ onClick
115
+ }) => {
116
+ var _a;
117
+ const { state, setState, setIsOpen, name } = useDropdownContext();
118
+ const testId = dataTestId != null ? dataTestId : `dropdown-option-${option.value}`;
119
+ const value = {
120
+ text: (_a = option.text) != null ? _a : option.value,
121
+ value: option.value
122
+ };
123
+ const handleClick = (event) => {
124
+ if (isDisabled) {
125
+ return;
126
+ }
127
+ setIsOpen(false);
128
+ setState(value);
129
+ onClick && onClick(option.value, name, event);
130
+ };
131
+ return /* @__PURE__ */ jsx3(
132
+ DropdownOptionStyled,
133
+ {
134
+ "data-testid": testId,
135
+ disabled: isDisabled,
136
+ isSelected: state.value === option.value,
137
+ onClick: handleClick,
138
+ role: "option",
139
+ style,
140
+ children
141
+ },
142
+ option.value
143
+ );
144
+ };
145
+
146
+ // src/components/select/DropdownSelect.tsx
147
+ import { Box } from "@dt-dds/react-box";
148
+ import { Icon } from "@dt-dds/react-icon";
149
+ import { IconButton } from "@dt-dds/react-icon-button";
150
+ import { Typography as Typography2 } from "@dt-dds/react-typography";
151
+ import { useTheme } from "@emotion/react";
152
+ import { Children, useEffect as useEffect2 } from "react";
153
+
154
+ // src/components/menu/DropdownMenu.styled.ts
155
+ import { DROPDOWN_MENU_Z_INDEX } from "@dt-dds/react-core";
156
+ import styled3 from "@emotion/styled";
157
+ var DropdownMenuStyled = styled3.ul`
158
+ ${({ theme }) => `
159
+ background: ${theme.palette.surface.contrast};
160
+ border: 1px solid ${theme.palette.border.default};
161
+ border-radius: ${theme.shape.dropdown};
162
+ width: 100%;
163
+ padding:${theme.spacing["2xs"]} ${theme.spacing.none};
164
+ margin: ${theme.spacing["5xs"]} ${theme.spacing.none};
165
+ position: absolute;
166
+ right: 0;
167
+ z-index: ${DROPDOWN_MENU_Z_INDEX};
168
+ max-height: 180px;
169
+ overflow: auto;
170
+ `}
171
+ `;
172
+
173
+ // src/components/menu/DropdownMenu.tsx
174
+ import { jsx as jsx4 } from "react/jsx-runtime";
175
+ var DropdownMenu = ({ children, dataTestId, style }) => {
176
+ return /* @__PURE__ */ jsx4(
177
+ DropdownMenuStyled,
178
+ {
179
+ "data-testid": `${dataTestId ? dataTestId + "-" : ""}menu`,
180
+ style,
181
+ children
182
+ }
183
+ );
184
+ };
185
+
186
+ // src/components/select/DropdownSelect.styled.ts
187
+ import styled4 from "@emotion/styled";
188
+ var getThemedBackgroundFill = (fill, theme) => ({
189
+ default: theme.palette.surface.default,
190
+ contrast: theme.palette.surface.contrast,
191
+ light: theme.palette.surface.light
192
+ })[fill];
193
+ var SelectDropdownStyled = styled4.button`
194
+ ${({
195
+ theme,
196
+ hasBorder = true,
197
+ hasError = false,
198
+ isOpen = false,
199
+ variant = "outlined",
200
+ fill = "default"
201
+ }) => {
202
+ const borderColor = theme.palette.border.medium;
203
+ const activeBorderColor = theme.palette.content.dark;
204
+ const errorBorderColor = theme.palette.error.default;
205
+ return `
206
+ background: ${theme.palette.surface.contrast};
207
+ padding: ${theme.spacing.xsmall} ${hasBorder ? theme.spacing.xmedium : "0"};
208
+ position: relative;
209
+ display: flex;
210
+ align-items: center;
211
+ justify-content: space-between;
212
+ text-align: left;
213
+ width: 100%;
214
+ height: 53px;
215
+ cursor: pointer;
216
+ outline: none;
217
+
218
+ background-color: ${getThemedBackgroundFill(fill, theme)};
219
+
220
+ border-width: ${variant === "outlined" ? "1px" : "0 0 1px"};
221
+ border-color: ${isOpen ? activeBorderColor : borderColor};
222
+ border-style: solid;
223
+
224
+ &:focus, &:hover {
225
+ border-color: ${hasError ? errorBorderColor : activeBorderColor};
226
+ }
227
+
228
+ ${hasError && `border-color: ${errorBorderColor}`};
229
+ ${!hasBorder && "border: none"};
230
+
231
+ &:disabled {
232
+ pointer-events: none;
233
+ }
234
+ `;
235
+ }}
236
+ `;
237
+
238
+ // src/components/select/DropdownSelect.tsx
239
+ import { Fragment, jsx as jsx5, jsxs } from "react/jsx-runtime";
240
+ var DropdownSelect = ({
241
+ children,
242
+ label,
243
+ style,
244
+ dataTestId = "dropdown-select",
245
+ isDisabled = false,
246
+ isRequired,
247
+ hasBorder = true,
248
+ hasError = false,
249
+ hasDeselect = false,
250
+ variant = "outlined",
251
+ fill = "default"
252
+ }) => {
253
+ const { state, setState, isOpen, setIsOpen } = useDropdownContext();
254
+ const theme = useTheme();
255
+ const childCount = Children.count(children);
256
+ const hasOneChild = childCount === 1;
257
+ const disabled = isDisabled || hasOneChild;
258
+ const disabledIconColor = disabled ? theme.palette.content.light : theme.palette.content.default;
259
+ const handleClick = (event) => {
260
+ event.preventDefault();
261
+ setIsOpen((prev) => !prev);
262
+ };
263
+ const handleDeselectClick = (event) => {
264
+ event.stopPropagation();
265
+ setState({ text: "", value: "" });
266
+ };
267
+ useEffect2(() => {
268
+ const hasOption = Children.toArray(children).find(
269
+ (child) => child.props.option.value === state.value
270
+ );
271
+ if (!hasOption) {
272
+ setState({ text: "", value: "" });
273
+ }
274
+ }, [children, setState, state.value]);
275
+ useEffect2(() => {
276
+ var _a;
277
+ if (hasOneChild) {
278
+ const options = Children.map(
279
+ children,
280
+ (child) => child && child.props.option
281
+ );
282
+ if (options && options[0]) {
283
+ const option = {
284
+ text: (_a = options[0].text) != null ? _a : options[0].value,
285
+ value: options[0].value
286
+ };
287
+ setState(option);
288
+ }
289
+ }
290
+ }, [hasOneChild, setState, children]);
291
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
292
+ /* @__PURE__ */ jsxs(
293
+ SelectDropdownStyled,
294
+ {
295
+ "data-testid": dataTestId,
296
+ disabled,
297
+ fill,
298
+ hasBorder,
299
+ hasError,
300
+ isOpen,
301
+ onClick: handleClick,
302
+ style,
303
+ variant,
304
+ children: [
305
+ /* @__PURE__ */ jsxs("div", { style: { overflow: "hidden" }, children: [
306
+ /* @__PURE__ */ jsxs(
307
+ Typography2,
308
+ {
309
+ color: disabled ? "content.light" : "content.default",
310
+ fontStyles: "body3",
311
+ children: [
312
+ label,
313
+ isRequired ? /* @__PURE__ */ jsx5(
314
+ Typography2,
315
+ {
316
+ color: "error.default",
317
+ element: "span",
318
+ fontStyles: "body3",
319
+ children: "*"
320
+ }
321
+ ) : null
322
+ ]
323
+ }
324
+ ),
325
+ /* @__PURE__ */ jsx5(
326
+ Typography2,
327
+ {
328
+ color: disabled ? "content.light" : "content.default",
329
+ fontStyles: "body2",
330
+ style: { textOverflow: "ellipsis", overflow: "hidden" },
331
+ children: !state.value ? "Select an option" : state.text
332
+ }
333
+ )
334
+ ] }),
335
+ /* @__PURE__ */ jsxs(Box, { style: { flexDirection: "row", gap: "0.5rem" }, children: [
336
+ hasDeselect && !!state.value ? /* @__PURE__ */ jsx5(IconButton, { onClick: handleDeselectClick, children: /* @__PURE__ */ jsx5(
337
+ Icon,
338
+ {
339
+ code: "close",
340
+ color: disabledIconColor,
341
+ dataTestId: "deselect-value",
342
+ size: "s"
343
+ }
344
+ ) }) : null,
345
+ /* @__PURE__ */ jsx5(
346
+ Icon,
347
+ {
348
+ code: isOpen ? "expand_less" : "expand_more",
349
+ color: disabledIconColor,
350
+ size: "l"
351
+ }
352
+ )
353
+ ] })
354
+ ]
355
+ }
356
+ ),
357
+ isOpen ? /* @__PURE__ */ jsx5(DropdownMenu, { dataTestId, children }) : null
358
+ ] });
359
+ };
360
+
361
+ // src/components/container/DropdownContainer.tsx
362
+ import { useClickOutside } from "@dt-dds/react-core";
363
+ import { useRef } from "react";
364
+ import { jsx as jsx6 } from "react/jsx-runtime";
365
+ var DropdownContainer = ({
366
+ children,
367
+ style,
368
+ dataTestId
369
+ }) => {
370
+ const { setIsOpen } = useDropdownContext();
371
+ const ref = useRef(null);
372
+ useClickOutside({ ref, handler: () => setIsOpen(false) });
373
+ return /* @__PURE__ */ jsx6("div", { "data-testid": dataTestId, ref, style, children });
374
+ };
375
+
376
+ // src/Dropdown.styled.ts
377
+ import styled5 from "@emotion/styled";
378
+ var DropdownStyled = styled5.div`
379
+ ${({ theme, style }) => `
380
+ margin: ${theme.spacing.none};
381
+ display: inline-block;
382
+ position: relative;
383
+ width: 100%;
384
+ ${style}
385
+ `}
386
+ `;
387
+
388
+ // src/Dropdown.tsx
389
+ import { jsx as jsx7 } from "react/jsx-runtime";
390
+ var Dropdown = ({
391
+ children,
392
+ defaultValue,
393
+ style,
394
+ name,
395
+ dataTestId = "dropdown"
396
+ }) => /* @__PURE__ */ jsx7(DropdownContextProvider, { defaultValue, name, children: /* @__PURE__ */ jsx7(DropdownStyled, { "data-testid": dataTestId, role: "menu", style, children }) });
397
+ Dropdown.Container = DropdownContainer;
398
+ Dropdown.Detail = DropdownDetail;
399
+ Dropdown.Select = DropdownSelect;
400
+ Dropdown.Option = DropdownOption;
401
+ Dropdown.Menu = DropdownMenu;
402
+ var Dropdown_default = Dropdown;
403
+ export {
404
+ Dropdown_default as Dropdown,
405
+ DropdownContainer,
406
+ DropdownContext,
407
+ DropdownContextProvider,
408
+ DropdownDetail,
409
+ DropdownMenu,
410
+ DropdownOption,
411
+ DropdownSelect,
412
+ useDropdownContext
413
+ };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@dt-dds/react-dropdown",
3
+ "version": "1.0.0-beta.31",
4
+ "license": "MIT",
5
+ "exports": {
6
+ ".": "./dist/index.js"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist/**"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "dev": "tsup --watch",
17
+ "lint": "eslint --cache .",
18
+ "test": "jest",
19
+ "test:report": "open ./jest-coverage/lcov-report/index.html",
20
+ "test:update:snapshot": "jest -u"
21
+ },
22
+ "dependencies": {
23
+ "@dt-dds/react-box": "1.0.0-beta.10",
24
+ "@dt-dds/react-core": "1.0.0-beta.41",
25
+ "@dt-dds/react-icon": "1.0.0-beta.42",
26
+ "@dt-dds/react-icon-button": "1.0.0-beta.9",
27
+ "@dt-dds/react-typography": "1.0.0-beta.32"
28
+ },
29
+ "devDependencies": {
30
+ "@babel/core": "^7.22.9",
31
+ "@babel/preset-env": "^7.22.9",
32
+ "@babel/preset-react": "^7.22.5",
33
+ "@babel/preset-typescript": "^7.23.3",
34
+ "@emotion/babel-plugin": "^11.11.0",
35
+ "@emotion/css": "^11.7.1",
36
+ "@emotion/jest": "^11.10.0",
37
+ "@emotion/react": "^11.8.2",
38
+ "@emotion/styled": "^11.8.1",
39
+ "@types/react": "^18.0.9",
40
+ "@types/react-dom": "^18.0.4",
41
+ "babel-loader": "^8.3.0",
42
+ "eslint-config-custom": "*",
43
+ "eslint-plugin-storybook": "^9.1.0",
44
+ "jest-config": "*",
45
+ "react": "^18.1.0",
46
+ "react-dom": "^18.2.0",
47
+ "tsconfig": "*",
48
+ "tsup": "^6.6.3",
49
+ "typescript": "^4.5.3"
50
+ },
51
+ "peerDependencies": {
52
+ "@emotion/css": "^11.7.1",
53
+ "@emotion/react": "^11.8.2",
54
+ "@emotion/styled": "^11.8.1",
55
+ "react": ">=17.0.2",
56
+ "react-dom": ">=17.0.2"
57
+ }
58
+ }