datocms-react-ui 0.3.26 → 0.3.30

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.
Files changed (92) hide show
  1. package/dist/cjs/FieldHint/styles.module.css.json +1 -1
  2. package/dist/esm/FieldHint/styles.module.css.json +1 -1
  3. package/package.json +4 -3
  4. package/src/Button/index.tsx +173 -0
  5. package/src/Button/styles.module.css +149 -0
  6. package/src/Button/styles.module.css.json +1 -0
  7. package/src/ButtonGroup/Button/index.tsx +40 -0
  8. package/src/ButtonGroup/Button/styles.module.css +72 -0
  9. package/src/ButtonGroup/Button/styles.module.css.json +1 -0
  10. package/src/ButtonGroup/Group/index.tsx +31 -0
  11. package/src/ButtonGroup/Group/styles.module.css +6 -0
  12. package/src/ButtonGroup/Group/styles.module.css.json +1 -0
  13. package/src/ButtonGroup/index.ts +4 -0
  14. package/src/Canvas/index.tsx +556 -0
  15. package/src/Canvas/styles.module.css +75 -0
  16. package/src/Canvas/styles.module.css.json +1 -0
  17. package/src/ContextInspector/index.tsx +316 -0
  18. package/src/ContextInspector/styles.module.css +90 -0
  19. package/src/ContextInspector/styles.module.css.json +1 -0
  20. package/src/Dropdown/Dropdown.tsx +171 -0
  21. package/src/Dropdown/DropdownContext.tsx +10 -0
  22. package/src/Dropdown/Group.tsx +16 -0
  23. package/src/Dropdown/Menu.tsx +351 -0
  24. package/src/Dropdown/MenuContext.tsx +18 -0
  25. package/src/Dropdown/Option.tsx +148 -0
  26. package/src/Dropdown/OptionAction.tsx +42 -0
  27. package/src/Dropdown/Portal.tsx +46 -0
  28. package/src/Dropdown/Separator.tsx +13 -0
  29. package/src/Dropdown/Text.tsx +8 -0
  30. package/src/Dropdown/index.tsx +26 -0
  31. package/src/Dropdown/styles.module.css +331 -0
  32. package/src/Dropdown/styles.module.css.json +1 -0
  33. package/src/FieldError/index.tsx +10 -0
  34. package/src/FieldError/styles.module.css +6 -0
  35. package/src/FieldError/styles.module.css.json +1 -0
  36. package/src/FieldGroup/index.tsx +25 -0
  37. package/src/FieldGroup/styles.module.css +12 -0
  38. package/src/FieldGroup/styles.module.css.json +1 -0
  39. package/src/FieldHint/index.tsx +10 -0
  40. package/src/FieldHint/styles.module.css +14 -0
  41. package/src/FieldHint/styles.module.css.json +1 -0
  42. package/src/Form/index.tsx +145 -0
  43. package/src/Form/styles.module.css +19 -0
  44. package/src/Form/styles.module.css.json +1 -0
  45. package/src/FormLabel/index.tsx +36 -0
  46. package/src/FormLabel/styles.module.css +31 -0
  47. package/src/FormLabel/styles.module.css.json +1 -0
  48. package/src/Section/index.tsx +104 -0
  49. package/src/Section/styles.module.css +100 -0
  50. package/src/Section/styles.module.css.json +1 -0
  51. package/src/SelectField/index.tsx +244 -0
  52. package/src/SelectInput/index.tsx +233 -0
  53. package/src/SidebarPanel/index.tsx +110 -0
  54. package/src/SidebarPanel/styles.module.css +49 -0
  55. package/src/SidebarPanel/styles.module.css.json +1 -0
  56. package/src/Spinner/index.tsx +68 -0
  57. package/src/Spinner/styles.module.css +31 -0
  58. package/src/Spinner/styles.module.css.json +1 -0
  59. package/src/SwitchField/index.tsx +67 -0
  60. package/src/SwitchField/styles.module.css +25 -0
  61. package/src/SwitchField/styles.module.css.json +1 -0
  62. package/src/SwitchInput/index.tsx +74 -0
  63. package/src/SwitchInput/styles.module.css +100 -0
  64. package/src/SwitchInput/styles.module.css.json +1 -0
  65. package/src/TextField/index.tsx +58 -0
  66. package/src/TextField/styles.module.css +0 -0
  67. package/src/TextField/styles.module.css.json +1 -0
  68. package/src/TextInput/index.tsx +73 -0
  69. package/src/TextInput/styles.module.css +52 -0
  70. package/src/TextInput/styles.module.css.json +1 -0
  71. package/src/Toolbar/Button/index.tsx +32 -0
  72. package/src/Toolbar/Button/styles.module.css +43 -0
  73. package/src/Toolbar/Button/styles.module.css.json +1 -0
  74. package/src/Toolbar/Stack/index.tsx +33 -0
  75. package/src/Toolbar/Stack/styles.module.css +18 -0
  76. package/src/Toolbar/Stack/styles.module.css.json +1 -0
  77. package/src/Toolbar/Title/index.tsx +17 -0
  78. package/src/Toolbar/Title/styles.module.css +12 -0
  79. package/src/Toolbar/Title/styles.module.css.json +1 -0
  80. package/src/Toolbar/Toolbar/index.tsx +112 -0
  81. package/src/Toolbar/Toolbar/styles.module.css +15 -0
  82. package/src/Toolbar/Toolbar/styles.module.css.json +1 -0
  83. package/src/Toolbar/index.ts +8 -0
  84. package/src/base.css +89 -0
  85. package/src/generateStyleFromCtx/index.ts +25 -0
  86. package/src/global.css +23 -0
  87. package/src/icons.tsx +108 -0
  88. package/src/index.ts +23 -0
  89. package/src/mergeRefs/index.ts +8 -0
  90. package/src/useClickOutside/index.ts +30 -0
  91. package/src/useMediaQuery/index.ts +185 -0
  92. package/styles.css +1 -1
