mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 02:17:31 +00:00
* plugins: components catalog 2 (forms, tabs, table, tree, markdown, code, images)
Adds 18 components to TSX components panels, drawn with Orca's own
primitives and gated by ui.catalog 2 / ui.has() (Orca 1.4.247):
Textarea, Checkbox, RadioGroup, Slider, Field, Tabs/Tab, Collapsible,
Toolbar, Grid, a virtualized Table with sort, selection and pull-based
paging, a keyboard Tree with lazy children, Markdown (sanitized, links
through the checked open path), CodeView (Orca's highlighter), Image
(header-checked plugin files read by main), KeyValue, Callout and
Skeleton, plus a tooltip prop on Button and IconButton.
Value controls share the edit protocol; handlers get plain JSON event
args, including small objects ({ keys }, { key, expanded }). The test kit
gains matching actions and hides unselected tabs and closed collapsibles;
a components-gallery example and e2e cover the catalog end to end.
* plugins: worker test harness, host refusals in tests and check
- orca/testing gains mountWorker(main, { host, events, commands }): it calls
the default-exported activate(orca) with the orca object Orca itself builds
(createPluginWorkerOrcaApi, moved to shared so the kit reuses it), backed by
mockHost. emit() checks payloads against Orca's event schemas and only
delivers subscribed events; command(), request() (the worker's
orca.panels.handle, as a panel's plugin.request), posts, logs, refusals and
deactivate(). Storage and settings share the mock host's in-memory store.
- orca plugin test loads a worker main's module graph as Orca's worker host
does (.ts/.mts transform, Node resolution, no runtime orca import).
- mockHost records refusals (capability_denied, not_permitted, ...) even
when plugin code catches them; panel.refusals exposes them and
orca plugin check reports them as warnings. Check dedupes repeated issues.
- Typings, docs and a generated references/testing.md skill reference; the
reference generator reads the split orca typings.
61 lines
2.4 KiB
TypeScript
61 lines
2.4 KiB
TypeScript
import { z } from 'zod'
|
|
import { PLUGIN_DECLARATIVE_LIMITS as LIMITS } from './plugin-declarative-limits'
|
|
import { PLUGIN_DECLARATIVE_EDIT_PROP } from './plugin-declarative-message-names'
|
|
|
|
/** Building blocks every catalog component's props are made of. */
|
|
|
|
export const PLUGIN_DECLARATIVE_CALLBACK_ID = /^[A-Za-z0-9_.:-]+$/
|
|
export const pluginDeclarativeCallbackSchema = z
|
|
.object({
|
|
$callback: z
|
|
.string()
|
|
.min(1)
|
|
.max(LIMITS.maxCallbackIdLength)
|
|
.regex(PLUGIN_DECLARATIVE_CALLBACK_ID)
|
|
})
|
|
.strict()
|
|
export type PluginDeclarativeCallback = z.infer<typeof pluginDeclarativeCallbackSchema>
|
|
|
|
/** The one colour vocabulary every component shares. */
|
|
export const PLUGIN_DECLARATIVE_TONES = [
|
|
'neutral',
|
|
'accent',
|
|
'success',
|
|
'warning',
|
|
'danger'
|
|
] as const
|
|
|
|
export const label = z.string().max(LIMITS.maxLabelLength)
|
|
export const requiredLabel = label.min(1)
|
|
export const callback = pluginDeclarativeCallbackSchema.optional()
|
|
// Why any short name: an unknown icon falls back to a glyph instead of rejecting the render.
|
|
export const icon = z.string().regex(/^[a-z0-9-]{1,64}$/)
|
|
export const gap = z.enum(['none', 'xs', 'sm', 'md', 'lg']).optional()
|
|
export const align = z.enum(['start', 'center', 'end', 'stretch']).optional()
|
|
export const tone = z.enum(PLUGIN_DECLARATIVE_TONES).optional()
|
|
export const size = z.enum(['xs', 'sm', 'md']).optional()
|
|
export const variant = z.enum(['solid', 'outline', 'ghost']).optional()
|
|
export const flag = z.boolean().optional()
|
|
export const text = z.string().max(LIMITS.maxTextLength)
|
|
/** A fixed-height scroll area for long content, so it does not push the rest of the panel away. */
|
|
export const maxHeight = z.enum(['sm', 'md', 'lg', 'none']).optional()
|
|
/** A row or item identity: what selection, sorting and events name. */
|
|
export const itemKey = z.string().min(1).max(LIMITS.maxLabelLength)
|
|
/** Wire-only on value controls (see PLUGIN_DECLARATIVE_EDIT_PROP); authors never set it. */
|
|
export const editAck = {
|
|
[PLUGIN_DECLARATIVE_EDIT_PROP]: z
|
|
.number()
|
|
.int()
|
|
.nonnegative()
|
|
.max(Number.MAX_SAFE_INTEGER)
|
|
.optional()
|
|
}
|
|
|
|
/** What a component accepts as children: `inline` is text plus Text/Link/Code/Badge; `items`,
|
|
* `tabs` hold only their one child type (ListItem, Tab). */
|
|
export type PluginDeclarativeChildPolicy = 'none' | 'text' | 'inline' | 'items' | 'tabs' | 'any'
|
|
|
|
export function component<P extends z.ZodObject>(props: P, children: PluginDeclarativeChildPolicy) {
|
|
return { props, children }
|
|
}
|