@owlmeans/create-app 0.1.18-rc.4 → 0.1.18-rc.41

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 (78) hide show
  1. package/README.md +39 -2
  2. package/build/args.d.ts +8 -0
  3. package/build/args.d.ts.map +1 -1
  4. package/build/args.js +60 -6
  5. package/build/args.js.map +1 -1
  6. package/build/index.d.ts +4 -1
  7. package/build/index.d.ts.map +1 -1
  8. package/build/index.js +2 -0
  9. package/build/index.js.map +1 -1
  10. package/build/naming.d.ts +11 -0
  11. package/build/naming.d.ts.map +1 -0
  12. package/build/naming.js +18 -0
  13. package/build/naming.js.map +1 -0
  14. package/build/run.d.ts.map +1 -1
  15. package/build/run.js +19 -13
  16. package/build/run.js.map +1 -1
  17. package/build/scaffold.d.ts +21 -0
  18. package/build/scaffold.d.ts.map +1 -0
  19. package/build/scaffold.js +18 -0
  20. package/build/scaffold.js.map +1 -0
  21. package/build/template.d.ts +19 -3
  22. package/build/template.d.ts.map +1 -1
  23. package/build/template.js +52 -12
  24. package/build/template.js.map +1 -1
  25. package/package.json +4 -3
  26. package/template/AGENTS.md +28 -1
  27. package/template/README.bare.md +57 -0
  28. package/template/README.md +5 -61
  29. package/template/_agents/scripts/link-skills.sh +310 -15
  30. package/template/_agents/skills/agent-memory/SKILL.md +12 -11
  31. package/template/_agents/skills/getting-started/SKILL.md +26 -86
  32. package/template/_agents/skills/memory-promotion/SKILL.md +10 -4
  33. package/template/_agents/skills/memory-recompact/SKILL.md +15 -14
  34. package/template/_agents/skills/reuse-code/SKILL.md +36 -8
  35. package/template/_agents/skills/self-education/SKILL.md +25 -5
  36. package/template/_agents/skills/skill-authoring/SKILL.md +78 -12
  37. package/template/_bare.json +23 -0
  38. package/template/_gitignore +3 -0
  39. package/template/bunfig.toml +2 -0
  40. package/template/package.json +3 -2
  41. package/template/sources/api/package.json +3 -3
  42. package/template/sources/api/src/app/session/add.ts +7 -6
  43. package/template/sources/api/src/app/session/list.ts +12 -9
  44. package/template/sources/api/src/app/session/remove.ts +7 -6
  45. package/template/sources/api/src/context.bare.ts +11 -0
  46. package/template/sources/api/src/entrypoints.bare.ts +4 -0
  47. package/template/sources/api/src/entrypoints.ts +13 -0
  48. package/template/sources/api/src/index.ts +2 -2
  49. package/template/sources/api/src/types.bare.ts +5 -0
  50. package/template/sources/common/package.json +6 -6
  51. package/template/sources/common/src/consts.bare.ts +8 -0
  52. package/template/sources/common/src/consts.ts +0 -13
  53. package/template/sources/common/src/entrypoints.bare.ts +14 -0
  54. package/template/sources/common/src/entrypoints.ts +60 -0
  55. package/template/sources/common/src/index.bare.ts +3 -0
  56. package/template/sources/common/src/index.ts +1 -1
  57. package/template/sources/common/src/schemas.ts +7 -7
  58. package/template/sources/web/index.html +3 -1
  59. package/template/sources/web/package.json +13 -11
  60. package/template/sources/web/src/components/ui/dropdown-menu.tsx +257 -0
  61. package/template/sources/web/src/components/ui/navigation-menu.tsx +169 -0
  62. package/template/sources/web/src/context.bare.ts +13 -0
  63. package/template/sources/web/src/context.ts +14 -2
  64. package/template/sources/web/src/entrypoints.bare.ts +13 -0
  65. package/template/sources/web/src/entrypoints.ts +16 -0
  66. package/template/sources/web/src/index.css +7 -0
  67. package/template/sources/web/src/index.tsx +2 -2
  68. package/template/sources/web/src/layout/main.tsx +16 -19
  69. package/template/sources/web/src/nav.bare.ts +23 -0
  70. package/template/sources/web/src/nav.ts +30 -0
  71. package/template/sources/web/src/screens/about.tsx +19 -0
  72. package/template/sources/web/src/screens/home.bare.tsx +17 -0
  73. package/template/sources/web/src/screens/session.tsx +28 -14
  74. package/template/sources/web/src/vite-env.d.ts +1 -0
  75. package/template/sources/api/src/modules.ts +0 -11
  76. package/template/sources/common/src/modules.ts +0 -26
  77. package/template/sources/web/src/components/nav/main.tsx +0 -15
  78. package/template/sources/web/src/modules.ts +0 -20
