base-themes 0.1.2 → 0.1.3

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 (262) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/CODE_OF_CONDUCT.md +22 -0
  3. package/CONTRIBUTING.md +98 -0
  4. package/LICENSE +21 -0
  5. package/README.md +316 -3
  6. package/RELEASE.md +80 -0
  7. package/SECURITY.md +49 -0
  8. package/bin/base-themes.mjs +143 -0
  9. package/dist/base-themes.css +1 -1
  10. package/dist/base-themes.js +857 -302
  11. package/dist/llms-full.txt +288 -0
  12. package/dist/llms.txt +79 -0
  13. package/dist/types/blocks/AuthCard.d.ts +2 -0
  14. package/dist/types/blocks/CommandPaletteBlock.d.ts +2 -0
  15. package/dist/types/blocks/DashboardShell.d.ts +2 -0
  16. package/dist/types/blocks/DataTableBlock.d.ts +2 -0
  17. package/dist/types/blocks/PricingPanel.d.ts +2 -0
  18. package/dist/types/blocks/SettingsForm.d.ts +2 -0
  19. package/dist/types/blocks/TeamActivityFeed.d.ts +2 -0
  20. package/dist/types/blocks/ThemeShowcaseCard.d.ts +2 -0
  21. package/dist/types/blocks/index.d.ts +8 -0
  22. package/dist/types/components/ui/Input.d.ts +3 -0
  23. package/dist/types/components/ui/index.d.ts +1 -1
  24. package/dist/types/lib.d.ts +1 -0
  25. package/docs/adoption-dashboard.md +149 -0
  26. package/docs/analytics-setup.md +145 -0
  27. package/docs/community-gallery-proposal.md +64 -0
  28. package/docs/community-proof-telemetry.md +47 -0
  29. package/docs/contributor-issue-seeds.md +240 -0
  30. package/docs/registry-access-telemetry.md +87 -0
  31. package/docs/release-announcement-kit.md +229 -0
  32. package/docs/search-console-setup.md +111 -0
  33. package/docs/theme-token-contract.md +113 -0
  34. package/examples/dashboard/README.md +24 -0
  35. package/examples/dashboard/index.html +12 -0
  36. package/examples/dashboard/package-lock.json +1212 -0
  37. package/examples/dashboard/package.json +24 -0
  38. package/examples/dashboard/src/App.tsx +115 -0
  39. package/examples/dashboard/src/main.tsx +11 -0
  40. package/examples/dashboard/src/styles.css +129 -0
  41. package/examples/dashboard/src/vite-env.d.ts +4 -0
  42. package/examples/dashboard/tsconfig.app.json +23 -0
  43. package/examples/dashboard/tsconfig.json +7 -0
  44. package/examples/dashboard/tsconfig.node.json +15 -0
  45. package/examples/dashboard/vite.config.ts +6 -0
  46. package/examples/next/README.md +29 -0
  47. package/examples/next/app/base-themes-demo.tsx +70 -0
  48. package/examples/next/app/layout.tsx +16 -0
  49. package/examples/next/app/page.tsx +9 -0
  50. package/examples/next/app/styles.css +106 -0
  51. package/examples/next/next-env.d.ts +6 -0
  52. package/examples/next/next.config.ts +5 -0
  53. package/examples/next/package-lock.json +1199 -0
  54. package/examples/next/package.json +27 -0
  55. package/examples/next/tsconfig.json +36 -0
  56. package/examples/registry-copy/README.md +73 -0
  57. package/examples/registry-copy/plan-copy.mjs +130 -0
  58. package/examples/theme-customization/README.md +26 -0
  59. package/examples/theme-customization/index.html +12 -0
  60. package/examples/theme-customization/package-lock.json +1212 -0
  61. package/examples/theme-customization/package.json +24 -0
  62. package/examples/theme-customization/src/App.tsx +138 -0
  63. package/examples/theme-customization/src/main.tsx +11 -0
  64. package/examples/theme-customization/src/styles.css +138 -0
  65. package/examples/theme-customization/src/vite-env.d.ts +4 -0
  66. package/examples/theme-customization/tsconfig.app.json +23 -0
  67. package/examples/theme-customization/tsconfig.json +7 -0
  68. package/examples/theme-customization/tsconfig.node.json +15 -0
  69. package/examples/theme-customization/vite.config.ts +6 -0
  70. package/examples/vite/README.md +32 -0
  71. package/examples/vite/index.html +12 -0
  72. package/examples/vite/package-lock.json +1200 -0
  73. package/examples/vite/package.json +24 -0
  74. package/examples/vite/src/App.tsx +101 -0
  75. package/examples/vite/src/main.tsx +11 -0
  76. package/examples/vite/src/styles.css +125 -0
  77. package/examples/vite/src/vite-env.d.ts +4 -0
  78. package/examples/vite/tsconfig.app.json +23 -0
  79. package/examples/vite/tsconfig.json +7 -0
  80. package/examples/vite/tsconfig.node.json +15 -0
  81. package/examples/vite/vite.config.ts +6 -0
  82. package/llms-full.txt +288 -0
  83. package/llms.txt +79 -0
  84. package/package.json +157 -14
  85. package/registry/items/accordion.json +101 -0
  86. package/registry/items/alert-dialog.json +107 -0
  87. package/registry/items/autocomplete.json +106 -0
  88. package/registry/items/avatar.json +101 -0
  89. package/registry/items/block-auth-card.json +105 -0
  90. package/registry/items/block-command-palette.json +99 -0
  91. package/registry/items/block-dashboard-shell.json +101 -0
  92. package/registry/items/block-data-table.json +99 -0
  93. package/registry/items/block-pricing-panel.json +99 -0
  94. package/registry/items/block-settings-form.json +107 -0
  95. package/registry/items/block-team-activity-feed.json +99 -0
  96. package/registry/items/block-theme-showcase-card.json +99 -0
  97. package/registry/items/button.json +102 -0
  98. package/registry/items/checkbox-group.json +106 -0
  99. package/registry/items/checkbox.json +102 -0
  100. package/registry/items/collapsible.json +101 -0
  101. package/registry/items/combobox.json +101 -0
  102. package/registry/items/context-menu.json +106 -0
  103. package/registry/items/csp-provider.json +96 -0
  104. package/registry/items/dialog.json +102 -0
  105. package/registry/items/direction-provider.json +101 -0
  106. package/registry/items/drawer.json +101 -0
  107. package/registry/items/field.json +101 -0
  108. package/registry/items/fieldset.json +101 -0
  109. package/registry/items/form.json +101 -0
  110. package/registry/items/input.json +102 -0
  111. package/registry/items/menu.json +101 -0
  112. package/registry/items/menubar.json +106 -0
  113. package/registry/items/meter.json +101 -0
  114. package/registry/items/navigation-menu.json +101 -0
  115. package/registry/items/number-field.json +101 -0
  116. package/registry/items/otp-field.json +101 -0
  117. package/registry/items/popover.json +102 -0
  118. package/registry/items/preview-card.json +101 -0
  119. package/registry/items/progress.json +101 -0
  120. package/registry/items/radio-group.json +102 -0
  121. package/registry/items/radio.json +101 -0
  122. package/registry/items/scroll-area.json +101 -0
  123. package/registry/items/select.json +102 -0
  124. package/registry/items/separator.json +101 -0
  125. package/registry/items/slider.json +102 -0
  126. package/registry/items/switch.json +102 -0
  127. package/registry/items/tabs.json +101 -0
  128. package/registry/items/theme-bauhaus.json +107 -0
  129. package/registry/items/theme-bento.json +107 -0
  130. package/registry/items/theme-calm.json +107 -0
  131. package/registry/items/theme-cyberpunk.json +108 -0
  132. package/registry/items/theme-data-dense.json +107 -0
  133. package/registry/items/theme-editorial.json +107 -0
  134. package/registry/items/theme-enterprise.json +108 -0
  135. package/registry/items/theme-fluent.json +107 -0
  136. package/registry/items/theme-glass.json +107 -0
  137. package/registry/items/theme-linear.json +107 -0
  138. package/registry/items/theme-luxury.json +107 -0
  139. package/registry/items/theme-material.json +107 -0
  140. package/registry/items/theme-minimal.json +107 -0
  141. package/registry/items/theme-mono.json +107 -0
  142. package/registry/items/theme-neo-brutalism.json +107 -0
  143. package/registry/items/theme-playful.json +107 -0
  144. package/registry/items/theme-retro.json +107 -0
  145. package/registry/items/theme-shadcn.json +107 -0
  146. package/registry/items/theme-soft-ui.json +107 -0
  147. package/registry/items/theme-terminal.json +107 -0
  148. package/registry/items/toast.json +106 -0
  149. package/registry/items/toggle-group.json +101 -0
  150. package/registry/items/toggle.json +101 -0
  151. package/registry/items/toolbar.json +101 -0
  152. package/registry/items/tooltip.json +102 -0
  153. package/registry/registry.json +564 -49
  154. package/registry/shadcn-registry.json +415 -0
  155. package/research/telemetry-fixtures/analytics-events.jsonl +9 -0
  156. package/research/telemetry-fixtures/bundle-report.json +44 -0
  157. package/research/telemetry-fixtures/community-proof.csv +5 -0
  158. package/research/telemetry-fixtures/registry-access.jsonl +10 -0
  159. package/research/telemetry-fixtures/search-console-export.csv +4 -0
  160. package/scripts/registry-plan.mjs +434 -0
  161. package/scripts/render-launch-actions.mjs +405 -0
  162. package/scripts/render-launch-status.mjs +373 -0
  163. package/scripts/render-release-announcement.mjs +329 -0
  164. package/scripts/verify-launch-readiness.mjs +415 -0
  165. package/scripts/verify-telemetry-fixtures.mjs +85 -0
  166. package/scripts/verify-telemetry-report.mjs +89 -0
  167. package/skills/base-themes/SKILL.md +151 -47
  168. package/src/blocks/AuthCard.tsx +29 -0
  169. package/src/blocks/Blocks.css +182 -0
  170. package/src/blocks/CommandPaletteBlock.tsx +32 -0
  171. package/src/blocks/DashboardShell.tsx +36 -0
  172. package/src/blocks/DataTableBlock.tsx +44 -0
  173. package/src/blocks/PricingPanel.tsx +28 -0
  174. package/src/blocks/SettingsForm.tsx +37 -0
  175. package/src/blocks/TeamActivityFeed.tsx +38 -0
  176. package/src/blocks/ThemeShowcaseCard.tsx +32 -0
  177. package/src/blocks/index.ts +8 -0
  178. package/src/components/ui/Accordion.css +42 -0
  179. package/src/components/ui/Accordion.tsx +41 -0
  180. package/src/components/ui/AlertDialog.css +40 -0
  181. package/src/components/ui/AlertDialog.tsx +52 -0
  182. package/src/components/ui/Autocomplete.css +3 -0
  183. package/src/components/ui/Autocomplete.tsx +50 -0
  184. package/src/components/ui/Avatar.css +45 -0
  185. package/src/components/ui/Avatar.tsx +36 -0
  186. package/src/components/ui/Button.css +79 -0
  187. package/src/components/ui/Button.tsx +20 -0
  188. package/src/components/ui/Checkbox.css +37 -0
  189. package/src/components/ui/Checkbox.tsx +32 -0
  190. package/src/components/ui/CheckboxGroup.tsx +21 -0
  191. package/src/components/ui/Collapsible.css +34 -0
  192. package/src/components/ui/Collapsible.tsx +29 -0
  193. package/src/components/ui/Combobox.css +75 -0
  194. package/src/components/ui/Combobox.tsx +53 -0
  195. package/src/components/ui/ContextMenu.css +9 -0
  196. package/src/components/ui/ContextMenu.tsx +47 -0
  197. package/src/components/ui/CspProvider.tsx +10 -0
  198. package/src/components/ui/Dialog.css +41 -0
  199. package/src/components/ui/Dialog.tsx +45 -0
  200. package/src/components/ui/DirectionProvider.tsx +17 -0
  201. package/src/components/ui/Drawer.css +77 -0
  202. package/src/components/ui/Drawer.tsx +56 -0
  203. package/src/components/ui/Field.css +19 -0
  204. package/src/components/ui/Field.tsx +24 -0
  205. package/src/components/ui/Fieldset.css +16 -0
  206. package/src/components/ui/Fieldset.tsx +19 -0
  207. package/src/components/ui/Form.css +5 -0
  208. package/src/components/ui/Form.tsx +12 -0
  209. package/src/components/ui/Input.css +50 -0
  210. package/src/components/ui/Input.tsx +62 -0
  211. package/src/components/ui/Menu.css +59 -0
  212. package/src/components/ui/Menu.tsx +50 -0
  213. package/src/components/ui/Menubar.css +26 -0
  214. package/src/components/ui/Menubar.tsx +42 -0
  215. package/src/components/ui/Meter.css +45 -0
  216. package/src/components/ui/Meter.tsx +37 -0
  217. package/src/components/ui/NavigationMenu.css +103 -0
  218. package/src/components/ui/NavigationMenu.tsx +64 -0
  219. package/src/components/ui/NumberField.css +38 -0
  220. package/src/components/ui/NumberField.tsx +28 -0
  221. package/src/components/ui/OtpField.css +28 -0
  222. package/src/components/ui/OtpField.tsx +24 -0
  223. package/src/components/ui/Popover.css +25 -0
  224. package/src/components/ui/Popover.tsx +37 -0
  225. package/src/components/ui/PreviewCard.css +33 -0
  226. package/src/components/ui/PreviewCard.tsx +43 -0
  227. package/src/components/ui/Progress.css +33 -0
  228. package/src/components/ui/Progress.tsx +28 -0
  229. package/src/components/ui/Radio.tsx +22 -0
  230. package/src/components/ui/RadioGroup.css +42 -0
  231. package/src/components/ui/RadioGroup.tsx +29 -0
  232. package/src/components/ui/ScrollArea.css +42 -0
  233. package/src/components/ui/ScrollArea.tsx +22 -0
  234. package/src/components/ui/Select.css +86 -0
  235. package/src/components/ui/Select.tsx +39 -0
  236. package/src/components/ui/Separator.css +14 -0
  237. package/src/components/ui/Separator.tsx +12 -0
  238. package/src/components/ui/Slider.css +39 -0
  239. package/src/components/ui/Slider.tsx +21 -0
  240. package/src/components/ui/Switch.css +45 -0
  241. package/src/components/ui/Switch.tsx +29 -0
  242. package/src/components/ui/Tabs.css +72 -0
  243. package/src/components/ui/Tabs.tsx +44 -0
  244. package/src/components/ui/Toast.css +75 -0
  245. package/src/components/ui/Toast.tsx +48 -0
  246. package/src/components/ui/Toggle.tsx +12 -0
  247. package/src/components/ui/ToggleGroup.css +35 -0
  248. package/src/components/ui/ToggleGroup.tsx +30 -0
  249. package/src/components/ui/Toolbar.css +60 -0
  250. package/src/components/ui/Toolbar.tsx +36 -0
  251. package/src/components/ui/Tooltip.css +14 -0
  252. package/src/components/ui/Tooltip.tsx +31 -0
  253. package/src/components/ui/index.ts +83 -0
  254. package/src/components/ui/useDirection.ts +1 -0
  255. package/src/components/ui/useToastManager.ts +11 -0
  256. package/src/docs/blockMeta.json +66 -0
  257. package/src/docs/componentMeta.json +322 -0
  258. package/src/docs/staticPageMeta.json +143 -0
  259. package/src/docs/themeMeta.json +22 -0
  260. package/src/styles/tokenContract.json +61 -0
  261. package/workers/analytics-receiver.mjs +170 -0
  262. package/wrangler.analytics.jsonc +12 -0
