@exponential-at/ui 0.0.0-stage → 0.1.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/LICENSE +201 -0
- package/NOTICE +54 -0
- package/README.md +360 -2
- package/catalog/a11y.json +668 -0
- package/catalog/basic-map.json +104 -0
- package/catalog/code.json +58 -0
- package/catalog/core.catalog.json +4752 -0
- package/catalog/core.schema.json +22667 -0
- package/catalog/host.json +64 -0
- package/catalog/layout.json +20 -0
- package/catalog/limits.json +9 -0
- package/catalog/locale.json +48 -0
- package/catalog/macros.json +3417 -0
- package/catalog/recipes.json +61 -0
- package/catalog/strings.json +72 -0
- package/catalog/style.json +128 -0
- package/catalog/theme.schema.json +42543 -0
- package/catalog/tokens.json +47 -0
- package/conformance/README.md +217 -0
- package/conformance/baseline.ts +101 -0
- package/conformance/browser-page.ts +146 -0
- package/conformance/browser-suites.ts +683 -0
- package/conformance/compare.ts +201 -0
- package/conformance/dom.ts +96 -0
- package/conformance/dump.ts +163 -0
- package/conformance/fonts.json +154 -0
- package/conformance/manifest.json +224 -0
- package/conformance/parity-compare.ts +191 -0
- package/conformance/parity-report.schema.json +73 -0
- package/conformance/parity.ts +412 -0
- package/conformance/pixel.ts +177 -0
- package/conformance/primitives-page.ts +49 -0
- package/conformance/report.schema.json +66 -0
- package/conformance/run.ts +118 -0
- package/dist/chunks/index-98npjvsd.js +3940 -0
- package/dist/chunks/index-98npjvsd.js.map +27 -0
- package/dist/chunks/index-gwkt14w3.js +7314 -0
- package/dist/chunks/index-gwkt14w3.js.map +10 -0
- package/dist/chunks/index-njt7yzzm.js +134 -0
- package/dist/chunks/index-njt7yzzm.js.map +9 -0
- package/dist/chunks/index-we7va6v6.js +7984 -0
- package/dist/chunks/index-we7va6v6.js.map +15 -0
- package/dist/chunks/index-xrm6f7wc.js +2563 -0
- package/dist/chunks/index-xrm6f7wc.js.map +10 -0
- package/dist/conformance.js +182749 -0
- package/dist/conformance.js.map +10 -0
- package/dist/entries/prompt.js +251 -0
- package/dist/entries/prompt.js.map +11 -0
- package/dist/entries/schema.js +1725 -0
- package/dist/entries/schema.js.map +11 -0
- package/dist/host/index.js +122 -0
- package/dist/host/index.js.map +9 -0
- package/dist/index.js +3213 -0
- package/dist/index.js.map +27 -0
- package/dist/types/src/a11y.d.ts +21 -0
- package/dist/types/src/animation.d.ts +76 -0
- package/dist/types/src/basic-map.d.ts +38 -0
- package/dist/types/src/builder.d.ts +50 -0
- package/dist/types/src/catalog.d.ts +54 -0
- package/dist/types/src/catalog.described.d.ts +33 -0
- package/dist/types/src/catalog.generated.d.ts +829 -0
- package/dist/types/src/chart.d.ts +46 -0
- package/dist/types/src/code.d.ts +44 -0
- package/dist/types/src/color.d.ts +20 -0
- package/dist/types/src/conformance.d.ts +39 -0
- package/dist/types/src/connector/app.d.ts +14 -0
- package/dist/types/src/connector/connector.d.ts +77 -0
- package/dist/types/src/connector/index.d.ts +4 -0
- package/dist/types/src/css.d.ts +29 -0
- package/dist/types/src/define.d.ts +66 -0
- package/dist/types/src/direction.d.ts +16 -0
- package/dist/types/src/dynamic.d.ts +159 -0
- package/dist/types/src/entries/prompt.d.ts +11 -0
- package/dist/types/src/entries/schema.d.ts +8 -0
- package/dist/types/src/expr.d.ts +71 -0
- package/dist/types/src/extension.d.ts +4 -0
- package/dist/types/src/format.d.ts +112 -0
- package/dist/types/src/geometry.d.ts +40 -0
- package/dist/types/src/host/contract.d.ts +188 -0
- package/dist/types/src/host/decoders.d.ts +61 -0
- package/dist/types/src/host/index.d.ts +11 -0
- package/dist/types/src/host/package.d.ts +58 -0
- package/dist/types/src/host/policy.d.ts +105 -0
- package/dist/types/src/host/router.d.ts +34 -0
- package/dist/types/src/host/runtime.d.ts +205 -0
- package/dist/types/src/host/sources.d.ts +15 -0
- package/dist/types/src/host/transports.d.ts +109 -0
- package/dist/types/src/index.d.ts +63 -0
- package/dist/types/src/layout.d.ts +20 -0
- package/dist/types/src/limits.d.ts +21 -0
- package/dist/types/src/list.d.ts +133 -0
- package/dist/types/src/locale.d.ts +22 -0
- package/dist/types/src/macros.d.ts +29 -0
- package/dist/types/src/overlay.d.ts +27 -0
- package/dist/types/src/prompt.d.ts +44 -0
- package/dist/types/src/recipes.d.ts +17 -0
- package/dist/types/src/reducer.d.ts +41 -0
- package/dist/types/src/resizable.d.ts +38 -0
- package/dist/types/src/schema.d.ts +7 -0
- package/dist/types/src/strings.d.ts +13 -0
- package/dist/types/src/style.d.ts +201 -0
- package/dist/types/src/test-preload.d.ts +1 -0
- package/dist/types/src/text-shimmer.d.ts +24 -0
- package/dist/types/src/theme-types.d.ts +162 -0
- package/dist/types/src/theme.d.ts +73 -0
- package/dist/types/src/themes.d.ts +22 -0
- package/dist/types/src/tree-guides.d.ts +17 -0
- package/dist/types/src/types.d.ts +314 -0
- package/dist/types/src/validate.d.ts +31 -0
- package/dist/types/src/web/base-css.d.ts +1 -0
- package/dist/types/src/web/box-css.d.ts +55 -0
- package/dist/types/src/web/coerce.d.ts +32 -0
- package/dist/types/src/web/data.d.ts +105 -0
- package/dist/types/src/web/dates.d.ts +12 -0
- package/dist/types/src/web/form.d.ts +44 -0
- package/dist/types/src/web/host-types.d.ts +119 -0
- package/dist/types/src/web/index.d.ts +28 -0
- package/dist/types/src/web/inputs.d.ts +55 -0
- package/dist/types/src/web/list.d.ts +13 -0
- package/dist/types/src/web/listbox.d.ts +14 -0
- package/dist/types/src/web/markdown.d.ts +96 -0
- package/dist/types/src/web/media.d.ts +62 -0
- package/dist/types/src/web/parts.d.ts +4 -0
- package/dist/types/src/web/primitives/alert-dialog.d.ts +10 -0
- package/dist/types/src/web/primitives/alert.d.ts +9 -0
- package/dist/types/src/web/primitives/avatar-color.d.ts +2 -0
- package/dist/types/src/web/primitives/avatar.d.ts +13 -0
- package/dist/types/src/web/primitives/badge.d.ts +10 -0
- package/dist/types/src/web/primitives/breadcrumb.d.ts +10 -0
- package/dist/types/src/web/primitives/button.d.ts +6 -0
- package/dist/types/src/web/primitives/calendar.d.ts +43 -0
- package/dist/types/src/web/primitives/card.d.ts +9 -0
- package/dist/types/src/web/primitives/checkbox.d.ts +5 -0
- package/dist/types/src/web/primitives/choice-tiles.d.ts +32 -0
- package/dist/types/src/web/primitives/cn.d.ts +3 -0
- package/dist/types/src/web/primitives/code-block.d.ts +24 -0
- package/dist/types/src/web/primitives/command.d.ts +134 -0
- package/dist/types/src/web/primitives/context-ring.d.ts +24 -0
- package/dist/types/src/web/primitives/dialog-arms.d.ts +6 -0
- package/dist/types/src/web/primitives/dialog.d.ts +24 -0
- package/dist/types/src/web/primitives/disclosure-header.d.ts +5 -0
- package/dist/types/src/web/primitives/dock.d.ts +42 -0
- package/dist/types/src/web/primitives/dropdown-menu.d.ts +14 -0
- package/dist/types/src/web/primitives/empty-state.d.ts +15 -0
- package/dist/types/src/web/primitives/glass-card.d.ts +4 -0
- package/dist/types/src/web/primitives/hover-card.d.ts +7 -0
- package/dist/types/src/web/primitives/icon-disc.d.ts +12 -0
- package/dist/types/src/web/primitives/index.d.ts +48 -0
- package/dist/types/src/web/primitives/input.d.ts +5 -0
- package/dist/types/src/web/primitives/kbd.d.ts +4 -0
- package/dist/types/src/web/primitives/label.d.ts +3 -0
- package/dist/types/src/web/primitives/menu-surface.d.ts +17 -0
- package/dist/types/src/web/primitives/meter.d.ts +21 -0
- package/dist/types/src/web/primitives/popover.d.ts +3 -0
- package/dist/types/src/web/primitives/progress-ring.d.ts +5 -0
- package/dist/types/src/web/primitives/progress.d.ts +8 -0
- package/dist/types/src/web/primitives/scroll-area.d.ts +49 -0
- package/dist/types/src/web/primitives/segmented-control.d.ts +5 -0
- package/dist/types/src/web/primitives/select.d.ts +47 -0
- package/dist/types/src/web/primitives/separator.d.ts +3 -0
- package/dist/types/src/web/primitives/sheet-chrome.d.ts +4 -0
- package/dist/types/src/web/primitives/sheet.d.ts +20 -0
- package/dist/types/src/web/primitives/skeleton.d.ts +3 -0
- package/dist/types/src/web/primitives/spinner.d.ts +3 -0
- package/dist/types/src/web/primitives/switch.d.ts +4 -0
- package/dist/types/src/web/primitives/table.d.ts +11 -0
- package/dist/types/src/web/primitives/tabs.d.ts +13 -0
- package/dist/types/src/web/primitives/textarea.d.ts +3 -0
- package/dist/types/src/web/primitives/toast.d.ts +163 -0
- package/dist/types/src/web/primitives/tooltip.d.ts +3 -0
- package/dist/types/src/web/primitives/truncate.d.ts +7 -0
- package/dist/types/src/web/primitives/typeahead-portal.d.ts +12 -0
- package/dist/types/src/web/share.d.ts +6 -0
- package/dist/types/src/web/table.d.ts +20 -0
- package/dist/types/src/web/theme-css.d.ts +69 -0
- package/dist/types/src/web/urls.d.ts +21 -0
- package/dist/web/index.js +2303 -0
- package/dist/web/index.js.map +26 -0
- package/dist/web/primitives/index.js +1450 -0
- package/dist/web/primitives/index.js.map +57 -0
- package/docs/components.generated.json +6238 -0
- package/docs/round-1-contract.md +679 -0
- package/docs/round-2-contract.md +476 -0
- package/docs/round-3-contract.md +174 -0
- package/docs/themes.generated.json +3503 -0
- package/fixtures/animations.json +2890 -0
- package/fixtures/bench-list.json +58 -0
- package/fixtures/bind-time.json +30664 -0
- package/fixtures/catalog-basic-map.json +1692 -0
- package/fixtures/catalog-components.json +9323 -0
- package/fixtures/catalog-extension.json +620 -0
- package/fixtures/catalog-macros.json +36370 -0
- package/fixtures/code-tokens.json +1993 -0
- package/fixtures/conformance-baseline.json +55544 -0
- package/fixtures/conformance-cases.json +49 -0
- package/fixtures/conformance-known.json +2123 -0
- package/fixtures/control-geometry.json +4200 -0
- package/fixtures/dashboard.data.json +74 -0
- package/fixtures/dashboard.json +752 -0
- package/fixtures/demo-surface.json +47 -0
- package/fixtures/format.json +870 -0
- package/fixtures/host-policy.json +1067 -0
- package/fixtures/host-router.json +1152 -0
- package/fixtures/host-transport.json +590 -0
- package/fixtures/interactions-round1.json +773 -0
- package/fixtures/kitchen-sink.expanded.json +10844 -0
- package/fixtures/kitchen-sink.json +3049 -0
- package/fixtures/layout-geometry-round1.json +7278 -0
- package/fixtures/layout-geometry.json +2072 -0
- package/fixtures/overlay-geometry.json +272 -0
- package/fixtures/primitive-specimens.json +58 -0
- package/fixtures/prompt-budget.json +33 -0
- package/fixtures/resizable.json +714 -0
- package/fixtures/round4-contract.json +2985 -0
- package/fixtures/specimens.json +9832 -0
- package/fixtures/style-conditions.json +336 -0
- package/fixtures/template-items.json +2215 -0
- package/fixtures/text-direction.json +309 -0
- package/fixtures/text-shimmer.json +96 -0
- package/fixtures/theme-extends.json +573 -0
- package/fixtures/theme-invalid.json +1296 -0
- package/fixtures/theme-recipes.json +58600 -0
- package/fixtures/theme-resolved.json +23949 -0
- package/fixtures/toast-stack.json +215 -0
- package/fixtures/tree-guides.json +224 -0
- package/fixtures/virtual-list.json +733 -0
- package/generated/ExponentialUICatalog.generated.kt +67 -0
- package/generated/ExponentialUICatalog.generated.swift +67 -0
- package/generated/ExponentialUIThemes.generated.kt +23 -0
- package/generated/ExponentialUIThemes.generated.swift +23 -0
- package/generated/catalog.descriptions.generated.rs +6 -0
- package/generated/catalog.generated.rs +80 -0
- package/generated/catalog.themes.generated.rs +34 -0
- package/generated/core.descriptions.json +2505 -0
- package/generated/core.runtime.json +3609 -0
- package/package.json +87 -4
- package/themes/exponential.recipes.json +49 -0
- package/themes/exponential.theme.json +755 -0
- package/themes/neutral.theme.json +5676 -0
- package/themes/orange.theme.json +43 -0
- package/themes/playful.theme.json +219 -0
- package/vendor/a2ui/LICENSE.txt +203 -0
- package/vendor/a2ui/README.md +27 -0
- package/vendor/a2ui/v0_9/basic_catalog.json +1387 -0
- package/vendor/a2ui/v0_9/basic_catalog_rules.txt +5 -0
- package/vendor/a2ui/v0_9/client_capabilities.json +97 -0
- package/vendor/a2ui/v0_9/client_to_server.json +104 -0
- package/vendor/a2ui/v0_9/common_types.json +315 -0
- package/vendor/a2ui/v0_9/server_to_client.json +132 -0
- package/vendor/json-render/LICENSE.txt +201 -0
- package/vendor/json-render/README.md +13 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "VAPP-91: the host API contract, the same on all four platforms (TS src/host/, the Rust core's `host` module, which the Swift and Kotlin painters reach through exponential-ui-ffi). A surface needs exactly these from its host: transport, functions, bindings (optional), extensions, theme, catalog negotiation and policy hooks. Every pure rule here is locked by fixtures/host-*.json, replayed by every renderer's conformance runner (conformance/manifest.json).",
|
|
3
|
+
"version": 2,
|
|
4
|
+
"a2uiVersion": "v0.9",
|
|
5
|
+
"messages": {
|
|
6
|
+
"$comment": "Server → client. The four A2UI v0.9 messages plus two Exponential UI extensions: `applyTemplate` (a registered declarative package's template becomes create + components + data + binds) and `bindDataModel` (a data model path follows a host `source`). A message is ONE object with `version` (optional, must equal a2uiVersion when present) and exactly one kind key.",
|
|
7
|
+
"a2ui": ["createSurface", "updateComponents", "updateDataModel", "deleteSurface"],
|
|
8
|
+
"extensions": ["applyTemplate", "bindDataModel"]
|
|
9
|
+
},
|
|
10
|
+
"ops": {
|
|
11
|
+
"$comment": "What the router (`HostRouter.route`) turns a message into. A platform host performs them in order: create = a new EMPTY surface (replacing one with that id), components = updateComponents on it, data = updateDataModel (no `value` = remove the path), bind = subscribe the path to a source resolver, delete = drop the surface and every subscription, send = a client message back over the transport (errors).",
|
|
12
|
+
"kinds": ["create", "components", "data", "bind", "delete", "send"]
|
|
13
|
+
},
|
|
14
|
+
"clientMessages": {
|
|
15
|
+
"$comment": "Client → server, A2UI v0.9 client_to_server: `{version, action: {name, surfaceId, sourceComponentId, timestamp, context}}` (+ `payload` when the component adds one, e.g. a Select's value) or `{version, error: {code, surfaceId, message, path?}}`.",
|
|
16
|
+
"errorCodes": ["VALIDATION_FAILED", "INVALID_MESSAGE", "UNSUPPORTED_CATALOG", "SURFACE_NOT_FOUND", "TEMPLATE_NOT_FOUND", "FUNCTION_NOT_FOUND", "FUNCTION_DENIED", "SOURCE_DENIED", "RENDER_FAILED"]
|
|
17
|
+
},
|
|
18
|
+
"functions": {
|
|
19
|
+
"$comment": "An `on.<event>` action `{functionCall: {call, args}}` (A2UI's key, the only one) runs on the client. The catalog's functions are built in (the basic 14 + the 15 core ones: value functions, `set`; `openUrl` is the one with an effect and goes through the URL policy). Any other name is a namespaced HOST function (`app.toast`; an un-namespaced unknown name is a validation issue) that must be REGISTERED by the host (an action function: side effects, may be async) and passes the policy gate first: decide(policy, name) → allow | ask | deny. `ask` = the host's onFunctionCall hook decides (the Exponential app's consent card). Patterns: an exact name or a prefix ending in `*` (`harness.*`). Order: deny wins, then allow, then ask, then `default`.",
|
|
20
|
+
"decisions": ["allow", "ask", "deny", "not_found"],
|
|
21
|
+
"defaultPolicy": { "allow": [], "ask": [], "deny": [], "default": "allow" }
|
|
22
|
+
},
|
|
23
|
+
"urls": {
|
|
24
|
+
"$comment": "EVERY href on every renderer goes through decideUrl(policy, url): openUrl, Link (external or not), markdown links, FileUpload file urls, a host's default opener. The scheme (lower-cased) must be in `schemes` (`[\"https\"]` = https only: drops http, mailto and tel) and, when `hosts` is set, an http(s) url's host must match one (exact or `*.example.com`). Relative urls resolve against `baseUrl` first; without one they are denied. A denied href is never navigated: the link paints as plain text. The defaults keep `mailto` and `tel`: they open the system mail or phone handler with the address visible, run nothing, and are not gated by `hosts`. VAPP-107 (decided by Danny): an http(s) url whose host is PRIVATE (`privateHosts`: localhost and *.localhost, *.local, the IPv4 blocks 0/8, 10/8, 127/8, 169.254/16, 172.16/12, 192.168/16, IPv6 ::, ::1, fe80::/10, fc00::/7 and an IPv4-mapped address of a private IPv4) is DENIED with reason `private` unless the host opts it back in with `allowPrivate` (exact names or addresses, `*.suffix`, or `*` for every private address); a `hosts` allowlist alone does not opt one in. LITERALS only: the policy never resolves a name (a public name that resolves to a private address is the host network's job: egress rules, a filtering resolver). The WHATWG parser normalizes an address before the check (`2130706433`, `0x7f.1`, `::ffff:127.0.0.1`). The Exponential app opts its own origin in only when that origin is private (the localhost dev setup); its cloud origin is public and needs nothing; the web renderers (React and Solid, through the shared web layer) do the same for the document's own host on top of the host's list (a dev server on localhost keeps its same-origin loads).",
|
|
25
|
+
"defaultSchemes": ["https", "http", "mailto", "tel"],
|
|
26
|
+
"privateHosts": ["localhost", "*.localhost", "*.local", "0.0.0.0/8", "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.168.0.0/16", "::", "::1", "fe80::/10", "fc00::/7", "::ffff:<private IPv4>"],
|
|
27
|
+
"reasons": ["invalid", "scheme", "host", "private"]
|
|
28
|
+
},
|
|
29
|
+
"media": {
|
|
30
|
+
"$comment": "EVERY src on every renderer (Image, Avatar, Video + poster, Audio, markdown images) goes through mediaRequest(url, {baseUrl, rules, schemes, hosts}) → {url, headers} | null. A relative url resolves against baseUrl; the absolute url must pass decideUrl with `schemes` (default `defaultSchemes`: no `file`, so no local file is ever read unless the host lists it; `[\"https\"]` = https only), `hosts` and `allowPrivate` (VAPP-107: a private, loopback or link-local host is denied unless opted in, like every href; a redirect hop passes the same rules); null = denied, nothing loads. Every rule whose `prefix` the url starts with adds its headers (later rules win per header): how the Exponential app sends auth for /api/attachments. Every image loader enforces `limits`: `maxBytes` (Content-Length up front and the body as it streams), `timeoutMs` (the whole request), `maxPixels` (width × height read from the image header BEFORE decoding); a load over a limit fails like a 404 (the fallback paints). Video/Audio stream through the platform player: the policy applies, the byte limits do not (a poster is an image: they do); a web player cannot send headers, so a request WITH headers goes to the host's `mediaStreamUrl(request)` (a signed or cookie-authed url, re-checked by the policy) and without that hook is fetched whole into a blob url under `limits.maxBytes` and `limits.timeoutMs` for the WHOLE download (VAPP-107: past either it fails like a 404; a long video needs `mediaStreamUrl`).",
|
|
31
|
+
"ruleKeys": ["prefix", "headers"],
|
|
32
|
+
"optionKeys": ["baseUrl", "rules", "schemes", "hosts", "allowPrivate"],
|
|
33
|
+
"defaultSchemes": ["https", "http", "data"],
|
|
34
|
+
"limits": { "maxBytes": 20971520, "timeoutMs": 30000, "maxPixels": 33554432 }
|
|
35
|
+
},
|
|
36
|
+
"sources": {
|
|
37
|
+
"$comment": "A binding source URI: `<scheme>:<name>[?k=v&…]`, scheme `[a-z][a-z0-9+.-]*` (lower-cased), name non-empty without `?`, params percent-decoded (`+` = space), the last value of a repeated key wins, keys sorted. The host registers one resolver per scheme (the Exponential app: `exp`); subscribe(source, emit) → cancel, every emit writes the value at the bound path.",
|
|
38
|
+
"pattern": "^([a-zA-Z][a-zA-Z0-9+.-]*):([^?]+)(?:\\?(.*))?$"
|
|
39
|
+
},
|
|
40
|
+
"transport": {
|
|
41
|
+
"$comment": "Adapters every SDK ships: in-memory, A2UI JSONL over a byte stream (one message per line; CRLF and blank lines tolerated; a bad line is an issue, never fatal), SSE (`data:` lines joined per event; an event's data is one message or JSONL; events named other than `message`/`a2ui` are ignored), WebSocket (one message or JSONL per frame), and the A2UI-over-MCP carrier (a tool result's `content[]` resources with one of `mcpMimeTypes`, text = JSONL / a JSON array / one message; or `structuredContent.a2ui` = an array). Actions out over MCP = tools/call `mcpActionTool` with `{message}`.",
|
|
42
|
+
"mcpMimeTypes": ["application/json+a2ui", "application/a2ui+json"],
|
|
43
|
+
"mcpActionTool": "a2ui_event",
|
|
44
|
+
"sseEvents": ["message", "a2ui"]
|
|
45
|
+
},
|
|
46
|
+
"negotiation": {
|
|
47
|
+
"$comment": "supportedCatalogIds = the core, the core lite, the A2UI basic catalog, then every registered extension id in registration order, de-duplicated. clientCapabilities = {\"v0.9\": {supportedCatalogIds}}. A createSurface whose catalogId is not in the list → UNSUPPORTED_CATALOG."
|
|
48
|
+
},
|
|
49
|
+
"package": {
|
|
50
|
+
"$comment": "A declarative app package (VAPP-82): data, never code. {id, name, version, catalogId, templates: {<id>: {components: [flat, one `root`], data?, bindings?: [{path, source}]}}, functions?: [allowed patterns], sources?: [allowed sources], theme?: a theme id or theme JSON, icon?}. Installing one registers its templates with the router (applyTemplate) and turns `functions` into the policy for its surfaces: listed = allow, anything else = deny. VAPP-107: `sources` is the same allowlist for binding sources (`exp:devices`, or a prefix `exp:*`, matched against the URI's scheme:name without its query): unset = any registered scheme; set, a template binding outside it is an install issue and a later bindDataModel on one of the package's surfaces answers SOURCE_DENIED (the data model never follows it).",
|
|
51
|
+
"required": ["id", "name", "version", "catalogId", "templates"]
|
|
52
|
+
},
|
|
53
|
+
"paint": {
|
|
54
|
+
"$comment": "A component whose painter fails (React: a render error; native: a painter that throws or meets props it cannot paint) paints an empty box in its place, never takes the surface down, and calls the host's `onPaintError({surfaceId, componentId, message})` ONCE per surface + component + message. ExponentialHost.paintError forwards it to the agent as an A2UI error `{code: errorCode, surfaceId, message, path: /components/<componentId>}` and reports it as a host issue with the same code.",
|
|
55
|
+
"hook": "onPaintError",
|
|
56
|
+
"errorCode": "RENDER_FAILED"
|
|
57
|
+
},
|
|
58
|
+
"surface": {
|
|
59
|
+
"$comment": "Round 2 (docs/round-2-contract.md §3, §5): what a host hands each surface besides messages. `settings` = the SurfaceSettings keys (src/types.ts): `timeZone` = the IANA zone instants show in (default the platform's). `formatter` = the methods of the host-supplied Formatter that formats every number, currency, percent, date and relative time (TS: intlFormatter(locale, timeZone); Rust: the Formatter trait, default the English fallback at the host's UTC offset per instant; FFI: a foreign Formatter, else the core's). `commands` = what a host may ask of a live surface (catalog/a11y.json `commands`; `scrollToIndex` takes the DATA index). Round 4 (VAPP-103): an unusable theme (an unknown built-in id, a missing or other `$schema`, any theme issue) NEVER fails a host: it paints with the default theme and reports the issues (TS `themeOrDefault` + React `HostPlugin.onThemeIssues`, Rust `themes::theme_or_default`, Swift/Kotlin `ThemeHandle.loadOrDefault`); a server's unusable `createSurface.theme` answers VALIDATION_FAILED at `/createSurface/theme`.",
|
|
60
|
+
"settings": ["locale", "timeZone", "strings", "mode", "density", "contrast", "theme"],
|
|
61
|
+
"formatter": ["number", "currency", "percent", "date", "relativeTime", "plural"],
|
|
62
|
+
"commands": ["focus", "announce", "scrollIntoView", "scrollToIndex"]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Round 2 (docs/round-2-contract.md §7): the layout NUMBERS every painter shares where no theme token decides (px unless noted). `windowThreshold` = items past which List and Table window; `windowOverscan` = items rendered beyond each viewport edge; `resizeStep` = percentage points per arrow key on a Resizable handle; `panelMin` = a panel's min (percent) when unset; `resizeHandleHit` = a handle's hit area across its hairline; `fieldIntrinsicWidth` = the max-content width of a text field (Input, Textarea, NumberField, ChipInput: never the browser's `size` default) — picker triggers (Select, DatePicker, DateRangePicker, TimePicker) size to their content; `mediaIntrinsicWidth` = the max-content width of an Image/Video without a width (its min-content is 0); `mediaAspectRatio` = width/height of an Image without `aspectRatio` or a height (Video: its `aspectRatio` default); `treeGuideColumn` = one TreeGuides gutter column (the recipe's `line` width is the STROKE; round 3: 14, the ×4 app indent, the elbow lands on the parent's lead glyph); `treeGuideRadius` = the elbow's corner radius; `treeGuideBridge` = how far the guide verticals overshoot the row's TOP edge (paint only) so a Section's hairline divider never breaks the line. EXP-1259 (packages/domain-contract/fixtures/feedback-states.json + search-list.json): `pendingDelayMs` = how long a `loading` Button waits before it shows the spinner and its `pendingLabel` (a fast action never flashes; presses are refused at once); `skeletonPulseMs` / `skeletonOpacityLow` / `skeletonOpacityHigh` = the placeholder's ONE opacity pulse (low → high → low, ease-in-out), `skeletonReducedOpacity` = its static opacity under reduce motion; `searchListFade` = the bottom fade over a SearchList (or a searchable submenu) while more rows sit below. Generated into every target; src/layout.ts reads it.",
|
|
3
|
+
"windowThreshold": 50,
|
|
4
|
+
"windowOverscan": 5,
|
|
5
|
+
"resizeStep": 10,
|
|
6
|
+
"panelMin": 10,
|
|
7
|
+
"resizeHandleHit": 8,
|
|
8
|
+
"fieldIntrinsicWidth": 160,
|
|
9
|
+
"mediaIntrinsicWidth": 320,
|
|
10
|
+
"mediaAspectRatio": 1.7777778,
|
|
11
|
+
"treeGuideColumn": 14,
|
|
12
|
+
"treeGuideRadius": 3,
|
|
13
|
+
"treeGuideBridge": 1,
|
|
14
|
+
"pendingDelayMs": 150,
|
|
15
|
+
"skeletonPulseMs": 1600,
|
|
16
|
+
"skeletonOpacityLow": 0.45,
|
|
17
|
+
"skeletonOpacityHigh": 0.9,
|
|
18
|
+
"skeletonReducedOpacity": 0.6,
|
|
19
|
+
"searchListFade": 24
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "VAPP-103: the input LIMITS every core enforces (the TS reference, the Rust core and through it Swift, Compose and gpui). An agent's input past a limit is refused with an issue, never worked on. `maxComponents` = nodes the reducer places in one surface's tree, template nodes included (the rest is dropped: `surface: more than N components; the rest is dropped`); a renderer's build holds at most `maxComponents` nodes too: the reduced tree's (after expansion, children and slots) plus, per template ITEM, its template subtree's (nested items charged when they are instantiated); the first item that does not fit and every later one are not rendered, with ONE issue on the template component (the same message). `maxDepth` = nesting levels of the REDUCED tree, after macro expansion (the root and every lifted template = 1, children and slots one level down; a Card, Section or Group macro adds a level; a deeper node is the Unknown placeholder, its subtree dropped: `nesting deeper than N levels`); 48 keeps every tree a core emits (2 JSON levels per node) inside serde_json's default recursion limit of 128, so reduced trees, fixtures and the FFI's JSON round-trip; the Rust core's recursive passes switch to a heap-allocated stack segment when the host thread runs low, so an iOS secondary thread's 512 KB never decides (a 48-level surface lays out on a 128 KB thread, debug build). `maxMessageBytes` = one server message as UTF-8 JSON (host routers refuse it: INVALID_MESSAGE). `maxTemplateItems` = template items one surface instantiates (beyond it the items are not rendered: `template: more than N items; the rest is not rendered`). `maxPointerBytes` / `maxPointerSegments` = a data pointer's length and token count (a longer write is refused). Generated into every target; src/limits.ts reads it.",
|
|
3
|
+
"maxComponents": 20000,
|
|
4
|
+
"maxDepth": 48,
|
|
5
|
+
"maxMessageBytes": 4194304,
|
|
6
|
+
"maxTemplateItems": 10000,
|
|
7
|
+
"maxPointerBytes": 1024,
|
|
8
|
+
"maxPointerSegments": 64
|
|
9
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Round 1 (docs/round-1-contract.md §4): the LOCALE contract. A surface carries one BCP 47 `locale` (SurfaceSettings.locale, default `en-US`); it drives the basic catalog's formatNumber/formatCurrency/formatDate/pluralize, NumberField's display, the calendar's month and weekday names and the default week start, and the text direction. Platforms format with their own ICU (Intl, Foundation, java.text, icu4x); what must not differ is decided HERE so every renderer agrees: `weekStart` = CLDR supplemental weekData `firstDay` by REGION (0 = Sunday … 6 = Saturday; a region not listed = `default`); a locale without a region takes `likelyRegion[language]` (CLDR likelySubtags: every rtl language and the most spoken ~90; else `default`); `languageAliases` = deprecated codes normalised FIRST (Java/Android still emit `iw`, `ji`, `in`); `rtl` = the languages whose text direction is right-to-left (the surface root gets `direction: rtl` unless the author set one); `rtlMirroredIcons` = the DIRECTIONAL glyphs (icons.json names, semantic and Lucide) a painter MIRRORS under rtl: scaleX(-1) as the OUTERMOST transform of the glyph, after the node's own `transform` (CSS `transform: scaleX(-1) <own>`), so a back arrow, a prev/next or breadcrumb chevron and a submenu indicator point the reading direction; media transport glyphs and everything else are never mirrored. Round 2: formatting goes through a host-supplied Formatter (SurfaceSettings.locale + timeZone; TS = Intl, Rust = a Formatter trait with the `englishFallback` below, FFI = a foreign Formatter). src/locale.ts + src/format.ts are the reference; generated into every target as constants. Append-only.",
|
|
3
|
+
"default": "en-US",
|
|
4
|
+
"weekStart": {
|
|
5
|
+
"default": 1,
|
|
6
|
+
"regions": {
|
|
7
|
+
"0": ["AG", "AS", "BD", "BR", "BS", "BT", "BW", "BZ", "CA", "CN", "CO", "DM", "DO", "ET", "GT", "GU", "HK", "HN", "ID", "IL", "IN", "JM", "JP", "KE", "KH", "KR", "LA", "MH", "MM", "MO", "MT", "MX", "MZ", "NI", "NP", "PA", "PE", "PH", "PK", "PR", "PT", "PY", "SA", "SG", "SV", "TH", "TT", "TW", "UM", "US", "VE", "VI", "WS", "YE", "ZA", "ZW"],
|
|
8
|
+
"5": ["MV"],
|
|
9
|
+
"6": ["AE", "AF", "BH", "DJ", "DZ", "EG", "IQ", "IR", "JO", "KW", "LY", "OM", "QA", "SD", "SY"]
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"likelyRegion": {
|
|
13
|
+
"af": "ZA", "am": "ET", "ar": "EG", "az": "AZ", "be": "BY", "bg": "BG", "bn": "BD", "bs": "BA", "ca": "ES", "ckb": "IQ", "cs": "CZ", "cy": "GB",
|
|
14
|
+
"da": "DK", "de": "DE", "dv": "MV", "el": "GR", "en": "US", "es": "ES", "et": "EE", "eu": "ES", "fa": "IR", "fi": "FI", "fil": "PH", "fr": "FR",
|
|
15
|
+
"ga": "IE", "gl": "ES", "gu": "IN", "ha": "NG", "he": "IL", "hi": "IN", "hr": "HR", "hu": "HU", "hy": "AM", "id": "ID", "ig": "NG", "is": "IS",
|
|
16
|
+
"it": "IT", "ja": "JP", "jv": "ID", "ka": "GE", "kk": "KZ", "km": "KH", "kn": "IN", "ko": "KR", "ku": "TR", "ky": "KG", "lo": "LA", "lt": "LT",
|
|
17
|
+
"lv": "LV", "mk": "MK", "ml": "IN", "mn": "MN", "mr": "IN", "ms": "MY", "mt": "MT", "my": "MM", "nb": "NO", "ne": "NP", "nl": "NL", "nn": "NO",
|
|
18
|
+
"no": "NO", "or": "IN", "pa": "IN", "pl": "PL", "ps": "AF", "pt": "BR", "ro": "RO", "ru": "RU", "sd": "PK", "si": "LK", "sk": "SK", "sl": "SI",
|
|
19
|
+
"so": "SO", "sq": "AL", "sr": "RS", "sv": "SE", "sw": "TZ", "ta": "IN", "te": "IN", "th": "TH", "tl": "PH", "tr": "TR", "ug": "CN", "uk": "UA",
|
|
20
|
+
"ur": "PK", "uz": "UZ", "vi": "VN", "yi": "001", "yo": "NG", "zh": "CN", "zu": "ZA"
|
|
21
|
+
},
|
|
22
|
+
"languageAliases": { "in": "id", "iw": "he", "ji": "yi", "jw": "jv", "mo": "ro", "tl": "fil" },
|
|
23
|
+
"rtl": ["ar", "ckb", "dv", "fa", "he", "ps", "sd", "ug", "ur", "yi"],
|
|
24
|
+
"rtlMirroredIcons": ["ui-back", "ui-chevron-left", "ui-chevron-right", "ui-arrow-right", "ui-send", "ui-undo", "ui-external-link", "arrow-left", "arrow-right", "chevron-left", "chevron-right", "send", "undo-2", "external-link"],
|
|
25
|
+
"englishFallback": {
|
|
26
|
+
"$comment": "Round 2 (docs/round-2-contract.md §3): the data of the ENGLISH fallback Formatter (src/format.ts englishFormatter; the Rust core's fallback reads the same): what a renderer without a platform ICU prints, equal to Intl en-US (ICU 74+) for every case of fixtures/format.json. `currencyPrefix` = the en-US prefix per ISO 4217 code (a code not listed prints `unknownCurrency`: `<CODE>` + U+00A0); `currencyDigits` = the minor digits where they are not 2; `relative` = the numeric:auto phrases of a unit at -1/0/+1 and the unit names (singular, plural); `datePatterns` = the TR35 pattern per `style`, `timePattern` = what `time: true` adds, joined by `dateTimeJoin[style]`. Instants show in the surface zone: the fallback takes the zone as a UTC offset per instant from the host (fixtures: `offsetMinutes`).",
|
|
27
|
+
"months": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
|
28
|
+
"monthsShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
|
29
|
+
"weekdays": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
|
30
|
+
"weekdaysShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
31
|
+
"dayPeriods": ["AM", "PM"],
|
|
32
|
+
"currencyPrefix": {
|
|
33
|
+
"USD": "$", "EUR": "€", "GBP": "£", "JPY": "¥", "CNY": "CN¥", "INR": "₹", "KRW": "₩", "CAD": "CA$", "AUD": "A$", "MXN": "MX$",
|
|
34
|
+
"BRL": "R$", "ILS": "₪", "NZD": "NZ$", "HKD": "HK$", "TWD": "NT$", "VND": "₫", "PHP": "₱", "XAF": "FCFA\u00a0", "XOF": "F\u202fCFA\u00a0"
|
|
35
|
+
},
|
|
36
|
+
"currencyDigits": { "JPY": 0, "KRW": 0, "VND": 0, "CLP": 0, "ISK": 0, "UGX": 0, "PYG": 0, "XAF": 0, "XOF": 0, "BHD": 3, "IQD": 3, "JOD": 3, "KWD": 3, "OMR": 3, "TND": 3 },
|
|
37
|
+
"relative": {
|
|
38
|
+
"units": { "second": ["second", "seconds"], "minute": ["minute", "minutes"], "hour": ["hour", "hours"], "day": ["day", "days"], "week": ["week", "weeks"], "month": ["month", "months"], "year": ["year", "years"] },
|
|
39
|
+
"auto": { "second": { "0": "now" }, "day": { "-1": "yesterday", "1": "tomorrow" }, "week": { "-1": "last week", "1": "next week" }, "month": { "-1": "last month", "1": "next month" }, "year": { "-1": "last year", "1": "next year" } },
|
|
40
|
+
"past": "{value} {unit} ago",
|
|
41
|
+
"future": "in {value} {unit}"
|
|
42
|
+
},
|
|
43
|
+
"unknownCurrency": "{code}\u00a0",
|
|
44
|
+
"datePatterns": { "short": "M/d/yy", "medium": "MMM d, y", "long": "MMMM d, y", "full": "EEEE, MMMM d, y" },
|
|
45
|
+
"timePattern": "h:mm a",
|
|
46
|
+
"dateTimeJoin": { "short": "{date}, {time}", "medium": "{date}, {time}", "long": "{date} at {time}", "full": "{date} at {time}" }
|
|
47
|
+
}
|
|
48
|
+
}
|