@adres/mgda-ui 0.0.0-stage → 0.0.2
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/brand-knowledge.json +451 -0
- package/knowledge/accordion.md +135 -0
- package/knowledge/activity-rings.md +123 -0
- package/knowledge/alert.md +184 -0
- package/knowledge/answer-actions.md +217 -0
- package/knowledge/aspect-ratio.md +82 -0
- package/knowledge/avatar.md +158 -0
- package/knowledge/badge.md +172 -0
- package/knowledge/bar-graph.md +167 -0
- package/knowledge/bento-grid.md +115 -0
- package/knowledge/blockquote.md +153 -0
- package/knowledge/box-list.md +177 -0
- package/knowledge/bullet-list.md +128 -0
- package/knowledge/button-group.md +179 -0
- package/knowledge/button.md +231 -0
- package/knowledge/calendar.md +168 -0
- package/knowledge/card.md +321 -0
- package/knowledge/cards-nav.md +170 -0
- package/knowledge/chain-of-thought.md +164 -0
- package/knowledge/chat-container.md +135 -0
- package/knowledge/chat-message.md +224 -0
- package/knowledge/checkbox-card.md +172 -0
- package/knowledge/checkbox.md +111 -0
- package/knowledge/citations.md +241 -0
- package/knowledge/combobox.md +265 -0
- package/knowledge/countdown-pill.md +153 -0
- package/knowledge/cta.md +118 -0
- package/knowledge/data-list.md +173 -0
- package/knowledge/data-table.md +220 -0
- package/knowledge/dialog.md +249 -0
- package/knowledge/drawer.md +236 -0
- package/knowledge/dropdown-menu.md +238 -0
- package/knowledge/dropzone.md +153 -0
- package/knowledge/email-chips-input.md +161 -0
- package/knowledge/empty-state.md +106 -0
- package/knowledge/entity-header.md +166 -0
- package/knowledge/feature-grid.md +120 -0
- package/knowledge/feedback-bar.md +127 -0
- package/knowledge/footer.md +116 -0
- package/knowledge/heading.md +189 -0
- package/knowledge/hero.md +361 -0
- package/knowledge/input-button.md +187 -0
- package/knowledge/input-group.md +185 -0
- package/knowledge/input.md +256 -0
- package/knowledge/inset.md +177 -0
- package/knowledge/kpi-card.md +206 -0
- package/knowledge/list-nav.md +181 -0
- package/knowledge/logo-cloud.md +102 -0
- package/knowledge/media-gallery.md +158 -0
- package/knowledge/message-actions.md +175 -0
- package/knowledge/nav-sidebar.md +225 -0
- package/knowledge/number-stepper.md +159 -0
- package/knowledge/page-header.md +109 -0
- package/knowledge/pagination.md +225 -0
- package/knowledge/popover.md +159 -0
- package/knowledge/pricing.md +132 -0
- package/knowledge/progress.md +156 -0
- package/knowledge/prompt-input.md +337 -0
- package/knowledge/prompt-suggestions.md +168 -0
- package/knowledge/quota-bar.md +160 -0
- package/knowledge/quote.md +116 -0
- package/knowledge/radio-card.md +172 -0
- package/knowledge/radio-group.md +135 -0
- package/knowledge/reasoning.md +142 -0
- package/knowledge/search.md +131 -0
- package/knowledge/section-nav.md +162 -0
- package/knowledge/segmented-control.md +181 -0
- package/knowledge/select-button.md +205 -0
- package/knowledge/select.md +210 -0
- package/knowledge/separator.md +75 -0
- package/knowledge/shimmer-text.md +140 -0
- package/knowledge/sidebar.md +227 -0
- package/knowledge/skeleton.md +142 -0
- package/knowledge/slider.md +133 -0
- package/knowledge/slideshow.md +159 -0
- package/knowledge/source.md +156 -0
- package/knowledge/spinner.md +120 -0
- package/knowledge/stat-strip.md +128 -0
- package/knowledge/stats.md +117 -0
- package/knowledge/step-indicator.md +157 -0
- package/knowledge/switch.md +88 -0
- package/knowledge/table.md +190 -0
- package/knowledge/tabs.md +169 -0
- package/knowledge/testimonials.md +115 -0
- package/knowledge/text-link.md +192 -0
- package/knowledge/text.md +194 -0
- package/knowledge/thinking-bar.md +115 -0
- package/knowledge/thinking-steps.md +140 -0
- package/knowledge/toaster.md +127 -0
- package/knowledge/toggle.md +113 -0
- package/knowledge/tool-call-card.md +241 -0
- package/knowledge/tooltip.md +120 -0
- package/knowledge/top-nav.md +138 -0
- package/knowledge.json +19854 -0
- package/package.json +94 -4
- package/src/components/accordion.stories.tsx +46 -0
- package/src/components/accordion.tsx +74 -0
- package/src/components/activity-rings.stories.tsx +73 -0
- package/src/components/activity-rings.tsx +121 -0
- package/src/components/alert.stories.tsx +43 -0
- package/src/components/alert.tsx +132 -0
- package/src/components/answer-actions.stories.tsx +54 -0
- package/src/components/answer-actions.test.tsx +37 -0
- package/src/components/answer-actions.tsx +313 -0
- package/src/components/aspect-ratio.stories.tsx +32 -0
- package/src/components/aspect-ratio.tsx +5 -0
- package/src/components/avatar.stories.tsx +40 -0
- package/src/components/avatar.tsx +154 -0
- package/src/components/badge.stories.tsx +27 -0
- package/src/components/badge.tsx +63 -0
- package/src/components/bar-graph.stories.tsx +28 -0
- package/src/components/bar-graph.tsx +204 -0
- package/src/components/bento-grid.stories.tsx +23 -0
- package/src/components/bento-grid.tsx +67 -0
- package/src/components/blockquote.stories.tsx +28 -0
- package/src/components/blockquote.tsx +88 -0
- package/src/components/box-list.stories.tsx +25 -0
- package/src/components/box-list.tsx +108 -0
- package/src/components/bullet-list.stories.tsx +22 -0
- package/src/components/bullet-list.tsx +101 -0
- package/src/components/button-group.stories.tsx +31 -0
- package/src/components/button-group.tsx +156 -0
- package/src/components/button.stories.tsx +66 -0
- package/src/components/button.test.ts +17 -0
- package/src/components/button.tsx +139 -0
- package/src/components/calendar.stories.tsx +25 -0
- package/src/components/calendar.tsx +367 -0
- package/src/components/card.stories.tsx +44 -0
- package/src/components/card.tsx +392 -0
- package/src/components/cards-nav.stories.tsx +35 -0
- package/src/components/cards-nav.tsx +115 -0
- package/src/components/chain-of-thought.stories.tsx +67 -0
- package/src/components/chain-of-thought.test.tsx +50 -0
- package/src/components/chain-of-thought.tsx +170 -0
- package/src/components/chat-container.stories.tsx +47 -0
- package/src/components/chat-container.test.tsx +49 -0
- package/src/components/chat-container.tsx +222 -0
- package/src/components/chat-message.stories.tsx +52 -0
- package/src/components/chat-message.test.tsx +36 -0
- package/src/components/chat-message.tsx +163 -0
- package/src/components/checkbox-card.stories.tsx +27 -0
- package/src/components/checkbox-card.tsx +200 -0
- package/src/components/checkbox.stories.tsx +26 -0
- package/src/components/checkbox.tsx +61 -0
- package/src/components/citations.stories.tsx +64 -0
- package/src/components/citations.test.tsx +61 -0
- package/src/components/citations.tsx +220 -0
- package/src/components/combobox.stories.tsx +184 -0
- package/src/components/combobox.test.tsx +82 -0
- package/src/components/combobox.tsx +407 -0
- package/src/components/countdown-pill.stories.tsx +24 -0
- package/src/components/countdown-pill.tsx +129 -0
- package/src/components/cta.stories.tsx +29 -0
- package/src/components/cta.tsx +52 -0
- package/src/components/data-list.stories.tsx +50 -0
- package/src/components/data-list.test.tsx +35 -0
- package/src/components/data-list.tsx +181 -0
- package/src/components/data-table.stories.tsx +29 -0
- package/src/components/data-table.tsx +200 -0
- package/src/components/dialog.stories.tsx +42 -0
- package/src/components/dialog.tsx +200 -0
- package/src/components/drawer.stories.tsx +48 -0
- package/src/components/drawer.tsx +385 -0
- package/src/components/dropdown-menu.stories.tsx +41 -0
- package/src/components/dropdown-menu.tsx +252 -0
- package/src/components/dropzone.stories.tsx +19 -0
- package/src/components/dropzone.tsx +250 -0
- package/src/components/email-chips-input.stories.tsx +135 -0
- package/src/components/email-chips-input.tsx +210 -0
- package/src/components/empty-state.stories.tsx +22 -0
- package/src/components/empty-state.tsx +35 -0
- package/src/components/entity-header.stories.tsx +43 -0
- package/src/components/entity-header.test.tsx +35 -0
- package/src/components/entity-header.tsx +92 -0
- package/src/components/feature-grid.stories.tsx +25 -0
- package/src/components/feature-grid.tsx +87 -0
- package/src/components/feedback-bar.stories.tsx +25 -0
- package/src/components/feedback-bar.test.tsx +24 -0
- package/src/components/feedback-bar.tsx +62 -0
- package/src/components/footer.stories.tsx +23 -0
- package/src/components/footer.tsx +78 -0
- package/src/components/heading.stories.tsx +45 -0
- package/src/components/heading.test.tsx +22 -0
- package/src/components/heading.tsx +77 -0
- package/src/components/hero.stories.tsx +38 -0
- package/src/components/hero.tsx +498 -0
- package/src/components/input-button.stories.tsx +19 -0
- package/src/components/input-button.tsx +112 -0
- package/src/components/input-group.stories.tsx +38 -0
- package/src/components/input-group.tsx +157 -0
- package/src/components/input.stories.tsx +31 -0
- package/src/components/input.tsx +284 -0
- package/src/components/inset.stories.tsx +29 -0
- package/src/components/inset.tsx +70 -0
- package/src/components/kpi-card.stories.tsx +29 -0
- package/src/components/kpi-card.tsx +284 -0
- package/src/components/list-nav.stories.tsx +22 -0
- package/src/components/list-nav.tsx +145 -0
- package/src/components/logo-cloud.stories.tsx +23 -0
- package/src/components/logo-cloud.tsx +42 -0
- package/src/components/media-gallery.stories.tsx +25 -0
- package/src/components/media-gallery.tsx +347 -0
- package/src/components/message-actions.stories.tsx +45 -0
- package/src/components/message-actions.test.tsx +32 -0
- package/src/components/message-actions.tsx +119 -0
- package/src/components/nav-sidebar.stories.tsx +58 -0
- package/src/components/nav-sidebar.test.tsx +54 -0
- package/src/components/nav-sidebar.tsx +462 -0
- package/src/components/number-stepper.stories.tsx +19 -0
- package/src/components/number-stepper.tsx +158 -0
- package/src/components/page-header.stories.tsx +25 -0
- package/src/components/page-header.tsx +64 -0
- package/src/components/pagination.stories.tsx +110 -0
- package/src/components/pagination.test.tsx +46 -0
- package/src/components/pagination.tsx +144 -0
- package/src/components/popover.stories.tsx +26 -0
- package/src/components/popover.tsx +62 -0
- package/src/components/pricing.stories.tsx +42 -0
- package/src/components/pricing.tsx +130 -0
- package/src/components/progress.stories.tsx +22 -0
- package/src/components/progress.tsx +189 -0
- package/src/components/prompt-input.stories.tsx +62 -0
- package/src/components/prompt-input.test.tsx +106 -0
- package/src/components/prompt-input.tsx +343 -0
- package/src/components/prompt-suggestions.stories.tsx +53 -0
- package/src/components/prompt-suggestions.test.tsx +37 -0
- package/src/components/prompt-suggestions.tsx +122 -0
- package/src/components/quota-bar.stories.tsx +19 -0
- package/src/components/quota-bar.tsx +191 -0
- package/src/components/quote.stories.tsx +18 -0
- package/src/components/quote.tsx +43 -0
- package/src/components/radio-card.stories.tsx +27 -0
- package/src/components/radio-card.tsx +225 -0
- package/src/components/radio-group.stories.tsx +32 -0
- package/src/components/radio-group.tsx +68 -0
- package/src/components/reasoning.stories.tsx +50 -0
- package/src/components/reasoning.test.tsx +48 -0
- package/src/components/reasoning.tsx +143 -0
- package/src/components/search.stories.tsx +18 -0
- package/src/components/search.tsx +133 -0
- package/src/components/section-nav.stories.tsx +59 -0
- package/src/components/section-nav.test.tsx +36 -0
- package/src/components/section-nav.tsx +146 -0
- package/src/components/segmented-control.stories.tsx +22 -0
- package/src/components/segmented-control.tsx +301 -0
- package/src/components/select-button.stories.tsx +27 -0
- package/src/components/select-button.tsx +174 -0
- package/src/components/select.stories.tsx +27 -0
- package/src/components/select.tsx +198 -0
- package/src/components/separator.stories.tsx +22 -0
- package/src/components/separator.tsx +23 -0
- package/src/components/shimmer-text.stories.tsx +23 -0
- package/src/components/shimmer-text.test.tsx +35 -0
- package/src/components/shimmer-text.tsx +43 -0
- package/src/components/sidebar.stories.tsx +25 -0
- package/src/components/sidebar.tsx +234 -0
- package/src/components/skeleton.stories.tsx +22 -0
- package/src/components/skeleton.tsx +96 -0
- package/src/components/slider.stories.tsx +20 -0
- package/src/components/slider.tsx +176 -0
- package/src/components/slideshow.stories.tsx +30 -0
- package/src/components/slideshow.tsx +291 -0
- package/src/components/source.stories.tsx +32 -0
- package/src/components/source.test.tsx +40 -0
- package/src/components/source.tsx +161 -0
- package/src/components/spinner.stories.tsx +19 -0
- package/src/components/spinner.tsx +76 -0
- package/src/components/stat-strip.stories.tsx +36 -0
- package/src/components/stat-strip.test.tsx +25 -0
- package/src/components/stat-strip.tsx +85 -0
- package/src/components/stats.stories.tsx +24 -0
- package/src/components/stats.tsx +83 -0
- package/src/components/step-indicator.stories.tsx +18 -0
- package/src/components/step-indicator.test.tsx +18 -0
- package/src/components/step-indicator.tsx +286 -0
- package/src/components/switch.stories.tsx +26 -0
- package/src/components/switch.tsx +32 -0
- package/src/components/table.stories.tsx +38 -0
- package/src/components/table.tsx +220 -0
- package/src/components/tabs.stories.tsx +25 -0
- package/src/components/tabs.tsx +276 -0
- package/src/components/testimonials.stories.tsx +22 -0
- package/src/components/testimonials.tsx +109 -0
- package/src/components/text-link.stories.tsx +47 -0
- package/src/components/text-link.test.tsx +18 -0
- package/src/components/text-link.tsx +88 -0
- package/src/components/text.stories.tsx +49 -0
- package/src/components/text.tsx +105 -0
- package/src/components/thinking-bar.stories.tsx +19 -0
- package/src/components/thinking-bar.test.tsx +27 -0
- package/src/components/thinking-bar.tsx +64 -0
- package/src/components/thinking-steps.stories.tsx +44 -0
- package/src/components/thinking-steps.test.tsx +42 -0
- package/src/components/thinking-steps.tsx +92 -0
- package/src/components/toaster.stories.tsx +80 -0
- package/src/components/toaster.tsx +36 -0
- package/src/components/toggle.stories.tsx +21 -0
- package/src/components/toggle.tsx +103 -0
- package/src/components/tool-call-card.stories.tsx +97 -0
- package/src/components/tool-call-card.test.tsx +88 -0
- package/src/components/tool-call-card.tsx +231 -0
- package/src/components/tooltip.stories.tsx +25 -0
- package/src/components/tooltip.tsx +43 -0
- package/src/components/top-nav.stories.tsx +20 -0
- package/src/components/top-nav.tsx +76 -0
- package/src/docs/Colors.stories.tsx +192 -0
- package/src/docs/GettingStarted.mdx +72 -0
- package/src/docs/Mcp.mdx +52 -0
- package/src/docs/Typography.stories.tsx +114 -0
- package/src/hooks/use-in-view.ts +32 -0
- package/src/hooks/use-reduced-motion.ts +26 -0
- package/src/index.ts +343 -0
- package/src/lib/cn.test.ts +67 -0
- package/src/lib/cn.ts +81 -0
- package/src/lib/motion.ts +109 -0
- package/src/lib/prefix-utilities.test.ts +56 -0
- package/src/lib/prefix-utilities.ts +50 -0
- package/src/styles/base.css +489 -0
- package/src/styles/motion.css +69 -0
- package/src/styles/overrides.css +44 -0
- package/src/styles/typography.css +173 -0
- package/src/theme/theme.css +391 -0
- package/src/theme/tokens.ts +29 -0
- package/src/theme/types.ts +26 -0
- package/README.md +0 -3
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: dropdown-menu
|
|
6
|
+
sourceFile: packages/design-system/src/components/dropdown-menu.tsx
|
|
7
|
+
client: true
|
|
8
|
+
category: web-app-overlays
|
|
9
|
+
categoryFromBarrel: web-app-overlays
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: DropdownMenu
|
|
14
|
+
kind: component
|
|
15
|
+
radixSource: "@radix-ui/react-dropdown-menu#Root"
|
|
16
|
+
typeText: "FC<DropdownMenuProps>"
|
|
17
|
+
- name: DropdownMenuCheckboxItem
|
|
18
|
+
kind: component
|
|
19
|
+
typeText: "ForwardRefExoticComponent<Omit<DropdownMenuCheckboxItemProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
|
|
20
|
+
- name: DropdownMenuContent
|
|
21
|
+
kind: component
|
|
22
|
+
typeText: "ForwardRefExoticComponent<DropdownMenuContentProps & RefAttributes<HTMLDivElement>>"
|
|
23
|
+
- name: DropdownMenuContentProps
|
|
24
|
+
kind: type
|
|
25
|
+
- name: DropdownMenuGroup
|
|
26
|
+
kind: component
|
|
27
|
+
radixSource: "@radix-ui/react-dropdown-menu#Group"
|
|
28
|
+
typeText: "ForwardRefExoticComponent<DropdownMenuGroupProps & RefAttributes<HTMLDivElement>>"
|
|
29
|
+
- name: DropdownMenuItem
|
|
30
|
+
kind: component
|
|
31
|
+
typeText: "ForwardRefExoticComponent<DropdownMenuItemProps & RefAttributes<HTMLDivElement>>"
|
|
32
|
+
- name: DropdownMenuItemProps
|
|
33
|
+
kind: type
|
|
34
|
+
- name: DropdownMenuLabel
|
|
35
|
+
kind: component
|
|
36
|
+
typeText: "ForwardRefExoticComponent<Omit<DropdownMenuLabelProps & RefAttributes<HTMLDivElement>, \"ref\"> & { inset?: boolean | undefined; } & RefAttributes<...>>"
|
|
37
|
+
- name: DropdownMenuPortal
|
|
38
|
+
kind: component
|
|
39
|
+
radixSource: "@radix-ui/react-dropdown-menu#Portal"
|
|
40
|
+
typeText: "FC<DropdownMenuPortalProps>"
|
|
41
|
+
- name: DropdownMenuRadioGroup
|
|
42
|
+
kind: component
|
|
43
|
+
radixSource: "@radix-ui/react-dropdown-menu#RadioGroup"
|
|
44
|
+
typeText: "ForwardRefExoticComponent<DropdownMenuRadioGroupProps & RefAttributes<HTMLDivElement>>"
|
|
45
|
+
- name: DropdownMenuRadioItem
|
|
46
|
+
kind: component
|
|
47
|
+
typeText: "ForwardRefExoticComponent<Omit<DropdownMenuRadioItemProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
|
|
48
|
+
- name: DropdownMenuSeparator
|
|
49
|
+
kind: component
|
|
50
|
+
typeText: "ForwardRefExoticComponent<Omit<DropdownMenuSeparatorProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
|
|
51
|
+
- name: DropdownMenuShortcut
|
|
52
|
+
kind: component
|
|
53
|
+
typeText: "{ ({ className, ...props }: HTMLAttributes<HTMLSpanElement>): Element; displayName: string; }"
|
|
54
|
+
- name: DropdownMenuSub
|
|
55
|
+
kind: component
|
|
56
|
+
radixSource: "@radix-ui/react-dropdown-menu#Sub"
|
|
57
|
+
typeText: "FC<DropdownMenuSubProps>"
|
|
58
|
+
- name: DropdownMenuSubContent
|
|
59
|
+
kind: component
|
|
60
|
+
typeText: "ForwardRefExoticComponent<Omit<DropdownMenuSubContentProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
|
|
61
|
+
- name: DropdownMenuSubTrigger
|
|
62
|
+
kind: component
|
|
63
|
+
typeText: "ForwardRefExoticComponent<Omit<DropdownMenuSubTriggerProps & RefAttributes<HTMLDivElement>, \"ref\"> & { inset?: boolean | undefined; } & RefAttributes<...>>"
|
|
64
|
+
- name: DropdownMenuTrigger
|
|
65
|
+
kind: component
|
|
66
|
+
radixSource: "@radix-ui/react-dropdown-menu#Trigger"
|
|
67
|
+
typeText: "ForwardRefExoticComponent<DropdownMenuTriggerProps & RefAttributes<HTMLButtonElement>>"
|
|
68
|
+
primaryExport: DropdownMenu
|
|
69
|
+
subcomponents:
|
|
70
|
+
- DropdownMenuCheckboxItem
|
|
71
|
+
- DropdownMenuContent
|
|
72
|
+
- DropdownMenuGroup
|
|
73
|
+
- DropdownMenuItem
|
|
74
|
+
- DropdownMenuLabel
|
|
75
|
+
- DropdownMenuPortal
|
|
76
|
+
- DropdownMenuRadioGroup
|
|
77
|
+
- DropdownMenuRadioItem
|
|
78
|
+
- DropdownMenuSeparator
|
|
79
|
+
- DropdownMenuShortcut
|
|
80
|
+
- DropdownMenuSub
|
|
81
|
+
- DropdownMenuSubContent
|
|
82
|
+
- DropdownMenuSubTrigger
|
|
83
|
+
- DropdownMenuTrigger
|
|
84
|
+
props:
|
|
85
|
+
DropdownMenuItem:
|
|
86
|
+
- name: inset
|
|
87
|
+
type: boolean
|
|
88
|
+
required: false
|
|
89
|
+
declaredIn: self
|
|
90
|
+
doc: "Indents the item to align with siblings that have a checkbox/radio indicator column."
|
|
91
|
+
- name: variant
|
|
92
|
+
type: "\"default\" | \"destructive\""
|
|
93
|
+
required: false
|
|
94
|
+
declaredIn: self
|
|
95
|
+
doc: "Colour treatment. `destructive` tints text + icon + hover/highlight background."
|
|
96
|
+
DropdownMenuLabel:
|
|
97
|
+
- name: inset
|
|
98
|
+
type: boolean
|
|
99
|
+
required: false
|
|
100
|
+
declaredIn: self
|
|
101
|
+
DropdownMenuSubTrigger:
|
|
102
|
+
- name: inset
|
|
103
|
+
type: boolean
|
|
104
|
+
required: false
|
|
105
|
+
declaredIn: self
|
|
106
|
+
extendsProps: []
|
|
107
|
+
variants:
|
|
108
|
+
variant:
|
|
109
|
+
kind: enum
|
|
110
|
+
options:
|
|
111
|
+
- default
|
|
112
|
+
- destructive
|
|
113
|
+
default: default
|
|
114
|
+
on: DropdownMenuItem
|
|
115
|
+
variantSource: prop-union
|
|
116
|
+
compoundVariants: []
|
|
117
|
+
sizeMaps: []
|
|
118
|
+
dataSlots: []
|
|
119
|
+
dependsOn:
|
|
120
|
+
internal: []
|
|
121
|
+
lib:
|
|
122
|
+
- cn
|
|
123
|
+
hooks: []
|
|
124
|
+
external:
|
|
125
|
+
- "@radix-ui/react-dropdown-menu"
|
|
126
|
+
- lucide-react
|
|
127
|
+
- react
|
|
128
|
+
contexts: []
|
|
129
|
+
stories:
|
|
130
|
+
- exportName: Default
|
|
131
|
+
id: components-dropdownmenu--default
|
|
132
|
+
storybookTitle: Components/DropdownMenu
|
|
133
|
+
docsId: components-dropdownmenu--documentation
|
|
134
|
+
argTypeOptions: {}
|
|
135
|
+
resolvedCleanly: true
|
|
136
|
+
contractHash: a3688fbae91f
|
|
137
|
+
factsHash: "23cea40a2ea6"
|
|
138
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
139
|
+
status: stable
|
|
140
|
+
summary: "A Radix-based dropdown menu triggered by a button, with items, checkboxes, radios, submenus, and a destructive row variant."
|
|
141
|
+
useWhen:
|
|
142
|
+
- "a button or icon triggers a list of actions or options, closing after a selection"
|
|
143
|
+
- "the menu needs checkbox or radio items, a nested submenu, or a destructive action row"
|
|
144
|
+
useInstead:
|
|
145
|
+
- id: select
|
|
146
|
+
when: "the trigger represents a form value being chosen, not a list of actions"
|
|
147
|
+
- id: popover
|
|
148
|
+
when: "the content is more than a list of commands - a form, rich content, or anything beyond selectable rows"
|
|
149
|
+
related:
|
|
150
|
+
- select
|
|
151
|
+
- popover
|
|
152
|
+
tokens:
|
|
153
|
+
- "--popover"
|
|
154
|
+
- "--popover-foreground"
|
|
155
|
+
- "--border"
|
|
156
|
+
- "--muted"
|
|
157
|
+
- "--destructive"
|
|
158
|
+
- "--destructive-strong"
|
|
159
|
+
a11y:
|
|
160
|
+
notes:
|
|
161
|
+
- "Wrap the real trigger element (typically a Button) with DropdownMenuTrigger asChild so Radix attaches its keyboard and ARIA handling directly to it instead of adding an extra wrapping element."
|
|
162
|
+
- "DropdownMenuShortcut is purely visual - it does not wire the actual keyboard shortcut to anything, so the real key handler must be registered separately if the shortcut should actually work."
|
|
163
|
+
keyboard:
|
|
164
|
+
- "Radix supplies full menu keyboard behavior: arrow keys move between items, Enter/Space activates, Escape closes, and typing jumps to a matching item's first letter - none of this needs to be built by hand."
|
|
165
|
+
radixHandles: true
|
|
166
|
+
pitfalls:
|
|
167
|
+
- "inset only aligns an item, label, or sub-trigger's text with siblings that have a checkbox/radio indicator column - it has no other layout effect."
|
|
168
|
+
- "DropdownMenuCheckboxItem and DropdownMenuRadioItem only manage their own visual indicator - the checked or selected state is still yours to own (checked/onCheckedChange, or value/onValueChange on the parent DropdownMenuRadioGroup)."
|
|
169
|
+
- "DropdownMenuShortcut only renders text - it is decoration, not a keybinding. Adding it does not wire up the shortcut."
|
|
170
|
+
- "Most of DropdownMenuContent's and DropdownMenuTrigger's real props (align, side, asChild, sideOffset) come straight from Radix's own types via an inlined generic, which the extractor does not resolve into derived.props/extendsProps - the same gap noted for separator/aspect-ratio in 15b-ii. The machine-checked canonicalSnippet below is intentionally minimal because of this; see the fuller example in ## Usage."
|
|
171
|
+
canonicalSnippet: |
|
|
172
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@adres/mgda-ui"
|
|
173
|
+
|
|
174
|
+
<DropdownMenu>
|
|
175
|
+
<DropdownMenuTrigger>Account</DropdownMenuTrigger>
|
|
176
|
+
<DropdownMenuContent>
|
|
177
|
+
<DropdownMenuItem onSelect={() => {}}>Profile</DropdownMenuItem>
|
|
178
|
+
<DropdownMenuItem variant="destructive" onSelect={() => {}}>Sign out</DropdownMenuItem>
|
|
179
|
+
</DropdownMenuContent>
|
|
180
|
+
</DropdownMenu>
|
|
181
|
+
reviewedAt: 2026-08-31
|
|
182
|
+
reviewedAgainstContractHash: a3688fbae91f
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Usage
|
|
186
|
+
|
|
187
|
+
`DropdownMenu` is for a list of actions or options triggered from a button -
|
|
188
|
+
reach for it when the trigger represents a set of commands, not a form value
|
|
189
|
+
being chosen (`Select`) or richer content like a form (`Popover`).
|
|
190
|
+
|
|
191
|
+
Wrap the real trigger element with `asChild` so Radix attaches its behavior
|
|
192
|
+
directly to it instead of adding an extra wrapping button - this is the real,
|
|
193
|
+
recommended usage, shown here since `asChild`/`align` cannot appear in this
|
|
194
|
+
file's machine-checked `canonicalSnippet` (see the pitfall on why):
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import {
|
|
198
|
+
Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem,
|
|
199
|
+
DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,
|
|
200
|
+
} from "@adres/mgda-ui"
|
|
201
|
+
|
|
202
|
+
<DropdownMenu>
|
|
203
|
+
<DropdownMenuTrigger asChild>
|
|
204
|
+
<Button variant="outline">Account</Button>
|
|
205
|
+
</DropdownMenuTrigger>
|
|
206
|
+
<DropdownMenuContent align="start">
|
|
207
|
+
<DropdownMenuLabel>My account</DropdownMenuLabel>
|
|
208
|
+
<DropdownMenuSeparator />
|
|
209
|
+
<DropdownMenuItem>Profile</DropdownMenuItem>
|
|
210
|
+
<DropdownMenuItem>Billing</DropdownMenuItem>
|
|
211
|
+
<DropdownMenuItem variant="destructive">Sign out</DropdownMenuItem>
|
|
212
|
+
</DropdownMenuContent>
|
|
213
|
+
</DropdownMenu>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Set `variant="destructive"` on a `DropdownMenuItem` for a destructive action
|
|
217
|
+
row - it tints text, icon, and hover background together. Use
|
|
218
|
+
`DropdownMenuSub` + `DropdownMenuSubTrigger` + `DropdownMenuSubContent` for a
|
|
219
|
+
nested submenu, and `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` (with
|
|
220
|
+
`DropdownMenuRadioGroup`) when a row needs to reflect a selection state you
|
|
221
|
+
own yourself.
|
|
222
|
+
|
|
223
|
+
## Anatomy
|
|
224
|
+
|
|
225
|
+
| Part | Role |
|
|
226
|
+
| --- | --- |
|
|
227
|
+
| `DropdownMenu` | Root. Holds open state. A direct Radix `Root` re-export. |
|
|
228
|
+
| `DropdownMenuTrigger` | Opens the menu. Use `asChild` to wrap a real `Button`. |
|
|
229
|
+
| `DropdownMenuContent` | The floating panel. Portals itself and handles positioning and animation. |
|
|
230
|
+
| `DropdownMenuItem` | A single action row. `variant="destructive"` tints it; `inset` aligns it with indicator-column siblings. |
|
|
231
|
+
| `DropdownMenuCheckboxItem` | A row with a checkbox indicator; you own the `checked` state. |
|
|
232
|
+
| `DropdownMenuRadioGroup` / `DropdownMenuRadioItem` | A mutually-exclusive group of rows; you own the `value` state on the group. |
|
|
233
|
+
| `DropdownMenuLabel` | A non-interactive section heading. |
|
|
234
|
+
| `DropdownMenuSeparator` | A visual divider between groups of rows. |
|
|
235
|
+
| `DropdownMenuGroup` | Groups related items semantically without adding a visible separator. |
|
|
236
|
+
| `DropdownMenuShortcut` | A right-aligned, purely visual keyboard-shortcut hint. |
|
|
237
|
+
| `DropdownMenuSub` / `DropdownMenuSubTrigger` / `DropdownMenuSubContent` | A nested submenu: root, the row that opens it, and its floating panel. |
|
|
238
|
+
| `DropdownMenuPortal` | Escape hatch. Already rendered by `DropdownMenuContent`/`DropdownMenuSubContent`. |
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: dropzone
|
|
6
|
+
sourceFile: packages/design-system/src/components/dropzone.tsx
|
|
7
|
+
client: true
|
|
8
|
+
category: web-app-patterns
|
|
9
|
+
categoryFromBarrel: web-app-patterns
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: Dropzone
|
|
14
|
+
kind: component
|
|
15
|
+
typeText: "ForwardRefExoticComponent<DropzoneProps & RefAttributes<HTMLDivElement>>"
|
|
16
|
+
- name: DropzoneError
|
|
17
|
+
kind: type
|
|
18
|
+
- name: DropzoneErrorReason
|
|
19
|
+
kind: type
|
|
20
|
+
- name: DropzoneProps
|
|
21
|
+
kind: type
|
|
22
|
+
primaryExport: Dropzone
|
|
23
|
+
subcomponents: []
|
|
24
|
+
props:
|
|
25
|
+
Dropzone:
|
|
26
|
+
- name: accept
|
|
27
|
+
type: string
|
|
28
|
+
required: false
|
|
29
|
+
declaredIn: self
|
|
30
|
+
doc: "Accept attribute passed through to the underlying `<input>` (e.g. `\".csv\"`, `\"image/*\"`). Also enforced on drag-and-drop - browsers don't natively validate `accept` for drops."
|
|
31
|
+
- name: disabled
|
|
32
|
+
type: boolean
|
|
33
|
+
required: false
|
|
34
|
+
declaredIn: self
|
|
35
|
+
doc: "Disables the drop target and Browse button."
|
|
36
|
+
- name: file
|
|
37
|
+
type: File
|
|
38
|
+
required: false
|
|
39
|
+
declaredIn: self
|
|
40
|
+
doc: "Currently-selected file. When set, the dropzone collapses to a selected-file row with a \"Replace\" button."
|
|
41
|
+
- name: maxSize
|
|
42
|
+
type: number
|
|
43
|
+
required: false
|
|
44
|
+
declaredIn: self
|
|
45
|
+
doc: "Maximum file size in bytes. Files exceeding this trigger `onError` rather than `onFile`."
|
|
46
|
+
- name: onError
|
|
47
|
+
type: "((error: DropzoneError) => void)"
|
|
48
|
+
required: false
|
|
49
|
+
declaredIn: self
|
|
50
|
+
doc: "Called when a dropped or picked file fails validation (wrong type, exceeds `maxSize`). The file is NOT forwarded to `onFile`."
|
|
51
|
+
- name: onFile
|
|
52
|
+
type: "(file: File) => void"
|
|
53
|
+
required: true
|
|
54
|
+
declaredIn: self
|
|
55
|
+
doc: "Called when a file is dropped or selected via the file picker AND passes type / size validation."
|
|
56
|
+
- name: processing
|
|
57
|
+
type: boolean
|
|
58
|
+
required: false
|
|
59
|
+
declaredIn: self
|
|
60
|
+
doc: "While true, the dropzone shows a spinner + \"Processing...\" instead of the upload affordances. Drive this from the parent's upload state."
|
|
61
|
+
- name: prompt
|
|
62
|
+
type: string
|
|
63
|
+
required: false
|
|
64
|
+
declaredIn: self
|
|
65
|
+
doc: "Localizable prompt text. Defaults to a CSV-flavored prompt."
|
|
66
|
+
- name: templateHref
|
|
67
|
+
type: string
|
|
68
|
+
required: false
|
|
69
|
+
declaredIn: self
|
|
70
|
+
doc: "Optional helper link rendered under the Browse button."
|
|
71
|
+
- name: templateLabel
|
|
72
|
+
type: string
|
|
73
|
+
required: false
|
|
74
|
+
declaredIn: self
|
|
75
|
+
extendsProps:
|
|
76
|
+
- "Omit<React.HTMLAttributes<HTMLDivElement>, \"onError\">"
|
|
77
|
+
variants: {}
|
|
78
|
+
variantSource: none
|
|
79
|
+
compoundVariants: []
|
|
80
|
+
sizeMaps: []
|
|
81
|
+
dataSlots: []
|
|
82
|
+
dependsOn:
|
|
83
|
+
internal:
|
|
84
|
+
- button
|
|
85
|
+
- spinner
|
|
86
|
+
lib:
|
|
87
|
+
- cn
|
|
88
|
+
hooks: []
|
|
89
|
+
external:
|
|
90
|
+
- lucide-react
|
|
91
|
+
- react
|
|
92
|
+
contexts: []
|
|
93
|
+
stories:
|
|
94
|
+
- exportName: Default
|
|
95
|
+
id: components-dropzone--default
|
|
96
|
+
storybookTitle: Components/Dropzone
|
|
97
|
+
docsId: components-dropzone--documentation
|
|
98
|
+
argTypeOptions: {}
|
|
99
|
+
resolvedCleanly: true
|
|
100
|
+
contractHash: e7ee09c72838
|
|
101
|
+
factsHash: b68586b1b136
|
|
102
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
103
|
+
status: stable
|
|
104
|
+
summary: "A fully-controlled file dropzone with drag-and-drop, a browse button, type/size validation, and three states: empty, selected, and processing."
|
|
105
|
+
useWhen:
|
|
106
|
+
- "a single-file upload with drag-and-drop plus a fallback browse button - a CSV import, a document upload"
|
|
107
|
+
useInstead:
|
|
108
|
+
- id: input-button
|
|
109
|
+
when: "the upload is a plain browse-only flow with no drag target needed"
|
|
110
|
+
related:
|
|
111
|
+
- input-button
|
|
112
|
+
a11y:
|
|
113
|
+
notes:
|
|
114
|
+
- "The drop target itself is not natively focusable or keyboard-operable - the Browse button is the keyboard path to select a file; drag-and-drop is a pointer-only affordance layered on top of it, not a replacement for it."
|
|
115
|
+
- "Validation errors (onError) are not announced automatically - there is no built-in live region or visible error message; render one from the DropzoneError passed to onError."
|
|
116
|
+
radixHandles: false
|
|
117
|
+
pitfalls:
|
|
118
|
+
- "Dropzone is fully controlled - file and processing are props you own, not internal state. Passing onFile without also updating file yourself means the component never visually reflects a successful selection."
|
|
119
|
+
- "onFile only fires after validation passes - a rejected file (wrong type, over maxSize) goes to onError instead and never reaches onFile; there is no need to re-validate in your own handler."
|
|
120
|
+
- "accept is enforced twice for a reason: browsers apply it natively to the file picker, but do not apply it to drag-and-drop - the component re-validates accept in JavaScript specifically to cover the drop path. A permissive accept on the input alone is not enough."
|
|
121
|
+
- "processing takes over the entire render regardless of file - once processing is true, the file row and its Replace button disappear, so there is no way to swap the file mid-upload without first clearing processing."
|
|
122
|
+
canonicalSnippet: |
|
|
123
|
+
import { Dropzone } from "@adres/mgda-ui"
|
|
124
|
+
|
|
125
|
+
<Dropzone
|
|
126
|
+
accept=".csv"
|
|
127
|
+
maxSize={5 * 1024 * 1024}
|
|
128
|
+
file={file}
|
|
129
|
+
onFile={setFile}
|
|
130
|
+
onError={(err) => console.error(err.message)}
|
|
131
|
+
/>
|
|
132
|
+
reviewedAt: 2026-09-01
|
|
133
|
+
reviewedAgainstContractHash: e7ee09c72838
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Usage
|
|
137
|
+
|
|
138
|
+
`Dropzone` is a fully-controlled, single-file upload target - drag-and-drop
|
|
139
|
+
onto the whole surface, or a `Browse File` button as the keyboard-accessible
|
|
140
|
+
fallback. Reach for `InputButton` instead when the flow is browse-only with
|
|
141
|
+
no need for a drag target.
|
|
142
|
+
|
|
143
|
+
The component has three states driven entirely by props: empty (the drag or
|
|
144
|
+
browse prompt), selected (`file` is set - a compact row with a `Replace`
|
|
145
|
+
button), and `processing` (a spinner, which takes over regardless of
|
|
146
|
+
`file`). You own `file` and `processing` in the parent and update them from
|
|
147
|
+
`onFile`/`onError`.
|
|
148
|
+
|
|
149
|
+
`accept` and `maxSize` gate what reaches `onFile` - a file that fails either
|
|
150
|
+
check goes to `onError` instead, with a `reason` (`"invalid-type"` or
|
|
151
|
+
`"too-large"`) and a ready-to-display `message`. `accept` is re-validated in
|
|
152
|
+
JavaScript specifically because browsers do not enforce the native `accept`
|
|
153
|
+
attribute on drag-and-drop, only on the file picker.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: email-chips-input
|
|
6
|
+
sourceFile: packages/design-system/src/components/email-chips-input.tsx
|
|
7
|
+
client: true
|
|
8
|
+
category: web-app-patterns
|
|
9
|
+
categoryFromBarrel: web-app-patterns
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: EmailChip
|
|
14
|
+
kind: type
|
|
15
|
+
- name: EmailChipsInput
|
|
16
|
+
kind: component
|
|
17
|
+
typeText: "ForwardRefExoticComponent<EmailChipsInputProps & RefAttributes<HTMLDivElement>>"
|
|
18
|
+
- name: EmailChipsInputProps
|
|
19
|
+
kind: type
|
|
20
|
+
- name: EmailChipsInputVariant
|
|
21
|
+
kind: type
|
|
22
|
+
primaryExport: EmailChipsInput
|
|
23
|
+
subcomponents: []
|
|
24
|
+
props:
|
|
25
|
+
EmailChipsInput:
|
|
26
|
+
- name: chips
|
|
27
|
+
type: "EmailChip[]"
|
|
28
|
+
required: true
|
|
29
|
+
declaredIn: self
|
|
30
|
+
- name: disabled
|
|
31
|
+
type: boolean
|
|
32
|
+
required: false
|
|
33
|
+
declaredIn: self
|
|
34
|
+
doc: "Disables the input and chip-removal buttons."
|
|
35
|
+
- name: id
|
|
36
|
+
type: string
|
|
37
|
+
required: false
|
|
38
|
+
declaredIn: self
|
|
39
|
+
doc: "id for the inner <input>, so a sibling <Label htmlFor> binds correctly."
|
|
40
|
+
- name: invalid
|
|
41
|
+
type: boolean
|
|
42
|
+
required: false
|
|
43
|
+
declaredIn: self
|
|
44
|
+
doc: "Tints the wrapper border destructive and sets `aria-invalid` on the inner input. Consumer-controlled - independent of per-chip validity."
|
|
45
|
+
- name: onChange
|
|
46
|
+
type: "(chips: EmailChip[]) => void"
|
|
47
|
+
required: true
|
|
48
|
+
declaredIn: self
|
|
49
|
+
- name: onDuplicate
|
|
50
|
+
type: "(() => void)"
|
|
51
|
+
required: false
|
|
52
|
+
declaredIn: self
|
|
53
|
+
doc: "Fired when the user tries to add an address that's already in the list. Useful for surfacing a non-blocking warning toast."
|
|
54
|
+
- name: placeholder
|
|
55
|
+
type: string
|
|
56
|
+
required: false
|
|
57
|
+
declaredIn: self
|
|
58
|
+
- name: variant
|
|
59
|
+
type: EmailChipsInputVariant
|
|
60
|
+
required: false
|
|
61
|
+
declaredIn: self
|
|
62
|
+
doc: "Tone applied to valid chips. `default` is neutral, `primary` tints brand, `destructive` tints destructive. Invalid chips always render in destructive regardless of variant - the error signal stays distinct."
|
|
63
|
+
extendsProps:
|
|
64
|
+
- "Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\">"
|
|
65
|
+
variants:
|
|
66
|
+
variant:
|
|
67
|
+
kind: enum
|
|
68
|
+
options:
|
|
69
|
+
- default
|
|
70
|
+
- primary
|
|
71
|
+
- destructive
|
|
72
|
+
default: default
|
|
73
|
+
on: EmailChipsInput
|
|
74
|
+
variantSource: prop-union
|
|
75
|
+
compoundVariants: []
|
|
76
|
+
sizeMaps:
|
|
77
|
+
- VARIANT_VALID_CLASS
|
|
78
|
+
dataSlots: []
|
|
79
|
+
dependsOn:
|
|
80
|
+
internal:
|
|
81
|
+
- tooltip
|
|
82
|
+
lib:
|
|
83
|
+
- cn
|
|
84
|
+
hooks: []
|
|
85
|
+
external:
|
|
86
|
+
- lucide-react
|
|
87
|
+
- react
|
|
88
|
+
contexts: []
|
|
89
|
+
stories:
|
|
90
|
+
- exportName: Default
|
|
91
|
+
id: components-emailchipsinput--default
|
|
92
|
+
- exportName: WithValues
|
|
93
|
+
id: components-emailchipsinput--with-values
|
|
94
|
+
- exportName: WithInvalid
|
|
95
|
+
id: components-emailchipsinput--with-invalid
|
|
96
|
+
- exportName: Primary
|
|
97
|
+
id: components-emailchipsinput--primary
|
|
98
|
+
- exportName: Destructive
|
|
99
|
+
id: components-emailchipsinput--destructive
|
|
100
|
+
- exportName: Invalid
|
|
101
|
+
id: components-emailchipsinput--invalid
|
|
102
|
+
- exportName: Disabled
|
|
103
|
+
id: components-emailchipsinput--disabled
|
|
104
|
+
storybookTitle: Components/EmailChipsInput
|
|
105
|
+
docsId: components-emailchipsinput--documentation
|
|
106
|
+
argTypeOptions: {}
|
|
107
|
+
resolvedCleanly: true
|
|
108
|
+
contractHash: "6de3b913a41b"
|
|
109
|
+
factsHash: "20ca26e967ec"
|
|
110
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
111
|
+
status: stable
|
|
112
|
+
summary: "A multi-email input that turns each accepted address into a removable chip, with paste-splitting and non-blocking per-chip validation."
|
|
113
|
+
useWhen:
|
|
114
|
+
- "collecting multiple email addresses in one field - invite lists, notification recipients, CC/BCC-style entry"
|
|
115
|
+
useInstead:
|
|
116
|
+
- id: input
|
|
117
|
+
when: "collecting a single email address, not a list"
|
|
118
|
+
related:
|
|
119
|
+
- input
|
|
120
|
+
a11y:
|
|
121
|
+
notes:
|
|
122
|
+
- "Each chip's remove button carries its own aria-label (\"Remove {email}\"), since the X icon alone has no accessible name."
|
|
123
|
+
- "Invalid chips get a Tooltip explaining why, wrapped in TooltipProvider automatically - no separate provider setup is needed at the call site."
|
|
124
|
+
- "invalid sets aria-invalid on the inner input and tints the wrapper - it is a consumer-controlled prop for form-level validation, independent of each chip's own valid flag. Pass it based on whatever the form's overall validity rule is, e.g. \"at least one chip\", not derived automatically from the chips array."
|
|
125
|
+
keyboard:
|
|
126
|
+
- "Enter or , commits the current text as a chip. Backspace on an empty input removes the last chip - a fast way to correct a mis-typed entry without reaching for the mouse."
|
|
127
|
+
radixHandles: false
|
|
128
|
+
pitfalls:
|
|
129
|
+
- "Validation is local (regex) and non-blocking - an invalid-looking address still becomes a chip, just tinted destructive with valid: false. Nothing stops form submission on its own; filter chip.valid before using the list."
|
|
130
|
+
- "Pasting a list only splits on the paste path when the pasted text looks list-shaped (contains a separator) - a single pasted address goes through the normal typed-entry flow instead, so it is not committed as a chip until Enter or blur."
|
|
131
|
+
- "Blur commits whatever is currently typed as a chip, if non-empty - clicking away from a half-typed address does not discard it, it adds it. This can surprise a user who meant to cancel by clicking elsewhere."
|
|
132
|
+
- "onDuplicate fires but the duplicate address is silently dropped either way, in both the single-add and paste-many paths - there is no prop to allow duplicates."
|
|
133
|
+
canonicalSnippet: |
|
|
134
|
+
import { EmailChipsInput } from "@adres/mgda-ui"
|
|
135
|
+
|
|
136
|
+
<EmailChipsInput chips={chips} onChange={setChips} variant="primary" />
|
|
137
|
+
reviewedAt: 2026-09-01
|
|
138
|
+
reviewedAgainstContractHash: "6de3b913a41b"
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Usage
|
|
142
|
+
|
|
143
|
+
`EmailChipsInput` collects multiple email addresses in one field, turning
|
|
144
|
+
each accepted entry into a removable chip - invite lists, notification
|
|
145
|
+
recipients, CC/BCC-style entry. Reach for `Input` instead when the field is
|
|
146
|
+
a single email address, not a list.
|
|
147
|
+
|
|
148
|
+
Add a chip with `Enter` or `,`, or by pasting a separator-delimited list
|
|
149
|
+
(commas, semicolons, newlines, tabs, or mixed) - the component splits and
|
|
150
|
+
de-dupes a paste automatically. `Backspace` on an empty input removes the
|
|
151
|
+
last chip.
|
|
152
|
+
|
|
153
|
+
Validation is local and non-blocking: every entry becomes a chip regardless
|
|
154
|
+
of whether it looks like a valid address, with invalid ones tinted
|
|
155
|
+
destructive and given an explanatory tooltip. Filter `chip.valid` before
|
|
156
|
+
treating the list as ready to submit - the component never blocks adding an
|
|
157
|
+
invalid-looking address.
|
|
158
|
+
|
|
159
|
+
`variant` only tints valid chips; invalid ones always render destructive
|
|
160
|
+
regardless of `variant`, so the error signal stays visually distinct no
|
|
161
|
+
matter the brand tone in use.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: empty-state
|
|
6
|
+
sourceFile: packages/design-system/src/components/empty-state.tsx
|
|
7
|
+
client: false
|
|
8
|
+
category: web-app-core-primitives
|
|
9
|
+
categoryFromBarrel: web-app-core-primitives
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: EmptyState
|
|
14
|
+
kind: component
|
|
15
|
+
typeText: "({ className, icon, title, description, action, ...props }: EmptyStateProps) => Element"
|
|
16
|
+
- name: EmptyStateProps
|
|
17
|
+
kind: type
|
|
18
|
+
primaryExport: EmptyState
|
|
19
|
+
subcomponents: []
|
|
20
|
+
props:
|
|
21
|
+
EmptyState:
|
|
22
|
+
- name: action
|
|
23
|
+
type: ReactNode
|
|
24
|
+
required: false
|
|
25
|
+
declaredIn: self
|
|
26
|
+
- name: description
|
|
27
|
+
type: string
|
|
28
|
+
required: false
|
|
29
|
+
declaredIn: self
|
|
30
|
+
- name: icon
|
|
31
|
+
type: ReactNode
|
|
32
|
+
required: false
|
|
33
|
+
declaredIn: self
|
|
34
|
+
- name: title
|
|
35
|
+
type: string
|
|
36
|
+
required: true
|
|
37
|
+
declaredIn: self
|
|
38
|
+
extendsProps:
|
|
39
|
+
- "React.HTMLAttributes<HTMLDivElement>"
|
|
40
|
+
variants: {}
|
|
41
|
+
variantSource: none
|
|
42
|
+
compoundVariants: []
|
|
43
|
+
sizeMaps: []
|
|
44
|
+
dataSlots: []
|
|
45
|
+
dependsOn:
|
|
46
|
+
internal: []
|
|
47
|
+
lib:
|
|
48
|
+
- cn
|
|
49
|
+
hooks: []
|
|
50
|
+
external:
|
|
51
|
+
- react
|
|
52
|
+
contexts: []
|
|
53
|
+
stories:
|
|
54
|
+
- exportName: Default
|
|
55
|
+
id: components-emptystate--default
|
|
56
|
+
storybookTitle: Components/EmptyState
|
|
57
|
+
docsId: components-emptystate--documentation
|
|
58
|
+
argTypeOptions: {}
|
|
59
|
+
resolvedCleanly: true
|
|
60
|
+
contractHash: "855787802b2a"
|
|
61
|
+
factsHash: "15a5f0623e3d"
|
|
62
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
63
|
+
status: stable
|
|
64
|
+
summary: "A centered placeholder for a surface with no content yet, pairing an optional icon with a title, description, and action."
|
|
65
|
+
useWhen:
|
|
66
|
+
- "a list, table, or panel genuinely has zero items to show, not still loading"
|
|
67
|
+
- "guiding the user toward the action that would fill the empty surface, e.g. \"Create your first project\""
|
|
68
|
+
useInstead:
|
|
69
|
+
- id: skeleton
|
|
70
|
+
when: "content is still loading, not confirmed empty"
|
|
71
|
+
- id: alert
|
|
72
|
+
when: "reporting a message or error tied to the page, not describing an empty content area"
|
|
73
|
+
related:
|
|
74
|
+
- skeleton
|
|
75
|
+
- alert
|
|
76
|
+
a11y:
|
|
77
|
+
notes:
|
|
78
|
+
- "title renders as an h3 - check that the surrounding page's heading hierarchy still makes sense with an h3 appearing where the empty content would have been."
|
|
79
|
+
- "The icon wrapper has no aria-hidden set automatically - a purely decorative icon (the common case) needs aria-hidden=\"true\" set on the icon element you pass in yourself."
|
|
80
|
+
radixHandles: false
|
|
81
|
+
pitfalls:
|
|
82
|
+
- "title is the only required prop, but description and action are what make an empty state actually useful - a bare title alone often reads as a dead end rather than guidance."
|
|
83
|
+
- "There is no built-in aria-hidden on the icon wrapper - EmptyState does not add it, so a decorative icon needs it set explicitly by the caller."
|
|
84
|
+
canonicalSnippet: |
|
|
85
|
+
import { Button, EmptyState } from "@adres/mgda-ui"
|
|
86
|
+
|
|
87
|
+
<EmptyState
|
|
88
|
+
title="No projects yet"
|
|
89
|
+
description="Create your first project to get started."
|
|
90
|
+
action={<Button size="sm">New project</Button>}
|
|
91
|
+
/>
|
|
92
|
+
reviewedAt: 2026-08-31
|
|
93
|
+
reviewedAgainstContractHash: "855787802b2a"
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Usage
|
|
97
|
+
|
|
98
|
+
`EmptyState` fills the center of a surface that genuinely has nothing to show
|
|
99
|
+
- an empty list, table, or search result - never a surface that is still
|
|
100
|
+
loading (use `Skeleton` for that) or a message about the page itself (use
|
|
101
|
+
`Alert`).
|
|
102
|
+
|
|
103
|
+
Pair `title` with a `description` that explains why it is empty or what to do
|
|
104
|
+
next, and an `action` (typically a `Button`) that does that next thing - a
|
|
105
|
+
bare title alone often reads as a dead end rather than guidance. `icon` is
|
|
106
|
+
optional decoration in a circular muted badge above the title.
|