aeon-ui-engine 1.1.0 → 1.3.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 (33) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/CONSUMER.md +45 -0
  3. package/package.json +1 -1
  4. package/packages/core/dist/index.d.ts +88 -8
  5. package/packages/core/dist/index.js +123 -0
  6. package/packages/core/src/anatomy.ts +38 -0
  7. package/packages/core/src/brand-theme.ts +183 -0
  8. package/packages/core/src/index.ts +1 -0
  9. package/packages/panda/aeon.css +1 -0
  10. package/packages/panda/src/theme/consumer-shell.css +250 -0
  11. package/packages/panda/src/theme/electron.css +114 -0
  12. package/packages/primitives/dist/chunk-4NOKRUSG.js +81 -0
  13. package/packages/primitives/dist/index.d.ts +1 -0
  14. package/packages/primitives/dist/index.js +16 -6
  15. package/packages/primitives/dist/machines/app-nav.d.ts +96 -0
  16. package/packages/primitives/dist/machines/app-nav.js +12 -0
  17. package/packages/primitives/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  18. package/packages/primitives/src/__tests__/app-nav.test.ts +30 -0
  19. package/packages/primitives/src/index.ts +1 -0
  20. package/packages/primitives/src/machines/app-nav.ts +107 -0
  21. package/packages/react/dist/index.d.ts +135 -3
  22. package/packages/react/dist/index.js +1126 -720
  23. package/packages/react/src/app-nav/index.tsx +249 -0
  24. package/packages/react/src/avatar/index.tsx +4 -1
  25. package/packages/react/src/hooks/use-fit-text.ts +59 -0
  26. package/packages/react/src/index.ts +4 -0
  27. package/packages/react/src/prompt/index.tsx +161 -0
  28. package/packages/react/src/status-banner/index.tsx +84 -0
  29. package/packages/ui/src/app-nav.tsx +2 -0
  30. package/packages/ui/src/index.ts +4 -0
  31. package/packages/ui/src/prompt.tsx +29 -0
  32. package/packages/ui/src/status-banner.tsx +1 -0
  33. package/scripts/vite-aliases.mjs +8 -0
