@easyops-cn/a2ui-react 0.0.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.
- package/.claude/commands/speckit.analyze.md +184 -0
- package/.claude/commands/speckit.checklist.md +294 -0
- package/.claude/commands/speckit.clarify.md +181 -0
- package/.claude/commands/speckit.constitution.md +82 -0
- package/.claude/commands/speckit.implement.md +135 -0
- package/.claude/commands/speckit.plan.md +89 -0
- package/.claude/commands/speckit.specify.md +256 -0
- package/.claude/commands/speckit.tasks.md +137 -0
- package/.claude/commands/speckit.taskstoissues.md +30 -0
- package/.github/workflows/deploy.yml +69 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc +7 -0
- package/.specify/memory/constitution.md +73 -0
- package/.specify/scripts/bash/check-prerequisites.sh +166 -0
- package/.specify/scripts/bash/common.sh +156 -0
- package/.specify/scripts/bash/create-new-feature.sh +297 -0
- package/.specify/scripts/bash/setup-plan.sh +61 -0
- package/.specify/scripts/bash/update-agent-context.sh +799 -0
- package/.specify/templates/agent-file-template.md +28 -0
- package/.specify/templates/checklist-template.md +40 -0
- package/.specify/templates/plan-template.md +105 -0
- package/.specify/templates/spec-template.md +115 -0
- package/.specify/templates/tasks-template.md +250 -0
- package/CLAUDE.md +105 -0
- package/CONTRIBUTING.md +97 -0
- package/README.md +126 -0
- package/components.json +21 -0
- package/eslint.config.js +25 -0
- package/netlify.toml +50 -0
- package/package.json +94 -0
- package/playground/README.md +75 -0
- package/playground/index.html +22 -0
- package/playground/package.json +32 -0
- package/playground/public/favicon.svg +8 -0
- package/playground/src/App.css +256 -0
- package/playground/src/App.tsx +115 -0
- package/playground/src/assets/react.svg +1 -0
- package/playground/src/components/ErrorDisplay.tsx +13 -0
- package/playground/src/components/ExampleSelector.tsx +64 -0
- package/playground/src/components/Header.tsx +47 -0
- package/playground/src/components/JsonEditor.tsx +32 -0
- package/playground/src/components/Preview.tsx +78 -0
- package/playground/src/components/ThemeToggle.tsx +19 -0
- package/playground/src/data/examples.ts +1571 -0
- package/playground/src/hooks/useTheme.ts +55 -0
- package/playground/src/index.css +220 -0
- package/playground/src/main.tsx +10 -0
- package/playground/tsconfig.app.json +34 -0
- package/playground/tsconfig.json +13 -0
- package/playground/tsconfig.node.json +26 -0
- package/playground/vite.config.ts +31 -0
- package/specs/001-a2ui-renderer/checklists/requirements.md +41 -0
- package/specs/001-a2ui-renderer/data-model.md +140 -0
- package/specs/001-a2ui-renderer/plan.md +123 -0
- package/specs/001-a2ui-renderer/quickstart.md +141 -0
- package/specs/001-a2ui-renderer/research.md +140 -0
- package/specs/001-a2ui-renderer/spec.md +165 -0
- package/specs/001-a2ui-renderer/tasks.md +310 -0
- package/specs/002-playground/checklists/requirements.md +37 -0
- package/specs/002-playground/contracts/components.md +120 -0
- package/specs/002-playground/data-model.md +149 -0
- package/specs/002-playground/plan.md +73 -0
- package/specs/002-playground/quickstart.md +158 -0
- package/specs/002-playground/research.md +117 -0
- package/specs/002-playground/spec.md +109 -0
- package/specs/002-playground/tasks.md +224 -0
- package/src/0.8/A2UIRender.test.tsx +793 -0
- package/src/0.8/A2UIRender.tsx +142 -0
- package/src/0.8/components/ComponentRenderer.test.tsx +373 -0
- package/src/0.8/components/ComponentRenderer.tsx +163 -0
- package/src/0.8/components/UnknownComponent.tsx +49 -0
- package/src/0.8/components/display/AudioPlayerComponent.tsx +37 -0
- package/src/0.8/components/display/DividerComponent.tsx +23 -0
- package/src/0.8/components/display/IconComponent.tsx +137 -0
- package/src/0.8/components/display/ImageComponent.tsx +57 -0
- package/src/0.8/components/display/TextComponent.tsx +56 -0
- package/src/0.8/components/display/VideoComponent.tsx +31 -0
- package/src/0.8/components/display/display.test.tsx +660 -0
- package/src/0.8/components/display/index.ts +10 -0
- package/src/0.8/components/index.ts +14 -0
- package/src/0.8/components/interactive/ButtonComponent.tsx +44 -0
- package/src/0.8/components/interactive/CheckBoxComponent.tsx +45 -0
- package/src/0.8/components/interactive/DateTimeInputComponent.tsx +176 -0
- package/src/0.8/components/interactive/MultipleChoiceComponent.tsx +157 -0
- package/src/0.8/components/interactive/SliderComponent.tsx +53 -0
- package/src/0.8/components/interactive/TextFieldComponent.tsx +65 -0
- package/src/0.8/components/interactive/index.ts +10 -0
- package/src/0.8/components/interactive/interactive.test.tsx +618 -0
- package/src/0.8/components/layout/CardComponent.tsx +30 -0
- package/src/0.8/components/layout/ColumnComponent.tsx +93 -0
- package/src/0.8/components/layout/ListComponent.tsx +81 -0
- package/src/0.8/components/layout/ModalComponent.tsx +41 -0
- package/src/0.8/components/layout/RowComponent.tsx +94 -0
- package/src/0.8/components/layout/TabsComponent.tsx +59 -0
- package/src/0.8/components/layout/index.ts +10 -0
- package/src/0.8/components/layout/layout.test.tsx +558 -0
- package/src/0.8/contexts/A2UIProvider.test.tsx +226 -0
- package/src/0.8/contexts/A2UIProvider.tsx +54 -0
- package/src/0.8/contexts/ActionContext.test.tsx +242 -0
- package/src/0.8/contexts/ActionContext.tsx +105 -0
- package/src/0.8/contexts/ComponentsMapContext.tsx +125 -0
- package/src/0.8/contexts/DataModelContext.test.tsx +335 -0
- package/src/0.8/contexts/DataModelContext.tsx +184 -0
- package/src/0.8/contexts/SurfaceContext.test.tsx +339 -0
- package/src/0.8/contexts/SurfaceContext.tsx +197 -0
- package/src/0.8/hooks/useA2UIMessageHandler.test.tsx +399 -0
- package/src/0.8/hooks/useA2UIMessageHandler.ts +123 -0
- package/src/0.8/hooks/useComponent.test.tsx +148 -0
- package/src/0.8/hooks/useComponent.ts +39 -0
- package/src/0.8/hooks/useDataBinding.test.tsx +334 -0
- package/src/0.8/hooks/useDataBinding.ts +99 -0
- package/src/0.8/hooks/useDispatchAction.test.tsx +83 -0
- package/src/0.8/hooks/useDispatchAction.ts +35 -0
- package/src/0.8/hooks/useSurface.test.tsx +114 -0
- package/src/0.8/hooks/useSurface.ts +34 -0
- package/src/0.8/index.ts +38 -0
- package/src/0.8/schemas/client_to_server.json +50 -0
- package/src/0.8/schemas/server_to_client.json +148 -0
- package/src/0.8/schemas/standard_catalog_definition.json +661 -0
- package/src/0.8/types/index.ts +448 -0
- package/src/0.8/utils/dataBinding.test.ts +443 -0
- package/src/0.8/utils/dataBinding.ts +212 -0
- package/src/0.8/utils/pathUtils.test.ts +353 -0
- package/src/0.8/utils/pathUtils.ts +200 -0
- package/src/components/ui/button.tsx +62 -0
- package/src/components/ui/calendar.tsx +220 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/dialog.tsx +141 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +22 -0
- package/src/components/ui/native-select.tsx +53 -0
- package/src/components/ui/popover.tsx +46 -0
- package/src/components/ui/select.tsx +188 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/slider.tsx +61 -0
- package/src/components/ui/tabs.tsx +64 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/index.ts +1 -0
- package/src/lib/utils.ts +6 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +29 -0
- package/vitest.config.ts +22 -0
- package/vitest.setup.ts +8 -0
- package/website/README.md +4 -0
- package/website/assets/favicon.svg +8 -0
- package/website/content/.gitkeep +0 -0
- package/website/content/index.md +122 -0
- package/website/global.d.ts +9 -0
- package/website/package.json +17 -0
- package/website/plain.config.js +28 -0
- package/website/serve.json +6 -0
- package/website/src/client/color-mode-switch.css +47 -0
- package/website/src/client/index.js +61 -0
- package/website/src/client/moon.svg +1 -0
- package/website/src/client/sun.svg +1 -0
- package/website/src/components/Footer.jsx +9 -0
- package/website/src/components/Header.jsx +44 -0
- package/website/src/components/Page.jsx +28 -0
- package/website/src/global.css +423 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UnknownComponent - Placeholder for unknown component types in development mode.
|
|
3
|
+
*
|
|
4
|
+
* In development mode, renders a visible placeholder to help developers
|
|
5
|
+
* identify missing or misspelled component types.
|
|
6
|
+
* In production mode, this component should not be rendered (ComponentRenderer skips unknown types).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { BaseComponentProps } from '../types'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Props for UnknownComponent.
|
|
13
|
+
*/
|
|
14
|
+
export interface UnknownComponentProps extends BaseComponentProps {
|
|
15
|
+
/** The unknown component type name */
|
|
16
|
+
componentType: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Placeholder component for unknown types in development mode.
|
|
21
|
+
*
|
|
22
|
+
* Displays a warning box with the unknown component type name
|
|
23
|
+
* to help developers identify configuration issues.
|
|
24
|
+
*/
|
|
25
|
+
export function UnknownComponent({
|
|
26
|
+
componentId,
|
|
27
|
+
componentType,
|
|
28
|
+
}: UnknownComponentProps) {
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
style={{
|
|
32
|
+
padding: '8px 12px',
|
|
33
|
+
margin: '4px',
|
|
34
|
+
backgroundColor: '#fff3cd',
|
|
35
|
+
border: '1px solid #ffc107',
|
|
36
|
+
borderRadius: '4px',
|
|
37
|
+
color: '#856404',
|
|
38
|
+
fontSize: '12px',
|
|
39
|
+
fontFamily: 'monospace',
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
<strong>Unknown component:</strong> {componentType}
|
|
43
|
+
<br />
|
|
44
|
+
<span style={{ opacity: 0.7 }}>ID: {componentId}</span>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
UnknownComponent.displayName = 'A2UI.UnknownComponent'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AudioPlayerComponent - Displays an audio player.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { memo } from 'react'
|
|
6
|
+
import type { AudioPlayerComponentProps } from '@/0.8/types'
|
|
7
|
+
import { useDataBinding } from '@/0.8/hooks/useDataBinding'
|
|
8
|
+
import { cn } from '@/lib/utils'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* AudioPlayer component for playing audio content.
|
|
12
|
+
*/
|
|
13
|
+
export const AudioPlayerComponent = memo(function AudioPlayerComponent({
|
|
14
|
+
surfaceId,
|
|
15
|
+
url,
|
|
16
|
+
description,
|
|
17
|
+
}: AudioPlayerComponentProps) {
|
|
18
|
+
const audioUrl = useDataBinding<string>(surfaceId, url, '')
|
|
19
|
+
const descriptionText = useDataBinding<string>(surfaceId, description, '')
|
|
20
|
+
|
|
21
|
+
if (!audioUrl) {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className={cn('flex flex-col gap-2')}>
|
|
27
|
+
{descriptionText && (
|
|
28
|
+
<p className="text-sm text-muted-foreground">{descriptionText}</p>
|
|
29
|
+
)}
|
|
30
|
+
<audio src={audioUrl} controls className="w-full">
|
|
31
|
+
Your browser does not support the audio element.
|
|
32
|
+
</audio>
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
AudioPlayerComponent.displayName = 'A2UI.AudioPlayer'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DividerComponent - Displays a separator line.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { memo } from 'react'
|
|
6
|
+
import type { DividerComponentProps } from '@/0.8/types'
|
|
7
|
+
import { Separator } from '@/components/ui/separator'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Divider component for visual separation.
|
|
11
|
+
*/
|
|
12
|
+
export const DividerComponent = memo(function DividerComponent({
|
|
13
|
+
axis = 'horizontal',
|
|
14
|
+
}: DividerComponentProps) {
|
|
15
|
+
return (
|
|
16
|
+
<Separator
|
|
17
|
+
orientation={axis}
|
|
18
|
+
className={axis === 'vertical' ? 'self-stretch h-auto!' : 'w-full'}
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
DividerComponent.displayName = 'A2UI.Divider'
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IconComponent - Displays icons from the A2UI icon set.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { memo } from 'react'
|
|
6
|
+
import type { IconComponentProps } from '@/0.8/types'
|
|
7
|
+
import { useDataBinding } from '@/0.8/hooks/useDataBinding'
|
|
8
|
+
import {
|
|
9
|
+
User,
|
|
10
|
+
Plus,
|
|
11
|
+
ArrowLeft,
|
|
12
|
+
ArrowRight,
|
|
13
|
+
Paperclip,
|
|
14
|
+
Calendar,
|
|
15
|
+
Phone,
|
|
16
|
+
Camera,
|
|
17
|
+
Check,
|
|
18
|
+
X,
|
|
19
|
+
Trash2,
|
|
20
|
+
Download,
|
|
21
|
+
Pencil,
|
|
22
|
+
CalendarDays,
|
|
23
|
+
AlertCircle,
|
|
24
|
+
Heart,
|
|
25
|
+
HeartOff,
|
|
26
|
+
Folder,
|
|
27
|
+
HelpCircle,
|
|
28
|
+
Home,
|
|
29
|
+
Info,
|
|
30
|
+
MapPin,
|
|
31
|
+
Lock,
|
|
32
|
+
Unlock,
|
|
33
|
+
Mail,
|
|
34
|
+
Menu,
|
|
35
|
+
MoreVertical,
|
|
36
|
+
MoreHorizontal,
|
|
37
|
+
BellOff,
|
|
38
|
+
Bell,
|
|
39
|
+
CreditCard,
|
|
40
|
+
UserCircle,
|
|
41
|
+
Image,
|
|
42
|
+
Printer,
|
|
43
|
+
RefreshCw,
|
|
44
|
+
Search,
|
|
45
|
+
Send,
|
|
46
|
+
Settings,
|
|
47
|
+
Share2,
|
|
48
|
+
ShoppingCart,
|
|
49
|
+
Star,
|
|
50
|
+
StarHalf,
|
|
51
|
+
StarOff,
|
|
52
|
+
Upload,
|
|
53
|
+
Eye,
|
|
54
|
+
EyeOff,
|
|
55
|
+
AlertTriangle,
|
|
56
|
+
type LucideIcon,
|
|
57
|
+
} from 'lucide-react'
|
|
58
|
+
import { cn } from '@/lib/utils'
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Maps A2UI icon names to Lucide React icons.
|
|
62
|
+
*/
|
|
63
|
+
const iconMap: Record<string, LucideIcon> = {
|
|
64
|
+
accountCircle: UserCircle,
|
|
65
|
+
add: Plus,
|
|
66
|
+
arrowBack: ArrowLeft,
|
|
67
|
+
arrowForward: ArrowRight,
|
|
68
|
+
attachFile: Paperclip,
|
|
69
|
+
calendarToday: Calendar,
|
|
70
|
+
call: Phone,
|
|
71
|
+
camera: Camera,
|
|
72
|
+
check: Check,
|
|
73
|
+
close: X,
|
|
74
|
+
delete: Trash2,
|
|
75
|
+
download: Download,
|
|
76
|
+
edit: Pencil,
|
|
77
|
+
event: CalendarDays,
|
|
78
|
+
error: AlertCircle,
|
|
79
|
+
favorite: Heart,
|
|
80
|
+
favoriteOff: HeartOff,
|
|
81
|
+
folder: Folder,
|
|
82
|
+
help: HelpCircle,
|
|
83
|
+
home: Home,
|
|
84
|
+
info: Info,
|
|
85
|
+
locationOn: MapPin,
|
|
86
|
+
lock: Lock,
|
|
87
|
+
lockOpen: Unlock,
|
|
88
|
+
mail: Mail,
|
|
89
|
+
menu: Menu,
|
|
90
|
+
moreVert: MoreVertical,
|
|
91
|
+
moreHoriz: MoreHorizontal,
|
|
92
|
+
notificationsOff: BellOff,
|
|
93
|
+
notifications: Bell,
|
|
94
|
+
payment: CreditCard,
|
|
95
|
+
person: User,
|
|
96
|
+
phone: Phone,
|
|
97
|
+
photo: Image,
|
|
98
|
+
print: Printer,
|
|
99
|
+
refresh: RefreshCw,
|
|
100
|
+
search: Search,
|
|
101
|
+
send: Send,
|
|
102
|
+
settings: Settings,
|
|
103
|
+
share: Share2,
|
|
104
|
+
shoppingCart: ShoppingCart,
|
|
105
|
+
star: Star,
|
|
106
|
+
starHalf: StarHalf,
|
|
107
|
+
starOff: StarOff,
|
|
108
|
+
upload: Upload,
|
|
109
|
+
visibility: Eye,
|
|
110
|
+
visibilityOff: EyeOff,
|
|
111
|
+
warning: AlertTriangle,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Icon component for displaying icons from the A2UI icon set.
|
|
116
|
+
*/
|
|
117
|
+
export const IconComponent = memo(function IconComponent({
|
|
118
|
+
surfaceId,
|
|
119
|
+
name,
|
|
120
|
+
}: IconComponentProps) {
|
|
121
|
+
const iconName = useDataBinding<string>(surfaceId, name, '')
|
|
122
|
+
|
|
123
|
+
if (!iconName) {
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const Icon = iconMap[iconName]
|
|
128
|
+
|
|
129
|
+
if (!Icon) {
|
|
130
|
+
console.warn(`A2UI: Unknown icon name: ${iconName}`)
|
|
131
|
+
return null
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return <Icon className={cn('w-5 h-5')} />
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
IconComponent.displayName = 'A2UI.Icon'
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ImageComponent - Displays an image with configurable sizing and fit.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { memo } from 'react'
|
|
6
|
+
import type { ImageComponentProps } from '@/0.8/types'
|
|
7
|
+
import { useDataBinding } from '@/0.8/hooks/useDataBinding'
|
|
8
|
+
import { cn } from '@/lib/utils'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Maps fit property to CSS object-fit values.
|
|
12
|
+
*/
|
|
13
|
+
const fitStyles: Record<string, string> = {
|
|
14
|
+
contain: 'object-contain',
|
|
15
|
+
cover: 'object-cover',
|
|
16
|
+
fill: 'object-fill',
|
|
17
|
+
none: 'object-none',
|
|
18
|
+
'scale-down': 'object-scale-down',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Maps usageHint to size and style classes.
|
|
23
|
+
*/
|
|
24
|
+
const usageHintStyles: Record<string, string> = {
|
|
25
|
+
icon: 'w-6 h-6',
|
|
26
|
+
avatar: 'w-10 h-10 rounded-full',
|
|
27
|
+
smallFeature: 'w-16 h-16',
|
|
28
|
+
mediumFeature: 'w-32 h-32',
|
|
29
|
+
largeFeature: 'w-48 h-48',
|
|
30
|
+
header: 'w-full h-48',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Image component for displaying images.
|
|
35
|
+
* Supports different sizes via usageHint and object-fit via fit property.
|
|
36
|
+
*/
|
|
37
|
+
export const ImageComponent = memo(function ImageComponent({
|
|
38
|
+
surfaceId,
|
|
39
|
+
url,
|
|
40
|
+
fit = 'cover',
|
|
41
|
+
usageHint,
|
|
42
|
+
}: ImageComponentProps) {
|
|
43
|
+
const imageUrl = useDataBinding<string>(surfaceId, url, '')
|
|
44
|
+
|
|
45
|
+
if (!imageUrl) {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const className = cn(
|
|
50
|
+
fitStyles[fit] || fitStyles.cover,
|
|
51
|
+
usageHint && usageHintStyles[usageHint]
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return <img src={imageUrl} alt="" className={className} loading="lazy" />
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
ImageComponent.displayName = 'A2UI.Image'
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TextComponent - Displays text content with optional Markdown support.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { memo, type JSX } from 'react'
|
|
6
|
+
import type { TextComponentProps } from '@/0.8/types'
|
|
7
|
+
import { useDataBinding } from '@/0.8/hooks/useDataBinding'
|
|
8
|
+
import { cn } from '@/lib/utils'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Maps usageHint to Tailwind CSS classes.
|
|
12
|
+
*/
|
|
13
|
+
const usageHintStyles: Record<string, string> = {
|
|
14
|
+
h1: 'text-3xl font-bold tracking-tight',
|
|
15
|
+
h2: 'text-2xl font-semibold tracking-tight',
|
|
16
|
+
h3: 'text-xl font-semibold',
|
|
17
|
+
h4: 'text-lg font-semibold',
|
|
18
|
+
h5: 'text-base font-semibold',
|
|
19
|
+
caption: 'text-sm text-muted-foreground',
|
|
20
|
+
body: 'text-base',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Maps usageHint to HTML element type.
|
|
25
|
+
*/
|
|
26
|
+
const usageHintElements: Record<string, keyof JSX.IntrinsicElements> = {
|
|
27
|
+
h1: 'h1',
|
|
28
|
+
h2: 'h2',
|
|
29
|
+
h3: 'h3',
|
|
30
|
+
h4: 'h4',
|
|
31
|
+
h5: 'h5',
|
|
32
|
+
caption: 'span',
|
|
33
|
+
body: 'p',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Text component for displaying text content.
|
|
38
|
+
* Supports basic Markdown formatting and different text styles via usageHint.
|
|
39
|
+
*/
|
|
40
|
+
export const TextComponent = memo(function TextComponent({
|
|
41
|
+
surfaceId,
|
|
42
|
+
text,
|
|
43
|
+
usageHint = 'body',
|
|
44
|
+
}: TextComponentProps) {
|
|
45
|
+
const textValue = useDataBinding<string>(surfaceId, text, '')
|
|
46
|
+
|
|
47
|
+
const className = cn(usageHintStyles[usageHint] || usageHintStyles.body)
|
|
48
|
+
|
|
49
|
+
const Element = (usageHintElements[usageHint] as 'p') || 'p'
|
|
50
|
+
|
|
51
|
+
// For now, render as plain text
|
|
52
|
+
// TODO: Add Markdown support if needed
|
|
53
|
+
return <Element className={className}>{textValue}</Element>
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
TextComponent.displayName = 'A2UI.Text'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VideoComponent - Displays video content.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { memo } from 'react'
|
|
6
|
+
import type { VideoComponentProps } from '@/0.8/types'
|
|
7
|
+
import { useDataBinding } from '@/0.8/hooks/useDataBinding'
|
|
8
|
+
import { cn } from '@/lib/utils'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Video component for displaying video content.
|
|
12
|
+
*/
|
|
13
|
+
export const VideoComponent = memo(function VideoComponent({
|
|
14
|
+
surfaceId,
|
|
15
|
+
url,
|
|
16
|
+
}: VideoComponentProps) {
|
|
17
|
+
const videoUrl = useDataBinding<string>(surfaceId, url, '')
|
|
18
|
+
|
|
19
|
+
if (!videoUrl) {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<video src={videoUrl} controls className={cn('w-full rounded-lg')}>
|
|
25
|
+
<track kind="captions" />
|
|
26
|
+
Your browser does not support the video tag.
|
|
27
|
+
</video>
|
|
28
|
+
)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
VideoComponent.displayName = 'A2UI.Video'
|