@@ -0,0 +1,38 @@
1
+ import { Avatar, AvatarGroup } from '../components/ui/Avatar'
2
+ import { Button } from '../components/ui/Button'
3
+ import './Blocks.css'
4
+
5
+ const activity = [
6
+ { title: 'Published enterprise theme', meta: 'Mina, 12m ago' },
7
+ { title: 'Reviewed registry copy plan', meta: 'Ava, 34m ago' },
8
+ { title: 'Updated dashboard block', meta: 'Noah, 1h ago' },
9
+ ]
10
+
11
+ export function TeamActivityFeed() {
12
+ return (
13
+ <section className="base-block" aria-label="Team activity feed block">
14
+ <div className="base-block-header">
15
+ <div>
16
+ <h2 className="base-block-title">Team Activity</h2>
17
+ <p className="base-block-copy">A feed block for recent workspace changes and collaboration status.</p>
18
+ </div>
19
+ <AvatarGroup>
20
+ <Avatar fallback="AV" size="sm" />
21
+ <Avatar fallback="MN" size="sm" />
22
+ <Avatar fallback="NH" size="sm" />
23
+ </AvatarGroup>
24
+ </div>
25
+ <div className="base-block-list">
26
+ {activity.map((item) => (
27
+ <div className="base-block-list-item" key={item.title}>
28
+ <div className="base-block-list-main">
29
+ <strong>{item.title}</strong>
30
+ <span>{item.meta}</span>
31
+ </div>
32
+ </div>
33
+ ))}
34
+ </div>
35
+ <Button type="button" variant="outline">Open activity</Button>
36
+ </section>
37
+ )
38
+ }
@@ -0,0 +1,32 @@
1
+ import { Button } from '../components/ui/Button'
2
+ import { Tabs } from '../components/ui/Tabs'
3
+ import './Blocks.css'
4
+
5
+ const panels = [
6
+ { value: 'tokens', label: 'Tokens', title: 'CSS variable contract', content: 'Theme styles use shared semantic tokens for surfaces, text, focus, and controls.' },
7
+ { value: 'registry', label: 'Registry', title: 'Copy-ready metadata', content: 'Components and blocks can be resolved from registry metadata for agent workflows.' },
8
+ ]
9
+
10
+ export function ThemeShowcaseCard() {
11
+ return (
12
+ <section className="base-block" aria-label="Theme showcase block">
13
+ <div className="base-block-header">
14
+ <div>
15
+ <h2 className="base-block-title">Theme Showcase</h2>
16
+ <p className="base-block-copy">A compact block for explaining theme value on landing or docs pages.</p>
17
+ </div>
18
+ <span className="base-block-pill">20 styles</span>
19
+ </div>
20
+ <div className="base-block-grid" aria-label="Theme swatches">
21
+ {['--bt-bg', '--bt-surface', '--bt-primary', '--bt-secondary'].map((token) => (
22
+ <div className="base-block-stat" key={token}>
23
+ <span className="base-block-muted">{token}</span>
24
+ <span style={{ display: 'block', height: 24, marginTop: 8, border: '1px solid var(--bt-border)', borderRadius: 'var(--bt-radius-sm)', background: `var(${token})` }} />
25
+ </div>
26
+ ))}
27
+ </div>
28
+ <Tabs panels={panels} defaultValue="tokens" />
29
+ <Button type="button">Open themes</Button>
30
+ </section>
31
+ )
32
+ }
@@ -0,0 +1,8 @@
1
+ export { AuthCard } from './AuthCard'
2
+ export { CommandPaletteBlock } from './CommandPaletteBlock'
3
+ export { DashboardShell } from './DashboardShell'
4
+ export { DataTableBlock } from './DataTableBlock'
5
+ export { PricingPanel } from './PricingPanel'
6
+ export { SettingsForm } from './SettingsForm'
7
+ export { TeamActivityFeed } from './TeamActivityFeed'
8
+ export { ThemeShowcaseCard } from './ThemeShowcaseCard'
@@ -0,0 +1,42 @@
1
+ .bento-accordion {
2
+ display: grid;
3
+ gap: 8px;
4
+ }
5
+
6
+ .bento-accordion-item {
7
+ border: 1px solid var(--bt-border);
8
+ border-radius: var(--bt-radius);
9
+ background: var(--group-bg);
10
+ }
11
+
12
+ .bento-accordion-header {
13
+ margin: 0;
14
+ }
15
+
16
+ .bento-accordion-trigger {
17
+ display: flex;
18
+ width: 100%;
19
+ min-height: 46px;
20
+ align-items: center;
21
+ justify-content: space-between;
22
+ border: 0;
23
+ padding: 0 14px;
24
+ color: var(--bt-fg);
25
+ background: transparent;
26
+ cursor: pointer;
27
+ font-weight: 760;
28
+ }
29
+
30
+ .bento-accordion-trigger svg {
31
+ transition: transform 160ms ease;
32
+ }
33
+
34
+ .bento-accordion-item[data-open] .bento-accordion-trigger svg {
35
+ transform: rotate(180deg);
36
+ }
37
+
38
+ .bento-accordion-panel {
39
+ padding: 0 14px 14px;
40
+ color: var(--bt-muted-fg);
41
+ line-height: 1.6;
42
+ }
@@ -0,0 +1,41 @@
1
+ import { Accordion as BaseAccordion } from '@base-ui/react/accordion'
2
+ import { type ComponentPropsWithoutRef } from 'react'
3
+ import clsx from 'clsx'
4
+ import { ChevronDown } from 'lucide-react'
5
+ import './Accordion.css'
6
+
7
+ type AccordionItem = {
8
+ value: string
9
+ label: string
10
+ content: string
11
+ }
12
+
13
+ type AccordionProps = Omit<ComponentPropsWithoutRef<typeof BaseAccordion.Root>, 'defaultValue'> & {
14
+ items: AccordionItem[]
15
+ defaultValue?: string | string[]
16
+ }
17
+
18
+ export function Accordion({ items, defaultValue, className, ...rest }: AccordionProps) {
19
+ return (
20
+ <BaseAccordion.Root
21
+ defaultValue={(defaultValue as never) ?? (items.slice(0, 1).map((i) => i.value) as never)}
22
+ className={clsx('bento-accordion', className)}
23
+ {...rest}
24
+ >
25
+ {items.map((item) => (
26
+ <BaseAccordion.Item className="bento-accordion-item" key={item.value} value={item.value}>
27
+ <BaseAccordion.Header className="bento-accordion-header">
28
+ <BaseAccordion.Trigger className="bento-accordion-trigger">
29
+ {item.label}
30
+ <ChevronDown size={15} />
31
+ </BaseAccordion.Trigger>
32
+ </BaseAccordion.Header>
33
+ <BaseAccordion.Panel className="bento-accordion-panel">{item.content}</BaseAccordion.Panel>
34
+ </BaseAccordion.Item>
35
+ ))}
36
+ </BaseAccordion.Root>
37
+ )
38
+ }
39
+
40
+ export { BaseAccordion }
41
+ export type { AccordionProps, AccordionItem }
@@ -0,0 +1,40 @@
1
+ .bento-alert-backdrop {
2
+ position: fixed;
3
+ inset: 0;
4
+ z-index: 60;
5
+ background: var(--backdrop);
6
+ backdrop-filter: blur(6px);
7
+ }
8
+
9
+ .bento-alert-popup {
10
+ position: fixed;
11
+ top: 50%;
12
+ left: 50%;
13
+ z-index: 61;
14
+ width: min(400px, calc(100vw - 32px));
15
+ padding: 24px;
16
+ border: 1px solid var(--bt-border);
17
+ border-radius: var(--bt-radius);
18
+ background: var(--bt-surface);
19
+ box-shadow: var(--bt-shadow);
20
+ transform: translate(-50%, -50%);
21
+ }
22
+
23
+ .bento-alert-title {
24
+ color: var(--bt-fg);
25
+ font-size: 20px;
26
+ font-weight: 780;
27
+ margin: 0;
28
+ }
29
+
30
+ .bento-alert-description {
31
+ margin: 14px 0 22px;
32
+ color: var(--bt-muted-fg);
33
+ line-height: 1.6;
34
+ }
35
+
36
+ .bento-alert-actions {
37
+ display: flex;
38
+ justify-content: flex-end;
39
+ gap: 10px;
40
+ }
@@ -0,0 +1,52 @@
1
+ import { AlertDialog as BaseAlertDialog } from '@base-ui/react/alert-dialog'
2
+ import { type ReactElement } from 'react'
3
+ import clsx from 'clsx'
4
+ import './AlertDialog.css'
5
+ import './Button.css'
6
+
7
+ type AlertDialogProps = {
8
+ trigger: ReactElement
9
+ title: string
10
+ description: string
11
+ confirmLabel?: string
12
+ cancelLabel?: string
13
+ onConfirm?: () => void
14
+ className?: string
15
+ }
16
+
17
+ export function AlertDialog({
18
+ trigger,
19
+ title,
20
+ description,
21
+ confirmLabel = 'Confirm',
22
+ cancelLabel = 'Cancel',
23
+ onConfirm,
24
+ className,
25
+ }: AlertDialogProps) {
26
+ return (
27
+ <BaseAlertDialog.Root>
28
+ <BaseAlertDialog.Trigger render={trigger} />
29
+ <BaseAlertDialog.Portal>
30
+ <BaseAlertDialog.Backdrop className="bento-alert-backdrop" />
31
+ <BaseAlertDialog.Popup className={clsx('bento-alert-popup', className)}>
32
+ <BaseAlertDialog.Title className="bento-alert-title">{title}</BaseAlertDialog.Title>
33
+ <BaseAlertDialog.Description className="bento-alert-description">
34
+ {description}
35
+ </BaseAlertDialog.Description>
36
+ <div className="bento-alert-actions">
37
+ <BaseAlertDialog.Close className="bento-button outline"> {cancelLabel}</BaseAlertDialog.Close>
38
+ <BaseAlertDialog.Close
39
+ className="bento-button accent"
40
+ onClick={onConfirm}
41
+ >
42
+ {confirmLabel}
43
+ </BaseAlertDialog.Close>
44
+ </div>
45
+ </BaseAlertDialog.Popup>
46
+ </BaseAlertDialog.Portal>
47
+ </BaseAlertDialog.Root>
48
+ )
49
+ }
50
+
51
+ export { BaseAlertDialog }
52
+ export type { AlertDialogProps }
@@ -0,0 +1,3 @@
1
+ .bento-autocomplete {
2
+ width: min(100%, 320px);
3
+ }
@@ -0,0 +1,50 @@
1
+ import { Autocomplete as BaseAutocomplete } from '@base-ui/react/autocomplete'
2
+ import { Check, Search } from 'lucide-react'
3
+ import clsx from 'clsx'
4
+ import './Combobox.css'
5
+ import './Autocomplete.css'
6
+
7
+ export type AutocompleteOption = { value: string; label: string }
8
+
9
+ export type AutocompleteProps = {
10
+ options: AutocompleteOption[]
11
+ label?: string
12
+ placeholder?: string
13
+ className?: string
14
+ defaultValue?: string
15
+ value?: string
16
+ onValueChange?: (value: string) => void
17
+ openOnInputClick?: boolean
18
+ disabled?: boolean
19
+ }
20
+
21
+ export function Autocomplete({ options, label, placeholder = 'Search...', className, ...rest }: AutocompleteProps) {
22
+ return (
23
+ <div className={clsx('bento-combobox bento-autocomplete', className)}>
24
+ <BaseAutocomplete.Root<AutocompleteOption> items={options} {...rest}>
25
+ {label && <label className="field-label">{label}</label>}
26
+ <BaseAutocomplete.InputGroup className="bento-combobox-input-wrap">
27
+ <Search size={15} />
28
+ <BaseAutocomplete.Input className="bento-combobox-input" placeholder={placeholder} />
29
+ </BaseAutocomplete.InputGroup>
30
+ <BaseAutocomplete.Portal>
31
+ <BaseAutocomplete.Positioner className="bento-combobox-positioner" sideOffset={8}>
32
+ <BaseAutocomplete.Popup className="bento-combobox-popup">
33
+ <BaseAutocomplete.Empty className="bento-combobox-empty">No results</BaseAutocomplete.Empty>
34
+ <BaseAutocomplete.List>
35
+ {(item: AutocompleteOption) => (
36
+ <BaseAutocomplete.Item className="bento-combobox-item" key={item.value} value={item.value}>
37
+ <BaseAutocomplete.Value>{item.label}</BaseAutocomplete.Value>
38
+ <Check size={14} />
39
+ </BaseAutocomplete.Item>
40
+ )}
41
+ </BaseAutocomplete.List>
42
+ </BaseAutocomplete.Popup>
43
+ </BaseAutocomplete.Positioner>
44
+ </BaseAutocomplete.Portal>
45
+ </BaseAutocomplete.Root>
46
+ </div>
47
+ )
48
+ }
49
+
50
+ export { BaseAutocomplete }
@@ -0,0 +1,45 @@
1
+ .bento-avatar {
2
+ display: inline-flex;
3
+ width: 40px;
4
+ height: 40px;
5
+ align-items: center;
6
+ justify-content: center;
7
+ border-radius: 999px;
8
+ background: var(--bt-surface-muted);
9
+ color: var(--bt-fg);
10
+ font-size: 16px;
11
+ font-weight: 760;
12
+ overflow: hidden;
13
+ user-select: none;
14
+ }
15
+
16
+ .bento-avatar img {
17
+ width: 100%;
18
+ height: 100%;
19
+ object-fit: cover;
20
+ }
21
+
22
+ .bento-avatar.sm {
23
+ width: 32px;
24
+ height: 32px;
25
+ font-size: 13px;
26
+ }
27
+
28
+ .bento-avatar.lg {
29
+ width: 56px;
30
+ height: 56px;
31
+ font-size: 22px;
32
+ }
33
+
34
+ .bento-avatar-group {
35
+ display: flex;
36
+ }
37
+
38
+ .bento-avatar-group .bento-avatar {
39
+ border: 2px solid var(--bt-surface);
40
+ margin-left: -10px;
41
+ }
42
+
43
+ .bento-avatar-group .bento-avatar:first-child {
44
+ margin-left: 0;
45
+ }
@@ -0,0 +1,36 @@
1
+ import { Avatar as BaseAvatar } from '@base-ui/react/avatar'
2
+ import { type ComponentPropsWithoutRef, forwardRef } from 'react'
3
+ import clsx from 'clsx'
4
+ import './Avatar.css'
5
+
6
+ export type AvatarProps = ComponentPropsWithoutRef<typeof BaseAvatar.Root> & {
7
+ src?: string
8
+ alt?: string
9
+ fallback?: string
10
+ size?: 'sm' | 'md' | 'lg'
11
+ }
12
+
13
+ export const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(
14
+ ({ src, alt, fallback, size, className, ...rest }, ref) => (
15
+ <BaseAvatar.Root
16
+ ref={ref}
17
+ className={clsx('bento-avatar', size && size !== 'md' && size, className)}
18
+ {...rest}
19
+ >
20
+ {src && <BaseAvatar.Image src={src} alt={alt} />}
21
+ <BaseAvatar.Fallback>{fallback}</BaseAvatar.Fallback>
22
+ </BaseAvatar.Root>
23
+ ),
24
+ )
25
+
26
+ Avatar.displayName = 'Avatar'
27
+
28
+ type AvatarGroupProps = ComponentPropsWithoutRef<'div'>
29
+
30
+ export const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(
31
+ ({ className, ...rest }, ref) => (
32
+ <div ref={ref} className={clsx('bento-avatar-group', className)} {...rest} />
33
+ ),
34
+ )
35
+
36
+ AvatarGroup.displayName = 'AvatarGroup'
@@ -0,0 +1,79 @@
1
+ .bento-button {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ gap: 8px;
6
+ min-height: 40px;
7
+ padding: 0 16px;
8
+ border: var(--bt-border-width, 1px) solid transparent;
9
+ border-radius: var(--bt-radius-sm);
10
+ color: var(--bt-bg);
11
+ background: var(--bt-surface-strong);
12
+ cursor: pointer;
13
+ font-weight: var(--bt-font-weight, 720);
14
+ text-decoration: none;
15
+ transition: background var(--bt-duration, 160ms) ease, box-shadow var(--bt-duration, 160ms) ease;
16
+ }
17
+
18
+ .bento-button:hover {
19
+ color: var(--bt-bg);
20
+ background: var(--bt-fg);
21
+ }
22
+
23
+ .bento-button:focus-visible {
24
+ outline: 3px solid var(--bt-ring, rgba(37, 99, 235, 0.32));
25
+ outline-offset: 2px;
26
+ }
27
+
28
+ .bento-button.outline {
29
+ color: var(--bt-fg);
30
+ border-color: var(--bt-border);
31
+ background: var(--bt-surface);
32
+ }
33
+
34
+ .bento-button.outline:hover {
35
+ border-color: var(--bt-border-strong);
36
+ box-shadow: var(--bt-shadow);
37
+ }
38
+
39
+ .bento-button.ghost {
40
+ color: var(--bt-fg);
41
+ background: transparent;
42
+ }
43
+
44
+ .bento-button.ghost:hover {
45
+ background: var(--bt-surface-muted);
46
+ }
47
+
48
+ .bento-button.icon {
49
+ width: 40px;
50
+ padding: 0;
51
+ color: var(--bt-fg);
52
+ border-color: var(--bt-border);
53
+ background: var(--bt-surface);
54
+ }
55
+
56
+ .bento-button.icon:hover {
57
+ border-color: var(--bt-border-strong);
58
+ box-shadow: var(--bt-shadow);
59
+ }
60
+
61
+ .bento-button.accent {
62
+ color: var(--bt-primary-fg);
63
+ background: var(--bt-primary);
64
+ }
65
+
66
+ .bento-button.accent:hover {
67
+ color: var(--bt-primary-fg);
68
+ background: var(--bt-primary-hover);
69
+ }
70
+
71
+ .bento-button.teal {
72
+ color: var(--bt-secondary-fg);
73
+ background: var(--bt-secondary);
74
+ }
75
+
76
+ .bento-button.teal:hover {
77
+ color: var(--bt-secondary-fg);
78
+ background: color-mix(in srgb, var(--bt-secondary), var(--bt-fg) 16%);
79
+ }
@@ -0,0 +1,20 @@
1
+ import { Button as BaseButton } from '@base-ui/react/button'
2
+ import { type ComponentPropsWithoutRef, forwardRef } from 'react'
3
+ import clsx from 'clsx'
4
+ import './Button.css'
5
+
6
+ export type ButtonProps = ComponentPropsWithoutRef<typeof BaseButton> & {
7
+ variant?: 'primary' | 'outline' | 'ghost' | 'icon' | 'accent' | 'teal'
8
+ }
9
+
10
+ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
11
+ ({ variant = 'primary', className, ...rest }, ref) => (
12
+ <BaseButton
13
+ ref={ref}
14
+ className={clsx('bento-button', variant !== 'primary' && variant, className)}
15
+ {...rest}
16
+ />
17
+ ),
18
+ )
19
+
20
+ Button.displayName = 'Button'
@@ -0,0 +1,37 @@
1
+ .bento-checkbox {
2
+ display: grid;
3
+ width: 22px;
4
+ height: 22px;
5
+ place-items: center;
6
+ border: 1px solid var(--bt-border-strong);
7
+ border-radius: 5px;
8
+ color: var(--bt-primary-fg);
9
+ background: var(--bt-surface);
10
+ cursor: pointer;
11
+ transition: border-color 140ms ease, background 140ms ease;
12
+ }
13
+
14
+ .bento-checkbox[data-checked] {
15
+ border-color: var(--bt-secondary);
16
+ background: var(--bt-secondary);
17
+ }
18
+
19
+ .bento-checkbox:focus-visible {
20
+ outline: 3px solid var(--bt-ring, rgba(37, 99, 235, 0.32));
21
+ outline-offset: 2px;
22
+ }
23
+
24
+ .bento-checkbox-label {
25
+ display: inline-flex;
26
+ align-items: center;
27
+ gap: 9px;
28
+ color: var(--bt-fg);
29
+ font-weight: 680;
30
+ cursor: pointer;
31
+ }
32
+
33
+ .bento-checkbox-group {
34
+ display: flex;
35
+ flex-wrap: wrap;
36
+ gap: 12px 16px;
37
+ }
@@ -0,0 +1,32 @@
1
+ import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox'
2
+ import { type ComponentPropsWithoutRef, forwardRef } from 'react'
3
+ import clsx from 'clsx'
4
+ import { Check } from 'lucide-react'
5
+ import './Checkbox.css'
6
+
7
+ export type CheckboxProps = ComponentPropsWithoutRef<typeof BaseCheckbox.Root> & {
8
+ label?: string
9
+ }
10
+
11
+ export const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(
12
+ ({ label, className, id, ...rest }, ref) => {
13
+ const inner = (
14
+ <BaseCheckbox.Root ref={ref} id={id} className={clsx('bento-checkbox', className)} {...rest}>
15
+ <BaseCheckbox.Indicator>
16
+ <Check size={14} />
17
+ </BaseCheckbox.Indicator>
18
+ </BaseCheckbox.Root>
19
+ )
20
+
21
+ if (!label) return inner
22
+
23
+ return (
24
+ <label className="bento-checkbox-label" htmlFor={id}>
25
+ {inner}
26
+ {label}
27
+ </label>
28
+ )
29
+ },
30
+ )
31
+
32
+ Checkbox.displayName = 'Checkbox'
@@ -0,0 +1,21 @@
1
+ import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group'
2
+ import { type ComponentPropsWithoutRef } from 'react'
3
+ import clsx from 'clsx'
4
+ import { Checkbox } from './Checkbox'
5
+ import './Checkbox.css'
6
+
7
+ export type CheckboxGroupOption = { value: string; label: string }
8
+
9
+ export type CheckboxGroupProps = Omit<ComponentPropsWithoutRef<typeof BaseCheckboxGroup>, 'children'> & {
10
+ options: CheckboxGroupOption[]
11
+ }
12
+
13
+ export function CheckboxGroup({ options, className, defaultValue, ...rest }: CheckboxGroupProps) {
14
+ return (
15
+ <BaseCheckboxGroup className={clsx('bento-checkbox-group', className)} defaultValue={defaultValue} {...rest}>
16
+ {options.map((option) => (
17
+ <Checkbox key={option.value} name={option.value} value={option.value} label={option.label} />
18
+ ))}
19
+ </BaseCheckboxGroup>
20
+ )
21
+ }
@@ -0,0 +1,34 @@
1
+ .bento-collapsible {
2
+ border: 1px solid var(--bt-border);
3
+ border-radius: var(--bt-radius);
4
+ background: var(--group-bg);
5
+ overflow: hidden;
6
+ }
7
+
8
+ .bento-collapsible-trigger {
9
+ display: flex;
10
+ width: 100%;
11
+ min-height: 46px;
12
+ align-items: center;
13
+ justify-content: space-between;
14
+ border: 0;
15
+ padding: 0 14px;
16
+ color: var(--bt-fg);
17
+ background: transparent;
18
+ cursor: pointer;
19
+ font-weight: 760;
20
+ }
21
+
22
+ .bento-collapsible-trigger svg {
23
+ transition: transform 160ms ease;
24
+ }
25
+
26
+ .bento-collapsible[data-open] .bento-collapsible-trigger svg {
27
+ transform: rotate(180deg);
28
+ }
29
+
30
+ .bento-collapsible-panel {
31
+ padding: 0 14px 14px;
32
+ color: var(--bt-muted-fg);
33
+ line-height: 1.6;
34
+ }
@@ -0,0 +1,29 @@
1
+ import { Collapsible as BaseCollapsible } from '@base-ui/react/collapsible'
2
+ import { type ReactNode } from 'react'
3
+ import clsx from 'clsx'
4
+ import { ChevronDown } from 'lucide-react'
5
+ import './Collapsible.css'
6
+
7
+ type CollapsibleProps = {
8
+ label: string
9
+ children: ReactNode
10
+ defaultOpen?: boolean
11
+ className?: string
12
+ }
13
+
14
+ export function Collapsible({ label, children, defaultOpen, className }: CollapsibleProps) {
15
+ return (
16
+ <BaseCollapsible.Root defaultOpen={defaultOpen} className={clsx('bento-collapsible', className)}>
17
+ <BaseCollapsible.Trigger className="bento-collapsible-trigger">
18
+ {label}
19
+ <ChevronDown size={15} />
20
+ </BaseCollapsible.Trigger>
21
+ <BaseCollapsible.Panel className="bento-collapsible-panel">
22
+ {children}
23
+ </BaseCollapsible.Panel>
24
+ </BaseCollapsible.Root>
25
+ )
26
+ }
27
+
28
+ export { BaseCollapsible }
29
+ export type { CollapsibleProps }