@neo4j-ndl/react 4.16.7 → 4.16.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/lib/cjs/color-picker/ColorPicker.js +3 -1
- package/lib/cjs/color-picker/ColorPicker.js.map +1 -1
- package/lib/cjs/color-picker/stories/color-picker-dialog.story.js +40 -0
- package/lib/cjs/color-picker/stories/color-picker-dialog.story.js.map +1 -0
- package/lib/cjs/color-picker/stories/color-picker-popover.story.js +32 -0
- package/lib/cjs/color-picker/stories/color-picker-popover.story.js.map +1 -0
- package/lib/cjs/color-picker/stories/index.js +9 -1
- package/lib/cjs/color-picker/stories/index.js.map +1 -1
- package/lib/cjs/popover/use-popover.js +1 -1
- package/lib/cjs/popover/use-popover.js.map +1 -1
- package/lib/cjs/select/Select.js +2 -0
- package/lib/cjs/select/Select.js.map +1 -1
- package/lib/esm/color-picker/ColorPicker.js +3 -1
- package/lib/esm/color-picker/ColorPicker.js.map +1 -1
- package/lib/esm/color-picker/stories/color-picker-dialog.story.js +38 -0
- package/lib/esm/color-picker/stories/color-picker-dialog.story.js.map +1 -0
- package/lib/esm/color-picker/stories/color-picker-popover.story.js +30 -0
- package/lib/esm/color-picker/stories/color-picker-popover.story.js.map +1 -0
- package/lib/esm/color-picker/stories/index.js +6 -0
- package/lib/esm/color-picker/stories/index.js.map +1 -1
- package/lib/esm/popover/use-popover.js +1 -1
- package/lib/esm/popover/use-popover.js.map +1 -1
- package/lib/esm/select/Select.js +2 -0
- package/lib/esm/select/Select.js.map +1 -1
- package/lib/types/color-picker/ColorPicker.d.ts +4 -0
- package/lib/types/color-picker/ColorPicker.d.ts.map +1 -1
- package/lib/types/color-picker/stories/color-picker-dialog.story.d.ts +24 -0
- package/lib/types/color-picker/stories/color-picker-dialog.story.d.ts.map +1 -0
- package/lib/types/color-picker/stories/color-picker-popover.story.d.ts +24 -0
- package/lib/types/color-picker/stories/color-picker-popover.story.d.ts.map +1 -0
- package/lib/types/color-picker/stories/index.d.ts +4 -0
- package/lib/types/color-picker/stories/index.d.ts.map +1 -1
- package/lib/types/select/Select.d.ts.map +1 -1
- package/package.json +5 -2
- package/skills/ndl-react/SKILL.md +152 -0
- package/skills/ndl-react/components/accordion.md +386 -0
- package/skills/ndl-react/components/ai/code-preview.md +128 -0
- package/skills/ndl-react/components/ai/file-tag.md +90 -0
- package/skills/ndl-react/components/ai/image-tag.md +91 -0
- package/skills/ndl-react/components/ai/more-files.md +73 -0
- package/skills/ndl-react/components/ai/presence.md +54 -0
- package/skills/ndl-react/components/ai/preview.md +498 -0
- package/skills/ndl-react/components/ai/prompt.md +362 -0
- package/skills/ndl-react/components/ai/reasoning.md +95 -0
- package/skills/ndl-react/components/ai/response.md +1109 -0
- package/skills/ndl-react/components/ai/suggestion.md +84 -0
- package/skills/ndl-react/components/ai/thinking.md +43 -0
- package/skills/ndl-react/components/ai/tool-call.md +43 -0
- package/skills/ndl-react/components/ai/user-bubble.md +187 -0
- package/skills/ndl-react/components/avatar.md +169 -0
- package/skills/ndl-react/components/banner.md +225 -0
- package/skills/ndl-react/components/box.md +39 -0
- package/skills/ndl-react/components/breadcrumbs.md +245 -0
- package/skills/ndl-react/components/checkbox.md +269 -0
- package/skills/ndl-react/components/clean-icon-button.md +294 -0
- package/skills/ndl-react/components/clipboard-button.md +154 -0
- package/skills/ndl-react/components/code-block.md +276 -0
- package/skills/ndl-react/components/code.md +68 -0
- package/skills/ndl-react/components/color-picker.md +131 -0
- package/skills/ndl-react/components/conditional-wrap.md +46 -0
- package/skills/ndl-react/components/data-grid.md +3121 -0
- package/skills/ndl-react/components/date-picker.md +652 -0
- package/skills/ndl-react/components/dialog.md +485 -0
- package/skills/ndl-react/components/dismissible-tag.md +136 -0
- package/skills/ndl-react/components/divider.md +96 -0
- package/skills/ndl-react/components/drawer.md +543 -0
- package/skills/ndl-react/components/dropdown-button.md +161 -0
- package/skills/ndl-react/components/dropzone.md +371 -0
- package/skills/ndl-react/components/filled-button.md +26 -0
- package/skills/ndl-react/components/flex.md +82 -0
- package/skills/ndl-react/components/graph-label.md +167 -0
- package/skills/ndl-react/components/icon-button-array.md +187 -0
- package/skills/ndl-react/components/icon-button.md +193 -0
- package/skills/ndl-react/components/inline-edit.md +209 -0
- package/skills/ndl-react/components/kbd.md +63 -0
- package/skills/ndl-react/components/loading-bar.md +43 -0
- package/skills/ndl-react/components/loading-spinner.md +57 -0
- package/skills/ndl-react/components/logo.md +57 -0
- package/skills/ndl-react/components/menu.md +993 -0
- package/skills/ndl-react/components/modal.md +27 -0
- package/skills/ndl-react/components/next/tree-view.md +966 -0
- package/skills/ndl-react/components/outlined-button.md +26 -0
- package/skills/ndl-react/components/popover.md +283 -0
- package/skills/ndl-react/components/progress-bar.md +70 -0
- package/skills/ndl-react/components/radio.md +150 -0
- package/skills/ndl-react/components/read-only-tag.md +96 -0
- package/skills/ndl-react/components/segmented-control.md +200 -0
- package/skills/ndl-react/components/select-icon-button.md +183 -0
- package/skills/ndl-react/components/select.md +530 -0
- package/skills/ndl-react/components/selectable-tag.md +203 -0
- package/skills/ndl-react/components/side-navigation.md +652 -0
- package/skills/ndl-react/components/skeleton.md +274 -0
- package/skills/ndl-react/components/slider.md +308 -0
- package/skills/ndl-react/components/spotlight.md +796 -0
- package/skills/ndl-react/components/status-indicator.md +57 -0
- package/skills/ndl-react/components/status-label.md +132 -0
- package/skills/ndl-react/components/switch.md +167 -0
- package/skills/ndl-react/components/tabs.md +433 -0
- package/skills/ndl-react/components/tag.md +91 -0
- package/skills/ndl-react/components/text-area.md +178 -0
- package/skills/ndl-react/components/text-button.md +25 -0
- package/skills/ndl-react/components/text-input.md +475 -0
- package/skills/ndl-react/components/text-link.md +119 -0
- package/skills/ndl-react/components/time-picker.md +137 -0
- package/skills/ndl-react/components/timezone-picker.md +496 -0
- package/skills/ndl-react/components/tooltip.md +478 -0
- package/skills/ndl-react/components/tree-view.md +545 -0
- package/skills/ndl-react/components/typography.md +72 -0
- package/skills/ndl-react/components/wizard.md +152 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# DropdownButton
|
|
2
|
+
|
|
3
|
+
Import: `import { DropdownButton } from '@neo4j-ndl/react'`
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
### DropdownButton
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Required | Default | Description |
|
|
10
|
+
|------|------|----------|---------|-------------|
|
|
11
|
+
| `as` | `ElementType<any, keyof IntrinsicElements>` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
12
|
+
| `children` | `ReactNode` | | | Content displayed in the button |
|
|
13
|
+
| `isDisabled` | `boolean` | | `false` | Whether the button is in disabled state |
|
|
14
|
+
| `isFloating` | `boolean` | | `false` | Whether the button is in floating state |
|
|
15
|
+
| `isLoading` | `boolean` | | `false` | If the button is loading. Will display a loading spinner |
|
|
16
|
+
| `isOpen` | `boolean` | | `false` | If the dropdown is activated |
|
|
17
|
+
| `leadingElement` | `ReactNode` | | | Element that is shown before the button content |
|
|
18
|
+
| `loadingMessage` | `string` | | `Loading` | Accessible message for screen readers when the button is in a loading state |
|
|
19
|
+
| `onClick` | `((e: MouseEvent<HTMLButtonElement, MouseEvent>) => void)` | | | Callback function to be called when the button is clicked |
|
|
20
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
21
|
+
| `size` | `'large' \| 'medium' \| 'small'` | | `medium` | Size of button |
|
|
22
|
+
|
|
23
|
+
Make sure to set `isOpen` to the corresponding state of the Menu that is being opened by the DropdownButton. That makes sure proper styling and aria attributes are applied to reflect the state.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### Default
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
31
|
+
|
|
32
|
+
import { DropdownButton } from '@neo4j-ndl/react';
|
|
33
|
+
|
|
34
|
+
const Component = () => {
|
|
35
|
+
return <DropdownButton>Dropdown Button</DropdownButton>;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default Component;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Disabled
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
45
|
+
|
|
46
|
+
import { DropdownButton } from '@neo4j-ndl/react';
|
|
47
|
+
|
|
48
|
+
const Component = () => {
|
|
49
|
+
return <DropdownButton isDisabled={true}>Dropdown Button</DropdownButton>;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default Component;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Floating
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
59
|
+
|
|
60
|
+
import { DropdownButton } from '@neo4j-ndl/react';
|
|
61
|
+
|
|
62
|
+
const Component = () => {
|
|
63
|
+
return <DropdownButton isFloating={true}>Dropdown Button</DropdownButton>;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default Component;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Loading
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
73
|
+
|
|
74
|
+
import { DropdownButton } from '@neo4j-ndl/react';
|
|
75
|
+
|
|
76
|
+
const Component = () => {
|
|
77
|
+
return (
|
|
78
|
+
<DropdownButton isLoading loadingMessage="Loading">
|
|
79
|
+
Dropdown Button
|
|
80
|
+
</DropdownButton>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default Component;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### With Avatar
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
91
|
+
|
|
92
|
+
import { Avatar, DropdownButton } from '@neo4j-ndl/react';
|
|
93
|
+
|
|
94
|
+
const Component = () => {
|
|
95
|
+
return (
|
|
96
|
+
<DropdownButton
|
|
97
|
+
leadingElement={<Avatar name="KM" type="icon" shape="square" />}
|
|
98
|
+
>
|
|
99
|
+
Dropdown Button
|
|
100
|
+
</DropdownButton>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export default Component;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### With Menu
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
111
|
+
|
|
112
|
+
import { DropdownButton, Menu } from '@neo4j-ndl/react';
|
|
113
|
+
import { useRef, useState } from 'react';
|
|
114
|
+
|
|
115
|
+
const Component = () => {
|
|
116
|
+
const anchorRef = useRef<HTMLButtonElement | null>(null);
|
|
117
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div>
|
|
121
|
+
<DropdownButton
|
|
122
|
+
isOpen={isMenuOpen}
|
|
123
|
+
onClick={() => setIsMenuOpen((old) => !old)}
|
|
124
|
+
ref={anchorRef}
|
|
125
|
+
>
|
|
126
|
+
Dropdown Button
|
|
127
|
+
</DropdownButton>
|
|
128
|
+
<Menu
|
|
129
|
+
isOpen={isMenuOpen}
|
|
130
|
+
anchorRef={anchorRef}
|
|
131
|
+
onClose={() => setIsMenuOpen(false)}
|
|
132
|
+
>
|
|
133
|
+
<Menu.Item title="Action 1" />
|
|
134
|
+
<Menu.Item title="Action 2" />
|
|
135
|
+
<Menu.Item title="Action 3" />
|
|
136
|
+
<Menu.Item title="Action 4" />
|
|
137
|
+
</Menu>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export default Component;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### With Status Indicator
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
149
|
+
|
|
150
|
+
import { DropdownButton, StatusIndicator } from '@neo4j-ndl/react';
|
|
151
|
+
|
|
152
|
+
const Component = () => {
|
|
153
|
+
return (
|
|
154
|
+
<DropdownButton leadingElement={<StatusIndicator variant="info" />}>
|
|
155
|
+
Dropdown Button
|
|
156
|
+
</DropdownButton>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default Component;
|
|
161
|
+
```
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# Dropzone
|
|
2
|
+
|
|
3
|
+
Import: `import { Dropzone } from '@neo4j-ndl/react'`
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
### Dropzone
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Required | Default | Description |
|
|
10
|
+
|------|------|----------|---------|-------------|
|
|
11
|
+
| `acceptedFileExtensions` | `string[]` | | | The accepted file extensions for the Drag-and-Drop. |
|
|
12
|
+
| `dropZoneOptions` | `DropzoneOptions` | ✅ | | Props for the underlying `react-dropzone` component. Don't use `accept`. If using custom file extensions as this option is broken. Instead use the `acceptedFileExtensions` property. |
|
|
13
|
+
| `heading` | `ReactNode` | | | Use when wanting a custom heading. |
|
|
14
|
+
| `loadingElement` | `ReactNode` | | | Element to display when uploading the file. |
|
|
15
|
+
| `ref` | `Ref<HTMLDivElement>` | | | A ref to apply to the root element. |
|
|
16
|
+
| `rejectedText` | `ReactNode` | | | Message to be shown when file is rejected. |
|
|
17
|
+
| `supportedFilesDescription` | `ReactNode` | | | Informational text that highlights the supported file types, will be displayed in the footer. |
|
|
18
|
+
|
|
19
|
+
Where `DropzoneOptions` is the props for the `react-dropzone` library. For more information, see the [react-dropzone documentation](https://react-dropzone.js.org/#src).
|
|
20
|
+
|
|
21
|
+
### Dropzone.LoadingProgressBar
|
|
22
|
+
|
|
23
|
+
| Prop | Type | Required | Default | Description |
|
|
24
|
+
|------|------|----------|---------|-------------|
|
|
25
|
+
| `progressBarMinute` | `number` | | | The time in minute left to upload the file. |
|
|
26
|
+
| `progressBarPrecentage` | `number` | ✅ | | The percentage of the progress bar. |
|
|
27
|
+
| `ref` | `Ref<HTMLDivElement>` | | | A ref to apply to the root element. |
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### Default
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { Dropzone } from '@neo4j-ndl/react';
|
|
35
|
+
import { type DropzoneOptions } from 'react-dropzone';
|
|
36
|
+
|
|
37
|
+
const Component = () => {
|
|
38
|
+
const onDrop: DropzoneOptions['onDrop'] = (files) => {
|
|
39
|
+
alert(
|
|
40
|
+
`attempted to upload ${
|
|
41
|
+
files.length
|
|
42
|
+
} file(s). Check console logs for more info`,
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Dropzone
|
|
48
|
+
dropZoneOptions={{
|
|
49
|
+
onDrop,
|
|
50
|
+
}}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default Component;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Csv Files
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { Dropzone } from '@neo4j-ndl/react';
|
|
62
|
+
import { type DropzoneOptions } from 'react-dropzone';
|
|
63
|
+
|
|
64
|
+
const Component = () => {
|
|
65
|
+
const onDrop: DropzoneOptions['onDrop'] = (files) => {
|
|
66
|
+
alert(
|
|
67
|
+
`attempted to upload ${
|
|
68
|
+
files.length
|
|
69
|
+
} file(s). Check console logs for more info`,
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Dropzone
|
|
75
|
+
supportedFilesDescription="Supports: CSV"
|
|
76
|
+
dropZoneOptions={{
|
|
77
|
+
accept: { 'text/csv': ['.csv'] },
|
|
78
|
+
onDrop,
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default Component;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Custom Extensions
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { Dropzone } from '@neo4j-ndl/react';
|
|
91
|
+
import { type DropzoneOptions } from 'react-dropzone';
|
|
92
|
+
|
|
93
|
+
const Component = () => {
|
|
94
|
+
const onDrop: DropzoneOptions['onDrop'] = (files) => {
|
|
95
|
+
alert(
|
|
96
|
+
`attempted to upload ${
|
|
97
|
+
files.length
|
|
98
|
+
} file(s). Check console logs for more info`,
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Dropzone
|
|
104
|
+
supportedFilesDescription="Supports: .dump"
|
|
105
|
+
acceptedFileExtensions={['.dump']}
|
|
106
|
+
dropZoneOptions={{
|
|
107
|
+
onDrop,
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export default Component;
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Disabled
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { Dropzone } from '@neo4j-ndl/react';
|
|
120
|
+
import { type DropzoneOptions } from 'react-dropzone';
|
|
121
|
+
|
|
122
|
+
const Component = () => {
|
|
123
|
+
const onDrop: DropzoneOptions['onDrop'] = (files) => {
|
|
124
|
+
alert(
|
|
125
|
+
`attempted to upload ${
|
|
126
|
+
files.length
|
|
127
|
+
} file(s). Check console logs for more info`,
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<Dropzone
|
|
133
|
+
supportedFilesDescription="Supports: CSV Files"
|
|
134
|
+
dropZoneOptions={{
|
|
135
|
+
accept: { 'text/csv': ['.csv'] },
|
|
136
|
+
disabled: true,
|
|
137
|
+
onDrop,
|
|
138
|
+
}}
|
|
139
|
+
/>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export default Component;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Full
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { XMarkIcon } from '@heroicons/react/24/solid';
|
|
150
|
+
import { Dropzone, FilledButton, Typography } from '@neo4j-ndl/react';
|
|
151
|
+
import { useCallback, useState } from 'react';
|
|
152
|
+
import {
|
|
153
|
+
type DropEvent,
|
|
154
|
+
type DropzoneOptions,
|
|
155
|
+
type FileRejection,
|
|
156
|
+
} from 'react-dropzone';
|
|
157
|
+
|
|
158
|
+
// Configuration constants
|
|
159
|
+
const CONFIG = {
|
|
160
|
+
MAX_FILES: 3,
|
|
161
|
+
MAX_FILE_SIZE: 5 * 1024 * 1024, // 5MB
|
|
162
|
+
PROGRESS_INCREMENT: 5,
|
|
163
|
+
UPDATE_INTERVAL: 100,
|
|
164
|
+
ACCEPTED_EXTENSIONS: ['.txt', '.json'] as string[],
|
|
165
|
+
} as const;
|
|
166
|
+
|
|
167
|
+
enum UploadState {
|
|
168
|
+
Idle = 'idle',
|
|
169
|
+
Uploading = 'uploading',
|
|
170
|
+
Success = 'success',
|
|
171
|
+
Error = 'error',
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
interface UploadData {
|
|
175
|
+
state: UploadState;
|
|
176
|
+
progress: number;
|
|
177
|
+
files: File[];
|
|
178
|
+
errors: string[];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const Component = () => {
|
|
182
|
+
const [uploadData, setUploadData] = useState<UploadData>({
|
|
183
|
+
errors: [],
|
|
184
|
+
files: [],
|
|
185
|
+
progress: 0,
|
|
186
|
+
state: UploadState.Idle,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const resetUpload = useCallback(() => {
|
|
190
|
+
setUploadData({
|
|
191
|
+
errors: [],
|
|
192
|
+
files: [],
|
|
193
|
+
progress: 0,
|
|
194
|
+
state: UploadState.Idle,
|
|
195
|
+
});
|
|
196
|
+
}, []);
|
|
197
|
+
|
|
198
|
+
const simulateUpload = useCallback((files: File[]) => {
|
|
199
|
+
setUploadData((prev) => ({
|
|
200
|
+
...prev,
|
|
201
|
+
state: UploadState.Uploading,
|
|
202
|
+
files,
|
|
203
|
+
progress: 0,
|
|
204
|
+
}));
|
|
205
|
+
|
|
206
|
+
const interval = setInterval(() => {
|
|
207
|
+
setUploadData((prev) => {
|
|
208
|
+
const newProgress = prev.progress + CONFIG.PROGRESS_INCREMENT;
|
|
209
|
+
if (newProgress >= 100) {
|
|
210
|
+
clearInterval(interval);
|
|
211
|
+
setTimeout(
|
|
212
|
+
() =>
|
|
213
|
+
setUploadData((current) => ({
|
|
214
|
+
...current,
|
|
215
|
+
state: UploadState.Success,
|
|
216
|
+
})),
|
|
217
|
+
500,
|
|
218
|
+
);
|
|
219
|
+
return { ...prev, progress: 100 };
|
|
220
|
+
}
|
|
221
|
+
return { ...prev, progress: newProgress };
|
|
222
|
+
});
|
|
223
|
+
}, CONFIG.UPDATE_INTERVAL);
|
|
224
|
+
}, []);
|
|
225
|
+
|
|
226
|
+
const handleDrop: DropzoneOptions['onDrop'] = useCallback(
|
|
227
|
+
(
|
|
228
|
+
acceptedFiles: File[],
|
|
229
|
+
rejectedFiles: FileRejection[],
|
|
230
|
+
event: DropEvent,
|
|
231
|
+
) => {
|
|
232
|
+
console.info('Drop event:', { acceptedFiles, event, rejectedFiles });
|
|
233
|
+
|
|
234
|
+
if (acceptedFiles.length > 0) {
|
|
235
|
+
simulateUpload(acceptedFiles);
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
[simulateUpload],
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const handleDropRejected: DropzoneOptions['onDropRejected'] = useCallback(
|
|
242
|
+
(rejectedFiles: FileRejection[]) => {
|
|
243
|
+
const errors = rejectedFiles.map(
|
|
244
|
+
(file) =>
|
|
245
|
+
`${file.file.name}: ${file.errors.map((e) => e.message).join(', ')}`,
|
|
246
|
+
);
|
|
247
|
+
setUploadData((prev) => ({ ...prev, state: UploadState.Error, errors }));
|
|
248
|
+
},
|
|
249
|
+
[],
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
const handleError = useCallback((error: Error) => {
|
|
253
|
+
console.error('Dropzone error:', error);
|
|
254
|
+
setUploadData((prev) => ({
|
|
255
|
+
...prev,
|
|
256
|
+
state: UploadState.Error,
|
|
257
|
+
errors: [error.message],
|
|
258
|
+
}));
|
|
259
|
+
}, []);
|
|
260
|
+
|
|
261
|
+
const renderStatusContent = () => {
|
|
262
|
+
const { state, progress, files, errors } = uploadData;
|
|
263
|
+
|
|
264
|
+
switch (state) {
|
|
265
|
+
case UploadState.Uploading:
|
|
266
|
+
return (
|
|
267
|
+
<Dropzone.LoadingProgressBar
|
|
268
|
+
progressBarPrecentage={Math.round(progress)}
|
|
269
|
+
/>
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
case UploadState.Success:
|
|
273
|
+
return (
|
|
274
|
+
<div className="n-flex n-flex-col n-justify-center n-items-center n-gap-y-token-32">
|
|
275
|
+
<Typography
|
|
276
|
+
variant="title-4"
|
|
277
|
+
className="n-text-success-text n-font-semibold"
|
|
278
|
+
>
|
|
279
|
+
Upload Complete!
|
|
280
|
+
</Typography>
|
|
281
|
+
<Typography
|
|
282
|
+
variant="body-small"
|
|
283
|
+
className="n-text-neutral-text-weak"
|
|
284
|
+
>
|
|
285
|
+
Successfully uploaded: {files.map((file) => file.name).join(', ')}
|
|
286
|
+
</Typography>
|
|
287
|
+
<FilledButton onClick={resetUpload}>Upload More Files</FilledButton>
|
|
288
|
+
</div>
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
case UploadState.Error:
|
|
292
|
+
return (
|
|
293
|
+
<div className="n-flex n-flex-col n-justify-center n-items-center n-gap-y-token-32">
|
|
294
|
+
<XMarkIcon className="n-w-token-32 n-h-token-32 n-text-danger-text" />
|
|
295
|
+
<div className="n-flex n-flex-col n-gap-y-token-2">
|
|
296
|
+
{errors.map((message, index) => (
|
|
297
|
+
<Typography
|
|
298
|
+
key={index}
|
|
299
|
+
variant="label"
|
|
300
|
+
className="n-text-danger-text n-font-semibold"
|
|
301
|
+
htmlAttributes={{ role: 'alert' }}
|
|
302
|
+
>
|
|
303
|
+
{message}
|
|
304
|
+
</Typography>
|
|
305
|
+
))}
|
|
306
|
+
</div>
|
|
307
|
+
<FilledButton onClick={resetUpload}>Try Again</FilledButton>
|
|
308
|
+
</div>
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
default:
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
<Dropzone
|
|
318
|
+
dropZoneOptions={{
|
|
319
|
+
disabled: uploadData.state === UploadState.Uploading,
|
|
320
|
+
maxFiles: CONFIG.MAX_FILES,
|
|
321
|
+
maxSize: CONFIG.MAX_FILE_SIZE,
|
|
322
|
+
multiple: true,
|
|
323
|
+
onDrop: handleDrop,
|
|
324
|
+
onDropRejected: handleDropRejected,
|
|
325
|
+
onError: handleError,
|
|
326
|
+
}}
|
|
327
|
+
supportedFilesDescription={
|
|
328
|
+
<div className="n-text-center n-flex n-flex-col n-gap-y-token-2">
|
|
329
|
+
<Typography variant="body-small" className="n-text-neutral-text-weak">
|
|
330
|
+
Supports: Text files (.txt, .json) only
|
|
331
|
+
</Typography>
|
|
332
|
+
<Typography variant="body-small" className="n-text-neutral-text-weak">
|
|
333
|
+
Max {CONFIG.MAX_FILES} files •{' '}
|
|
334
|
+
{CONFIG.MAX_FILE_SIZE / (1024 * 1024)}MB per file
|
|
335
|
+
</Typography>
|
|
336
|
+
</div>
|
|
337
|
+
}
|
|
338
|
+
acceptedFileExtensions={CONFIG.ACCEPTED_EXTENSIONS}
|
|
339
|
+
loadingElement={renderStatusContent()}
|
|
340
|
+
rejectedText="Error: Please make sure to only upload .json or .txt files"
|
|
341
|
+
heading="Drag & Drop your files"
|
|
342
|
+
/>
|
|
343
|
+
);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
export default Component;
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Loading Progress
|
|
350
|
+
|
|
351
|
+
```tsx
|
|
352
|
+
import { Dropzone } from '@neo4j-ndl/react';
|
|
353
|
+
|
|
354
|
+
const Component = () => {
|
|
355
|
+
return (
|
|
356
|
+
<Dropzone
|
|
357
|
+
loadingElement={
|
|
358
|
+
<Dropzone.LoadingProgressBar
|
|
359
|
+
progressBarPrecentage={50}
|
|
360
|
+
progressBarMinute={5}
|
|
361
|
+
/>
|
|
362
|
+
}
|
|
363
|
+
dropZoneOptions={{
|
|
364
|
+
onDrop: () => void 0,
|
|
365
|
+
}}
|
|
366
|
+
/>
|
|
367
|
+
);
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
export default Component;
|
|
371
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# FilledButton
|
|
2
|
+
|
|
3
|
+
Import: `import { FilledButton } from '@neo4j-ndl/react'`
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
### FilledButton
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Required | Default | Description |
|
|
10
|
+
|------|------|----------|---------|-------------|
|
|
11
|
+
| `as` | `("a" & ElementType<any, keyof IntrinsicElements>) \| ("symbol" & ElementType<any, keyof IntrinsicElements>) \| ... 178 more ...` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
12
|
+
| `children` | `ReactNode` | | | |
|
|
13
|
+
| `href` | `string` | | | The URL to link to. Only applies when `as="a"` |
|
|
14
|
+
| `isDisabled` | `boolean` | | `false` | If the button is in disabled state |
|
|
15
|
+
| `isFloating` | `boolean` | | `false` | If the button is in floating state |
|
|
16
|
+
| `isFluid` | `boolean` | | | If the button is fluid, it will take the full width of its container |
|
|
17
|
+
| `isLoading` | `boolean` | | `false` | If the button is doing something Async, it will display a loading spinner |
|
|
18
|
+
| `leadingVisual` | `ReactNode` | | | Icon to display before the button content |
|
|
19
|
+
| `loadingMessage` | `string` | | | Accessible message for screen readers when the button is in a loading state |
|
|
20
|
+
| `onClick` | `((e: MouseEvent<HTMLButtonElement, MouseEvent>) => void)` | | | onClick callback |
|
|
21
|
+
| `onKeyDown` | `((e: KeyboardEvent<HTMLButtonElement>) => void)` | | | onKeyDown callback |
|
|
22
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
23
|
+
| `size` | `'large' \| 'medium' \| 'small'` | | `medium` | Size of button |
|
|
24
|
+
| `target` | `HTMLAttributeAnchorTarget` | | | The target window for the link. Only applies when `as="a"`. Not present or required for other element types. |
|
|
25
|
+
| `type` | `'button' \| 'reset' \| 'submit'` | | `button` | Type of button |
|
|
26
|
+
| `variant` | `'danger' \| 'primary'` | | `primary` | Variant of the button |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Flex
|
|
2
|
+
|
|
3
|
+
Import: `import { Flex } from '@neo4j-ndl/react'`
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
### Flex
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Required | Default | Description |
|
|
10
|
+
|------|------|----------|---------|-------------|
|
|
11
|
+
| `alignItems` | `AlignItems` | | `undefined` | @see https://developer.mozilla.org/en-US/docs/Web/CSS/align-items |
|
|
12
|
+
| `as` | `'div' \| 'li' \| 'ol' \| 'span' \| 'ul'` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
13
|
+
| `borderRadius` | `'2xl' \| '3xl' \| 'full' \| 'lg' \| 'md' \| 'none' \| 'sm' \| 'xl'` | | `undefined` | |
|
|
14
|
+
| `children` | `ReactNode` | | | |
|
|
15
|
+
| `columnGap` | `'12' \| '16' \| '2' \| '20' \| '24' \| '32' \| '4' \| '48' \| '6' \| '64' \| '8'` | | `undefined` | |
|
|
16
|
+
| `flexDirection` | `'-moz-initial' \| 'column' \| 'inherit' \| 'initial' \| 'revert-layer' \| 'revert' \| 'row' \| 'unset'` | | `column` | Flex direction is set to column by default. The `row-reverse` and `column-reverse` values are skipped due to accessibility concerns. @see https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction#accessibility_concerns |
|
|
17
|
+
| `flexWrap` | `'-moz-initial' \| 'inherit' \| 'initial' \| 'nowrap' \| 'revert-layer' \| 'revert' \| 'unset' \| 'wrap-reverse' \| 'wrap'` | | `nowrap` | @see https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap |
|
|
18
|
+
| `gap` | `'12' \| '16' \| '2' \| '20' \| '24' \| '32' \| '4' \| '48' \| '6' \| '64' \| '8'` | | `8` | |
|
|
19
|
+
| `justifyContent` | `JustifyContent` | | `undefined` | @see https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content |
|
|
20
|
+
| `ref` | `((instance: HTMLDivElement \| null) => void \| (() => VoidOrUndefinedOnly)) \| RefObject<HTMLDivElement \| null> \| ... 9 more ...` | | | A ref to apply to the root element. |
|
|
21
|
+
| `rowGap` | `'12' \| '16' \| '2' \| '20' \| '24' \| '32' \| '4' \| '48' \| '6' \| '64' \| '8'` | | `undefined` | |
|
|
22
|
+
|
|
23
|
+
## Examples
|
|
24
|
+
|
|
25
|
+
### Default
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { tokens } from '@neo4j-ndl/base';
|
|
29
|
+
import { Box, Flex } from '@neo4j-ndl/react';
|
|
30
|
+
|
|
31
|
+
const Tiles = `
|
|
32
|
+
linear-gradient(
|
|
33
|
+
45deg,
|
|
34
|
+
var(--theme-color-neutral-bg-strong) 25%,
|
|
35
|
+
transparent 25%
|
|
36
|
+
),
|
|
37
|
+
linear-gradient(
|
|
38
|
+
135deg,
|
|
39
|
+
var(--theme-color-neutral-bg-strong) 25%,
|
|
40
|
+
transparent 25%
|
|
41
|
+
),
|
|
42
|
+
linear-gradient(
|
|
43
|
+
45deg,
|
|
44
|
+
transparent 75%,
|
|
45
|
+
var(--theme-color-neutral-bg-strong) 75%
|
|
46
|
+
),
|
|
47
|
+
linear-gradient(
|
|
48
|
+
135deg,
|
|
49
|
+
transparent 75%,
|
|
50
|
+
var(--theme-color-neutral-bg-strong) 75%
|
|
51
|
+
)
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
const TiledTransparentBackground: React.CSSProperties = {
|
|
55
|
+
backgroundColor: 'white',
|
|
56
|
+
backgroundImage: Tiles,
|
|
57
|
+
backgroundPosition: '0px 0px, 10px 0px, 10px -10px, 0px 10px',
|
|
58
|
+
backgroundSize: '20px 20px',
|
|
59
|
+
border: '1px solid var(--theme-color-neutral-border-weak)',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const component = () => (
|
|
63
|
+
<Flex
|
|
64
|
+
style={{
|
|
65
|
+
...TiledTransparentBackground,
|
|
66
|
+
borderRadius: tokens.borderRadius['xl'],
|
|
67
|
+
padding: tokens.space['12'],
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{Array.from({ length: 3 }).map((_, i) => (
|
|
71
|
+
<Box
|
|
72
|
+
key={`box-${i}`}
|
|
73
|
+
borderRadius="xl"
|
|
74
|
+
style={{ height: '80px', minWidth: '240px' }}
|
|
75
|
+
className="n-bg-primary-bg-weak n-border n-border-primary-border-strong"
|
|
76
|
+
></Box>
|
|
77
|
+
))}
|
|
78
|
+
</Flex>
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
export default component;
|
|
82
|
+
```
|