@@ -0,0 +1,249 @@
1
+ import {
2
+ appNavAnatomy,
3
+ partAttrs,
4
+ scopeAttrs,
5
+ } from '@aeon-ui/core'
6
+ import {
7
+ appNavChild,
8
+ appNavMachine,
9
+ appNavStateAttr,
10
+ type AppNavChild,
11
+ type AppNavContext,
12
+ } from '@aeon-ui/primitives'
13
+ import {
14
+ createContext,
15
+ forwardRef,
16
+ useContext,
17
+ useMemo,
18
+ type ButtonHTMLAttributes,
19
+ type HTMLAttributes,
20
+ type ReactNode,
21
+ } from 'react'
22
+ import { useAeonMachine } from '../hooks/use-aeon-machine.js'
23
+ import { mergeProps } from '../utils/merge-props.js'
24
+
25
+ export type { AppNavChild, AppNavContext }
26
+
27
+ interface AppNavContextValue {
28
+ section: string
29
+ stack: AppNavChild[]
30
+ child: AppNavChild | null
31
+ stateAttr: string
32
+ send: ReturnType<typeof useAeonMachine<typeof appNavMachine>>[1]
33
+ setSection: (section: string) => void
34
+ push: (child: AppNavChild) => void
35
+ replace: (child: AppNavChild) => void
36
+ pop: () => void
37
+ popTo: (id: string) => void
38
+ clear: () => void
39
+ }
40
+
41
+ const AppNavCtx = createContext<AppNavContextValue | null>(null)
42
+
43
+ export function useAppNav() {
44
+ const ctx = useContext(AppNavCtx)
45
+ if (!ctx) throw new Error('AppNav parts must be used within AppNav.Root')
46
+ return ctx
47
+ }
48
+
49
+ /** Use the machine without the compound tree. */
50
+ export function useAppNavMachine(input?: { section?: string; stack?: AppNavChild[] }) {
51
+ const [snapshot, send] = useAeonMachine(appNavMachine, {
52
+ input: { section: input?.section ?? 'home', stack: input?.stack ?? [] },
53
+ })
54
+ const section = snapshot.context.section
55
+ const stack = snapshot.context.stack
56
+ const child = appNavChild(snapshot.context)
57
+ const stateAttr = appNavStateAttr(snapshot.context)
58
+
59
+ return useMemo(
60
+ () => ({
61
+ section,
62
+ stack,
63
+ child,
64
+ stateAttr,
65
+ send,
66
+ setSection: (next: string) => send({ type: 'SET_SECTION', section: next }),
67
+ push: (next: AppNavChild) => send({ type: 'PUSH', child: next }),
68
+ replace: (next: AppNavChild) => send({ type: 'REPLACE', child: next }),
69
+ pop: () => send({ type: 'POP' }),
70
+ popTo: (id: string) => send({ type: 'POP_TO', id }),
71
+ clear: () => send({ type: 'CLEAR' }),
72
+ reset: (next: string) => send({ type: 'RESET', section: next }),
73
+ }),
74
+ [section, stack, child, stateAttr, send],
75
+ )
76
+ }
77
+
78
+ export interface AppNavRootProps extends HTMLAttributes<HTMLDivElement> {
79
+ defaultSection?: string
80
+ children?: ReactNode
81
+ }
82
+
83
+ const Root = forwardRef<HTMLDivElement, AppNavRootProps>(function AppNavRoot(
84
+ { defaultSection = 'home', children, ...rest },
85
+ ref,
86
+ ) {
87
+ const nav = useAppNavMachine({ section: defaultSection })
88
+
89
+ return (
90
+ <AppNavCtx.Provider value={nav}>
91
+ <div
92
+ ref={ref}
93
+ {...mergeProps(
94
+ scopeAttrs(appNavAnatomy.scope, appNavAnatomy.root, { state: nav.stateAttr }),
95
+ rest,
96
+ )}
97
+ >
98
+ {children}
99
+ </div>
100
+ </AppNavCtx.Provider>
101
+ )
102
+ })
103
+
104
+ const Rail = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function AppNavRail(props, ref) {
105
+ const { stateAttr } = useAppNav()
106
+ return (
107
+ <nav
108
+ ref={ref as never}
109
+ {...mergeProps(partAttrs(appNavAnatomy.scope, appNavAnatomy.rail, { state: stateAttr }), props)}
110
+ />
111
+ )
112
+ })
113
+
114
+ export interface AppNavSectionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
115
+ value: string
116
+ }
117
+
118
+ const Section = forwardRef<HTMLButtonElement, AppNavSectionProps>(function AppNavSection(
119
+ { value, onClick, ...rest },
120
+ ref,
121
+ ) {
122
+ const { section, child, setSection } = useAppNav()
123
+ const isActive = section === value && !child
124
+
125
+ return (
126
+ <button
127
+ ref={ref}
128
+ type="button"
129
+ aria-current={isActive ? 'page' : undefined}
130
+ data-aeon-value={value}
131
+ onClick={(e) => {
132
+ onClick?.(e)
133
+ if (e.defaultPrevented) return
134
+ setSection(value)
135
+ }}
136
+ {...mergeProps(
137
+ partAttrs(appNavAnatomy.scope, appNavAnatomy.section, {
138
+ state: section === value ? (child ? 'section-active' : 'active') : 'inactive',
139
+ }),
140
+ rest,
141
+ )}
142
+ />
143
+ )
144
+ })
145
+
146
+ const Stage = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(function AppNavStage(
147
+ props,
148
+ ref,
149
+ ) {
150
+ const { stateAttr } = useAppNav()
151
+ return (
152
+ <div
153
+ ref={ref}
154
+ {...mergeProps(partAttrs(appNavAnatomy.scope, appNavAnatomy.stage, { state: stateAttr }), props)}
155
+ />
156
+ )
157
+ })
158
+
159
+ export interface AppNavBreadcrumbProps extends HTMLAttributes<HTMLElement> {
160
+ /** Labels for section + each stack entry (length = 1 + stack.length). */
161
+ labels?: string[]
162
+ }
163
+
164
+ const Breadcrumb = forwardRef<HTMLElement, AppNavBreadcrumbProps>(function AppNavBreadcrumb(
165
+ { labels, ...rest },
166
+ ref,
167
+ ) {
168
+ const { section, stack, setSection, popTo, clear, stateAttr } = useAppNav()
169
+ const crumbs = [
170
+ { id: section, label: labels?.[0] ?? section, kind: 'section' as const },
171
+ ...stack.map((entry, i) => ({
172
+ id: entry.id,
173
+ label: labels?.[i + 1] ?? entry.type,
174
+ kind: 'child' as const,
175
+ })),
176
+ ]
177
+
178
+ return (
179
+ <nav
180
+ ref={ref as never}
181
+ aria-label="Breadcrumb"
182
+ {...mergeProps(
183
+ partAttrs(appNavAnatomy.scope, appNavAnatomy.breadcrumb, { state: stateAttr }),
184
+ rest,
185
+ )}
186
+ >
187
+ {crumbs.map((crumb, index) => {
188
+ const last = index === crumbs.length - 1
189
+ return (
190
+ <button
191
+ key={`${crumb.kind}:${crumb.id}`}
192
+ type="button"
193
+ disabled={last}
194
+ {...partAttrs(appNavAnatomy.scope, appNavAnatomy.crumb, {
195
+ state: last ? 'current' : 'ancestor',
196
+ })}
197
+ onClick={() => {
198
+ if (crumb.kind === 'section') {
199
+ clear()
200
+ setSection(crumb.id)
201
+ } else {
202
+ popTo(crumb.id)
203
+ }
204
+ }}
205
+ >
206
+ {crumb.label}
207
+ </button>
208
+ )
209
+ })}
210
+ </nav>
211
+ )
212
+ })
213
+
214
+ const Back = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
215
+ function AppNavBack({ onClick, children = 'Back', ...rest }, ref) {
216
+ const { child, pop, stateAttr } = useAppNav()
217
+ if (!child) return null
218
+ return (
219
+ <button
220
+ ref={ref}
221
+ type="button"
222
+ onClick={(e) => {
223
+ onClick?.(e)
224
+ if (e.defaultPrevented) return
225
+ pop()
226
+ }}
227
+ {...mergeProps(
228
+ partAttrs(appNavAnatomy.scope, appNavAnatomy.back, { state: stateAttr }),
229
+ rest,
230
+ )}
231
+ >
232
+ {children}
233
+ </button>
234
+ )
235
+ },
236
+ )
237
+
238
+ /**
239
+ * AppNav — section rail + detail stack.
240
+ * Machine: SET_SECTION / PUSH / POP / CLEAR. UI = f(section, stack).
241
+ */
242
+ export const AppNav = {
243
+ Root,
244
+ Rail,
245
+ Section,
246
+ Stage,
247
+ Breadcrumb,
248
+ Back,
249
+ }
@@ -47,7 +47,10 @@ const Root = forwardRef<HTMLSpanElement, AvatarRootProps>(function AvatarRoot(
47
47
  ref={ref}
48
48
  className={className}
49
49
  {...mergeProps(
50
- partAttrs(avatarAnatomy.scope, avatarAnatomy.root, { state: status }),
50
+ partAttrs(avatarAnatomy.scope, avatarAnatomy.root, {
51
+ // `ready` alias keeps product CSS friendly; `loaded` stays for existing recipes.
52
+ state: status === 'loaded' ? 'loaded ready' : status,
53
+ }),
51
54
  rest,
52
55
  )}
53
56
  >
@@ -0,0 +1,59 @@
1
+ import { useLayoutEffect, type RefObject } from 'react'
2
+
3
+ export type FitTextOptions = {
4
+ maxPx?: number
5
+ minPx?: number
6
+ /** Re-run when this value changes (e.g. display string). */
7
+ watch?: unknown
8
+ }
9
+
10
+ /**
11
+ * Shrink font-size (then scale) so `contentRef` fits inside `slotRef`
12
+ * without expanding parent layout. Universal for balance rows, titles, tickers.
13
+ */
14
+ export function useFitText(
15
+ slotRef: RefObject<HTMLElement | null>,
16
+ contentRef: RefObject<HTMLElement | null>,
17
+ opts: FitTextOptions = {},
18
+ ) {
19
+ const maxPx = opts.maxPx ?? 28
20
+ const minPx = opts.minPx ?? 8
21
+ const watch = opts.watch
22
+
23
+ useLayoutEffect(() => {
24
+ const slot = slotRef.current
25
+ const content = contentRef.current
26
+ if (!slot || !content) return
27
+
28
+ const fit = () => {
29
+ const available = slot.clientWidth
30
+ if (available <= 0) return
31
+
32
+ content.style.transform = ''
33
+ content.style.transformOrigin = ''
34
+ content.style.fontSize = `${maxPx}px`
35
+
36
+ let size = maxPx
37
+ while (size > minPx && content.scrollWidth > available + 0.5) {
38
+ size -= 0.5
39
+ content.style.fontSize = `${size}px`
40
+ }
41
+
42
+ if (content.scrollWidth > available + 0.5) {
43
+ const scale = Math.max(0.35, available / content.scrollWidth)
44
+ content.style.transformOrigin = 'center center'
45
+ content.style.transform = `scale(${scale})`
46
+ }
47
+ }
48
+
49
+ fit()
50
+ const ro = new ResizeObserver(fit)
51
+ ro.observe(slot)
52
+ return () => {
53
+ ro.disconnect()
54
+ content.style.fontSize = ''
55
+ content.style.transform = ''
56
+ content.style.transformOrigin = ''
57
+ }
58
+ }, [slotRef, contentRef, maxPx, minPx, watch])
59
+ }
@@ -2,6 +2,8 @@ export * from './button/index.js'
2
2
  export * from './switch/index.js'
3
3
  export * from './checkbox/index.js'
4
4
  export * from './dialog/index.js'
5
+ export * from './prompt/index.js'
6
+ export * from './status-banner/index.js'
5
7
  export * from './tabs/index.js'
6
8
  export * from './separator/index.js'
7
9
  export * from './progress/index.js'
@@ -31,8 +33,10 @@ export * from './profile-header/index.js'
31
33
  export * from './bar/index.js'
32
34
  export * from './panel/index.js'
33
35
  export * from './app-shell/index.js'
36
+ export * from './app-nav/index.js'
34
37
  export * from './content/index.js'
35
38
  export * from './nav/index.js'
36
39
  export * from './sticky-bar/index.js'
37
40
  export { useAeonMachine } from './hooks/use-aeon-machine.js'
38
41
  export { useLayoutMode } from './hooks/use-layout-mode.js'
42
+ export { useFitText } from './hooks/use-fit-text.js'
@@ -0,0 +1,161 @@
1
+ import { partAttrs, promptAnatomy, scopeAttrs } from '@aeon-ui/core'
2
+ import {
3
+ createContext,
4
+ forwardRef,
5
+ useContext,
6
+ useMemo,
7
+ type ButtonHTMLAttributes,
8
+ type HTMLAttributes,
9
+ type ReactNode,
10
+ } from 'react'
11
+ import { Dialog } from '../dialog/index.js'
12
+ import { mergeProps } from '../utils/merge-props.js'
13
+
14
+ export type PromptStatus = 'pending' | 'confirming' | 'dismissed' | 'confirmed'
15
+
16
+ interface PromptContextValue {
17
+ status: PromptStatus
18
+ }
19
+
20
+ const PromptCtx = createContext<PromptContextValue | null>(null)
21
+
22
+ function usePromptCtx() {
23
+ const ctx = useContext(PromptCtx)
24
+ if (!ctx) throw new Error('Prompt parts must be used within Prompt.Root')
25
+ return ctx
26
+ }
27
+
28
+ export interface PromptRootProps {
29
+ open?: boolean
30
+ defaultOpen?: boolean
31
+ onOpenChange?: (open: boolean) => void
32
+ /** Projected onto data-aeon-state (default: pending when open). */
33
+ status?: PromptStatus
34
+ children?: ReactNode
35
+ className?: string
36
+ }
37
+
38
+ /**
39
+ * Prompt — confirm / permission / “restart to update” dialog.
40
+ * Composes Dialog (portal, focus trap, escape) with product-facing parts.
41
+ */
42
+ const Root = forwardRef<HTMLDivElement, PromptRootProps>(function PromptRoot(
43
+ { status = 'pending', children, className, ...dialogProps },
44
+ ref,
45
+ ) {
46
+ const value = useMemo(() => ({ status }), [status])
47
+ return (
48
+ <PromptCtx.Provider value={value}>
49
+ <Dialog.Root {...dialogProps}>
50
+ <div
51
+ ref={ref}
52
+ className={className}
53
+ {...scopeAttrs(promptAnatomy.scope, promptAnatomy.root, { state: status })}
54
+ >
55
+ {children}
56
+ </div>
57
+ </Dialog.Root>
58
+ </PromptCtx.Provider>
59
+ )
60
+ })
61
+
62
+ const Eyebrow = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(
63
+ function PromptEyebrow(props, ref) {
64
+ const { status } = usePromptCtx()
65
+ return (
66
+ <p
67
+ ref={ref}
68
+ {...mergeProps(partAttrs(promptAnatomy.scope, promptAnatomy.eyebrow, { state: status }), props)}
69
+ />
70
+ )
71
+ },
72
+ )
73
+
74
+ const Meta = forwardRef<HTMLDListElement, HTMLAttributes<HTMLDListElement>>(function PromptMeta(
75
+ props,
76
+ ref,
77
+ ) {
78
+ const { status } = usePromptCtx()
79
+ return (
80
+ <dl
81
+ ref={ref}
82
+ {...mergeProps(partAttrs(promptAnatomy.scope, promptAnatomy.meta, { state: status }), props)}
83
+ />
84
+ )
85
+ })
86
+
87
+ const Amount = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(function PromptAmount(
88
+ props,
89
+ ref,
90
+ ) {
91
+ const { status } = usePromptCtx()
92
+ return (
93
+ <div
94
+ ref={ref}
95
+ {...mergeProps(partAttrs(promptAnatomy.scope, promptAnatomy.amount, { state: status }), props)}
96
+ />
97
+ )
98
+ })
99
+
100
+ const Actions = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(function PromptActions(
101
+ props,
102
+ ref,
103
+ ) {
104
+ const { status } = usePromptCtx()
105
+ return (
106
+ <div
107
+ ref={ref}
108
+ {...mergeProps(partAttrs(promptAnatomy.scope, promptAnatomy.actions, { state: status }), props)}
109
+ />
110
+ )
111
+ })
112
+
113
+ const Primary = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
114
+ function PromptPrimary(props, ref) {
115
+ const { status } = usePromptCtx()
116
+ return (
117
+ <button
118
+ ref={ref}
119
+ type="button"
120
+ {...mergeProps(
121
+ partAttrs(promptAnatomy.scope, promptAnatomy.primary, { state: status }),
122
+ props,
123
+ )}
124
+ />
125
+ )
126
+ },
127
+ )
128
+
129
+ const Secondary = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
130
+ function PromptSecondary(props, ref) {
131
+ const { status } = usePromptCtx()
132
+ return (
133
+ <button
134
+ ref={ref}
135
+ type="button"
136
+ {...mergeProps(
137
+ partAttrs(promptAnatomy.scope, promptAnatomy.secondary, { state: status }),
138
+ props,
139
+ )}
140
+ />
141
+ )
142
+ },
143
+ )
144
+
145
+ export const Prompt = {
146
+ Root,
147
+ Trigger: Dialog.Trigger,
148
+ Portal: Dialog.Portal,
149
+ Backdrop: Dialog.Backdrop,
150
+ Positioner: Dialog.Positioner,
151
+ Content: Dialog.Content,
152
+ Title: Dialog.Title,
153
+ Description: Dialog.Description,
154
+ CloseTrigger: Dialog.CloseTrigger,
155
+ Eyebrow,
156
+ Meta,
157
+ Amount,
158
+ Actions,
159
+ Primary,
160
+ Secondary,
161
+ }
@@ -0,0 +1,84 @@
1
+ import { partAttrs, scopeAttrs, statusBannerAnatomy } from '@aeon-ui/core'
2
+ import { forwardRef, type ButtonHTMLAttributes, type HTMLAttributes, type ReactNode } from 'react'
3
+ import { mergeProps } from '../utils/merge-props.js'
4
+
5
+ export type StatusBannerTone = 'info' | 'success' | 'warning' | 'danger'
6
+
7
+ export interface StatusBannerRootProps extends HTMLAttributes<HTMLDivElement> {
8
+ tone?: StatusBannerTone
9
+ /** Machine-ish status string projected to data-aeon-state (e.g. ready, downloading). */
10
+ status?: string
11
+ children?: ReactNode
12
+ }
13
+
14
+ const Root = forwardRef<HTMLDivElement, StatusBannerRootProps>(function StatusBannerRoot(
15
+ { tone = 'info', status, children, ...rest },
16
+ ref,
17
+ ) {
18
+ const state = [tone, status].filter(Boolean).join(' ')
19
+ return (
20
+ <div
21
+ ref={ref}
22
+ role="status"
23
+ {...mergeProps(scopeAttrs(statusBannerAnatomy.scope, statusBannerAnatomy.root, { state }), rest)}
24
+ >
25
+ {children}
26
+ </div>
27
+ )
28
+ })
29
+
30
+ const Copy = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(function StatusBannerCopy(
31
+ props,
32
+ ref,
33
+ ) {
34
+ return <div ref={ref} {...mergeProps(partAttrs(statusBannerAnatomy.scope, statusBannerAnatomy.copy), props)} />
35
+ })
36
+
37
+ const Title = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function StatusBannerTitle(
38
+ props,
39
+ ref,
40
+ ) {
41
+ return (
42
+ <strong
43
+ ref={ref as never}
44
+ {...mergeProps(partAttrs(statusBannerAnatomy.scope, statusBannerAnatomy.title), props)}
45
+ />
46
+ )
47
+ })
48
+
49
+ const Body = forwardRef<HTMLSpanElement, HTMLAttributes<HTMLSpanElement>>(function StatusBannerBody(
50
+ props,
51
+ ref,
52
+ ) {
53
+ return (
54
+ <span ref={ref} {...mergeProps(partAttrs(statusBannerAnatomy.scope, statusBannerAnatomy.body), props)} />
55
+ )
56
+ })
57
+
58
+ const Actions = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(function StatusBannerActions(
59
+ props,
60
+ ref,
61
+ ) {
62
+ return (
63
+ <div
64
+ ref={ref}
65
+ {...mergeProps(partAttrs(statusBannerAnatomy.scope, statusBannerAnatomy.actions), props)}
66
+ />
67
+ )
68
+ })
69
+
70
+ const Action = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
71
+ function StatusBannerAction(props, ref) {
72
+ return <button ref={ref} type="button" {...props} />
73
+ },
74
+ )
75
+
76
+ /** Non-blocking top-of-app notice (updates, sync, offline). */
77
+ export const StatusBanner = {
78
+ Root,
79
+ Copy,
80
+ Title,
81
+ Body,
82
+ Actions,
83
+ Action,
84
+ }
@@ -0,0 +1,2 @@
1
+ export { AppNav, useAppNav, useAppNavMachine } from '@aeon-ui/react'
2
+ export type { AppNavChild, AppNavContext } from '@aeon-ui/react'
@@ -13,6 +13,10 @@ export { Field } from './field.js'
13
13
  export { Switch } from './switch.js'
