@commercetools/nimbus-mcp 3.2.0 → 3.4.0
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/README.md +9 -1
- package/data/docs/route-manifest.json +1608 -143
- package/data/docs/routes/components-buttons-button.json +25 -2
- package/data/docs/routes/components-chat-chat-message-list.json +448 -0
- package/data/docs/routes/components-chat-chat-message.json +580 -0
- package/data/docs/routes/components-content-markdown.json +548 -0
- package/data/docs/routes/components-data-display-item-group.json +413 -0
- package/data/docs/routes/components-data-display-item.json +611 -0
- package/data/docs/routes/components-feedback-activity-indicator.json +396 -0
- package/data/docs/routes/components-feedback-skeleton.json +481 -0
- package/data/docs/routes/components-feedback-skeletoncircle.json +429 -0
- package/data/docs/routes/components-feedback-skeletontext.json +417 -0
- package/data/docs/routes/components-feedback-tooltip.json +23 -1
- package/data/docs/routes/components-inputs-drop-zone.json +562 -0
- package/data/docs/routes/components-inputs-file-trigger.json +421 -0
- package/data/docs/routes/components-inputs-range-slider.json +633 -0
- package/data/docs/routes/components-inputs-slider.json +611 -0
- package/data/docs/routes/components-layout-splitter.json +3 -3
- package/data/docs/routes/components-media-avatar.json +16 -5
- package/data/docs/routes/components-navigation-breadcrumbs.json +565 -0
- package/data/docs/routes/components-navigation-menu.json +1 -1
- package/data/docs/routes/components-navigation-tabnav.json +80 -14
- package/data/docs/routes/components-navigation-tabs.json +44 -11
- package/data/docs/routes/components-navigation-tree.json +445 -0
- package/data/docs/routes/home-getting-started-mcp-server-overview.json +2 -2
- package/data/docs/routes/home-getting-started-mcp-server-setup.json +2 -2
- package/data/docs/routes/icons.json +3 -3
- package/data/docs/routes/patterns-buttons-floating-action-button.json +392 -0
- package/data/docs/routes/patterns-buttons.json +58 -0
- package/data/docs/search-index.json +1 -1
- package/data/docs/types/AccordionContent.json +24 -24
- package/data/docs/types/AccordionHeader.json +88 -88
- package/data/docs/types/AccordionItem.json +20 -20
- package/data/docs/types/AccordionRoot.json +14 -14
- package/data/docs/types/ActivityIndicator.json +202 -0
- package/data/docs/types/AlertDescription.json +8 -8
- package/data/docs/types/AlertDismissButton.json +98 -81
- package/data/docs/types/AlertTitle.json +8 -8
- package/data/docs/types/Avatar.json +19 -2
- package/data/docs/types/Badge.json +2 -2
- package/data/docs/types/Body.json +6 -6
- package/data/docs/types/Box.json +6 -6
- package/data/docs/types/Breadcrumbs.json +12 -0
- package/data/docs/types/BreadcrumbsItem.json +296 -0
- package/data/docs/types/BreadcrumbsItemProps.json +9 -0
- package/data/docs/types/BreadcrumbsProps.json +9 -0
- package/data/docs/types/BreadcrumbsRoot.json +110 -0
- package/data/docs/types/Button.json +106 -89
- package/data/docs/types/Calendar.json +56 -56
- package/data/docs/types/Caption.json +6 -6
- package/data/docs/types/CardRoot.json +2 -2
- package/data/docs/types/Cell.json +6 -6
- package/data/docs/types/ChatMessage.json +12 -0
- package/data/docs/types/ChatMessageActions.json +42 -0
- package/data/docs/types/ChatMessageAvatar.json +140 -0
- package/data/docs/types/ChatMessageBody.json +42 -0
- package/data/docs/types/ChatMessageList.json +12 -0
- package/data/docs/types/ChatMessageListItem.json +42 -0
- package/data/docs/types/ChatMessageListRoot.json +78 -0
- package/data/docs/types/ChatMessageMeta.json +42 -0
- package/data/docs/types/ChatMessageRoot.json +119 -0
- package/data/docs/types/ChatMessageTyping.json +42 -0
- package/data/docs/types/Checkbox.json +86 -86
- package/data/docs/types/Code.json +11 -11
- package/data/docs/types/Column.json +6 -6
- package/data/docs/types/ColumnGroup.json +6 -6
- package/data/docs/types/ColumnHeader.json +6 -6
- package/data/docs/types/ComboBoxListBox.json +70 -70
- package/data/docs/types/ComboBoxOption.json +64 -64
- package/data/docs/types/ComboBoxPopover.json +91 -70
- package/data/docs/types/ComboBoxRoot.json +8 -8
- package/data/docs/types/ComboBoxSection.json +24 -24
- package/data/docs/types/ComboBoxTrigger.json +6 -6
- package/data/docs/types/DataTable.json +2 -2
- package/data/docs/types/DataTableBody.json +20 -20
- package/data/docs/types/DataTableHeader.json +25 -25
- package/data/docs/types/DataTableRoot.json +2 -2
- package/data/docs/types/DataTableTable.json +6 -6
- package/data/docs/types/DateInput.json +73 -73
- package/data/docs/types/DatePicker.json +58 -58
- package/data/docs/types/DateRangePicker.json +86 -86
- package/data/docs/types/DateRangePickerField.json +86 -86
- package/data/docs/types/DefaultPageRoot.json +2 -2
- package/data/docs/types/DialogCloseTrigger.json +96 -79
- package/data/docs/types/DraggableListField.json +88 -60
- package/data/docs/types/DraggableListItem.json +52 -52
- package/data/docs/types/DraggableListRoot.json +88 -60
- package/data/docs/types/DrawerCloseTrigger.json +96 -79
- package/data/docs/types/DropZone.json +161 -0
- package/data/docs/types/FieldErrors.json +2 -2
- package/data/docs/types/FileTrigger.json +130 -0
- package/data/docs/types/Flex.json +22 -22
- package/data/docs/types/FloatingActionButton.json +1036 -0
- package/data/docs/types/Footer.json +6 -6
- package/data/docs/types/FormActionBar.json +1 -1
- package/data/docs/types/FormFieldRoot.json +2 -2
- package/data/docs/types/Grid.json +24 -24
- package/data/docs/types/Group.json +12 -12
- package/data/docs/types/Header.json +6 -6
- package/data/docs/types/Heading.json +8 -8
- package/data/docs/types/Icon.json +4 -4
- package/data/docs/types/IconButton.json +106 -89
- package/data/docs/types/IconToggleButton.json +71 -71
- package/data/docs/types/Image.json +43 -43
- package/data/docs/types/Indicator.json +6 -6
- package/data/docs/types/InlineSvg.json +2 -2
- package/data/docs/types/Item.json +6 -6
- package/data/docs/types/ItemActions.json +27 -0
- package/data/docs/types/ItemContent.json +27 -0
- package/data/docs/types/ItemDescription.json +27 -0
- package/data/docs/types/ItemFooter.json +27 -0
- package/data/docs/types/ItemGroup.json +12 -0
- package/data/docs/types/ItemGroupRoot.json +27 -0
- package/data/docs/types/ItemGroupSeparator.json +27 -0
- package/data/docs/types/ItemHeader.json +27 -0
- package/data/docs/types/ItemMedia.json +56 -0
- package/data/docs/types/ItemRoot.json +239 -0
- package/data/docs/types/ItemTitle.json +27 -0
- package/data/docs/types/Kbd.json +8 -8
- package/data/docs/types/Link.json +14 -14
- package/data/docs/types/ListIndicator.json +6 -6
- package/data/docs/types/ListItem.json +6 -6
- package/data/docs/types/ListRoot.json +11 -11
- package/data/docs/types/LoadingSpinner.json +2 -2
- package/data/docs/types/MakeElementFocusable.json +18 -18
- package/data/docs/types/Markdown.json +183 -0
- package/data/docs/types/MenuItem.json +62 -62
- package/data/docs/types/MenuRoot.json +55 -55
- package/data/docs/types/MenuSection.json +30 -30
- package/data/docs/types/MenuSubmenuTrigger.json +4 -4
- package/data/docs/types/MenuTrigger.json +88 -88
- package/data/docs/types/MultilineTextInput.json +104 -104
- package/data/docs/types/MultilineTextInputField.json +102 -102
- package/data/docs/types/NumberInput.json +86 -86
- package/data/docs/types/NumberInputField.json +82 -82
- package/data/docs/types/PageContentColumn.json +6 -6
- package/data/docs/types/PageContentRoot.json +6 -6
- package/data/docs/types/PasswordInput.json +100 -100
- package/data/docs/types/PasswordInputField.json +100 -100
- package/data/docs/types/ProgressBar.json +13 -13
- package/data/docs/types/RadioInputOption.json +56 -56
- package/data/docs/types/RadioInputRoot.json +48 -48
- package/data/docs/types/RangeCalendar.json +58 -58
- package/data/docs/types/RangeSlider.json +337 -0
- package/data/docs/types/RangeSliderProps.json +9 -0
- package/data/docs/types/Region.json +6 -6
- package/data/docs/types/RegionTarget.json +6 -6
- package/data/docs/types/RichTextInput.json +2 -2
- package/data/docs/types/Root.json +11 -11
- package/data/docs/types/Row.json +6 -6
- package/data/docs/types/ScrollArea.json +2 -2
- package/data/docs/types/SearchInput.json +106 -106
- package/data/docs/types/SearchInputField.json +102 -102
- package/data/docs/types/SelectOption.json +54 -54
- package/data/docs/types/SelectOptionGroup.json +18 -18
- package/data/docs/types/SelectOptions.json +64 -64
- package/data/docs/types/SelectRoot.json +92 -92
- package/data/docs/types/Separator.json +4 -4
- package/data/docs/types/SimpleGrid.json +28 -28
- package/data/docs/types/Skeleton.json +129 -0
- package/data/docs/types/SkeletonCircle.json +103 -0
- package/data/docs/types/SkeletonCircleProps.json +9 -0
- package/data/docs/types/SkeletonProps.json +9 -0
- package/data/docs/types/SkeletonText.json +62 -0
- package/data/docs/types/SkeletonTextProps.json +9 -0
- package/data/docs/types/Slider.json +337 -0
- package/data/docs/types/SlidingIndicatorGeometry.json +9 -0
- package/data/docs/types/SlidingIndicatorRects.json +9 -0
- package/data/docs/types/SplitButton.json +16 -20
- package/data/docs/types/Stack.json +2 -2
- package/data/docs/types/StepsRoot.json +2 -2
- package/data/docs/types/Switch.json +34 -34
- package/data/docs/types/TabNavItem.json +5 -5
- package/data/docs/types/TabNavRoot.json +5 -5
- package/data/docs/types/TableBody.json +6 -6
- package/data/docs/types/TableCaption.json +6 -6
- package/data/docs/types/TableCell.json +6 -6
- package/data/docs/types/TableColumn.json +6 -6
- package/data/docs/types/TableColumnGroup.json +6 -6
- package/data/docs/types/TableColumnHeader.json +6 -6
- package/data/docs/types/TableFooter.json +6 -6
- package/data/docs/types/TableHeader.json +6 -6
- package/data/docs/types/TableRoot.json +19 -19
- package/data/docs/types/TableRow.json +6 -6
- package/data/docs/types/TableScrollArea.json +6 -6
- package/data/docs/types/TabsList.json +2 -2
- package/data/docs/types/TabsPanel.json +2 -2
- package/data/docs/types/TabsPanels.json +2 -2
- package/data/docs/types/TabsRoot.json +3 -3
- package/data/docs/types/TabsTab.json +2 -2
- package/data/docs/types/TagGroupRoot.json +24 -24
- package/data/docs/types/TagGroupTag.json +56 -56
- package/data/docs/types/TagGroupTagList.json +14 -14
- package/data/docs/types/Text.json +8 -8
- package/data/docs/types/TextInput.json +102 -102
- package/data/docs/types/TextInputField.json +100 -100
- package/data/docs/types/TimeInput.json +68 -68
- package/data/docs/types/ToggleButton.json +73 -73
- package/data/docs/types/ToggleButtonGroupButton.json +30 -30
- package/data/docs/types/ToggleButtonGroupRoot.json +20 -20
- package/data/docs/types/Toolbar.json +9 -9
- package/data/docs/types/TooltipContent.json +28 -28
- package/data/docs/types/TooltipRoot.json +16 -16
- package/data/docs/types/Tree.json +12 -0
- package/data/docs/types/TreeIndicator.json +828 -0
- package/data/docs/types/TreeItem.json +559 -0
- package/data/docs/types/TreeItemContent.json +27 -0
- package/data/docs/types/TreeRoot.json +636 -0
- package/data/docs/types/TreeSubTree.json +40 -0
- package/data/docs/types/VisuallyHidden.json +6 -6
- package/data/docs/types/createItemsFromCsvDrop.json +4 -4
- package/data/docs/types/createItemsFromDirectoryDrop.json +4 -4
- package/data/docs/types/createItemsFromFileDrop.json +4 -4
- package/data/docs/types/createItemsFromImageDrop.json +4 -4
- package/data/docs/types/createItemsFromJsonDrop.json +4 -4
- package/data/docs/types/manifest.json +50 -0
- package/data/docs/types/useRegion.json +2 -2
- package/data/docs/types/useSlidingIndicator.json +145 -0
- package/data/docs/types/useTree.json +267 -0
- package/data/tokens.json +21 -0
- package/data/uikit-tokens.json +894 -0
- package/dist/index.js +3298 -109
- package/package.json +8 -6
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"id": "Components-DropZone",
|
|
4
|
+
"title": "Drop zone",
|
|
5
|
+
"exportName": "DropZone",
|
|
6
|
+
"description": "An accessible drop target for drag-and-drop file and data uploads, with a built-in click-to-upload fallback via FileTrigger.",
|
|
7
|
+
"lifecycleState": "Beta",
|
|
8
|
+
"order": 999,
|
|
9
|
+
"repoPath": "packages/nimbus/src/components/drop-zone/drop-zone.mdx",
|
|
10
|
+
"menu": [
|
|
11
|
+
"Components",
|
|
12
|
+
"Inputs",
|
|
13
|
+
"Drop zone"
|
|
14
|
+
],
|
|
15
|
+
"route": "components/inputs/drop-zone",
|
|
16
|
+
"tags": [
|
|
17
|
+
"component",
|
|
18
|
+
"dropzone",
|
|
19
|
+
"upload",
|
|
20
|
+
"drag-and-drop"
|
|
21
|
+
],
|
|
22
|
+
"toc": [
|
|
23
|
+
{
|
|
24
|
+
"value": "Overview",
|
|
25
|
+
"href": "#overview",
|
|
26
|
+
"depth": 2,
|
|
27
|
+
"numbering": [
|
|
28
|
+
1,
|
|
29
|
+
1
|
|
30
|
+
],
|
|
31
|
+
"parent": "root"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"value": "Resources",
|
|
35
|
+
"href": "#resources",
|
|
36
|
+
"depth": 3,
|
|
37
|
+
"numbering": [
|
|
38
|
+
1,
|
|
39
|
+
1,
|
|
40
|
+
1
|
|
41
|
+
],
|
|
42
|
+
"parent": "root"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"value": "Variables",
|
|
46
|
+
"href": "#variables",
|
|
47
|
+
"depth": 2,
|
|
48
|
+
"numbering": [
|
|
49
|
+
1,
|
|
50
|
+
2
|
|
51
|
+
],
|
|
52
|
+
"parent": "root"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"value": "States",
|
|
56
|
+
"href": "#states",
|
|
57
|
+
"depth": 3,
|
|
58
|
+
"numbering": [
|
|
59
|
+
1,
|
|
60
|
+
2,
|
|
61
|
+
1
|
|
62
|
+
],
|
|
63
|
+
"parent": "root"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"value": "Default content",
|
|
67
|
+
"href": "#default-content",
|
|
68
|
+
"depth": 3,
|
|
69
|
+
"numbering": [
|
|
70
|
+
1,
|
|
71
|
+
2,
|
|
72
|
+
2
|
|
73
|
+
],
|
|
74
|
+
"parent": "root"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"value": "Composing a click-to-upload button",
|
|
78
|
+
"href": "#composing-a-click-to-upload-button",
|
|
79
|
+
"depth": 3,
|
|
80
|
+
"numbering": [
|
|
81
|
+
1,
|
|
82
|
+
2,
|
|
83
|
+
3
|
|
84
|
+
],
|
|
85
|
+
"parent": "root"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"value": "Guidelines",
|
|
89
|
+
"href": "#guidelines",
|
|
90
|
+
"depth": 2,
|
|
91
|
+
"numbering": [
|
|
92
|
+
1,
|
|
93
|
+
3
|
|
94
|
+
],
|
|
95
|
+
"parent": "root"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"layout": "app-frame",
|
|
99
|
+
"tabs": [
|
|
100
|
+
{
|
|
101
|
+
"key": "overview",
|
|
102
|
+
"title": "Overview",
|
|
103
|
+
"order": 0
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"key": "guidelines",
|
|
107
|
+
"title": "Guidelines",
|
|
108
|
+
"order": 2
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"key": "dev",
|
|
112
|
+
"title": "Implementation",
|
|
113
|
+
"order": 3
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"key": "a11y",
|
|
117
|
+
"title": "Accessibility",
|
|
118
|
+
"order": 4
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
"mdx": "\n## Overview\n\nA drop zone is a dedicated area users drag files or other data onto to upload\nthem. It renders a dashed-border area that highlights when a valid drag is\nheld over it. DropZone is built for upload flows such as asset managers, CSV\nimporters, and avatar pickers, where a visible, on-brand drop target improves\non a bare button.\n\nDragging is not the only way in: DropZone pairs with `FileTrigger` to add a\nclick-to-upload button inside the zone, so a mouse, keyboard, or screen-reader\nuser can all reach the same upload flow.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[React Aria DropZone](https://react-spectrum.adobe.com/react-aria/DropZone.html)\n\n## Variables\n\nGet familiar with the features.\n\n### States\n\nIdle, drag-over, and disabled are the states DropZone styles. Drag a file over\nthe first zone to see the highlight; the second zone shows the disabled\ntreatment.\n\n```jsx live\nconst App = () => (\n <Stack direction=\"row\" gap=\"400\" alignItems=\"flex-start\">\n <DropZone>\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n <DropZone isDisabled>\n <FileTrigger>\n <Button variant=\"ghost\" isDisabled>\n Browse files\n </Button>\n </FileTrigger>\n </DropZone>\n </Stack>\n);\n```\n\n### Default content\n\nWith no children, DropZone shows a default upload icon and instruction label,\nso it never appears as an empty box.\n\n```jsx live\nconst App = () => <DropZone />;\n```\n\n### Composing a click-to-upload button\n\nChildren, when provided, replace the default content entirely. Compose\n`FileTrigger` and `Button` inside DropZone to add a click-to-upload path\nalongside dragging.\n\n```jsx live\nconst App = () => (\n <DropZone>\n <FileTrigger allowsMultiple>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n);\n```\n\n## Guidelines\n\nSee the Guidelines tab for best practices, and the Accessibility tab for\nkeyboard and screen-reader behavior.\n",
|
|
123
|
+
"views": {
|
|
124
|
+
"overview": {
|
|
125
|
+
"mdx": "\n## Overview\n\nA drop zone is a dedicated area users drag files or other data onto to upload\nthem. It renders a dashed-border area that highlights when a valid drag is\nheld over it. DropZone is built for upload flows such as asset managers, CSV\nimporters, and avatar pickers, where a visible, on-brand drop target improves\non a bare button.\n\nDragging is not the only way in: DropZone pairs with `FileTrigger` to add a\nclick-to-upload button inside the zone, so a mouse, keyboard, or screen-reader\nuser can all reach the same upload flow.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[React Aria DropZone](https://react-spectrum.adobe.com/react-aria/DropZone.html)\n\n## Variables\n\nGet familiar with the features.\n\n### States\n\nIdle, drag-over, and disabled are the states DropZone styles. Drag a file over\nthe first zone to see the highlight; the second zone shows the disabled\ntreatment.\n\n```jsx live\nconst App = () => (\n <Stack direction=\"row\" gap=\"400\" alignItems=\"flex-start\">\n <DropZone>\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n <DropZone isDisabled>\n <FileTrigger>\n <Button variant=\"ghost\" isDisabled>\n Browse files\n </Button>\n </FileTrigger>\n </DropZone>\n </Stack>\n);\n```\n\n### Default content\n\nWith no children, DropZone shows a default upload icon and instruction label,\nso it never appears as an empty box.\n\n```jsx live\nconst App = () => <DropZone />;\n```\n\n### Composing a click-to-upload button\n\nChildren, when provided, replace the default content entirely. Compose\n`FileTrigger` and `Button` inside DropZone to add a click-to-upload path\nalongside dragging.\n\n```jsx live\nconst App = () => (\n <DropZone>\n <FileTrigger allowsMultiple>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n);\n```\n\n## Guidelines\n\nSee the Guidelines tab for best practices, and the Accessibility tab for\nkeyboard and screen-reader behavior.\n",
|
|
126
|
+
"toc": [
|
|
127
|
+
{
|
|
128
|
+
"value": "Overview",
|
|
129
|
+
"href": "#overview",
|
|
130
|
+
"depth": 2,
|
|
131
|
+
"numbering": [
|
|
132
|
+
1,
|
|
133
|
+
1
|
|
134
|
+
],
|
|
135
|
+
"parent": "root"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"value": "Resources",
|
|
139
|
+
"href": "#resources",
|
|
140
|
+
"depth": 3,
|
|
141
|
+
"numbering": [
|
|
142
|
+
1,
|
|
143
|
+
1,
|
|
144
|
+
1
|
|
145
|
+
],
|
|
146
|
+
"parent": "root"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"value": "Variables",
|
|
150
|
+
"href": "#variables",
|
|
151
|
+
"depth": 2,
|
|
152
|
+
"numbering": [
|
|
153
|
+
1,
|
|
154
|
+
2
|
|
155
|
+
],
|
|
156
|
+
"parent": "root"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"value": "States",
|
|
160
|
+
"href": "#states",
|
|
161
|
+
"depth": 3,
|
|
162
|
+
"numbering": [
|
|
163
|
+
1,
|
|
164
|
+
2,
|
|
165
|
+
1
|
|
166
|
+
],
|
|
167
|
+
"parent": "root"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"value": "Default content",
|
|
171
|
+
"href": "#default-content",
|
|
172
|
+
"depth": 3,
|
|
173
|
+
"numbering": [
|
|
174
|
+
1,
|
|
175
|
+
2,
|
|
176
|
+
2
|
|
177
|
+
],
|
|
178
|
+
"parent": "root"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"value": "Composing a click-to-upload button",
|
|
182
|
+
"href": "#composing-a-click-to-upload-button",
|
|
183
|
+
"depth": 3,
|
|
184
|
+
"numbering": [
|
|
185
|
+
1,
|
|
186
|
+
2,
|
|
187
|
+
3
|
|
188
|
+
],
|
|
189
|
+
"parent": "root"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"value": "Guidelines",
|
|
193
|
+
"href": "#guidelines",
|
|
194
|
+
"depth": 2,
|
|
195
|
+
"numbering": [
|
|
196
|
+
1,
|
|
197
|
+
3
|
|
198
|
+
],
|
|
199
|
+
"parent": "root"
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
"a11y": {
|
|
204
|
+
"mdx": "\n## Accessibility\n\nDropZone is keyboard- and screen-reader-accessible by default through React\nAria, without any extra setup. It reaches WCAG 2.1 AA for contrast, focus\nvisibility, and non-color state changes.\n\n```jsx live\nconst App = () => (\n <DropZone>\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n);\n```\n\n### Accessibility standards\n\n- **Accessible name:** with no children and no explicit label, DropZone\n supplies a default, localized accessible name automatically — no setup\n required. An explicit `aria-label` or `aria-labelledby` replaces the default\n entirely and is forwarded straight to React Aria's `DropZone`, which applies\n it to its focusable element. For a visible label instead, render a\n `<Text slot=\"label\">` child — see the Implementation tab.\n- **Not color-only:** The drag-over state changes the border from dashed to\n solid and switches to a heavier, tinted background — it does not rely on a\n color shift alone. The dashed idle border and the drag-over highlight both\n meet WCAG 1.4.11 non-text contrast (at least 3:1 against the surrounding\n page).\n- **Forced-colors mode:** The border and drag-over outline remain visible when\n the operating system's forced-colors (high-contrast) mode is active.\n- **Reduced motion:** Drag-over transitions respect `prefers-reduced-motion`\n and are removed for users who request less motion.\n- **Focus indication:** A keyboard-focused drop target shows a visible focus\n ring that meets contrast requirements.\n- **Disabled state:** `isDisabled` is conveyed both visually (a lower-emphasis\n treatment) and to assistive technology, and rejects drops. It has no effect\n on descendants — set `isDisabled` explicitly on a composed\n `FileTrigger`/`Button` as well, so both controls stay in sync (see the\n Implementation tab).\n\n### Keyboard navigation\n\n| Key | Action |\n| -------- | ---------------------------------------------------------------- |\n| `Tab` | Move focus to or from the drop target |\n| `Enter` | While focused, enter drag-and-drop mode; while in that mode on a valid target, drop |\n| `Tab` (in drag mode) | Move between available drop targets |\n| `Escape` | Cancel drag-and-drop mode without dropping |\n\nThis keyboard drag-and-drop model is built into React Aria's `DropZone` and\nrequires no extra wiring. It only operates **within the browser window** — it\ncannot reach the operating system's file system, so a keyboard or\nscreen-reader user cannot use it alone to upload a file from disk.\n\n> [!NOTE]\\\n> Because keyboard drag-and-drop can't reach OS files, compose a `FileTrigger`\n> inside the drop zone whenever the zone is meant for file uploads. The\n> `FileTrigger`'s button gives keyboard and screen-reader users a direct path\n> to the native file picker, equivalent to what a mouse user gets by dragging\n> a file in from their desktop.\n\n### Screen reader support\n\n- The drop target is announced as a focusable, interactive element with its\n accessible name (the default instruction label, or an explicit label when\n one is provided).\n- Entering and exiting drag-and-drop mode, moving between drop targets, and\n completing or canceling a drop are all announced by React Aria as the user\n progresses through the keyboard flow.\n- A composed `FileTrigger`'s button is announced independently, using its own\n accessible name — give it a clear label such as \"Browse files\" or \"Upload\n file\" rather than a generic \"Choose\".\n\n### ARIA attributes\n\n- **`aria-label` / `aria-labelledby`** — forwarded as-is to React Aria's\n `DropZone`. DropZone has a default accessible name out of the box; provide\n one of these, or a `<Text slot=\"label\">` child, to replace it with your own.\n- **`data-drop-target`** — present while a valid drag is held over the zone;\n drives the drag-over visual treatment described above.\n- **`data-focus-visible`** — present when the zone has keyboard focus; drives\n the visible focus ring.\n- **`data-disabled`** — present when `isDisabled` is set; drives the disabled\n visual treatment and is not paired with any active drop or focus state.\n",
|
|
205
|
+
"toc": [
|
|
206
|
+
{
|
|
207
|
+
"value": "Accessibility",
|
|
208
|
+
"href": "#accessibility",
|
|
209
|
+
"depth": 2,
|
|
210
|
+
"numbering": [
|
|
211
|
+
1,
|
|
212
|
+
1
|
|
213
|
+
],
|
|
214
|
+
"parent": "root"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"value": "Accessibility standards",
|
|
218
|
+
"href": "#accessibility-standards",
|
|
219
|
+
"depth": 3,
|
|
220
|
+
"numbering": [
|
|
221
|
+
1,
|
|
222
|
+
1,
|
|
223
|
+
1
|
|
224
|
+
],
|
|
225
|
+
"parent": "root"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"value": "Keyboard navigation",
|
|
229
|
+
"href": "#keyboard-navigation",
|
|
230
|
+
"depth": 3,
|
|
231
|
+
"numbering": [
|
|
232
|
+
1,
|
|
233
|
+
1,
|
|
234
|
+
2
|
|
235
|
+
],
|
|
236
|
+
"parent": "root"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"value": "Screen reader support",
|
|
240
|
+
"href": "#screen-reader-support",
|
|
241
|
+
"depth": 3,
|
|
242
|
+
"numbering": [
|
|
243
|
+
1,
|
|
244
|
+
1,
|
|
245
|
+
3
|
|
246
|
+
],
|
|
247
|
+
"parent": "root"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"value": "ARIA attributes",
|
|
251
|
+
"href": "#aria-attributes",
|
|
252
|
+
"depth": 3,
|
|
253
|
+
"numbering": [
|
|
254
|
+
1,
|
|
255
|
+
1,
|
|
256
|
+
4
|
|
257
|
+
],
|
|
258
|
+
"parent": "root"
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
},
|
|
262
|
+
"dev": {
|
|
263
|
+
"mdx": "\n## Getting started\n\n### Import\n\n```tsx\nimport { DropZone, type DropZoneProps } from \"@commercetools/nimbus\";\n```\n\n### Basic usage\n\n`DropZone` wraps React Aria's `DropZone`. With no children, it renders a\ndefault upload icon and localized instruction label, so `<DropZone />` alone\nis never an empty box. Passing any children replaces that default content\nentirely — compose a `FileTrigger` inside the children for a click/keyboard\nupload path (see\n[Composing a click-to-upload path](#composing-a-click-to-upload-path)).\n\n```jsx live-dev\nconst App = () => (\n <DropZone onDrop={(event) => console.log(event.items)}>\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n);\n```\n\n## Usage examples\n\n### Handling dropped files\n\n`onDrop` receives a React Aria `DropEvent` whose `items` are `DragItem`\nobjects, not `File` objects. For files dragged from the OS, each item has\n`kind === \"file\"` and exposes `getFile()`, which resolves to the native\n`File`. Filter for file items and resolve them before using the result:\n\n```jsx live-dev\nconst App = () => {\n const [fileNames, setFileNames] = React.useState([]);\n\n const handleFiles = (files) => {\n setFileNames(files.map((file) => file.name));\n };\n\n const handleDrop = async (event) => {\n const files = await Promise.all(\n event.items\n .filter((item) => item.kind === \"file\")\n .map((item) => item.getFile())\n );\n handleFiles(files);\n };\n\n return (\n <Stack direction=\"column\" gap=\"400\" alignItems=\"stretch\">\n <DropZone onDrop={handleDrop}>\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n {fileNames.length > 0 && (\n <Text>Dropped: {fileNames.join(\", \")}</Text>\n )}\n </Stack>\n );\n};\n```\n\n### Composing a click-to-upload path\n\nPassing children replaces DropZone's default icon and label entirely. Compose\nthe existing `FileTrigger` (wrapping a `Button`) to add a click/keyboard\nupload path alongside dragging. Share a single `handleFiles(files: File[])`\nhelper between `onDrop` and the\n`FileTrigger`'s `onSelect` so the file-handling logic exists in one place —\n`FileTrigger`'s `onSelect` hands you a `FileList`, so convert it with\n`Array.from` before passing it to the same helper:\n\n```jsx live-dev\nconst App = () => {\n const [fileNames, setFileNames] = React.useState([]);\n\n // Shared by both onDrop and the composed FileTrigger's onSelect, so the\n // file-handling logic is not duplicated between the drag and click paths.\n const handleFiles = (files) => {\n setFileNames(files.map((file) => file.name));\n };\n\n const handleDrop = async (event) => {\n const files = await Promise.all(\n event.items\n .filter((item) => item.kind === \"file\")\n .map((item) => item.getFile())\n );\n handleFiles(files);\n };\n\n const handleSelect = (fileList) => {\n handleFiles(fileList ? Array.from(fileList) : []);\n };\n\n return (\n <Stack direction=\"column\" gap=\"400\" alignItems=\"stretch\">\n <DropZone onDrop={handleDrop}>\n <FileTrigger allowsMultiple onSelect={handleSelect}>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n {fileNames.length > 0 && (\n <Text>Selected: {fileNames.join(\", \")}</Text>\n )}\n </Stack>\n );\n};\n```\n\n### Restricting accepted drops\n\nPass `getDropOperation` as a type guard that inspects the dragged types and\nreturns `\"cancel\"` for anything the zone doesn't accept. A rejected drag never\nsets the drag-over highlight, so consumers don't need a separate invalid\nstate:\n\n```jsx live-dev\nconst App = () => {\n const acceptedType = \"image/png\";\n\n const getDropOperation = (types) =>\n types.has(acceptedType) ? \"copy\" : \"cancel\";\n\n return (\n <DropZone\n getDropOperation={getDropOperation}\n onDrop={(event) => console.log(event.items)}\n >\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n );\n};\n```\n\n### Disabling the zone and its composed trigger\n\n`isDisabled` disables the drop target itself and rejects drops. It has no\neffect on descendants — set `isDisabled` explicitly on the composed\n`FileTrigger`'s `Button` as well (`FileTrigger` has no `isDisabled` prop of\nits own — disabling is always done on the pressable child):\n\n```jsx live-dev\nconst App = () => {\n const [disabled, setDisabled] = React.useState(true);\n\n return (\n <Stack direction=\"column\" gap=\"400\" alignItems=\"flex-start\">\n <DropZone isDisabled={disabled}>\n <FileTrigger>\n <Button variant=\"ghost\" isDisabled={disabled}>\n Browse files\n </Button>\n </FileTrigger>\n </DropZone>\n <Button onClick={() => setDisabled((prev) => !prev)}>\n {disabled ? \"Enable\" : \"Disable\"}\n </Button>\n </Stack>\n );\n};\n```\n\n### Accessible name\n\nWith no children and no explicit label, DropZone's default content supplies\nits own accessible name automatically — no setup required. An explicit\n`aria-label` or `aria-labelledby` overrides only the accessible name: it is\nforwarded straight to React Aria's `DropZone` and applied to the focusable\nelement, while the default icon and instruction still render (the default's\nvisible text is opted out of the name, so it never conflicts with your\nlabel). Passing children, on the other hand, replaces the default content\nentirely — so you can combine the two: keep the default visual and give it a\nmore descriptive accessible name. For a visible label of your own, render a\n`<Text slot=\"label\">` child — React Aria wires the label association\nautomatically through the `slot` prop, and the presence of this child (like\nany child) replaces the default content:\n\n```jsx live-dev\nconst App = () => (\n <DropZone aria-label=\"Upload files\">\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n);\n```\n\n### Filled state\n\nDropZone has no controlled `isFilled` prop — express the filled state by\nswapping the children you render once files exist, the same mechanism that\nreplaces the default icon and label as soon as you pass any children at all.\nThis example replaces the `FileTrigger` with a file list after files are\ndropped or selected:\n\n```jsx live-dev\nconst App = () => {\n const [files, setFiles] = React.useState([]);\n\n const handleFiles = (newFiles) => {\n setFiles((prev) => [...prev, ...newFiles]);\n };\n\n const handleDrop = async (event) => {\n const dropped = await Promise.all(\n event.items\n .filter((item) => item.kind === \"file\")\n .map((item) => item.getFile())\n );\n handleFiles(dropped);\n };\n\n const handleSelect = (fileList) => {\n handleFiles(fileList ? Array.from(fileList) : []);\n };\n\n if (files.length > 0) {\n return (\n <DropZone onDrop={handleDrop}>\n <Stack direction=\"column\" gap=\"200\" alignItems=\"stretch\">\n {files.map((file, index) => (\n <Text key={`${file.name}-${index}`}>{file.name}</Text>\n ))}\n </Stack>\n <FileTrigger allowsMultiple onSelect={handleSelect}>\n <Button variant=\"ghost\">Add more files</Button>\n </FileTrigger>\n </DropZone>\n );\n }\n\n return (\n <DropZone onDrop={handleDrop}>\n <FileTrigger allowsMultiple onSelect={handleSelect}>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n );\n};\n```\n\n### Multiple files\n\nNothing in DropZone limits a drop to one file — `event.items` already\ncontains every dropped item. Pair it with `allowsMultiple` on the composed\n`FileTrigger` so the click path also accepts more than one file at a time, as\nshown in the examples above. To cap the count, check `files.length` inside\n`handleFiles` and ignore or reject the excess before updating state.\n\n## Working with React Aria drag-and-drop types\n\nDropZone re-exports `DropEvent`, `DropOperation`, and `DragTypes` from\n`@commercetools/nimbus` so `onDrop` and `getDropOperation` handlers can be\ntyped without a direct dependency on `react-aria-components`:\n\n```tsx\nimport type {\n DropEvent,\n DropOperation,\n DragTypes,\n} from \"@commercetools/nimbus\";\n\nconst handleDrop = async (event: DropEvent) => {\n const files = await Promise.all(\n event.items\n .filter((item) => item.kind === \"file\")\n .map((item) => item.getFile())\n );\n // ...\n};\n\nconst getDropOperation = (types: DragTypes): DropOperation =>\n types.has(\"image/png\") ? \"copy\" : \"cancel\";\n```\n\n## Component requirements\n\n### Accessibility\n\nDropZone handles most accessibility requirements internally via React Aria.\n\n- **Labeling**: with no children and no explicit label, DropZone has a default\n accessible name out of the box. An explicit `aria-label` / `aria-labelledby`\n overrides only the accessible name — it is forwarded to React Aria's\n `DropZone` and applied to its focusable element, while the default icon and\n instruction still render. Passing children replaces the default visual; for\n a visible label of your own, render a `<Text slot=\"label\">` child.\n- **Role**: The rendered element is React Aria's `DropZone`, which behaves as\n a focusable, keyboard-operable drop target with built-in drag-and-drop\n semantics — see the Accessibility tab for the full keyboard model.\n- **Focus management**: Focus and the drag-over highlight are managed by React\n Aria; don't override the `data-drop-target` or `data-focus-visible`\n attributes it sets.\n\nIf your use case requires tracking and analytics for this component, it is\ngood practice to add a **persistent**, **unique** id:\n\n```tsx\nconst PERSISTENT_ID = \"asset-manager-drop-zone\";\n\nexport const Example = () => (\n <DropZone id={PERSISTENT_ID}>\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n);\n```\n\n#### Keyboard navigation\n\nThe drop target supports full keyboard interaction — see the Accessibility\ntab for the complete key/action table and its limits for OS file uploads.\n\n## API reference\n\n<PropsTable id=\"DropZone\" />\n\n## Notes and limitations\n\n- **Default content vs. accessible name.** With no children, DropZone renders a\n default upload icon and localized instruction label, which also serves as its\n accessible name. Passing any children replaces that default visual entirely.\n An explicit `aria-label` / `aria-labelledby` is independent: it overrides only\n the accessible name and leaves the default icon and instruction in place — so\n you can keep the default visual while giving it a more descriptive name.\n Compose a `FileTrigger` (and any supporting copy) as children for a\n click-to-upload path.\n- **No file-selection props.** DropZone does not expose `acceptedFileTypes`,\n `allowsMultiple`, or any other file-picker configuration — that surface\n belongs to the composed `FileTrigger`.\n\n## Testing your implementation\n\nThese examples demonstrate how to test your implementation when using\n`DropZone` within your application. As the component's internal functionality\nis already tested by Nimbus, these patterns help you verify your integration\nand application-specific logic.\n\n### Basic Rendering Tests\n\nVerify the drop zone renders with an accessible name\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport {\n DropZone,\n FileTrigger,\n Button,\n NimbusProvider,\n} from \"@commercetools/nimbus\";\nimport type {\n DropEvent,\n DragTypes,\n DropOperation,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"DropZone - Basic rendering\", () => {\n it(\"renders with an explicit accessible name\", () => {\n render(\n <NimbusProvider>\n <DropZone aria-label=\"Upload files\" />\n </NimbusProvider>\n );\n\n expect(\n screen.getByRole(\"button\", { name: /upload files/i })\n ).toBeInTheDocument();\n });\n});\n```\n\n### Handling Dropped Files\n\nExtract native File objects from a DropEvent and share the result with a composed FileTrigger\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport {\n DropZone,\n FileTrigger,\n Button,\n NimbusProvider,\n} from \"@commercetools/nimbus\";\nimport type {\n DropEvent,\n DragTypes,\n DropOperation,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"DropZone - onDrop file extraction\", () => {\n it(\"resolves File objects from file drag items via getFile()\", async () => {\n const handleFiles = vi.fn();\n\n const handleDrop = async (event: DropEvent) => {\n const files = await Promise.all(\n event.items\n .filter((item) => item.kind === \"file\")\n .map((item) =>\n \"getFile\" in item ? item.getFile() : Promise.resolve(null)\n )\n );\n handleFiles(files.filter((file): file is File => file !== null));\n };\n\n const fakeFile = new File([\"hello\"], \"report.txt\", {\n type: \"text/plain\",\n });\n const fakeEvent = {\n items: [\n {\n kind: \"file\" as const,\n type: \"text/plain\",\n name: \"report.txt\",\n getFile: () => Promise.resolve(fakeFile),\n },\n ],\n } as unknown as DropEvent;\n\n await handleDrop(fakeEvent);\n\n expect(handleFiles).toHaveBeenCalledTimes(1);\n expect(handleFiles).toHaveBeenCalledWith([fakeFile]);\n });\n\n it(\"shares a single handleFiles helper between onDrop and a composed FileTrigger\", async () => {\n const handleFiles = vi.fn();\n\n const handleDrop = async (event: DropEvent) => {\n const files = await Promise.all(\n event.items\n .filter((item) => item.kind === \"file\")\n .map((item) =>\n \"getFile\" in item ? item.getFile() : Promise.resolve(null)\n )\n );\n handleFiles(files.filter((file): file is File => file !== null));\n };\n\n const handleSelect = (fileList: FileList | null) => {\n handleFiles(fileList ? Array.from(fileList) : []);\n };\n\n render(\n <NimbusProvider>\n <DropZone onDrop={handleDrop}>\n <FileTrigger onSelect={handleSelect}>\n <Button>Browse files</Button>\n </FileTrigger>\n </DropZone>\n </NimbusProvider>\n );\n\n expect(\n screen.getByRole(\"button\", { name: /browse files/i })\n ).toBeInTheDocument();\n\n // Both paths funnel through the same handleFiles helper.\n handleSelect(null);\n expect(handleFiles).toHaveBeenCalledWith([]);\n });\n});\n```\n\n### Restricting Accepted Drop Types\n\nUse getDropOperation as a type guard to reject unsupported drag types\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport {\n DropZone,\n FileTrigger,\n Button,\n NimbusProvider,\n} from \"@commercetools/nimbus\";\nimport type {\n DropEvent,\n DragTypes,\n DropOperation,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"DropZone - getDropOperation guard\", () => {\n // This case exercises a standalone `getDropOperation` guard to illustrate the\n // accept/reject shape a consumer would write — it does not drive `DropZone`\n // itself, so it documents the pattern rather than asserting component\n // behavior. The following case renders `DropZone` with the guard supplied.\n it(\"rejects types the zone does not accept\", () => {\n const acceptedType = \"image/png\";\n const getDropOperation = (types: DragTypes): DropOperation =>\n types.has(acceptedType) ? \"copy\" : \"cancel\";\n\n const rejectingTypes = new Set([\"application/x-msdownload\"]);\n const acceptingTypes = new Set([acceptedType]);\n\n expect(getDropOperation(rejectingTypes as unknown as DragTypes)).toBe(\n \"cancel\"\n );\n expect(getDropOperation(acceptingTypes as unknown as DragTypes)).toBe(\n \"copy\"\n );\n });\n\n it(\"renders with a getDropOperation guard supplied\", () => {\n const getDropOperation = (types: DragTypes): DropOperation =>\n types.has(\"image/png\") ? \"copy\" : \"cancel\";\n\n render(\n <NimbusProvider>\n <DropZone getDropOperation={getDropOperation} />\n </NimbusProvider>\n );\n\n expect(screen.getByRole(\"button\")).toBeInTheDocument();\n });\n});\n```\n\n### Disabling the Zone and Its Composed Trigger\n\nSet isDisabled explicitly on both DropZone and the composed FileTrigger/Button\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport {\n DropZone,\n FileTrigger,\n Button,\n NimbusProvider,\n} from \"@commercetools/nimbus\";\nimport type {\n DropEvent,\n DragTypes,\n DropOperation,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"DropZone - disabled composition\", () => {\n it(\"disables both the drop target and the composed button\", () => {\n const { container } = render(\n <NimbusProvider>\n <DropZone isDisabled data-testid=\"drop-zone-root\">\n <FileTrigger>\n <Button isDisabled>Browse files</Button>\n </FileTrigger>\n </DropZone>\n </NimbusProvider>\n );\n\n const zone = container.querySelector(\n \"[data-testid='drop-zone-root']\"\n ) as HTMLElement;\n const trigger = screen.getByRole(\"button\", { name: /browse files/i });\n\n expect(zone).toHaveAttribute(\"data-disabled\", \"true\");\n expect(trigger).toBeDisabled();\n });\n});\n```\n\n\n## Resources\n\n- [Storybook](https://nimbus-storybook.vercel.app/?path=/docs/components-dropzone--docs)\n- [React Aria DropZone](https://react-spectrum.adobe.com/react-aria/DropZone.html)\n- [FileTrigger](/components/inputs/filetrigger)\n",
|
|
264
|
+
"toc": [
|
|
265
|
+
{
|
|
266
|
+
"value": "Getting started",
|
|
267
|
+
"href": "#getting-started",
|
|
268
|
+
"depth": 2,
|
|
269
|
+
"numbering": [
|
|
270
|
+
1,
|
|
271
|
+
1
|
|
272
|
+
],
|
|
273
|
+
"parent": "root"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"value": "Import",
|
|
277
|
+
"href": "#import",
|
|
278
|
+
"depth": 3,
|
|
279
|
+
"numbering": [
|
|
280
|
+
1,
|
|
281
|
+
1,
|
|
282
|
+
1
|
|
283
|
+
],
|
|
284
|
+
"parent": "root"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"value": "Basic usage",
|
|
288
|
+
"href": "#basic-usage",
|
|
289
|
+
"depth": 3,
|
|
290
|
+
"numbering": [
|
|
291
|
+
1,
|
|
292
|
+
1,
|
|
293
|
+
2
|
|
294
|
+
],
|
|
295
|
+
"parent": "root"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"value": "Usage examples",
|
|
299
|
+
"href": "#usage-examples",
|
|
300
|
+
"depth": 2,
|
|
301
|
+
"numbering": [
|
|
302
|
+
1,
|
|
303
|
+
2
|
|
304
|
+
],
|
|
305
|
+
"parent": "root"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"value": "Handling dropped files",
|
|
309
|
+
"href": "#handling-dropped-files",
|
|
310
|
+
"depth": 3,
|
|
311
|
+
"numbering": [
|
|
312
|
+
1,
|
|
313
|
+
2,
|
|
314
|
+
1
|
|
315
|
+
],
|
|
316
|
+
"parent": "root"
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"value": "Composing a click-to-upload path",
|
|
320
|
+
"href": "#composing-a-click-to-upload-path",
|
|
321
|
+
"depth": 3,
|
|
322
|
+
"numbering": [
|
|
323
|
+
1,
|
|
324
|
+
2,
|
|
325
|
+
2
|
|
326
|
+
],
|
|
327
|
+
"parent": "root"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"value": "Restricting accepted drops",
|
|
331
|
+
"href": "#restricting-accepted-drops",
|
|
332
|
+
"depth": 3,
|
|
333
|
+
"numbering": [
|
|
334
|
+
1,
|
|
335
|
+
2,
|
|
336
|
+
3
|
|
337
|
+
],
|
|
338
|
+
"parent": "root"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"value": "Disabling the zone and its composed trigger",
|
|
342
|
+
"href": "#disabling-the-zone-and-its-composed-trigger",
|
|
343
|
+
"depth": 3,
|
|
344
|
+
"numbering": [
|
|
345
|
+
1,
|
|
346
|
+
2,
|
|
347
|
+
4
|
|
348
|
+
],
|
|
349
|
+
"parent": "root"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"value": "Accessible name",
|
|
353
|
+
"href": "#accessible-name",
|
|
354
|
+
"depth": 3,
|
|
355
|
+
"numbering": [
|
|
356
|
+
1,
|
|
357
|
+
2,
|
|
358
|
+
5
|
|
359
|
+
],
|
|
360
|
+
"parent": "root"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"value": "Filled state",
|
|
364
|
+
"href": "#filled-state",
|
|
365
|
+
"depth": 3,
|
|
366
|
+
"numbering": [
|
|
367
|
+
1,
|
|
368
|
+
2,
|
|
369
|
+
6
|
|
370
|
+
],
|
|
371
|
+
"parent": "root"
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
"value": "Multiple files",
|
|
375
|
+
"href": "#multiple-files",
|
|
376
|
+
"depth": 3,
|
|
377
|
+
"numbering": [
|
|
378
|
+
1,
|
|
379
|
+
2,
|
|
380
|
+
7
|
|
381
|
+
],
|
|
382
|
+
"parent": "root"
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
"value": "Working with React Aria drag-and-drop types",
|
|
386
|
+
"href": "#working-with-react-aria-drag-and-drop-types",
|
|
387
|
+
"depth": 2,
|
|
388
|
+
"numbering": [
|
|
389
|
+
1,
|
|
390
|
+
3
|
|
391
|
+
],
|
|
392
|
+
"parent": "root"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"value": "Component requirements",
|
|
396
|
+
"href": "#component-requirements",
|
|
397
|
+
"depth": 2,
|
|
398
|
+
"numbering": [
|
|
399
|
+
1,
|
|
400
|
+
4
|
|
401
|
+
],
|
|
402
|
+
"parent": "root"
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
"value": "Accessibility",
|
|
406
|
+
"href": "#accessibility",
|
|
407
|
+
"depth": 3,
|
|
408
|
+
"numbering": [
|
|
409
|
+
1,
|
|
410
|
+
4,
|
|
411
|
+
1
|
|
412
|
+
],
|
|
413
|
+
"parent": "root"
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"value": "Keyboard navigation",
|
|
417
|
+
"href": "#keyboard-navigation",
|
|
418
|
+
"depth": 4,
|
|
419
|
+
"numbering": [
|
|
420
|
+
1,
|
|
421
|
+
4,
|
|
422
|
+
1,
|
|
423
|
+
1
|
|
424
|
+
],
|
|
425
|
+
"parent": "root"
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"value": "API reference",
|
|
429
|
+
"href": "#api-reference",
|
|
430
|
+
"depth": 2,
|
|
431
|
+
"numbering": [
|
|
432
|
+
1,
|
|
433
|
+
5
|
|
434
|
+
],
|
|
435
|
+
"parent": "root"
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"value": "Notes and limitations",
|
|
439
|
+
"href": "#notes-and-limitations",
|
|
440
|
+
"depth": 2,
|
|
441
|
+
"numbering": [
|
|
442
|
+
1,
|
|
443
|
+
6
|
|
444
|
+
],
|
|
445
|
+
"parent": "root"
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"value": "Testing your implementation",
|
|
449
|
+
"href": "#testing-your-implementation",
|
|
450
|
+
"depth": 2,
|
|
451
|
+
"numbering": [
|
|
452
|
+
1,
|
|
453
|
+
7
|
|
454
|
+
],
|
|
455
|
+
"parent": "root"
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"value": "Basic Rendering Tests",
|
|
459
|
+
"href": "#basic-rendering-tests",
|
|
460
|
+
"depth": 3,
|
|
461
|
+
"numbering": [
|
|
462
|
+
1,
|
|
463
|
+
7,
|
|
464
|
+
1
|
|
465
|
+
],
|
|
466
|
+
"parent": "root"
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"value": "Handling Dropped Files",
|
|
470
|
+
"href": "#handling-dropped-files-1",
|
|
471
|
+
"depth": 3,
|
|
472
|
+
"numbering": [
|
|
473
|
+
1,
|
|
474
|
+
7,
|
|
475
|
+
2
|
|
476
|
+
],
|
|
477
|
+
"parent": "root"
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
"value": "Restricting Accepted Drop Types",
|
|
481
|
+
"href": "#restricting-accepted-drop-types",
|
|
482
|
+
"depth": 3,
|
|
483
|
+
"numbering": [
|
|
484
|
+
1,
|
|
485
|
+
7,
|
|
486
|
+
3
|
|
487
|
+
],
|
|
488
|
+
"parent": "root"
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
"value": "Disabling the Zone and Its Composed Trigger",
|
|
492
|
+
"href": "#disabling-the-zone-and-its-composed-trigger-1",
|
|
493
|
+
"depth": 3,
|
|
494
|
+
"numbering": [
|
|
495
|
+
1,
|
|
496
|
+
7,
|
|
497
|
+
4
|
|
498
|
+
],
|
|
499
|
+
"parent": "root"
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
"value": "Resources",
|
|
503
|
+
"href": "#resources",
|
|
504
|
+
"depth": 2,
|
|
505
|
+
"numbering": [
|
|
506
|
+
1,
|
|
507
|
+
8
|
|
508
|
+
],
|
|
509
|
+
"parent": "root"
|
|
510
|
+
}
|
|
511
|
+
]
|
|
512
|
+
},
|
|
513
|
+
"guidelines": {
|
|
514
|
+
"mdx": "\n## Guidelines\n\nDropZone gives users a visible, on-brand target for dragging in files. It\nworks best as one part of an upload flow, not the whole flow — pair it with a\nclick-to-upload trigger and let the consumer's application own what happens\nonce files arrive.\n\n### Best practices\n\n- **Always pair dragging with a click-to-upload button.** Not every user can\n drag: compose a `FileTrigger` and `Button` inside the drop zone so keyboard\n and screen-reader users have an equally direct path to the file picker.\n- **State what the zone accepts.** If the drop zone only takes certain file\n types or a size limit, say so in nearby text — don't make users find out by\n trying and failing.\n- **Reserve space for the filled state.** Once files are dropped or selected,\n swap the zone's content to show what was added (a file list, a thumbnail).\n Don't leave the empty-state copy showing alongside the result.\n- **Replace the default label when you add your own content.** DropZone has a\n default icon and accessible name out of the box, but composing children\n (such as a `FileTrigger`) replaces that default entirely. Once you add\n children, include a heading, instructional text, or an `aria-label` of your\n own so the zone keeps a clear accessible name.\n\n### When to use\n\n> [!TIP]\\\n> **Do** — use a drop zone when uploading a file is a primary action on the\n> page, and dragging is a plausible way users will get there.\n\n- A dedicated upload step, such as an asset manager or CSV importer.\n- An avatar or logo picker where the target area is large enough to make\n dragging comfortable.\n- Any flow where a click-to-upload button alone would leave power users\n without a faster drag-and-drop option.\n\n> [!CAUTION]\\\n> **Don't** — reach for `FileTrigger` alone instead when a drop target adds\n> more visual weight than the flow needs.\n\n- A single inline \"Attach file\" action next to a text field or in a toolbar.\n- A space-constrained layout where a full drop zone would crowd other\n content.\n- A flow where files are the only content — DropZone doesn't add upload\n progress, retries, or a file list; you still build that part yourself.\n\n### Common mistakes\n\n> [!CAUTION]\\\n> **Don't** show a drop zone with no way to reach it by keyboard.\n\n```jsx live\nconst App = () => (\n // Drag-only: this zone has a default icon and accessible name, but no\n // click-to-upload path. A keyboard or screen-reader user can't reach the\n // operating system's file picker from it.\n <DropZone />\n);\n```\n\n> [!TIP]\\\n> **Do** compose a `FileTrigger` so every user has a path to the same picker.\n\n```jsx live\nconst App = () => (\n <DropZone>\n <FileTrigger>\n <Button variant=\"ghost\">Browse files</Button>\n </FileTrigger>\n </DropZone>\n);\n```\n",
|
|
515
|
+
"toc": [
|
|
516
|
+
{
|
|
517
|
+
"value": "Guidelines",
|
|
518
|
+
"href": "#guidelines",
|
|
519
|
+
"depth": 2,
|
|
520
|
+
"numbering": [
|
|
521
|
+
1,
|
|
522
|
+
1
|
|
523
|
+
],
|
|
524
|
+
"parent": "root"
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
"value": "Best practices",
|
|
528
|
+
"href": "#best-practices",
|
|
529
|
+
"depth": 3,
|
|
530
|
+
"numbering": [
|
|
531
|
+
1,
|
|
532
|
+
1,
|
|
533
|
+
1
|
|
534
|
+
],
|
|
535
|
+
"parent": "root"
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
"value": "When to use",
|
|
539
|
+
"href": "#when-to-use",
|
|
540
|
+
"depth": 3,
|
|
541
|
+
"numbering": [
|
|
542
|
+
1,
|
|
543
|
+
1,
|
|
544
|
+
2
|
|
545
|
+
],
|
|
546
|
+
"parent": "root"
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
"value": "Common mistakes",
|
|
550
|
+
"href": "#common-mistakes",
|
|
551
|
+
"depth": 3,
|
|
552
|
+
"numbering": [
|
|
553
|
+
1,
|
|
554
|
+
1,
|
|
555
|
+
3
|
|
556
|
+
],
|
|
557
|
+
"parent": "root"
|
|
558
|
+
}
|
|
559
|
+
]
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|