@shipfox/react-ui 0.13.0 → 0.15.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.
Files changed (268) hide show
  1. package/.storybook/preview.tsx +7 -0
  2. package/.turbo/turbo-build.log +7 -7
  3. package/.turbo/turbo-check.log +2 -2
  4. package/.turbo/turbo-type.log +1 -1
  5. package/CHANGELOG.md +16 -0
  6. package/dist/components/avatar/avatar.js +1 -1
  7. package/dist/components/avatar/avatar.js.map +1 -1
  8. package/dist/components/button-group/button-group.d.ts +17 -0
  9. package/dist/components/button-group/button-group.d.ts.map +1 -0
  10. package/dist/components/button-group/button-group.js +74 -0
  11. package/dist/components/button-group/button-group.js.map +1 -0
  12. package/dist/components/button-group/button-group.stories.js +644 -0
  13. package/dist/components/button-group/button-group.stories.js.map +1 -0
  14. package/dist/components/button-group/index.d.ts +2 -0
  15. package/dist/components/button-group/index.d.ts.map +1 -0
  16. package/dist/components/button-group/index.js +3 -0
  17. package/dist/components/button-group/index.js.map +1 -0
  18. package/dist/components/code-block/code-block-footer.d.ts.map +1 -1
  19. package/dist/components/code-block/code-block-footer.js +13 -5
  20. package/dist/components/code-block/code-block-footer.js.map +1 -1
  21. package/dist/components/command/command.d.ts +28 -0
  22. package/dist/components/command/command.d.ts.map +1 -0
  23. package/dist/components/command/command.js +190 -0
  24. package/dist/components/command/command.js.map +1 -0
  25. package/dist/components/command/command.stories.js +228 -0
  26. package/dist/components/command/command.stories.js.map +1 -0
  27. package/dist/components/command/index.d.ts +2 -0
  28. package/dist/components/command/index.d.ts.map +1 -0
  29. package/dist/components/command/index.js +3 -0
  30. package/dist/components/command/index.js.map +1 -0
  31. package/dist/components/confetti/confetti.d.ts +21 -0
  32. package/dist/components/confetti/confetti.d.ts.map +1 -0
  33. package/dist/components/confetti/confetti.js +101 -0
  34. package/dist/components/confetti/confetti.js.map +1 -0
  35. package/dist/components/confetti/confetti.stories.js +41 -0
  36. package/dist/components/confetti/confetti.stories.js.map +1 -0
  37. package/dist/components/confetti/index.d.ts +2 -0
  38. package/dist/components/confetti/index.d.ts.map +1 -0
  39. package/dist/components/confetti/index.js +3 -0
  40. package/dist/components/confetti/index.js.map +1 -0
  41. package/dist/components/dashboard/components/analytics-content.d.ts +2 -0
  42. package/dist/components/dashboard/components/analytics-content.d.ts.map +1 -0
  43. package/dist/components/dashboard/components/analytics-content.js +180 -0
  44. package/dist/components/dashboard/components/analytics-content.js.map +1 -0
  45. package/dist/components/dashboard/components/animated-logo.d.ts +4 -0
  46. package/dist/components/dashboard/components/animated-logo.d.ts.map +1 -0
  47. package/dist/components/dashboard/components/animated-logo.js +23 -0
  48. package/dist/components/dashboard/components/animated-logo.js.map +1 -0
  49. package/dist/components/dashboard/components/complete-setup-button.d.ts +4 -0
  50. package/dist/components/dashboard/components/complete-setup-button.d.ts.map +1 -0
  51. package/dist/components/dashboard/components/complete-setup-button.js +28 -0
  52. package/dist/components/dashboard/components/complete-setup-button.js.map +1 -0
  53. package/dist/components/dashboard/components/jobs-content.d.ts +2 -0
  54. package/dist/components/dashboard/components/jobs-content.d.ts.map +1 -0
  55. package/dist/components/dashboard/components/jobs-content.js +69 -0
  56. package/dist/components/dashboard/components/jobs-content.js.map +1 -0
  57. package/dist/components/dashboard/components/mobile-menu.d.ts +2 -0
  58. package/dist/components/dashboard/components/mobile-menu.d.ts.map +1 -0
  59. package/dist/components/dashboard/components/mobile-menu.js +65 -0
  60. package/dist/components/dashboard/components/mobile-menu.js.map +1 -0
  61. package/dist/components/dashboard/components/organization-selector.d.ts +2 -0
  62. package/dist/components/dashboard/components/organization-selector.d.ts.map +1 -0
  63. package/dist/components/dashboard/components/organization-selector.js +92 -0
  64. package/dist/components/dashboard/components/organization-selector.js.map +1 -0
  65. package/dist/components/dashboard/components/top-menu.d.ts +5 -0
  66. package/dist/components/dashboard/components/top-menu.d.ts.map +1 -0
  67. package/dist/components/dashboard/components/top-menu.js +31 -0
  68. package/dist/components/dashboard/components/top-menu.js.map +1 -0
  69. package/dist/components/dashboard/components/topbar-button.d.ts +7 -0
  70. package/dist/components/dashboard/components/topbar-button.d.ts.map +1 -0
  71. package/dist/components/dashboard/components/topbar-button.js +18 -0
  72. package/dist/components/dashboard/components/topbar-button.js.map +1 -0
  73. package/dist/components/dashboard/components/topbar.d.ts +4 -0
  74. package/dist/components/dashboard/components/topbar.d.ts.map +1 -0
  75. package/dist/components/dashboard/components/topbar.js +62 -0
  76. package/dist/components/dashboard/components/topbar.js.map +1 -0
  77. package/dist/components/dashboard/components/user-profile.d.ts +2 -0
  78. package/dist/components/dashboard/components/user-profile.d.ts.map +1 -0
  79. package/dist/components/dashboard/components/user-profile.js +146 -0
  80. package/dist/components/dashboard/components/user-profile.js.map +1 -0
  81. package/dist/components/dashboard/dashboard.d.ts +2 -0
  82. package/dist/components/dashboard/dashboard.d.ts.map +1 -0
  83. package/dist/components/dashboard/dashboard.js +70 -0
  84. package/dist/components/dashboard/dashboard.js.map +1 -0
  85. package/dist/components/dashboard/dashboard.stories.js +23 -0
  86. package/dist/components/dashboard/dashboard.stories.js.map +1 -0
  87. package/dist/components/dashboard/index.d.ts +2 -0
  88. package/dist/components/dashboard/index.d.ts.map +1 -0
  89. package/dist/components/dashboard/index.js +3 -0
  90. package/dist/components/dashboard/index.js.map +1 -0
  91. package/dist/components/form/form.stories.js +6 -1
  92. package/dist/components/form/form.stories.js.map +1 -1
  93. package/dist/components/icon/icon.d.ts +3 -2
  94. package/dist/components/icon/icon.d.ts.map +1 -1
  95. package/dist/components/icon/icon.js +7 -2
  96. package/dist/components/icon/icon.js.map +1 -1
  97. package/dist/components/index.d.ts +9 -0
  98. package/dist/components/index.d.ts.map +1 -1
  99. package/dist/components/index.js +9 -0
  100. package/dist/components/index.js.map +1 -1
  101. package/dist/components/kbd/index.d.ts +2 -0
  102. package/dist/components/kbd/index.d.ts.map +1 -0
  103. package/dist/components/kbd/index.js +3 -0
  104. package/dist/components/kbd/index.js.map +1 -0
  105. package/dist/components/kbd/kbd.d.ts +7 -0
  106. package/dist/components/kbd/kbd.d.ts.map +1 -0
  107. package/dist/components/kbd/kbd.js +18 -0
  108. package/dist/components/kbd/kbd.js.map +1 -0
  109. package/dist/components/kbd/kbd.stories.js +119 -0
  110. package/dist/components/kbd/kbd.stories.js.map +1 -0
  111. package/dist/components/modal/modal.stories.js +227 -168
  112. package/dist/components/modal/modal.stories.js.map +1 -1
  113. package/dist/components/search/index.d.ts +7 -0
  114. package/dist/components/search/index.d.ts.map +1 -0
  115. package/dist/components/search/index.js +8 -0
  116. package/dist/components/search/index.js.map +1 -0
  117. package/dist/components/search/search-context.d.ts +11 -0
  118. package/dist/components/search/search-context.d.ts.map +1 -0
  119. package/dist/components/search/search-context.js +56 -0
  120. package/dist/components/search/search-context.js.map +1 -0
  121. package/dist/components/search/search-inline.d.ts +9 -0
  122. package/dist/components/search/search-inline.d.ts.map +1 -0
  123. package/dist/components/search/search-inline.js +85 -0
  124. package/dist/components/search/search-inline.js.map +1 -0
  125. package/dist/components/search/search-modal.d.ts +25 -0
  126. package/dist/components/search/search-modal.d.ts.map +1 -0
  127. package/dist/components/search/search-modal.js +162 -0
  128. package/dist/components/search/search-modal.js.map +1 -0
  129. package/dist/components/search/search-trigger.d.ts +9 -0
  130. package/dist/components/search/search-trigger.d.ts.map +1 -0
  131. package/dist/components/search/search-trigger.js +37 -0
  132. package/dist/components/search/search-trigger.js.map +1 -0
  133. package/dist/components/search/search-variants.d.ts +14 -0
  134. package/dist/components/search/search-variants.d.ts.map +1 -0
  135. package/dist/components/search/search-variants.js +90 -0
  136. package/dist/components/search/search-variants.js.map +1 -0
  137. package/dist/components/search/search.d.ts +11 -0
  138. package/dist/components/search/search.d.ts.map +1 -0
  139. package/dist/components/search/search.js +35 -0
  140. package/dist/components/search/search.js.map +1 -0
  141. package/dist/components/search/search.stories.js +630 -0
  142. package/dist/components/search/search.stories.js.map +1 -0
  143. package/dist/components/select/index.d.ts +2 -0
  144. package/dist/components/select/index.d.ts.map +1 -0
  145. package/dist/components/select/index.js +3 -0
  146. package/dist/components/select/index.js.map +1 -0
  147. package/dist/components/select/select.d.ts +25 -0
  148. package/dist/components/select/select.d.ts.map +1 -0
  149. package/dist/components/select/select.js +153 -0
  150. package/dist/components/select/select.js.map +1 -0
  151. package/dist/components/select/select.stories.js +393 -0
  152. package/dist/components/select/select.stories.js.map +1 -0
  153. package/dist/components/shiny-text/index.d.ts +2 -0
  154. package/dist/components/shiny-text/index.d.ts.map +1 -0
  155. package/dist/components/shiny-text/index.js +3 -0
  156. package/dist/components/shiny-text/index.js.map +1 -0
  157. package/dist/components/shiny-text/shiny-text.d.ts +10 -0
  158. package/dist/components/shiny-text/shiny-text.d.ts.map +1 -0
  159. package/dist/components/shiny-text/shiny-text.js +17 -0
  160. package/dist/components/shiny-text/shiny-text.js.map +1 -0
  161. package/dist/components/skeleton/index.d.ts +2 -0
  162. package/dist/components/skeleton/index.d.ts.map +1 -0
  163. package/dist/components/skeleton/index.js +3 -0
  164. package/dist/components/skeleton/index.js.map +1 -0
  165. package/dist/components/skeleton/skeleton.d.ts +5 -0
  166. package/dist/components/skeleton/skeleton.d.ts.map +1 -0
  167. package/dist/components/skeleton/skeleton.js +11 -0
  168. package/dist/components/skeleton/skeleton.js.map +1 -0
  169. package/dist/components/skeleton/skeleton.stories.js +345 -0
  170. package/dist/components/skeleton/skeleton.stories.js.map +1 -0
  171. package/dist/components/table/data-table.d.ts +70 -0
  172. package/dist/components/table/data-table.d.ts.map +1 -0
  173. package/dist/components/table/data-table.js +159 -0
  174. package/dist/components/table/data-table.js.map +1 -0
  175. package/dist/components/table/index.d.ts +6 -0
  176. package/dist/components/table/index.d.ts.map +1 -0
  177. package/dist/components/table/index.js +6 -0
  178. package/dist/components/table/index.js.map +1 -0
  179. package/dist/components/table/table-column-header.d.ts +79 -0
  180. package/dist/components/table/table-column-header.d.ts.map +1 -0
  181. package/dist/components/table/table-column-header.js +99 -0
  182. package/dist/components/table/table-column-header.js.map +1 -0
  183. package/dist/components/table/table-pagination.d.ts +53 -0
  184. package/dist/components/table/table-pagination.d.ts.map +1 -0
  185. package/dist/components/table/table-pagination.js +139 -0
  186. package/dist/components/table/table-pagination.js.map +1 -0
  187. package/dist/components/table/table.d.ts +11 -0
  188. package/dist/components/table/table.d.ts.map +1 -0
  189. package/dist/components/table/table.js +64 -0
  190. package/dist/components/table/table.js.map +1 -0
  191. package/dist/components/table/table.stories.columns.d.ts +24 -0
  192. package/dist/components/table/table.stories.columns.d.ts.map +1 -0
  193. package/dist/components/table/table.stories.columns.js +310 -0
  194. package/dist/components/table/table.stories.columns.js.map +1 -0
  195. package/dist/components/table/table.stories.components.d.ts +14 -0
  196. package/dist/components/table/table.stories.components.d.ts.map +1 -0
  197. package/dist/components/table/table.stories.components.js +107 -0
  198. package/dist/components/table/table.stories.components.js.map +1 -0
  199. package/dist/components/table/table.stories.data.d.ts +54 -0
  200. package/dist/components/table/table.stories.data.d.ts.map +1 -0
  201. package/dist/components/table/table.stories.data.js +122 -0
  202. package/dist/components/table/table.stories.data.js.map +1 -0
  203. package/dist/components/table/table.stories.js +302 -0
  204. package/dist/components/table/table.stories.js.map +1 -0
  205. package/dist/index.d.ts +1 -0
  206. package/dist/index.d.ts.map +1 -1
  207. package/dist/index.js +1 -0
  208. package/dist/index.js.map +1 -1
  209. package/dist/styles.css +1 -1
  210. package/index.css +79 -0
  211. package/package.json +6 -2
  212. package/src/components/avatar/avatar.tsx +1 -1
  213. package/src/components/button-group/button-group.stories.tsx +361 -0
  214. package/src/components/button-group/button-group.tsx +111 -0
  215. package/src/components/button-group/index.ts +1 -0
  216. package/src/components/code-block/code-block-footer.tsx +19 -2
  217. package/src/components/command/command.stories.tsx +133 -0
  218. package/src/components/command/command.tsx +265 -0
  219. package/src/components/command/index.ts +1 -0
  220. package/src/components/confetti/confetti.stories.tsx +38 -0
  221. package/src/components/confetti/confetti.tsx +140 -0
  222. package/src/components/confetti/index.ts +1 -0
  223. package/src/components/dashboard/components/analytics-content.tsx +102 -0
  224. package/src/components/dashboard/components/animated-logo.tsx +25 -0
  225. package/src/components/dashboard/components/complete-setup-button.tsx +30 -0
  226. package/src/components/dashboard/components/jobs-content.tsx +51 -0
  227. package/src/components/dashboard/components/mobile-menu.tsx +50 -0
  228. package/src/components/dashboard/components/organization-selector.tsx +51 -0
  229. package/src/components/dashboard/components/top-menu.tsx +26 -0
  230. package/src/components/dashboard/components/topbar-button.tsx +27 -0
  231. package/src/components/dashboard/components/topbar.tsx +40 -0
  232. package/src/components/dashboard/components/user-profile.tsx +90 -0
  233. package/src/components/dashboard/dashboard.stories.tsx +25 -0
  234. package/src/components/dashboard/dashboard.tsx +61 -0
  235. package/src/components/dashboard/index.ts +1 -0
  236. package/src/components/form/form.stories.tsx +5 -0
  237. package/src/components/icon/icon.tsx +7 -3
  238. package/src/components/index.ts +9 -0
  239. package/src/components/kbd/index.ts +1 -0
  240. package/src/components/kbd/kbd.stories.tsx +64 -0
  241. package/src/components/kbd/kbd.tsx +32 -0
  242. package/src/components/modal/modal.stories.tsx +58 -4
  243. package/src/components/search/index.ts +28 -0
  244. package/src/components/search/search-context.tsx +78 -0
  245. package/src/components/search/search-inline.tsx +107 -0
  246. package/src/components/search/search-modal.tsx +198 -0
  247. package/src/components/search/search-trigger.tsx +47 -0
  248. package/src/components/search/search-variants.ts +88 -0
  249. package/src/components/search/search.stories.tsx +392 -0
  250. package/src/components/search/search.tsx +47 -0
  251. package/src/components/select/index.ts +1 -0
  252. package/src/components/select/select.stories.tsx +207 -0
  253. package/src/components/select/select.tsx +220 -0
  254. package/src/components/shiny-text/index.ts +1 -0
  255. package/src/components/shiny-text/shiny-text.tsx +21 -0
  256. package/src/components/skeleton/index.ts +1 -0
  257. package/src/components/skeleton/skeleton.stories.tsx +178 -0
  258. package/src/components/skeleton/skeleton.tsx +14 -0
  259. package/src/components/table/data-table.tsx +254 -0
  260. package/src/components/table/index.ts +5 -0
  261. package/src/components/table/table-column-header.tsx +141 -0
  262. package/src/components/table/table-pagination.tsx +161 -0
  263. package/src/components/table/table.stories.columns.tsx +198 -0
  264. package/src/components/table/table.stories.components.tsx +104 -0
  265. package/src/components/table/table.stories.data.ts +117 -0
  266. package/src/components/table/table.stories.tsx +256 -0
  267. package/src/components/table/table.tsx +95 -0
  268. package/src/index.ts +1 -0