@@ -1,13 +1,14 @@
1
- import { handleParams } from '@owlmeans/server-app'
2
- import type { ItemParams, SessionItem } from '__APP_SLUG__-common'
1
+ import { handlers } from '@owlmeans/server-app'
2
+ import { session, type SessionItem } from '__APP_SLUG__-common'
3
3
  import { SESSION_ITEMS } from '../../consts.js'
4
4
  import type { Context } from '../../types.js'
5
5
 
6
- export const remove = handleParams<ItemParams>(async (params, context) => {
7
- const ctx = context as Context
8
- const resource = ctx.getStaticResource<SessionItem>(SESSION_ITEMS)
6
+ const handle = handlers<Context>()
9
7
 
10
- const existing = await resource.load<SessionItem>(params.id)
8
+ export const remove = handle.params(session.remove, async (params, context) => {
9
+ const resource = context.getStaticResource<SessionItem>(SESSION_ITEMS)
10
+
11
+ const existing = await resource.load(params.id)
11
12
  // Only remove the item if it belongs to the requesting session.
12
13
  if (existing == null || existing.sessionId !== params.sid) {
13
14
  return { removed: false }
@@ -0,0 +1,11 @@
1
+ import { makeContext as makeBasicContext } from '@owlmeans/server-app'
2
+ import type { Config, Context } from './types.js'
3
+
4
+ /**
5
+ * Where the app's resources are registered. `@owlmeans/static-resource` is already a dependency,
6
+ * so `appendStaticResource<C, T>(context, ALIAS)` gives you an in-memory store with no database
7
+ * behind it; a mongo/postgres resource takes its place once the data has to outlive the process.
8
+ * Whatever you append here must also widen `Context` in `types.ts`, or the getter will not exist.
9
+ */
10
+ export const makeContext = <C extends Config, T extends Context<C>>(cfg: C): T =>
11
+ makeBasicContext<C, T>(cfg, true)
@@ -0,0 +1,4 @@
1
+ import { entrypoints } from '@owlmeans/server-app'
2
+
3
+ // The bare shell has no API declarations yet. Bind new protocols here as they are added.
4
+ export const appBindings = [...entrypoints]
@@ -0,0 +1,13 @@
1
+ import { entrypoints } from '@owlmeans/server-app'
2
+ import { bind } from '@owlmeans/server-entrypoint'
3
+ import { appProtocols } from '__APP_SLUG__-common'
4
+ import * as handlers from './app/session/index.js'
5
+
6
+ /** Local server bindings for the shared session protocol tree. */
7
+ export const appBindings = [
8
+ ...entrypoints,
9
+ bind(appProtocols.api.session.base),
10
+ bind(appProtocols.api.session.list, handlers.list),
11
+ bind(appProtocols.api.session.add, handlers.add),
12
+ bind(appProtocols.api.session.remove, handlers.remove),
13
+ ]
@@ -1,9 +1,9 @@
1
1
  import { main } from '@owlmeans/server-app'
2
2
  import config from './config.js'
3
3
  import { makeContext } from './context.js'
4
- import { appModules } from './modules.js'
4
+ import { appBindings } from './entrypoints.js'
5
5
  import type { Config, Context } from './types.js'
6
6
 
7
7
  const context = makeContext<Config, Context>(config)
8
8
 
9
- main<{}, Config, Context>(context, appModules)
9
+ main<{}, Config, Context>(context, appBindings)
@@ -0,0 +1,5 @@
1
+ import type { AppConfig, AppContext } from '@owlmeans/server-app'
2
+
3
+ export interface Config extends AppConfig {}
4
+
5
+ export interface Context<C extends Config = Config> extends AppContext<C> {}
@@ -19,15 +19,15 @@
19
19
  "typecheck": "tsc -b"
20
20
  },
21
21
  "dependencies": {
22
- "@owlmeans/config": "^0.1.16",
23
- "@owlmeans/entrypoint": "^0.1.16",
24
- "@owlmeans/error": "^0.1.16",
25
- "@owlmeans/resource": "^0.1.16",
26
- "@owlmeans/route": "^0.1.16",
22
+ "@owlmeans/config": "^0.1.18-rc.33",
23
+ "@owlmeans/entrypoint": "^0.1.18-rc.32",
24
+ "@owlmeans/error": "^0.1.18-rc.31",
25
+ "@owlmeans/resource": "^0.1.18-rc.31",
26
+ "@owlmeans/route": "^0.1.18-rc.30",
27
27
  "ajv": "^8.17.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@owlmeans/dep-config": "^0.1.16",
30
+ "@owlmeans/dep-config": "^0.1.18-rc.6",
31
31
  "@types/node": "^24.10.1",
32
32
  "typescript": "^7.0.2"
33
33
  }
@@ -0,0 +1,8 @@
1
+ /** Service aliases shared between web and api. */
2
+ export const APP = '__APP_SLUG__'
3
+ export const APP_WEB = '__APP_SLUG__-web'
4
+ export const APP_API = '__APP_SLUG__-api'
5
+
6
+ /** Local development ports. */
7
+ export const WEB_PORT = 3001
8
+ export const API_PORT = 3000
@@ -6,16 +6,3 @@ export const APP_API = '__APP_SLUG__-api'
6
6
  /** Local development ports. */
7
7
  export const WEB_PORT = 3001
8
8
  export const API_PORT = 3000
9
-
10
- /** Backend (API) entrypoint identifiers. */
11
- export const session = {
12
- base: '__APP_SLUG__:api:session',
13
- list: '__APP_SLUG__:api:session:list',
14
- add: '__APP_SLUG__:api:session:add',
15
- remove: '__APP_SLUG__:api:session:remove',
16
- }
17
-
18
- /** Frontend (web) entrypoint identifiers. */
19
- export const web = {
20
- session: '__APP_SLUG__:web:session',
21
- }
@@ -0,0 +1,14 @@
1
+ import { openProtocol } from '@owlmeans/entrypoint'
2
+ import { BASE, HOME } from '@owlmeans/context'
3
+ import { frontend, route } from '@owlmeans/route'
4
+
5
+ const webBase = openProtocol(route(BASE, '/', frontend()))
6
+
7
+ /** The shared immutable protocol tree. Add API declarations below `api` as the shell grows. */
8
+ export const appProtocols = {
9
+ api: {},
10
+ web: {
11
+ base: webBase,
12
+ home: openProtocol(route(HOME, '/', frontend({ default: true, parent: webBase }))),
13
+ },
14
+ }
@@ -0,0 +1,60 @@
1
+ import { contract, openProtocol, protocol, typed } from '@owlmeans/entrypoint'
2
+ import { route, RouteMethod, frontend } from '@owlmeans/route'
3
+ import { AddItemSchema, ItemParamsSchema, SessionParamsSchema } from './schemas.js'
4
+ import type { SessionItem } from './types.js'
5
+
6
+ const aliases = {
7
+ session: {
8
+ base: '__APP_SLUG__:api:session',
9
+ list: '__APP_SLUG__:api:session:list',
10
+ add: '__APP_SLUG__:api:session:add',
11
+ remove: '__APP_SLUG__:api:session:remove',
12
+ },
13
+ web: {
14
+ base: '__APP_SLUG__:web:base',
15
+ home: '__APP_SLUG__:web:home',
16
+ session: '__APP_SLUG__:web:session',
17
+ about: '__APP_SLUG__:web:about',
18
+ },
19
+ }
20
+
21
+ const sessionBase = protocol(route(aliases.session.base, '/session'), contract())
22
+ const webBase = openProtocol(route(aliases.web.base, '/', frontend()))
23
+
24
+ /**
25
+ * Shared entrypoint declarations. The api materializes these with handlers; the web
26
+ * materializes them with screen components and calls them. Routes resolve under the
27
+ * api service `base` (`/api`), so e.g. `session.list` → `GET /api/session/:sid/items`.
28
+ */
29
+ export const session = {
30
+ base: sessionBase,
31
+ list: protocol(
32
+ route(aliases.session.list, '/:sid/items', { parent: sessionBase, method: RouteMethod.GET }),
33
+ contract.request({ params: SessionParamsSchema }, typed<SessionItem[]>()),
34
+ ),
35
+ add: protocol(
36
+ route(aliases.session.add, '/:sid/items', { parent: sessionBase, method: RouteMethod.POST }),
37
+ contract.request({
38
+ params: SessionParamsSchema,
39
+ body: AddItemSchema,
40
+ }, typed<SessionItem>()),
41
+ ),
42
+ remove: protocol(
43
+ route(aliases.session.remove, '/:sid/items/:id', { parent: sessionBase, method: RouteMethod.DELETE }),
44
+ contract.request({ params: ItemParamsSchema }, typed<{ removed: boolean }>()),
45
+ ),
46
+ }
47
+
48
+ /** Frontend routes are protocol declarations too; their renderer is bound by the web project. */
49
+ export const web = {
50
+ base: webBase,
51
+ home: openProtocol(route(aliases.web.home, '/', frontend({ default: true, parent: webBase }))),
52
+ session: openProtocol(route(aliases.web.session, '/session', frontend({ parent: webBase }))),
53
+ about: openProtocol(route(aliases.web.about, '/about', frontend({ parent: webBase }))),
54
+ }
55
+
56
+ /** The shared immutable protocol tree. Runtime packages bind their own local handlers and screens. */
57
+ export const appProtocols = Object.freeze({
58
+ api: Object.freeze({ session }),
59
+ web: Object.freeze(web),
60
+ })
@@ -0,0 +1,3 @@
1
+ export * from './consts.js'
2
+ export * from './config.js'
3
+ export * from './entrypoints.js'
@@ -2,4 +2,4 @@ export * from './consts.js'
2
2
  export * from './types.js'
3
3
  export * from './schemas.js'
4
4
  export * from './config.js'
5
- export * from './modules.js'
5
+ export * from './entrypoints.js'
@@ -1,25 +1,25 @@
1
- import type { JSONSchemaType } from 'ajv'
1
+ import { schema } from '@owlmeans/entrypoint'
2
2
  import type { AddItemPayload, ItemParams, SessionParams } from './types.js'
3
3
 
4
- export const AddItemSchema: JSONSchemaType<AddItemPayload> = {
4
+ export const AddItemSchema = schema<AddItemPayload>({
5
5
  type: 'object',
6
6
  properties: {
7
7
  text: { type: 'string', minLength: 1, maxLength: 280 },
8
8
  },
9
9
  required: ['text'],
10
10
  additionalProperties: false,
11
- }
11
+ })
12
12
 
13
- export const SessionParamsSchema: JSONSchemaType<SessionParams> = {
13
+ export const SessionParamsSchema = schema<SessionParams>({
14
14
  type: 'object',
15
15
  properties: {
16
16
  sid: { type: 'string', minLength: 1 },
17
17
  },
18
18
  required: ['sid'],
19
19
  additionalProperties: false,
20
- }
20
+ })
21
21
 
22
- export const ItemParamsSchema: JSONSchemaType<ItemParams> = {
22
+ export const ItemParamsSchema = schema<ItemParams>({
23
23
  type: 'object',
24
24
  properties: {
25
25
  sid: { type: 'string', minLength: 1 },
@@ -27,4 +27,4 @@ export const ItemParamsSchema: JSONSchemaType<ItemParams> = {
27
27
  },
28
28
  required: ['sid', 'id'],
29
29
  additionalProperties: false,
30
- }
30
+ })
@@ -1,9 +1,11 @@
1
1
  <!doctype html>
2
- <html lang="en">
2
+ <html lang="__APP_LANG__">
3
3
 
4
4
  <head>
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <meta name="application-name" content="__APP_NAME__" />
8
+ <meta name="description" content="__APP_DESCRIPTION__" />
7
9
  <title>__APP_NAME__</title>
8
10
  </head>
9
11
 
@@ -11,19 +11,21 @@
11
11
  "preview": "vite preview"
12
12
  },
13
13
  "dependencies": {
14
- "@owlmeans/client": "^0.1.16",
15
- "@owlmeans/client-config": "^0.1.16",
16
- "@owlmeans/client-context": "^0.1.16",
17
- "@owlmeans/client-entrypoint": "^0.1.16",
18
- "@owlmeans/client-i18n": "^0.1.16",
19
- "@owlmeans/entrypoint": "^0.1.16",
20
- "@owlmeans/route": "^0.1.16",
21
- "@owlmeans/web-client": "^0.1.16",
22
- "@owlmeans/web-panel": "^0.1.16",
23
- "__APP_SLUG__-common": "workspace:^",
14
+ "@owlmeans/client": "^0.1.18-rc.36",
15
+ "@owlmeans/client-config": "^0.1.18-rc.33",
16
+ "@owlmeans/client-context": "^0.1.18-rc.34",
17
+ "@owlmeans/client-entrypoint": "^0.1.18-rc.33",
18
+ "@owlmeans/client-i18n": "^0.1.18-rc.35",
19
+ "@owlmeans/entrypoint": "^0.1.18-rc.32",
20
+ "@owlmeans/route": "^0.1.18-rc.30",
21
+ "@owlmeans/state": "^0.1.18-rc.30",
22
+ "@owlmeans/web-client": "^0.1.18-rc.45",
23
+ "@owlmeans/web-panel": "^0.1.18-rc.55",
24
24
  "@radix-ui/react-label": "^2.1.0",
25
+ "@radix-ui/react-navigation-menu": "^1.2.14",
25
26
  "@radix-ui/react-progress": "^1.1.0",
26
27
  "@radix-ui/react-slot": "^1.1.0",
28
+ "__APP_SLUG__-common": "workspace:^",
27
29
  "ajv": "^8.17.1",
28
30
  "class-variance-authority": "^0.7.0",
29
31
  "clsx": "^2.1.0",
@@ -37,7 +39,7 @@
37
39
  "tailwindcss": "^4.1.13"
38
40
  },
39
41
  "devDependencies": {
40
- "@owlmeans/dep-config": "^0.1.16",
42
+ "@owlmeans/dep-config": "^0.1.18-rc.6",
41
43
  "@tailwindcss/vite": "^4.1.13",
42
44
  "@types/react": "^19.2.17",
43
45
  "@types/react-dom": "^19.2.3",
@@ -0,0 +1,257 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
5
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ function DropdownMenu({
10
+ ...props
11
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
12
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
13
+ }
14
+
15
+ function DropdownMenuPortal({
16
+ ...props
17
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
18
+ return (
19
+ <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
20
+ )
21
+ }
22
+
23
+ function DropdownMenuTrigger({
24
+ ...props
25
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
26
+ return (
27
+ <DropdownMenuPrimitive.Trigger
28
+ data-slot="dropdown-menu-trigger"
29
+ {...props}
30
+ />
31
+ )
32
+ }
33
+
34
+ function DropdownMenuContent({
35
+ className,
36
+ sideOffset = 4,
37
+ ...props
38
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
39
+ return (
40
+ <DropdownMenuPrimitive.Portal>
41
+ <DropdownMenuPrimitive.Content
42
+ data-slot="dropdown-menu-content"
43
+ sideOffset={sideOffset}
44
+ className={cn(
45
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ </DropdownMenuPrimitive.Portal>
51
+ )
52
+ }
53
+
54
+ function DropdownMenuGroup({
55
+ ...props
56
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
57
+ return (
58
+ <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
59
+ )
60
+ }
61
+
62
+ function DropdownMenuItem({
63
+ className,
64
+ inset,
65
+ variant = "default",
66
+ ...props
67
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
68
+ inset?: boolean
69
+ variant?: "default" | "destructive"
70
+ }) {
71
+ return (
72
+ <DropdownMenuPrimitive.Item
73
+ data-slot="dropdown-menu-item"
74
+ data-inset={inset}
75
+ data-variant={variant}
76
+ className={cn(
77
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ )
83
+ }
84
+
85
+ function DropdownMenuCheckboxItem({
86
+ className,
87
+ children,
88
+ checked,
89
+ ...props
90
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
91
+ return (
92
+ <DropdownMenuPrimitive.CheckboxItem
93
+ data-slot="dropdown-menu-checkbox-item"
94
+ className={cn(
95
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
96
+ className
97
+ )}
98
+ checked={checked}
99
+ {...props}
100
+ >
101
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
102
+ <DropdownMenuPrimitive.ItemIndicator>
103
+ <CheckIcon className="size-4" />
104
+ </DropdownMenuPrimitive.ItemIndicator>
105
+ </span>
106
+ {children}
107
+ </DropdownMenuPrimitive.CheckboxItem>
108
+ )
109
+ }
110
+
111
+ function DropdownMenuRadioGroup({
112
+ ...props
113
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
114
+ return (
115
+ <DropdownMenuPrimitive.RadioGroup
116
+ data-slot="dropdown-menu-radio-group"
117
+ {...props}
118
+ />
119
+ )
120
+ }
121
+
122
+ function DropdownMenuRadioItem({
123
+ className,
124
+ children,
125
+ ...props
126
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
127
+ return (
128
+ <DropdownMenuPrimitive.RadioItem
129
+ data-slot="dropdown-menu-radio-item"
130
+ className={cn(
131
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
132
+ className
133
+ )}
134
+ {...props}
135
+ >
136
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
137
+ <DropdownMenuPrimitive.ItemIndicator>
138
+ <CircleIcon className="size-2 fill-current" />
139
+ </DropdownMenuPrimitive.ItemIndicator>
140
+ </span>
141
+ {children}
142
+ </DropdownMenuPrimitive.RadioItem>
143
+ )
144
+ }
145
+
146
+ function DropdownMenuLabel({
147
+ className,
148
+ inset,
149
+ ...props
150
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
151
+ inset?: boolean
152
+ }) {
153
+ return (
154
+ <DropdownMenuPrimitive.Label
155
+ data-slot="dropdown-menu-label"
156
+ data-inset={inset}
157
+ className={cn(
158
+ "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
159
+ className
160
+ )}
161
+ {...props}
162
+ />
163
+ )
164
+ }
165
+
166
+ function DropdownMenuSeparator({
167
+ className,
168
+ ...props
169
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
170
+ return (
171
+ <DropdownMenuPrimitive.Separator
172
+ data-slot="dropdown-menu-separator"
173
+ className={cn("bg-border -mx-1 my-1 h-px", className)}
174
+ {...props}
175
+ />
176
+ )
177
+ }
178
+
179
+ function DropdownMenuShortcut({
180
+ className,
181
+ ...props
182
+ }: React.ComponentProps<"span">) {
183
+ return (
184
+ <span
185
+ data-slot="dropdown-menu-shortcut"
186
+ className={cn(
187
+ "text-muted-foreground ml-auto text-xs tracking-widest",
188
+ className
189
+ )}
190
+ {...props}
191
+ />
192
+ )
193
+ }
194
+
195
+ function DropdownMenuSub({
196
+ ...props
197
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
198
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
199
+ }
200
+
201
+ function DropdownMenuSubTrigger({
202
+ className,
203
+ inset,
204
+ children,
205
+ ...props
206
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
207
+ inset?: boolean
208
+ }) {
209
+ return (
210
+ <DropdownMenuPrimitive.SubTrigger
211
+ data-slot="dropdown-menu-sub-trigger"
212
+ data-inset={inset}
213
+ className={cn(
214
+ "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
215
+ className
216
+ )}
217
+ {...props}
218
+ >
219
+ {children}
220
+ <ChevronRightIcon className="ml-auto size-4" />
221
+ </DropdownMenuPrimitive.SubTrigger>
222
+ )
223
+ }
224
+
225
+ function DropdownMenuSubContent({
226
+ className,
227
+ ...props
228
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
229
+ return (
230
+ <DropdownMenuPrimitive.SubContent
231
+ data-slot="dropdown-menu-sub-content"
232
+ className={cn(
233
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
234
+ className
235
+ )}
236
+ {...props}
237
+ />
238
+ )
239
+ }
240
+
241
+ export {
242
+ DropdownMenu,
243
+ DropdownMenuPortal,
244
+ DropdownMenuTrigger,
245
+ DropdownMenuContent,
246
+ DropdownMenuGroup,
247
+ DropdownMenuLabel,
248
+ DropdownMenuItem,
249
+ DropdownMenuCheckboxItem,
250
+ DropdownMenuRadioGroup,
251
+ DropdownMenuRadioItem,
252
+ DropdownMenuSeparator,
253
+ DropdownMenuShortcut,
254
+ DropdownMenuSub,
255
+ DropdownMenuSubTrigger,
256
+ DropdownMenuSubContent,
257
+ }