@@ -0,0 +1,316 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import React, { useEffect, useState } from 'react';
3
+ import { Button, useCtx } from '..';
4
+ import s from './styles.module.css.json';
5
+
6
+ const baseUrl =
7
+ 'https://github.com/datocms/plugins-sdk/blob/master/packages/sdk/src/types.ts';
8
+
9
+ function copyTextToClipboard(text: string) {
10
+ const textArea = document.createElement('textarea');
11
+ textArea.style.position = 'fixed';
12
+ textArea.style.top = '0';
13
+ textArea.style.left = '0';
14
+ textArea.style.width = '2em';
15
+ textArea.style.height = '2em';
16
+ textArea.style.padding = '0';
17
+ textArea.style.border = 'none';
18
+ textArea.style.outline = 'none';
19
+ textArea.style.boxShadow = 'none';
20
+ textArea.style.background = 'transparent';
21
+ textArea.value = text;
22
+ document.body.appendChild(textArea);
23
+ textArea.focus();
24
+ textArea.select();
25
+
26
+ try {
27
+ document.execCommand('copy');
28
+ } catch (err) {
29
+ // NOP
30
+ }
31
+
32
+ document.body.removeChild(textArea);
33
+ }
34
+
35
+ function addFinalPeriod(text: string) {
36
+ if (['!', '.'].includes(text[text.length - 1])) {
37
+ return text;
38
+ }
39
+
40
+ return `${text}.`;
41
+ }
42
+
43
+ function findChildrenById(manifest: any, id: string) {
44
+ return manifest.children.find((child: any) => child.id === id);
45
+ }
46
+
47
+ function findShortText(signature: any) {
48
+ return (
49
+ (signature.comment && addFinalPeriod(signature.comment.shortText)) || null
50
+ );
51
+ }
52
+
53
+ function findFirstTag(signature: any, tagName: string): string | null {
54
+ if (!signature.comment || !signature.comment.tags) {
55
+ return null;
56
+ }
57
+
58
+ const tagNode = signature.comment.tags.find(
59
+ (tag: any) => tag.tag === tagName,
60
+ );
61
+
62
+ if (!tagNode) {
63
+ return null;
64
+ }
65
+
66
+ return tagNode.text;
67
+ }
68
+
69
+ function findExample(signature: any) {
70
+ const example = findFirstTag(signature, 'example');
71
+
72
+ if (!example) {
73
+ return null;
74
+ }
75
+
76
+ const lines = example
77
+ .split(/\n/)
78
+ .filter((l, i, all) => l.length !== 0 || (i !== 0 && i !== all.length - 1));
79
+
80
+ const spacesPerLine = lines.map((line) => {
81
+ const spaces = line.match(/^\s*/);
82
+ return spaces ? spaces[0].length : 0;
83
+ });
84
+
85
+ const commonIndentation = Math.min(...spacesPerLine);
86
+
87
+ const result = lines
88
+ .map((line) => line.substring(commonIndentation))
89
+ .join('\n');
90
+
91
+ return result.match(/```[a-z]*\n([\s\S]*?)\n```/)?.[1].trim();
92
+ }
93
+
94
+ function buildCtx(manifest: any, definition: any) {
95
+ if (definition.type.type === 'intersection') {
96
+ let result: any[] = [];
97
+
98
+ definition.type.types.forEach((elementInIntersection: any) => {
99
+ if (elementInIntersection.type === 'reference') {
100
+ const innerDefinition = findChildrenById(
101
+ manifest,
102
+ elementInIntersection.id,
103
+ );
104
+ result = [...result, buildCtx(manifest, innerDefinition)];
105
+ }
106
+ });
107
+
108
+ return result.flat().filter((x) => x);
109
+ }
110
+
111
+ if (definition.type.type === 'reflection') {
112
+ const properties = definition.type.declaration.children.filter(
113
+ (child: any) =>
114
+ !['mode', 'getSettings', 'setHeight', 'bodyPadding'].includes(
115
+ child.name,
116
+ ),
117
+ );
118
+
119
+ if (properties.length === 0) {
120
+ return null;
121
+ }
122
+
123
+ return {
124
+ name: definition.name,
125
+ description: findShortText(definition),
126
+ properties: properties.map((child: any) => {
127
+ if (
128
+ child.type &&
129
+ child.type.declaration &&
130
+ child.type.declaration.signatures
131
+ ) {
132
+ child.signatures = child.type.declaration.signatures;
133
+ }
134
+
135
+ if (child.signatures) {
136
+ const signature = child.signatures[0];
137
+ return {
138
+ name: child.name,
139
+ type: 'function',
140
+ description: findShortText(signature),
141
+ example: findExample(signature),
142
+ group: definition.name,
143
+ lineNumber: child.sources[0].line,
144
+ };
145
+ }
146
+
147
+ return {
148
+ name: child.name,
149
+ type: 'property',
150
+ description: findShortText(child),
151
+ example: findExample(child),
152
+ groupDescription: findShortText(definition),
153
+ group: definition.name,
154
+ lineNumber: child.sources[0].line,
155
+ };
156
+ }),
157
+ };
158
+ }
159
+
160
+ throw new Error(`Don\t know how to handle ${definition}`);
161
+ }
162
+
163
+ const ExpandablePane = ({ children, label }: any) => {
164
+ const [open, setOpen] = useState(false);
165
+
166
+ return (
167
+ <div className={s.panel}>
168
+ <button
169
+ className={s.panelHandle}
170
+ onClick={() => setOpen((open) => !open)}
171
+ >
172
+ {label}
173
+ </button>
174
+ {open && <div className={s.panelBody}>{children}</div>}
175
+ </div>
176
+ );
177
+ };
178
+
179
+ export function ContextInspector(): JSX.Element {
180
+ const ctx = useCtx();
181
+ const [groups, setGroups] = useState<any[] | null>(null);
182
+
183
+ useEffect(() => {
184
+ const runner = async () => {
185
+ const response = await fetch(
186
+ 'https://unpkg.com/datocms-plugin-sdk/types.json',
187
+ );
188
+ const manifest = await response.json();
189
+
190
+ const connectParameters = manifest.children.find(
191
+ (child: any) => child.name === 'FullConnectParameters',
192
+ );
193
+
194
+ const hook = connectParameters.type.declaration.children.find(
195
+ (hook: any) => hook.signatures[0].name === (ctx as any).mode,
196
+ );
197
+
198
+ const signature = hook.signatures[0];
199
+ const ctxParameter = signature.parameters.find(
200
+ (p: any) => p.name === 'ctx',
201
+ );
202
+
203
+ setGroups(
204
+ buildCtx(
205
+ manifest,
206
+ findChildrenById(manifest, ctxParameter.type.id),
207
+ ) as any[],
208
+ );
209
+ };
210
+
211
+ runner();
212
+ }, [setGroups]);
213
+
214
+ const handleCopy = (text: string) => {
215
+ copyTextToClipboard(text);
216
+ (ctx as any).notice('Copied to clipboard!');
217
+ };
218
+
219
+ const handleRun = (example: string) => {
220
+ Function(
221
+ `
222
+ "use strict";
223
+ return(
224
+ async function(ctx) {
225
+ try {
226
+ ${example}
227
+ } catch(e) {
228
+ console.error(e);
229
+ await ctx.alert('Execution failed! See console for errors!');
230
+ }
231
+ }
232
+ )
233
+ `,
234
+ )()(ctx);
235
+ };
236
+
237
+ return (
238
+ <div className={s.inspector}>
239
+ {groups &&
240
+ groups.map((group) => {
241
+ const name = group.name
242
+ .replace('AdditionalMethods', 'Methods')
243
+ .replace('AdditionalProperties', 'Properties')
244
+ .replace('Methods', ' methods')
245
+ .replace('Properties', ' properties')
246
+ .replace('Utilities', ' utilities');
247
+
248
+ return (
249
+ <ExpandablePane label={`${name}`} key={name}>
250
+ <div className={s.groupDescription}>{group.description}</div>
251
+ <div className={s.propertyGroup}>
252
+ {(group.properties || []).map((item: any) => (
253
+ <div key={item.name} className={s.propertyOrMethod}>
254
+ <div className={s.propertyOrMethodBody}>
255
+ <a
256
+ className={s.propertyOrMethodName}
257
+ href={`${baseUrl}#L${item.lineNumber}`}
258
+ target="_blank"
259
+ rel="noreferrer"
260
+ >
261
+ {item.name}
262
+ {item.type === 'function' ? '()' : ''}
263
+ </a>
264
+
265
+ <div>{item.description}</div>
266
+ </div>
267
+ {item.type === 'property' && (
268
+ <div className={s.propertyOrMethodExample}>
269
+ <pre>
270
+ {JSON.stringify((ctx as any)[item.name], null, 2)}
271
+ </pre>
272
+ <div className={s.propertyOrMethodExampleActions}>
273
+ <Button
274
+ type="button"
275
+ buttonSize="xxs"
276
+ onClick={handleCopy.bind(
277
+ null,
278
+ JSON.stringify((ctx as any)[item.name], null, 2),
279
+ )}
280
+ >
281
+ Copy value
282
+ </Button>
283
+ </div>
284
+ </div>
285
+ )}
286
+ {item.example && (
287
+ <div className={s.propertyOrMethodExample}>
288
+ <pre>{item.example}</pre>
289
+ <div className={s.propertyOrMethodExampleActions}>
290
+ <Button
291
+ type="button"
292
+ buttonSize="xxs"
293
+ buttonType="primary"
294
+ onClick={handleRun.bind(null, item.example)}
295
+ >
296
+ Run example
297
+ </Button>
298
+ <Button
299
+ type="button"
300
+ buttonSize="xxs"
301
+ onClick={handleCopy.bind(null, item.example)}
302
+ >
303
+ Copy example
304
+ </Button>
305
+ </div>
306
+ </div>
307
+ )}
308
+ </div>
309
+ ))}
310
+ </div>
311
+ </ExpandablePane>
312
+ );
313
+ })}
314
+ </div>
315
+ );
316
+ }
@@ -0,0 +1,90 @@
1
+ .inspector {
2
+ margin: var(--spacing-l) 0;
3
+ }
4
+
5
+ .panel {
6
+ border-bottom: 1px solid var(--border-color);
7
+ }
8
+
9
+ .panelHandle {
10
+ all: inherit;
11
+ display: block;
12
+ box-sizing: border-box;
13
+ width: 100%;
14
+ font-weight: var(--font-weight-bold);
15
+ background: var(--light-bg-color);
16
+ border: 0;
17
+ padding: 5px 10px;
18
+ cursor: pointer;
19
+
20
+ &:hover {
21
+ background: var(--lighter-bg-color);
22
+ }
23
+ }
24
+
25
+ .panelBody {
26
+ padding: 20px;
27
+ border-left: 1px solid var(--border-color);
28
+ border-right: 1px solid var(--border-color);
29
+ }
30
+
31
+ .groupDescription {
32
+ line-height: 1.2;
33
+ margin-bottom: 20px;
34
+ font-size: var(--font-size-s);
35
+ }
36
+
37
+ .propertyGroup {
38
+ border: 1px solid var(--border-color);
39
+ border-radius: 5px;
40
+ }
41
+
42
+ .propertyOrMethod {
43
+ border-bottom: 1px solid var(--border-color);
44
+ line-height: 1.2;
45
+
46
+ p {
47
+ margin: 0;
48
+ }
49
+ }
50
+
51
+ .propertyOrMethodBody {
52
+ padding: 15px;
53
+ }
54
+
55
+ .propertyOrMethodExample {
56
+ position: relative;
57
+
58
+ pre {
59
+ padding: 15px;
60
+ background: var(--light-bg-color);
61
+ font-size: 0.8em;
62
+ margin: 0;
63
+ max-height: 240px;
64
+ overflow: auto;
65
+ }
66
+ }
67
+
68
+ .propertyOrMethodName {
69
+ display: block;
70
+ text-decoration: none;
71
+ font-weight: bold;
72
+ color: var(--light-body-color);
73
+ font-family: var(--monospaced-font-family);
74
+ font-size: 0.9em;
75
+ margin-bottom: 5px;
76
+
77
+ &:hover {
78
+ text-decoration: underline;
79
+ }
80
+ }
81
+
82
+ .propertyOrMethodExampleActions {
83
+ padding: 15px;
84
+ background: white;
85
+ display: flex;
86
+
87
+ > * {
88
+ margin-right: 10px;
89
+ }
90
+ }
@@ -0,0 +1 @@
1
+ {"inspector":"_inspector_u6041_1","panel":"_panel_u6041_5","panelHandle":"_panelHandle_u6041_9","panelBody":"_panelBody_u6041_25","groupDescription":"_groupDescription_u6041_31","propertyGroup":"_propertyGroup_u6041_37","propertyOrMethod":"_propertyOrMethod_u6041_42","propertyOrMethodBody":"_propertyOrMethodBody_u6041_51","propertyOrMethodExample":"_propertyOrMethodExample_u6041_55","propertyOrMethodName":"_propertyOrMethodName_u6041_68","propertyOrMethodExampleActions":"_propertyOrMethodExampleActions_u6041_82"}
@@ -0,0 +1,171 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { MediaQuery } from '../useMediaQuery';
3
+ import { useClickOutside } from '../useClickOutside';
4
+ import { DropdownContext } from './DropdownContext';
5
+ import s from './styles.module.css.json';
6
+
7
+ type RenderTriggerCtx = {
8
+ open: boolean;
9
+ onClick: () => void;
10
+ };
11
+
12
+ export type DropdownProps = {
13
+ renderTrigger: (ctx: RenderTriggerCtx) => JSX.Element;
14
+ children: React.ReactNode;
15
+ };
16
+
17
+ /**
18
+ * @example Basic example
19
+ *
20
+ * ```js
21
+ * <Canvas ctx={ctx}>
22
+ * <Dropdown
23
+ * renderTrigger={({ open, onClick }) => (
24
+ * <Button
25
+ * onClick={onClick}
26
+ * rightIcon={open ? <CaretUpIcon /> : <CaretDownIcon />}
27
+ * >
28
+ * Options
29
+ * </Button>
30
+ * )}
31
+ * >
32
+ * <DropdownMenu>
33
+ * <DropdownOption onClick={() => {}}>Edit</DropdownOption>
34
+ * <DropdownOption disabled onClick={() => {}}>
35
+ * Duplicate
36
+ * </DropdownOption>
37
+ * <DropdownSeparator />
38
+ * <DropdownOption red onClick={() => {}}>
39
+ * Delete
40
+ * </DropdownOption>
41
+ * </DropdownMenu>
42
+ * </Dropdown>
43
+ * </Canvas>;
44
+ * ```
45
+ *
46
+ * @example Option actions
47
+ *
48
+ * ```js
49
+ * <Canvas ctx={ctx}>
50
+ * <Dropdown
51
+ * renderTrigger={({ open, onClick }) => (
52
+ * <Button
53
+ * onClick={onClick}
54
+ * rightIcon={open ? <CaretUpIcon /> : <CaretDownIcon />}
55
+ * >
56
+ * Fields
57
+ * </Button>
58
+ * )}
59
+ * >
60
+ * <DropdownMenu>
61
+ * <DropdownOption>
62
+ * First option
63
+ * <DropdownOptionAction icon={<PlusIcon />} onClick={() => {}} />
64
+ * <DropdownOptionAction
65
+ * red
66
+ * icon={<TrashIcon />}
67
+ * onClick={() => {}}
68
+ * />
69
+ * </DropdownOption>
70
+ * <DropdownOption>
71
+ * Second option
72
+ * <DropdownOptionAction icon={<PlusIcon />} onClick={() => {}} />
73
+ * <DropdownOptionAction
74
+ * red
75
+ * icon={<TrashIcon />}
76
+ * onClick={() => {}}
77
+ * />
78
+ * </DropdownOption>
79
+ * </DropdownMenu>
80
+ * </Dropdown>
81
+ * </Canvas>;
82
+ * ```
83
+ *
84
+ * @example Option groups
85
+ *
86
+ * ```js
87
+ * <Canvas ctx={ctx}>
88
+ * <Dropdown
89
+ * renderTrigger={({ open, onClick }) => (
90
+ * <Button
91
+ * onClick={onClick}
92
+ * rightIcon={open ? <CaretUpIcon /> : <CaretDownIcon />}
93
+ * >
94
+ * Fields
95
+ * </Button>
96
+ * )}
97
+ * >
98
+ * <DropdownMenu>
99
+ * <DropdownGroup name="Group 1">
100
+ * <DropdownOption>Foo</DropdownOption>
101
+ * <DropdownOption>Bar</DropdownOption>
102
+ * <DropdownOption>Qux</DropdownOption>
103
+ * </DropdownGroup>
104
+ * <DropdownGroup name="Group 2">
105
+ * <DropdownOption>Foo</DropdownOption>
106
+ * <DropdownOption>Bar</DropdownOption>
107
+ * <DropdownOption>Qux</DropdownOption>
108
+ * </DropdownGroup>
109
+ * <DropdownGroup name="Group 3">
110
+ * <DropdownOption>Foo</DropdownOption>
111
+ * <DropdownOption>Bar</DropdownOption>
112
+ * <DropdownOption>Qux</DropdownOption>
113
+ * </DropdownGroup>
114
+ * </DropdownMenu>
115
+ * </Dropdown>
116
+ * </Canvas>;
117
+ * ```
118
+ */
119
+ export function Dropdown({
120
+ renderTrigger,
121
+ children,
122
+ }: DropdownProps): JSX.Element {
123
+ const isClickOutsideEnabled = useRef<boolean>();
124
+ const [isOpen, setOpen] = useState(false);
125
+
126
+ useEffect(() => {
127
+ isClickOutsideEnabled.current = false;
128
+ }, []);
129
+
130
+ const handleClickOutside = useCallback(
131
+ (event) => {
132
+ if (
133
+ isClickOutsideEnabled.current &&
134
+ !event.target.closest('.' + s['Dropdown__menu']) &&
135
+ isOpen
136
+ ) {
137
+ setOpen(false);
138
+ }
139
+ },
140
+ [setOpen, isOpen, isClickOutsideEnabled],
141
+ );
142
+
143
+ const outsideRef = useClickOutside<HTMLDivElement>(handleClickOutside);
144
+
145
+ const handleClose = useCallback(() => {
146
+ setOpen(false);
147
+ }, [setOpen]);
148
+
149
+ const handleToggle = useCallback(() => {
150
+ setOpen((open) => !open);
151
+ }, [setOpen]);
152
+
153
+ return (
154
+ <MediaQuery media="(max-width: 1024px)">
155
+ {({ matches }) => {
156
+ // In small devices click outside is disabled because
157
+ // the menu goes full screen and has a close button.
158
+ isClickOutsideEnabled.current = !matches;
159
+
160
+ return (
161
+ <DropdownContext.Provider value={{ closeMenu: handleClose }}>
162
+ <div className={s['Dropdown']} ref={outsideRef}>
163
+ {renderTrigger({ open: isOpen, onClick: handleToggle })}
164
+ {isOpen && children}
165
+ </div>
166
+ </DropdownContext.Provider>
167
+ );
168
+ }}
169
+ </MediaQuery>
170
+ );
171
+ }
@@ -0,0 +1,10 @@
1
+ import { createContext } from 'react';
2
+
3
+ type DropdownContextType = {
4
+ closeMenu: () => void;
5
+ };
6
+
7
+ export const DropdownContext = createContext<DropdownContextType>({
8
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
9
+ closeMenu: () => {},
10
+ });
@@ -0,0 +1,16 @@
1
+ import React, { ReactNode } from 'react';
2
+ import s from './styles.module.css.json';
3
+
4
+ export type GroupProps = {
5
+ children: React.ReactNode;
6
+ name: ReactNode;
7
+ };
8
+
9
+ export const Group = ({ children, name }: GroupProps): JSX.Element => {
10
+ return (
11
+ <div>
12
+ <div className={s['Dropdown__menu__group__title']}>{name}</div>
13
+ <div className={s['Dropdown__menu__group__content']}>{children}</div>
14
+ </div>
15
+ );
16
+ };