@@ -0,0 +1,392 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {useState} from 'react';
3
+ import {Icon} from '../icon';
4
+ import {
5
+ Search,
6
+ SearchContent,
7
+ SearchEmpty,
8
+ SearchFooter,
9
+ SearchGroup,
10
+ SearchInline,
11
+ SearchInput,
12
+ SearchItem,
13
+ SearchList,
14
+ SearchSeparator,
15
+ SearchTrigger,
16
+ } from './index';
17
+
18
+ const meta: Meta = {
19
+ title: 'Components/Search',
20
+ tags: ['autodocs'],
21
+ parameters: {
22
+ docs: {
23
+ description: {
24
+ component:
25
+ 'A search component with two types: inline (input-style) and modal (trigger + overlay). Supports primary/secondary variants, base/small sizes, and squared/rounded radius options.',
26
+ },
27
+ },
28
+ },
29
+ };
30
+
31
+ export default meta;
32
+
33
+ type Story = StoryObj;
34
+
35
+ export const Inline: Story = {
36
+ render: () => {
37
+ function InlineDemo() {
38
+ const [value, setValue] = useState('');
39
+
40
+ return (
41
+ <div className="flex flex-col gap-16 max-w-400">
42
+ <SearchInline
43
+ placeholder="Search..."
44
+ value={value}
45
+ onChange={(e) => setValue(e.target.value)}
46
+ onClear={() => setValue('')}
47
+ />
48
+ {value && (
49
+ <p className="text-sm text-foreground-neutral-muted">Searching for: "{value}"</p>
50
+ )}
51
+ </div>
52
+ );
53
+ }
54
+ return <InlineDemo />;
55
+ },
56
+ };
57
+
58
+ export const InlineVariants: Story = {
59
+ render: () => (
60
+ <div className="flex flex-col gap-16">
61
+ <div className="flex flex-col gap-8">
62
+ <span className="text-xs text-foreground-neutral-muted">Primary (default)</span>
63
+ <div className="flex gap-8">
64
+ <SearchInline
65
+ variant="primary"
66
+ radius="squared"
67
+ placeholder="Search..."
68
+ defaultValue="random"
69
+ className="w-200"
70
+ />
71
+ <SearchInline
72
+ variant="primary"
73
+ radius="rounded"
74
+ placeholder="Search..."
75
+ defaultValue="random"
76
+ className="w-200"
77
+ />
78
+ </div>
79
+ </div>
80
+ <div className="flex flex-col gap-8">
81
+ <span className="text-xs text-foreground-neutral-muted">Secondary</span>
82
+ <div className="flex gap-8">
83
+ <SearchInline
84
+ variant="secondary"
85
+ radius="squared"
86
+ placeholder="Search..."
87
+ defaultValue="random"
88
+ className="w-200"
89
+ />
90
+ <SearchInline
91
+ variant="secondary"
92
+ radius="rounded"
93
+ placeholder="Search..."
94
+ defaultValue="random"
95
+ className="w-200"
96
+ />
97
+ </div>
98
+ </div>
99
+ </div>
100
+ ),
101
+ };
102
+
103
+ export const InlineSizes: Story = {
104
+ render: () => (
105
+ <div className="flex flex-col gap-16">
106
+ <div className="flex flex-col gap-8">
107
+ <span className="text-xs text-foreground-neutral-muted">Base (32px)</span>
108
+ <div className="flex gap-8">
109
+ <SearchInline
110
+ size="base"
111
+ placeholder="Search..."
112
+ defaultValue="random"
113
+ className="w-200"
114
+ />
115
+ </div>
116
+ </div>
117
+ <div className="flex flex-col gap-8">
118
+ <span className="text-xs text-foreground-neutral-muted">Small (28px)</span>
119
+ <div className="flex gap-8">
120
+ <SearchInline
121
+ size="small"
122
+ placeholder="Search..."
123
+ defaultValue="random"
124
+ className="w-200"
125
+ />
126
+ </div>
127
+ </div>
128
+ </div>
129
+ ),
130
+ };
131
+
132
+ function ModalSearchDemo() {
133
+ const [open, setOpen] = useState(false);
134
+
135
+ return (
136
+ <Search open={open} onOpenChange={setOpen} shortcutKey="meta+k">
137
+ <SearchTrigger placeholder="Find..." className="w-full max-w-280" />
138
+ <SearchContent aria-describedby={undefined}>
139
+ <SearchInput placeholder="Search for anything..." />
140
+ <SearchList>
141
+ <SearchEmpty>No results found.</SearchEmpty>
142
+ <SearchGroup heading="Recent">
143
+ <SearchItem
144
+ icon={
145
+ <Icon name="gitBranchLine" className="size-16 text-foreground-neutral-subtle" />
146
+ }
147
+ description="qr-attendance"
148
+ >
149
+ feat/data-processing
150
+ </SearchItem>
151
+ <SearchItem
152
+ icon={
153
+ <Icon name="gitBranchLine" className="size-16 text-foreground-neutral-subtle" />
154
+ }
155
+ description="qr-attendance"
156
+ >
157
+ feat/pagination-polling
158
+ </SearchItem>
159
+ </SearchGroup>
160
+ <SearchSeparator />
161
+ <SearchGroup heading="Team">
162
+ <SearchItem
163
+ icon={<Icon name="rocketLine" className="size-16 text-foreground-neutral-subtle" />}
164
+ description="Team"
165
+ >
166
+ Deployments
167
+ </SearchItem>
168
+ <SearchItem
169
+ icon={<Icon name="linksLine" className="size-16 text-foreground-neutral-subtle" />}
170
+ description="Team"
171
+ >
172
+ Integrations
173
+ </SearchItem>
174
+ </SearchGroup>
175
+ </SearchList>
176
+ <SearchFooter />
177
+ </SearchContent>
178
+ </Search>
179
+ );
180
+ }
181
+
182
+ export const Modal: Story = {
183
+ render: () => <ModalSearchDemo />,
184
+ };
185
+
186
+ function TriggerPreview({
187
+ variant,
188
+ size,
189
+ radius,
190
+ className,
191
+ }: {
192
+ variant?: 'primary' | 'secondary';
193
+ size?: 'base' | 'small';
194
+ radius?: 'squared' | 'rounded';
195
+ className?: string;
196
+ }) {
197
+ return (
198
+ <Search>
199
+ <SearchTrigger variant={variant} size={size} radius={radius} className={className} />
200
+ </Search>
201
+ );
202
+ }
203
+
204
+ export const ModalTriggerVariants: Story = {
205
+ render: () => (
206
+ <div className="flex flex-col gap-16">
207
+ <div className="flex flex-col gap-8">
208
+ <span className="text-xs text-foreground-neutral-muted">Primary (default)</span>
209
+ <div className="flex gap-8">
210
+ <TriggerPreview variant="primary" radius="squared" className="w-200" />
211
+ <TriggerPreview variant="primary" radius="rounded" className="w-200" />
212
+ </div>
213
+ </div>
214
+ <div className="flex flex-col gap-8">
215
+ <span className="text-xs text-foreground-neutral-muted">Secondary</span>
216
+ <div className="flex gap-8">
217
+ <TriggerPreview variant="secondary" radius="squared" className="w-200" />
218
+ <TriggerPreview variant="secondary" radius="rounded" className="w-200" />
219
+ </div>
220
+ </div>
221
+ </div>
222
+ ),
223
+ };
224
+
225
+ export const ModalTriggerSizes: Story = {
226
+ render: () => (
227
+ <div className="flex flex-col gap-16">
228
+ <div className="flex flex-col gap-8">
229
+ <span className="text-xs text-foreground-neutral-muted">Base (32px)</span>
230
+ <div className="flex gap-8">
231
+ <TriggerPreview size="base" variant="primary" className="w-200" />
232
+ <TriggerPreview size="base" variant="secondary" className="w-200" />
233
+ </div>
234
+ </div>
235
+ <div className="flex flex-col gap-8">
236
+ <span className="text-xs text-foreground-neutral-muted">Small (28px)</span>
237
+ <div className="flex gap-8">
238
+ <TriggerPreview size="small" variant="primary" className="w-200" />
239
+ <TriggerPreview size="small" variant="secondary" className="w-200" />
240
+ </div>
241
+ </div>
242
+ </div>
243
+ ),
244
+ };
245
+
246
+ export const AllCombinations: Story = {
247
+ render: () => (
248
+ <div className="flex flex-col gap-24">
249
+ <div>
250
+ <h3 className="text-sm font-medium text-foreground-neutral-base mb-12">Inline Search</h3>
251
+ <div className="grid grid-cols-4 gap-12">
252
+ <div className="flex flex-col gap-4">
253
+ <span className="text-xs text-foreground-neutral-muted">Primary / Squared / Base</span>
254
+ <SearchInline
255
+ variant="primary"
256
+ radius="squared"
257
+ size="base"
258
+ placeholder="Search..."
259
+ className="w-full"
260
+ />
261
+ </div>
262
+ <div className="flex flex-col gap-4">
263
+ <span className="text-xs text-foreground-neutral-muted">Primary / Squared / Small</span>
264
+ <SearchInline
265
+ variant="primary"
266
+ radius="squared"
267
+ size="small"
268
+ placeholder="Search..."
269
+ className="w-full"
270
+ />
271
+ </div>
272
+ <div className="flex flex-col gap-4">
273
+ <span className="text-xs text-foreground-neutral-muted">Primary / Rounded / Base</span>
274
+ <SearchInline
275
+ variant="primary"
276
+ radius="rounded"
277
+ size="base"
278
+ placeholder="Search..."
279
+ className="w-full"
280
+ />
281
+ </div>
282
+ <div className="flex flex-col gap-4">
283
+ <span className="text-xs text-foreground-neutral-muted">Primary / Rounded / Small</span>
284
+ <SearchInline
285
+ variant="primary"
286
+ radius="rounded"
287
+ size="small"
288
+ placeholder="Search..."
289
+ className="w-full"
290
+ />
291
+ </div>
292
+ <div className="flex flex-col gap-4">
293
+ <span className="text-xs text-foreground-neutral-muted">
294
+ Secondary / Squared / Base
295
+ </span>
296
+ <SearchInline
297
+ variant="secondary"
298
+ radius="squared"
299
+ size="base"
300
+ placeholder="Search..."
301
+ className="w-full"
302
+ />
303
+ </div>
304
+ <div className="flex flex-col gap-4">
305
+ <span className="text-xs text-foreground-neutral-muted">
306
+ Secondary / Squared / Small
307
+ </span>
308
+ <SearchInline
309
+ variant="secondary"
310
+ radius="squared"
311
+ size="small"
312
+ placeholder="Search..."
313
+ className="w-full"
314
+ />
315
+ </div>
316
+ <div className="flex flex-col gap-4">
317
+ <span className="text-xs text-foreground-neutral-muted">
318
+ Secondary / Rounded / Base
319
+ </span>
320
+ <SearchInline
321
+ variant="secondary"
322
+ radius="rounded"
323
+ size="base"
324
+ placeholder="Search..."
325
+ className="w-full"
326
+ />
327
+ </div>
328
+ <div className="flex flex-col gap-4">
329
+ <span className="text-xs text-foreground-neutral-muted">
330
+ Secondary / Rounded / Small
331
+ </span>
332
+ <SearchInline
333
+ variant="secondary"
334
+ radius="rounded"
335
+ size="small"
336
+ placeholder="Search..."
337
+ className="w-full"
338
+ />
339
+ </div>
340
+ </div>
341
+ </div>
342
+
343
+ <div>
344
+ <h3 className="text-sm font-medium text-foreground-neutral-base mb-12">
345
+ Modal Search Triggers
346
+ </h3>
347
+ <div className="grid grid-cols-4 gap-12">
348
+ <div className="flex flex-col gap-4">
349
+ <span className="text-xs text-foreground-neutral-muted">Primary / Squared / Base</span>
350
+ <TriggerPreview variant="primary" radius="squared" size="base" className="w-full" />
351
+ </div>
352
+ <div className="flex flex-col gap-4">
353
+ <span className="text-xs text-foreground-neutral-muted">Primary / Squared / Small</span>
354
+ <TriggerPreview variant="primary" radius="squared" size="small" className="w-full" />
355
+ </div>
356
+ <div className="flex flex-col gap-4">
357
+ <span className="text-xs text-foreground-neutral-muted">Primary / Rounded / Base</span>
358
+ <TriggerPreview variant="primary" radius="rounded" size="base" className="w-full" />
359
+ </div>
360
+ <div className="flex flex-col gap-4">
361
+ <span className="text-xs text-foreground-neutral-muted">Primary / Rounded / Small</span>
362
+ <TriggerPreview variant="primary" radius="rounded" size="small" className="w-full" />
363
+ </div>
364
+ <div className="flex flex-col gap-4">
365
+ <span className="text-xs text-foreground-neutral-muted">
366
+ Secondary / Squared / Base
367
+ </span>
368
+ <TriggerPreview variant="secondary" radius="squared" size="base" className="w-full" />
369
+ </div>
370
+ <div className="flex flex-col gap-4">
371
+ <span className="text-xs text-foreground-neutral-muted">
372
+ Secondary / Squared / Small
373
+ </span>
374
+ <TriggerPreview variant="secondary" radius="squared" size="small" className="w-full" />
375
+ </div>
376
+ <div className="flex flex-col gap-4">
377
+ <span className="text-xs text-foreground-neutral-muted">
378
+ Secondary / Rounded / Base
379
+ </span>
380
+ <TriggerPreview variant="secondary" radius="rounded" size="base" className="w-full" />
381
+ </div>
382
+ <div className="flex flex-col gap-4">
383
+ <span className="text-xs text-foreground-neutral-muted">
384
+ Secondary / Rounded / Small
385
+ </span>
386
+ <TriggerPreview variant="secondary" radius="rounded" size="small" className="w-full" />
387
+ </div>
388
+ </div>
389
+ </div>
390
+ </div>
391
+ ),
392
+ };
@@ -0,0 +1,47 @@
1
+ import {Command as CommandPrimitive} from 'cmdk';
2
+ import type {ReactNode} from 'react';
3
+ import {useCallback, useState} from 'react';
4
+ import {SearchContext, useControllableState, useKeyboardShortcut} from './search-context';
5
+
6
+ export type SearchProps = {
7
+ children: ReactNode;
8
+ open?: boolean;
9
+ onOpenChange?: (open: boolean) => void;
10
+ defaultOpen?: boolean;
11
+ shortcutKey?: string;
12
+ shouldFilter?: boolean;
13
+ };
14
+
15
+ export function Search({
16
+ children,
17
+ open: controlledOpen,
18
+ onOpenChange,
19
+ defaultOpen = false,
20
+ shortcutKey,
21
+ shouldFilter = true,
22
+ }: SearchProps) {
23
+ const [open, setOpen] = useControllableState(controlledOpen, defaultOpen, onOpenChange);
24
+ const [searchValue, setSearchValue] = useState('');
25
+
26
+ const handleOpen = useCallback(() => setOpen(true), [setOpen]);
27
+
28
+ useKeyboardShortcut(shortcutKey, handleOpen);
29
+
30
+ const handleSetOpen = useCallback(
31
+ (newOpen: boolean) => {
32
+ if (!newOpen) {
33
+ setSearchValue('');
34
+ }
35
+ setOpen(newOpen);
36
+ },
37
+ [setOpen],
38
+ );
39
+
40
+ return (
41
+ <SearchContext.Provider value={{open, setOpen: handleSetOpen, searchValue, setSearchValue}}>
42
+ <CommandPrimitive data-slot="search" shouldFilter={shouldFilter}>
43
+ {children}
44
+ </CommandPrimitive>
45
+ </SearchContext.Provider>
46
+ );
47
+ }
@@ -0,0 +1 @@
1
+ export * from './select';
@@ -0,0 +1,207 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {Kbd} from '../kbd';
3
+ import {
4
+ Select,
5
+ SelectContent,
6
+ SelectGroup,
7
+ SelectItem,
8
+ SelectLabel,
9
+ SelectSeparator,
10
+ SelectTrigger,
11
+ SelectValue,
12
+ } from './select';
13
+
14
+ const meta = {
15
+ title: 'Components/Select',
16
+ component: Select,
17
+ tags: ['autodocs'],
18
+ } satisfies Meta<typeof Select>;
19
+
20
+ export default meta;
21
+
22
+ type Story = StoryObj<typeof meta>;
23
+
24
+ export const Default: Story = {
25
+ render: () => (
26
+ <Select>
27
+ <SelectTrigger className="w-200">
28
+ <SelectValue placeholder="Select an option" />
29
+ </SelectTrigger>
30
+ <SelectContent>
31
+ <SelectItem value="option1">Option 1</SelectItem>
32
+ <SelectItem value="option2">Option 2</SelectItem>
33
+ <SelectItem value="option3">Option 3</SelectItem>
34
+ </SelectContent>
35
+ </Select>
36
+ ),
37
+ };
38
+
39
+ export const WithGroups: Story = {
40
+ render: () => (
41
+ <Select defaultValue="typescript">
42
+ <SelectTrigger className="w-280">
43
+ <SelectValue placeholder="Select a technology" />
44
+ </SelectTrigger>
45
+ <SelectContent>
46
+ <SelectGroup>
47
+ <SelectLabel>Frontend</SelectLabel>
48
+ <SelectItem value="react">React</SelectItem>
49
+ <SelectItem value="vue">Vue</SelectItem>
50
+ <SelectItem value="angular">Angular</SelectItem>
51
+ <SelectItem value="svelte">Svelte</SelectItem>
52
+ </SelectGroup>
53
+ <SelectSeparator />
54
+ <SelectGroup>
55
+ <SelectLabel>Backend</SelectLabel>
56
+ <SelectItem value="nodejs">Node.js</SelectItem>
57
+ <SelectItem value="python">Python</SelectItem>
58
+ <SelectItem value="ruby">Ruby</SelectItem>
59
+ <SelectItem value="go">Go</SelectItem>
60
+ </SelectGroup>
61
+ <SelectSeparator />
62
+ <SelectGroup>
63
+ <SelectLabel>Languages</SelectLabel>
64
+ <SelectItem value="typescript">TypeScript</SelectItem>
65
+ <SelectItem value="javascript">JavaScript</SelectItem>
66
+ <SelectItem value="rust">Rust</SelectItem>
67
+ </SelectGroup>
68
+ </SelectContent>
69
+ </Select>
70
+ ),
71
+ };
72
+
73
+ export const WithIcons: Story = {
74
+ render: () => (
75
+ <div className="flex flex-col gap-12">
76
+ <Select defaultValue="active">
77
+ <SelectTrigger className="w-200">
78
+ <SelectValue placeholder="Select status" />
79
+ </SelectTrigger>
80
+ <SelectContent>
81
+ <SelectItem value="active" icon="checkboxCircleLine">
82
+ Active
83
+ </SelectItem>
84
+ <SelectItem value="pending" icon="timeLine">
85
+ Pending
86
+ </SelectItem>
87
+ <SelectItem value="inactive" icon="closeLine">
88
+ Inactive
89
+ </SelectItem>
90
+ </SelectContent>
91
+ </Select>
92
+
93
+ <Select defaultValue="medium">
94
+ <SelectTrigger className="w-200">
95
+ <SelectValue placeholder="Select priority" />
96
+ </SelectTrigger>
97
+ <SelectContent>
98
+ <SelectItem value="high" icon="arrowUpLine">
99
+ High
100
+ </SelectItem>
101
+ <SelectItem value="medium" icon="equalLine">
102
+ Medium
103
+ </SelectItem>
104
+ <SelectItem value="low" icon="arrowDownLine">
105
+ Low
106
+ </SelectItem>
107
+ </SelectContent>
108
+ </Select>
109
+ </div>
110
+ ),
111
+ };
112
+
113
+ export const Sizes: Story = {
114
+ render: () => (
115
+ <div className="flex flex-col gap-12">
116
+ <Select>
117
+ <SelectTrigger size="small" className="w-200">
118
+ <SelectValue placeholder="Small" />
119
+ </SelectTrigger>
120
+ <SelectContent>
121
+ <SelectItem value="option1">Option 1</SelectItem>
122
+ <SelectItem value="option2">Option 2</SelectItem>
123
+ </SelectContent>
124
+ </Select>
125
+
126
+ <Select>
127
+ <SelectTrigger size="base" className="w-200">
128
+ <SelectValue placeholder="Base (default)" />
129
+ </SelectTrigger>
130
+ <SelectContent>
131
+ <SelectItem value="option1">Option 1</SelectItem>
132
+ <SelectItem value="option2">Option 2</SelectItem>
133
+ </SelectContent>
134
+ </Select>
135
+ </div>
136
+ ),
137
+ };
138
+
139
+ export const Variants: Story = {
140
+ render: () => (
141
+ <div className="flex flex-col gap-12">
142
+ <Select>
143
+ <SelectTrigger variant="base" className="w-200">
144
+ <SelectValue placeholder="Base variant" />
145
+ </SelectTrigger>
146
+ <SelectContent>
147
+ <SelectItem value="option1">Option 1</SelectItem>
148
+ <SelectItem value="option2">Option 2</SelectItem>
149
+ </SelectContent>
150
+ </Select>
151
+
152
+ <Select>
153
+ <SelectTrigger variant="component" className="w-200">
154
+ <SelectValue placeholder="Component variant" />
155
+ </SelectTrigger>
156
+ <SelectContent>
157
+ <SelectItem value="option1">Option 1</SelectItem>
158
+ <SelectItem value="option2">Option 2</SelectItem>
159
+ </SelectContent>
160
+ </Select>
161
+ </div>
162
+ ),
163
+ };
164
+
165
+ export const TimeSelector: Story = {
166
+ render: () => (
167
+ <Select defaultValue="2days">
168
+ <SelectTrigger className="w-280">
169
+ <div className="flex items-center gap-8 flex-1 min-w-0">
170
+ <SelectValue placeholder="Select time range" />
171
+ </div>
172
+ </SelectTrigger>
173
+ <SelectContent>
174
+ <SelectItem value="1hour">
175
+ <div className="flex items-center gap-8">
176
+ <Kbd className="h-16">1h</Kbd>
177
+ <span>Past 1 Hour</span>
178
+ </div>
179
+ </SelectItem>
180
+ <SelectItem value="1day">
181
+ <div className="flex items-center gap-8">
182
+ <Kbd className="h-16">1d</Kbd>
183
+ <span>Past 1 Day</span>
184
+ </div>
185
+ </SelectItem>
186
+ <SelectItem value="2days">
187
+ <div className="flex items-center gap-8">
188
+ <Kbd className="h-16">2d</Kbd>
189
+ <span>Past 2 Days</span>
190
+ </div>
191
+ </SelectItem>
192
+ <SelectItem value="7days">
193
+ <div className="flex items-center gap-8">
194
+ <Kbd className="h-16">7d</Kbd>
195
+ <span>Past 7 Days</span>
196
+ </div>
197
+ </SelectItem>
198
+ <SelectItem value="30days">
199
+ <div className="flex items-center gap-8">
200
+ <Kbd className="h-16">30d</Kbd>
201
+ <span>Past 30 Days</span>
202
+ </div>
203
+ </SelectItem>
204
+ </SelectContent>
205
+ </Select>
206
+ ),
207
+ };