diff --git a/code-gen-library/TestsAccessibilityNodeAddAction/Android.kt b/code-gen-library/TestsAccessibilityNodeAddAction/Android.kt new file mode 100644 index 000000000..fe205dabe --- /dev/null +++ b/code-gen-library/TestsAccessibilityNodeAddAction/Android.kt @@ -0,0 +1,26 @@ +//begin imports +import com.infragistics.mobile.controls.IgaAccessibilityNodeCreatingEventArgs; +import com.infragistics.mobile.controls.IgaAccessibilityAction; +import com.infragistics.mobile.controls.IgaAccessibilityActionCollection; +import com.infragistics.mobile.controls.IgaAccessibilityRole; +//end imports + +public class TestsAccessibilityNodeAddAction { + //begin eventHandler + public fun testsAccessibilityNodeAddAction(sender: Any?, args: IgaAccessibilityNodeCreatingEventArgs) { + var node = args.node; + if (node != null && node.role == IgaAccessibilityRole.ITEM) { + // Assign the collection first, then add to it through the property. + // The wrapper's getter lazily builds a collection that reads from the + // implementation but carries no sync target, so items added through it + // never reach the implementation; only the setter wires that + // write-through. It also means the null check the other platforms make + // would never fire here -- this getter does not return null. + node.actions = IgaAccessibilityActionCollection(); + var action = IgaAccessibilityAction(); + action.name = "Activate"; + node.actions!!.add(action); + } + } + //end eventHandler +} diff --git a/code-gen-library/TestsAccessibilityNodeAddAction/Desktop.cs b/code-gen-library/TestsAccessibilityNodeAddAction/Desktop.cs new file mode 100644 index 000000000..8c92c3c57 --- /dev/null +++ b/code-gen-library/TestsAccessibilityNodeAddAction/Desktop.cs @@ -0,0 +1,23 @@ +//begin imports +using Infragistics.Controls; +using Infragistics.Controls.Charts; +//end imports + +public class TestsAccessibilityNodeAddAction +{ + + //begin eventHandler + //WPF: Infragistics.Controls.Charts.AccessibilityNodeCreatingEventHandler + public void TestsAccessibilityNodeAddAction(object sender, AccessibilityNodeCreatingEventArgs args) + { + if (args.Node != null && args.Node.Role == AccessibilityRole.Item) + { + if (args.Node.Actions == null) + { + args.Node.Actions = new AccessibilityActionCollection(); + } + args.Node.Actions.Add(new AccessibilityAction() { Name = "Activate" }); + } + } + //end eventHandler +} diff --git a/code-gen-library/TestsAccessibilityNodeCancelAuto/Android.kt b/code-gen-library/TestsAccessibilityNodeCancelAuto/Android.kt new file mode 100644 index 000000000..633e69fa8 --- /dev/null +++ b/code-gen-library/TestsAccessibilityNodeCancelAuto/Android.kt @@ -0,0 +1,16 @@ +//begin imports +import com.infragistics.mobile.controls.IgaAccessibilityNodeCreatingEventArgs; +import com.infragistics.mobile.controls.IgaAccessibilityRole; +//end imports + +public class TestsAccessibilityNodeCancelAuto { + //begin eventHandler + public fun testsAccessibilityNodeCancelAuto(sender: Any?, args: IgaAccessibilityNodeCreatingEventArgs) { + var node = args.node; + if (node != null && node.role == IgaAccessibilityRole.ITEM) { + node.descriptionText = ""; + args.cancelAuto = true; + } + } + //end eventHandler +} diff --git a/code-gen-library/TestsAccessibilityNodeCancelAuto/Desktop.cs b/code-gen-library/TestsAccessibilityNodeCancelAuto/Desktop.cs new file mode 100644 index 000000000..5b2f69a23 --- /dev/null +++ b/code-gen-library/TestsAccessibilityNodeCancelAuto/Desktop.cs @@ -0,0 +1,20 @@ +//begin imports +using Infragistics.Controls; +using Infragistics.Controls.Charts; +//end imports + +public class TestsAccessibilityNodeCancelAuto +{ + + //begin eventHandler + //WPF: Infragistics.Controls.Charts.AccessibilityNodeCreatingEventHandler + public void TestsAccessibilityNodeCancelAuto(object sender, AccessibilityNodeCreatingEventArgs args) + { + if (args.Node != null && args.Node.Role == AccessibilityRole.Item) + { + args.Node.DescriptionText = ""; + args.CancelAuto = true; + } + } + //end eventHandler +} diff --git a/code-gen-library/TestsAccessibilityNodeCancelAuto/GTK.cs b/code-gen-library/TestsAccessibilityNodeCancelAuto/GTK.cs index 2587ac0b2..5b2f69a23 100644 --- a/code-gen-library/TestsAccessibilityNodeCancelAuto/GTK.cs +++ b/code-gen-library/TestsAccessibilityNodeCancelAuto/GTK.cs @@ -12,7 +12,7 @@ public void TestsAccessibilityNodeCancelAuto(object sender, AccessibilityNodeCre { if (args.Node != null && args.Node.Role == AccessibilityRole.Item) { - args.Node.Description = ""; + args.Node.DescriptionText = ""; args.CancelAuto = true; } } diff --git a/code-gen-library/TestsAccessibilityNodeCancelAuto/Web.ts b/code-gen-library/TestsAccessibilityNodeCancelAuto/Web.ts index 592d8e1a4..0123de373 100644 --- a/code-gen-library/TestsAccessibilityNodeCancelAuto/Web.ts +++ b/code-gen-library/TestsAccessibilityNodeCancelAuto/Web.ts @@ -7,7 +7,7 @@ export class TestsAccessibilityNodeCancelAuto { //begin eventHandler public testsAccessibilityNodeCancelAuto(sender: any, args: IgcAccessibilityNodeCreatingEventArgs): void { if (args.node != null && args.node.role == AccessibilityRole.Item) { - args.node.description = ""; + args.node.descriptionText = ""; args.cancelAuto = true; } } diff --git a/code-gen-library/TestsAccessibilityNodeOverrideDescription/Android.kt b/code-gen-library/TestsAccessibilityNodeOverrideDescription/Android.kt new file mode 100644 index 000000000..098f19cb9 --- /dev/null +++ b/code-gen-library/TestsAccessibilityNodeOverrideDescription/Android.kt @@ -0,0 +1,15 @@ +//begin imports +import com.infragistics.mobile.controls.IgaAccessibilityNodeCreatingEventArgs; +import com.infragistics.mobile.controls.IgaAccessibilityRole; +//end imports + +public class TestsAccessibilityNodeOverrideDescription { + //begin eventHandler + public fun testsAccessibilityNodeOverrideDescription(sender: Any?, args: IgaAccessibilityNodeCreatingEventArgs) { + var node = args.node; + if (node != null && node.role == IgaAccessibilityRole.ITEM) { + node.descriptionText = "custom override"; + } + } + //end eventHandler +} diff --git a/code-gen-library/TestsAccessibilityNodeOverrideDescription/Desktop.cs b/code-gen-library/TestsAccessibilityNodeOverrideDescription/Desktop.cs new file mode 100644 index 000000000..3657e9c61 --- /dev/null +++ b/code-gen-library/TestsAccessibilityNodeOverrideDescription/Desktop.cs @@ -0,0 +1,19 @@ +//begin imports +using Infragistics.Controls; +using Infragistics.Controls.Charts; +//end imports + +public class TestsAccessibilityNodeOverrideDescription +{ + + //begin eventHandler + //WPF: Infragistics.Controls.Charts.AccessibilityNodeCreatingEventHandler + public void TestsAccessibilityNodeOverrideDescription(object sender, AccessibilityNodeCreatingEventArgs args) + { + if (args.Node != null && args.Node.Role == AccessibilityRole.Item) + { + args.Node.DescriptionText = "custom override"; + } + } + //end eventHandler +} diff --git a/code-gen-library/TestsAccessibilityNodeOverrideDescription/GTK.cs b/code-gen-library/TestsAccessibilityNodeOverrideDescription/GTK.cs index 3f20ec6fd..3657e9c61 100644 --- a/code-gen-library/TestsAccessibilityNodeOverrideDescription/GTK.cs +++ b/code-gen-library/TestsAccessibilityNodeOverrideDescription/GTK.cs @@ -12,7 +12,7 @@ public void TestsAccessibilityNodeOverrideDescription(object sender, Accessibili { if (args.Node != null && args.Node.Role == AccessibilityRole.Item) { - args.Node.Description = "custom override"; + args.Node.DescriptionText = "custom override"; } } //end eventHandler diff --git a/code-gen-library/TestsAccessibilityNodeOverrideDescription/Web.ts b/code-gen-library/TestsAccessibilityNodeOverrideDescription/Web.ts index 0daa9de92..09a4a7aef 100644 --- a/code-gen-library/TestsAccessibilityNodeOverrideDescription/Web.ts +++ b/code-gen-library/TestsAccessibilityNodeOverrideDescription/Web.ts @@ -7,7 +7,7 @@ export class TestsAccessibilityNodeOverrideDescription { //begin eventHandler public testsAccessibilityNodeOverrideDescription(sender: any, args: IgcAccessibilityNodeCreatingEventArgs): void { if (args.node != null && args.node.role == AccessibilityRole.Item) { - args.node.description = "custom override"; + args.node.descriptionText = "custom override"; } } //end eventHandler diff --git a/tooling/src/codegen-api.ts b/tooling/src/codegen-api.ts index 8adec07b4..636651497 100644 --- a/tooling/src/codegen-api.ts +++ b/tooling/src/codegen-api.ts @@ -1105,8 +1105,7 @@ export function emitLibrary(platformName: string, opts: { const templateDir = itemTemplateDirFor(platformName, opts.templatesRoot); const library: any = libraryFor(opts.examplesRoot); - const names: string[] = (opts.only ?? (library.getItemNames?.() ?? library.getKeys())) - .filter((name: string) => !isAccessibilityLibraryItem(name)); + const names: string[] = opts.only ?? (library.getItemNames?.() ?? library.getKeys()); // A renderer per item, sharing one registered context — which is what the library project // emitter does, and not an optimisation. An emitter keeps state across an emission: the set of @@ -1156,7 +1155,7 @@ export function emitLibrary(platformName: string, opts: { const requires: string[] | null = item.getRequiresForPlatform(platform); if (requires !== null && requires !== undefined) { for (const required of requires) { - if (isAccessibilityLibraryItem(required) || seen.has(required) || !library.hasItem(required)) continue; + if (seen.has(required) || !library.hasItem(required)) continue; seen.add(required); queue.push(required); } @@ -1260,12 +1259,13 @@ function emitBlazorLibrary(platform: any, opts: { if (!fs.existsSync(templateDir)) throw new Error(`no blazor-template found at ${templateDir}`); const excluded = new Set(opts.exclude ?? []); const names: string[] = (opts.only ?? (library.getItemNames?.() ?? library.getKeys())) - .filter((name: string) => !excluded.has(name) && !isAccessibilityLibraryItem(name)); + .filter((name: string) => !excluded.has(name)); const queue = [...names]; const seen = new Set(names); const files: Record = {}; const problems: { item: string; reason: string }[] = []; const tracked: { name: string; access?: string; script?: boolean }[] = []; + let needsBlazorNamespace = false; let dataItems = 0; let handlerItems = 0; let context: any = null; @@ -1286,8 +1286,7 @@ function emitBlazorLibrary(platform: any, opts: { const item: any = library.getItem(name); const requires: string[] | null = item.getRequiresForPlatform(platform); for (const required of requires ?? []) { - if (!excluded.has(required) && !isAccessibilityLibraryItem(required) && - !seen.has(required) && library.hasItem(required)) { + if (!excluded.has(required) && !seen.has(required) && library.hasItem(required)) { seen.add(required); queue.push(required); } } @@ -1333,6 +1332,7 @@ function emitBlazorLibrary(platform: any, opts: { const source = emitted[`${stem}.razor`]; if (source === undefined) { problems.push({ item: name, reason: "no Razor source emitted" }); continue; } files[`${name}Holder.razor`] = source.split("PlaceholderHolder").join(`${name}Holder`); + needsBlazorNamespace = true; tracked.push({ name, access: `new Tuple, Func>(() => new ${name}Holder(), () => new ${name}Holder().${name})` }); } const css = emitted[`${stem}.css`]; @@ -1341,7 +1341,14 @@ function emitBlazorLibrary(platform: any, opts: { } files["BlazorLibrary.csproj"] = fs.readFileSync(path.join(templateDir, "BlazorLibrary.csproj"), "utf8"); - return { files, manager: dotNetManagerFor(tracked, "BlazorLibrary"), managerFile: "LibraryManager.cs", problems, dataItems, handlerItems }; + return { + files, + manager: dotNetManagerFor(tracked, needsBlazorNamespace ? "BlazorLibrary" : undefined), + managerFile: "LibraryManager.cs", + problems, + dataItems, + handlerItems, + }; } function emitNativeXamlLibrary(platformName: "WinUI" | "Uno", platform: any, opts: { @@ -1352,8 +1359,7 @@ function emitNativeXamlLibrary(platformName: "WinUI" | "Uno", platform: any, opt }, library: any): EmittedLibrary { const templateDir = path.join(opts.templatesRoot ?? "", "winui-template"); if (!fs.existsSync(templateDir)) throw new Error(`no winui-template found at ${templateDir}`); - const names: string[] = (opts.only ?? (library.getItemNames?.() ?? library.getKeys())) - .filter((name: string) => !isAccessibilityLibraryItem(name)); + const names: string[] = opts.only ?? (library.getItemNames?.() ?? library.getKeys()); const queue = [...names]; const seen = new Set(names); const files: Record = {}; @@ -1389,9 +1395,7 @@ function emitNativeXamlLibrary(platformName: "WinUI" | "Uno", platform: any, opt const item: any = library.getItem(name); const requires: string[] | null = item.getRequiresForPlatform(platform); for (const required of requires ?? []) { - if (!isAccessibilityLibraryItem(required) && !seen.has(required) && library.hasItem(required)) { - seen.add(required); queue.push(required); - } + if (!seen.has(required) && library.hasItem(required)) { seen.add(required); queue.push(required); } } const content = contentFor(item); if (content === null || content === undefined) continue; @@ -1504,17 +1508,12 @@ function enqueueSiblings(content: string, library: any, seen: Set, queue let match: RegExpExecArray | null; while ((match = pattern.exec(content)) !== null) { const name = match[1]; - if (name === "libraryManager" || isAccessibilityLibraryItem(name) || - seen.has(name) || !library.hasItem(name)) continue; + if (name === "libraryManager" || seen.has(name) || !library.hasItem(name)) continue; seen.add(name); queue.push(name); } } -function isAccessibilityLibraryItem(name: string): boolean { - return name.startsWith("Accessibility") || name.startsWith("TestsAccessibility"); -} - /** Where the per-item templates live: the library project emitter's own copy of them. */ function itemTemplateDirFor(platformName: string, templatesRoot?: string): string { const folder = platformName === "WebComponents" ? "webcomponents-template" diff --git a/tooling/test/tooling.test.mjs b/tooling/test/tooling.test.mjs index c710add5e..c9e6e4ad8 100644 --- a/tooling/test/tooling.test.mjs +++ b/tooling/test/tooling.test.mjs @@ -14,7 +14,7 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const CLI = path.join(ROOT, 'src', 'cli.mjs'); const require = createRequire(import.meta.url); require('../src/dom-shim.cjs'); -const { emitLibrary, emitProject } = require('../dist/codegen-api.cjs'); +const { emitProject } = require('../dist/codegen-api.cjs'); test('maps emitted folder diffs back to added, modified, and removed samples', () => { const workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'xplat-impact-test-')); @@ -465,22 +465,6 @@ test('emits and type-compiles a library item on every hosted web platform', () = } }); -test('temporarily skips accessibility items during library emission', () => { - for (const platform of ['Angular', 'React', 'WebComponents', 'Blazor', 'WinUI', 'Uno']) { - const emitted = emitLibrary(platform, { - examplesRoot: path.resolve(ROOT, '..'), - templatesRoot: path.join(ROOT, 'library-templates'), - only: ['SalesData', 'AccessibilityFutureItem', 'TestsAccessibilityNodeAddAction'], - }); - - assert.deepEqual(emitted.problems, []); - assert.equal(Object.keys(emitted.files) - .some(name => name.startsWith('TestsAccessibilityNodeAddAction')), false); - assert.doesNotMatch(emitted.manager, /TestsAccessibilityNodeAddAction/); - assert.ok(emitted.files[`SalesData.${['Angular', 'React', 'WebComponents'].includes(platform) ? 'ts' : 'cs'}`]); - } -}); - test('emits a Blazor Razor library with data, handlers, manager, and project', () => { const output = fs.mkdtempSync(path.join(os.tmpdir(), 'xplat-blazor-library-test-')); try { @@ -501,6 +485,20 @@ test('emits a Blazor Razor library with data, handlers, manager, and project', ( } }); +test('emits a Blazor data-only library manager without importing Blazor holder namespace', () => { + const output = fs.mkdtempSync(path.join(os.tmpdir(), 'xplat-blazor-data-only-library-test-')); + try { + execFileSync(process.execPath, [ + CLI, 'library', '--platform=Blazor', + '--only=SalesData', + `--output=${output}`, '--clean', + ], { cwd: ROOT, stdio: 'pipe' }); + assert.doesNotMatch(fs.readFileSync(path.join(output, 'LibraryManager.cs'), 'utf8'), /using BlazorLibrary;/); + } finally { + fs.rmSync(output, { recursive: true, force: true }); + } +}); + test('emits WinUI and Uno libraries through the native product renderers', () => { for (const platform of ['WinUI', 'Uno']) { const output = fs.mkdtempSync(path.join(os.tmpdir(), `xplat-${platform.toLowerCase()}-library-test-`));