14
14
  export { Checkbox } from './checkbox.js'
15
15
  export { Dialog } from './dialog.js'
16
+ export { Prompt } from './prompt.js'
17
+ export { StatusBanner } from './status-banner.js'
18
+ export { AppNav, useAppNav, useAppNavMachine } from './app-nav.js'
19
+ export type { AppNavChild, AppNavContext } from './app-nav.js'
16
20
  export { Tabs } from './tabs.js'
17
21
  export { Separator } from './separator.js'
18
22
  export { Progress } from './progress.js'
@@ -0,0 +1,29 @@
1
+ import { Prompt as Headless } from '@aeon-ui/react'
2
+ import type { ComponentProps } from 'react'
3
+ import { Dialog } from './dialog.js'
4
+ import { cn } from './cn.js'
5
+
6
+ /** Styled Prompt — Dialog recipes + prompt action parts. */
7
+ export const Prompt = {
8
+ Root: Headless.Root,
9
+ Trigger: Dialog.Trigger,
10
+ Portal: Dialog.Portal,
11
+ Backdrop: Dialog.Backdrop,
12
+ Positioner: Dialog.Positioner,
13
+ Content: Dialog.Content,
14
+ Title: Dialog.Title,
15
+ Description: Dialog.Description,
16
+ CloseTrigger: Dialog.CloseTrigger,
17
+ Eyebrow: ({ className, ...props }: ComponentProps<typeof Headless.Eyebrow>) => (
18
+ <Headless.Eyebrow className={cn(className)} {...props} />
19
+ ),
20
+ Meta: Headless.Meta,
21
+ Amount: Headless.Amount,
22
+ Actions: Headless.Actions,
23
+ Primary: ({ className, ...props }: ComponentProps<typeof Headless.Primary>) => (
24
+ <Headless.Primary className={cn(className)} {...props} />
25
+ ),
26
+ Secondary: ({ className, ...props }: ComponentProps<typeof Headless.Secondary>) => (
27
+ <Headless.Secondary className={cn(className)} {...props} />
28
+ ),
29
+ }
@@ -0,0 +1 @@
1
+ export { StatusBanner } from '@aeon-ui/react'
@@ -63,6 +63,14 @@ export function aeonUiViteAliases(opts = {}) {
63
63
  find: '@aeon-ui/panda/chrome.css',
64
64
  replacement: path.join(packages, 'panda/src/theme/chrome.css'),
65
65
  },
66
+ {
67
+ find: '@aeon-ui/panda/consumer-shell.css',
68
+ replacement: path.join(packages, 'panda/src/theme/consumer-shell.css'),
69
+ },
70
+ {
71
+ find: '@aeon-ui/panda/electron.css',
72
+ replacement: path.join(packages, 'panda/src/theme/electron.css'),
73
+ },
66
74
  {
67
75
  find: '@aeon-ui/panda/styled-system/css',
68
76
  replacement: path.join(packages, 'panda/styled-system/css/index.mjs'),