diff --git a/conformance/test_data/validation_schema/test_v09_basic_validation_schema.json b/conformance/test_data/validation_schema/test_v09_basic_validation_schema.json index cfb75ac577..f52ab2b28b 100644 --- a/conformance/test_data/validation_schema/test_v09_basic_validation_schema.json +++ b/conformance/test_data/validation_schema/test_v09_basic_validation_schema.json @@ -1082,6 +1082,15 @@ "$ref": "#/$defs/ComponentId", "description": "The unique identifier for a component, used for both definitions and references within the same surface." }, + "listStyle": { + "description": "The style of the list (ordered, unordered, or none).", + "enum": [ + "none", + "ordered", + "unordered" + ], + "type": "string" + }, "weight": { "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column.", "type": "number" diff --git a/dart/a2ui_core/CHANGELOG.md b/dart/a2ui_core/CHANGELOG.md index b4fc493a20..9913ce3319 100644 --- a/dart/a2ui_core/CHANGELOG.md +++ b/dart/a2ui_core/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- (v0_9) Restore `listStyle` property to basic catalog `List` component schema ([#3956](https://github.com/a2ui-project/a2ui/pull/3956)). + ## 0.5.0 - **Breaking:** The basic catalog `regex` function now validates patterns diff --git a/dart/a2ui_core/lib/src/basic_catalog/v0_9/catalog.g.dart b/dart/a2ui_core/lib/src/basic_catalog/v0_9/catalog.g.dart index d9be9ce0f9..7a907a14fc 100644 --- a/dart/a2ui_core/lib/src/basic_catalog/v0_9/catalog.g.dart +++ b/dart/a2ui_core/lib/src/basic_catalog/v0_9/catalog.g.dart @@ -494,6 +494,16 @@ List basicComponentsV0_9() => [ ], 'default': 'stretch', }, + 'listStyle': { + 'type': 'string', + 'description': + 'The style of the list (ordered, unordered, or none).', + 'enum': [ + 'ordered', + 'unordered', + 'none', + ], + }, }, 'required': [ 'component', diff --git a/python/a2ui_core/CHANGELOG.md b/python/a2ui_core/CHANGELOG.md index e5dfd630f8..19f3e4b98c 100644 --- a/python/a2ui_core/CHANGELOG.md +++ b/python/a2ui_core/CHANGELOG.md @@ -1,5 +1,6 @@ ## Unreleased +- (v0_9) Restore `list_style` (`listStyle`) property to basic catalog `List` component schema ([#3956](https://github.com/a2ui-project/a2ui/pull/3956)). - **BREAKING CHANGE**: Basic catalog `regex` function (`v0_9` and `v1_0`) now validates patterns against the A2UI portable regex subset (ECMAScript `Pattern` in Unicode mode with no flags), enforces the 4-rule static ReDoS safety guard (`PATTERN_TOO_LONG` at 256 code points, `NESTED_QUANTIFIER`, `OVERLAPPING_ALTERNATION`, and `ADJACENT_OVERLAP`), translates patterns to Python `re` with exact ECMAScript character class and anchor semantics (`\A`, `\Z`, ASCII `\d`/`\w`/`\b`/`\B`, and `\uXXXX`/`\UXXXXXXXX` bracket classes), raises `A2uiExpressionError` with the rejection token on invalid or unsafe patterns, and returns `False` / `{"valid": False}` without raising when the input value exceeds 4,096 Unicode code points. Recommended migration: rewrite patterns that use lookbehind, backreferences, named groups, `\p{...}`, inline flags, or nested/overlapping unbounded quantifiers to the portable subset. Exports `parse_regex_subset`, `check_regex_safety`, `analyze_regex`, `translate_to_python`, `compile_guarded`, `regex_test`, `RegexNode`, `RegexRejection`, `RegexAnalysisResult`, `RegexSyntaxError`, `MAX_REGEX_PATTERN_CODE_POINTS`, and `MAX_REGEX_VALUE_CODE_POINTS` from `a2ui.core` and `a2ui.core.common` ([#3854](https://github.com/a2ui-project/a2ui/pull/3854)). - **BREAKING CHANGE**: (v1_0) The basic catalog `TextField` requires `value`, as the other input components do, so a `TextField` without one fails diff --git a/python/a2ui_core/src/a2ui/core/basic_catalog/v0_9/components.py b/python/a2ui_core/src/a2ui/core/basic_catalog/v0_9/components.py index 1a995fc217..7e8e17564e 100644 --- a/python/a2ui_core/src/a2ui/core/basic_catalog/v0_9/components.py +++ b/python/a2ui_core/src/a2ui/core/basic_catalog/v0_9/components.py @@ -314,6 +314,11 @@ class ListComponent(CatalogComponentCommon): description="Defines the alignment of children along the cross axis.", json_schema_extra={"default": "stretch"}, ) + list_style: Literal["ordered", "unordered", "none"] | None = Field( + default=None, + alias="listStyle", + description="The style of the list (ordered, unordered, or none).", + ) class CardComponent(CatalogComponentCommon): diff --git a/specification/v0_9/catalogs/basic/catalog.json b/specification/v0_9/catalogs/basic/catalog.json index f8131a8572..c279eab364 100644 --- a/specification/v0_9/catalogs/basic/catalog.json +++ b/specification/v0_9/catalogs/basic/catalog.json @@ -356,6 +356,11 @@ "description": "Defines the alignment of children along the cross axis.", "enum": ["start", "center", "end", "stretch"], "default": "stretch" + }, + "listStyle": { + "type": "string", + "description": "The style of the list (ordered, unordered, or none).", + "enum": ["ordered", "unordered", "none"] } }, "required": ["component", "children"] diff --git a/typescript/core/web_core/CHANGELOG.md b/typescript/core/web_core/CHANGELOG.md index d5664c3504..61a17f1822 100644 --- a/typescript/core/web_core/CHANGELOG.md +++ b/typescript/core/web_core/CHANGELOG.md @@ -1,5 +1,6 @@ ## Unreleased +- (v0_9) Restore `listStyle` to the v0.9 basic catalog `ListApi` schema. - **BREAKING CHANGE**: Add `domId`, `accessibilityTarget()`, `renderValidationErrors()`, and `applyAccessibilityAttributes()` to `A2uiLitElement`, and export `CheckableResolvedProps` and `ResolvedAccessibilityAttributes` from `@a2ui/web_core/universal` (`@a2ui/web_core/v0_9/universal`), so universal custom elements apply `aria-live`, `aria-hidden`, and `inert` on the host, forward `accessibility.label`, `accessibility.description`, `aria-invalid`, and `aria-describedby` to `accessibilityTarget()` when provided, and fall back to `role="group"` (preserving any existing host `role`) plus `aria-label` and `aria-description` on the host when `accessibilityTarget()` returns `null`. Recommended migration: custom `A2uiLitElement` subclasses that already bind `props.accessibility.label` onto an inner element should override `accessibilityTarget()` to return that element so the label is not announced twice. [#3841](https://github.com/a2ui-project/a2ui/pull/3841) - **BREAKING CHANGE**: Stop assigning `element.context` in `renderA2uiNode(node)`, and deprecate `ComponentNode.context`, `A2uiLitElement.context`, and `A2uiWebComponentElement.context`. Recommended migration: accept `node` on custom `A2uiWebComponentElement` classes and read resolved values from `node.props` (or `this.controller.props`), obtaining the surface from the adapter's ambient context when needed. [#3841](https://github.com/a2ui-project/a2ui/pull/3841) - Track the schemas on the current recursion path in `analyzeChildRefSchema` and its union/array analysis so recursive Zod schemas (such as `z.lazy` unions containing arrays) terminate rather than throwing a call stack size exceeded RangeError during catalog reference map building. Sibling properties and union options that reuse one schema instance are still analyzed. diff --git a/typescript/core/web_core/src/universal/basic_catalog/components/List.test.ts b/typescript/core/web_core/src/universal/basic_catalog/components/List.test.ts index fc3c40036e..e86628476d 100644 --- a/typescript/core/web_core/src/universal/basic_catalog/components/List.test.ts +++ b/typescript/core/web_core/src/universal/basic_catalog/components/List.test.ts @@ -33,6 +33,8 @@ import { registerUniversalElement, type WebComponentImplementation, } from '../../index.js'; +import {ListApi} from '../../../v0_9/basic_catalog/components/basic_components.js'; +import {PayloadValidator} from '../../../validation/payload-validator.js'; describe('List Component', () => { let basicCatalog: Catalog; @@ -432,4 +434,47 @@ describe('List Component', () => { const ul = el.querySelector('ul.a2ui-list'); assert.strictEqual(ul?.getAttribute('aria-label'), 'Bullet points'); }); + + describe('ListApi schema validation', () => { + it('should parse valid list with listStyle', () => { + const parsed = ListApi.schema.parse({ + children: [], + listStyle: 'none', + }); + assert.strictEqual(parsed.listStyle, 'none'); + }); + + it('should parse valid listStyle variants', () => { + assert.strictEqual( + ListApi.schema.parse({children: [], listStyle: 'ordered'}).listStyle, + 'ordered', + ); + assert.strictEqual( + ListApi.schema.parse({children: [], listStyle: 'unordered'}).listStyle, + 'unordered', + ); + assert.strictEqual(ListApi.schema.parse({children: [], listStyle: 'none'}).listStyle, 'none'); + }); + + it('should reject invalid listStyle', () => { + assert.throws(() => + ListApi.schema.parse({ + children: [], + listStyle: 'invalid', + }), + ); + }); + + it('should validate list component with listStyle via PayloadValidator', () => { + const validator = new PayloadValidator(basicCatalog); + assert.doesNotThrow(() => { + validator.validateComponent({ + id: 'list-style-test', + component: 'List', + children: [], + listStyle: 'none', + }); + }); + }); + }); }); diff --git a/typescript/core/web_core/src/v0_9/basic_catalog/components/basic_components.ts b/typescript/core/web_core/src/v0_9/basic_catalog/components/basic_components.ts index 9fdf4aaa5a..4ecb1c91b3 100644 --- a/typescript/core/web_core/src/v0_9/basic_catalog/components/basic_components.ts +++ b/typescript/core/web_core/src/v0_9/basic_catalog/components/basic_components.ts @@ -347,6 +347,10 @@ export const ListApi = { .default('stretch') .describe('Defines the alignment of children along the cross axis.') .optional(), + 'listStyle': z + .enum(['ordered', 'unordered', 'none']) + .describe('The style of the list (ordered, unordered, or none).') + .optional(), }) .strict(), {mixins: ['ComponentCommon', CatalogComponentCommonSchema]},