@public-ui/mcp 4.1.1 → 4.1.2-rc.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@public-ui/mcp",
3
- "version": "4.1.1",
3
+ "version": "4.1.2-rc.1",
4
4
  "license": "EUPL-1.2",
5
5
  "homepage": "https://public-ui.github.io",
6
6
  "repository": {
@@ -46,19 +46,19 @@
46
46
  "express": "5.2.1",
47
47
  "fuse.js": "7.1.0",
48
48
  "zod": "4.3.6",
49
- "@public-ui/components": "4.1.1"
49
+ "@public-ui/components": "4.1.2-rc.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@eslint/js": "9.39.4",
53
53
  "@modelcontextprotocol/inspector": "0.21.1",
54
54
  "@types/express": "5.0.6",
55
- "@types/node": "25.3.5",
56
- "@typescript-eslint/eslint-plugin": "8.56.1",
57
- "@typescript-eslint/parser": "8.56.1",
55
+ "@types/node": "25.4.0",
56
+ "@typescript-eslint/eslint-plugin": "8.57.0",
57
+ "@typescript-eslint/parser": "8.57.0",
58
58
  "eslint": "9.39.4",
59
59
  "eslint-plugin-json": "4.0.1",
60
60
  "globals": "17.4.0",
61
- "knip": "5.85.0",
61
+ "knip": "5.86.0",
62
62
  "nodemon": "3.1.14",
63
63
  "prettier": "3.8.1",
64
64
  "prettier-plugin-organize-imports": "4.3.0",
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "metadata": {
3
- "generatedAt": "2026-03-09T08:31:38.848Z",
3
+ "generatedAt": "2026-03-11T12:32:37.972Z",
4
4
  "buildMode": "ci",
5
5
  "counts": {
6
- "total": 276,
7
- "totalDocs": 48,
6
+ "total": 277,
7
+ "totalDocs": 47,
8
8
  "totalSpecs": 54,
9
- "totalSamples": 156,
9
+ "totalSamples": 158,
10
10
  "totalScenarios": 18
11
11
  },
12
12
  "repo": {
13
- "commit": "3d811ac1c92cc2dc322639b18bf240059d522cf3",
13
+ "commit": "ce9415f097839e7c05d9d2d66f8c805aabb4fe7d",
14
14
  "branch": "develop",
15
15
  "repoUrl": "https://github.com/public-ui/kolibri"
16
16
  }
@@ -293,7 +293,7 @@
293
293
  "group": "docs",
294
294
  "name": "CVE_OVERVIEW",
295
295
  "path": "docs/CVE_OVERVIEW.md",
296
- "code": "# CVE Overview\n\n> For more security information, see [SECURITY.md](./SECURITY.md)\n\n## 1. Production Dependencies\n\n### Summary\n\n| Severity | v4 | v3 | v2 | v1 |\n| -------- | --: | --: | --: | --: |\n| critical | 0 | 0 | 0 | 0 |\n| high | 0 | 0 | 0 | 4 |\n| moderate | 0 | 0 | 0 | 0 |\n| low | 0 | 0 | 0 | 0 |\n| info | 0 | 0 | 0 | 0 |\n| unknown | 0 | 0 | 0 | 0 |\n\n### Vulnerabilities\n\n| Package | Severity | CVE | Affected Versions | Description |\n| -------------------- | -------- | ------------------- | ----------------- | --------------------------------------------------------------------------------- |\n| lodash.pick | high | CVE-2020-8203 | v1 | Prototype Pollution in lodash |\n| minimatch | high | CVE-2026-27903 | v1 | minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja |\n| minimatch | high | CVE-2026-27904 | v1 | minimatch ReDoS: nested \\*() extglobs generate catastrophically backtracking regu |\n| serialize-javascript | high | GHSA-5c6j-r48x-rmvq | v1 | Serialize JavaScript is Vulnerable to RCE via RegExp.flags and Date.prototype.to |\n\n## 2. All Dependencies\n\n### Summary\n\n| Severity | v4 | v3 | v2 | v1 |\n| -------- | --: | --: | --: | --: |\n| critical | 3 | 3 | 3 | 1 |\n| high | 17 | 17 | 27 | 20 |\n| moderate | 1 | 2 | 13 | 1 |\n| low | 3 | 3 | 8 | 0 |\n| info | 0 | 0 | 0 | 0 |\n| unknown | 0 | 0 | 0 | 0 |\n\n### Vulnerabilities\n\n| Package | Severity | CVE | Affected Versions | Description |\n| -------------------- | -------- | ------------------- | ----------------- | --------------------------------------------------------------------------------- |\n| basic-ftp | critical | CVE-2026-27699 | v4, v3, v2 | Basic FTP has Path Traversal Vulnerability in its downloadToDir() method |\n| fast-xml-parser | critical | CVE-2026-25896 | v4, v3, v2 | fast-xml-parser has an entity encoding bypass via regex injection in DOCTYPE ent |\n| locutus | critical | CVE-2026-25521 | v4, v3, v2, v1 | locutus is vulnerable to Prototype Pollution |\n| @angular/common | high | CVE-2025-66035 | v1 | Angular is Vulnerable to XSRF Token Leakage via Protocol-Relative URLs in Angula |\n| @angular/compiler | high | CVE-2025-66412 | v1 | Angular Stored XSS Vulnerability via SVG Animation, SVG URL and MathML Attribute |\n| @angular/compiler | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\n| @angular/core | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\n| @angular/core | high | CVE-2026-27970 | v1 | Angular i18n vulnerable to Cross-Site Scripting |\n| @hono/node-server | high | CVE-2026-29087 | v2 | @hono/node-server has authorization bypass for protected static paths via encode |\n| axios | high | CVE-2026-25639 | v3, v2 | Axios is Vulnerable to Denial of Service via **proto** Key in mergeConfig |\n| braces | high | CVE-2024-4068 | v4, v3, v2, v1 | Uncontrolled resource consumption in braces |\n| express-rate-limit | high | CVE-2026-30827 | v2 | express-rate-limit: IPv4-mapped IPv6 addresses bypass per-client rate limiting o |\n| fast-xml-parser | high | CVE-2026-25128 | v4, v3, v2 | fast-xml-parser has RangeError DoS Numeric Entities Bug |\n| fast-xml-parser | high | CVE-2026-26278 | v4, v3, v2 | fast-xml-parser affected by DoS through entity expansion in DOCTYPE (no expansio |\n| hono | high | CVE-2026-29045 | v2 | Hono vulnerable to arbitrary file access via serveStatic vulnerability |\n| immutable | high | CVE-2026-29063 | v2 | Immutable is vulnerable to Prototype Pollution |\n| locutus | high | CVE-2026-29091 | v4, v3, v2, v1 | locutus call_user_func_array vulnerable to Remote Code Execution (RCE) due to Co |\n| lodash.pick | high | CVE-2020-8203 | v2, v1 | Prototype Pollution in lodash |\n| minimatch | high | CVE-2026-27903 | v4, v3, v2, v1 | minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja |\n| minimatch | high | CVE-2026-27904 | v4, v3, v2, v1 | minimatch ReDoS: nested \\*() extglobs generate catastrophically backtracking regu |\n| minimatch | high | CVE-2026-26996 | v4, v3, v2 | minimatch has a ReDoS via repeated wildcards with non-matching literal in patter |\n| rollup | high | CVE-2026-27606 | v1 | Rollup 4 has Arbitrary File Write via Path Traversal |\n| semver | high | CVE-2022-25883 | v2 | semver vulnerable to Regular Expression Denial of Service |\n| serialize-javascript | high | GHSA-5c6j-r48x-rmvq | v4, v3, v2, v1 | Serialize JavaScript is Vulnerable to RCE via RegExp.flags and Date.prototype.to |\n| svgo | high | CVE-2026-29074 | v4, v3, v2, v1 | SVGO DoS through entity expansion in DOCTYPE (Billion Laughs) |\n| tar | high | CVE-2026-23950 | v1 | Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on |\n| tar | high | CVE-2026-24842 | v1 | node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Trave |\n| tar | high | CVE-2026-23745 | v1 | node-tar is Vulnerable to Arbitrary File Overwrite and Symlink Poisoning via Ins |\n| tar | high | CVE-2026-26960 | v4, v3, v1 | Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in no |\n| tar | high | CVE-2026-29786 | v4, v3, v2, v1 | tar has Hardlink Path Traversal via Drive-Relative Linkpath |\n| ajv | moderate | CVE-2025-69873 | v3, v2 | ajv has ReDoS when using `$data` option |\n| ejs | moderate | CVE-2024-33883 | v2 | ejs lacks certain pollution protection |\n| esbuild | moderate | GHSA-67mh-4wv8-2f99 | v2 | esbuild enables any website to send any requests to the development server and r |\n| hono | moderate | CVE-2026-29086 | v2 | Hono Vulnerable to Cookie Attribute Injection via Unsanitized domain and path in |\n| hono | moderate | CVE-2026-29085 | v2 | Hono Vulnerable to SSE Control Field Injection via CR/LF in writeSSE() |\n| js-yaml | moderate | CVE-2025-64718 | v2 | js-yaml has prototype pollution in merge (<<) |\n| micromatch | moderate | CVE-2024-4067 | v4, v3, v2, v1 | Regular Expression Denial of Service (ReDoS) in micromatch |\n| nanoid | moderate | CVE-2024-55565 | v2 | Predictable results in nanoid generation when given non-integer values |\n| qs | moderate | CVE-2025-15284 | v2 | qs's arrayLimit bypass in its bracket notation allows DoS via memory exhaustion |\n| serialize-javascript | moderate | CVE-2024-11831 | v2 | Cross-site Scripting (XSS) in serialize-javascript |\n| webpack | moderate | CVE-2024-43788 | v2 | Webpack's AutoPublicPathRuntimeModule has a DOM Clobbering Gadget that leads to |\n| webpack-dev-server | moderate | CVE-2025-30360 | v2 | webpack-dev-server users' source code may be stolen when they access a malicious |\n| webpack-dev-server | moderate | CVE-2025-30359 | v2 | webpack-dev-server users' source code may be stolen when they access a malicious |\n| @tootallnate/once | low | CVE-2026-3449 | v4, v3, v2 | @tootallnate/once vulnerable to Incorrect Control Flow Scoping |\n| diff | low | CVE-2026-24001 | v4, v3, v2 | jsdiff has a Denial of Service vulnerability in parsePatch and applyPatch |\n| fast-xml-parser | low | CVE-2026-27942 | v4, v3, v2 | fast-xml-parser has stack overflow in XMLBuilder with preserveOrder |\n| hono | low | GHSA-gq3j-xvxp-8hrf | v2 | Hono added timing comparison hardening in basicAuth and bearerAuth |\n| qs | low | CVE-2026-2391 | v2 | qs's arrayLimit bypass in comma parsing allows denial of service |\n| webpack | low | CVE-2025-68458 | v2 | webpack buildHttp: allowedUris allow-list bypass via URL userinfo (@) leading to |\n| webpack | low | CVE-2025-68157 | v2 | webpack buildHttp HttpUriPlugin allowedUris bypass via HTTP redirects → SSRF + c |\n",
296
+ "code": "# CVE Overview\n\n> For more security information, see [SECURITY.md](./SECURITY.md)\n\n## 1. Production Dependencies\n\n### Summary\n\n| Severity | v4 | v3 | v2 | v1 |\n| -------- | --: | --: | --: | --: |\n| critical | 0 | 0 | 0 | 0 |\n| high | 0 | 0 | 0 | 4 |\n| moderate | 0 | 0 | 0 | 0 |\n| low | 0 | 0 | 0 | 0 |\n| info | 0 | 0 | 0 | 0 |\n| unknown | 0 | 0 | 0 | 0 |\n\n### Vulnerabilities\n\n| Package | Severity | CVE | Affected Versions | Description |\n| -------------------- | -------- | ------------------- | ----------------- | --------------------------------------------------------------------------------- |\n| lodash.pick | high | CVE-2020-8203 | v1 | Prototype Pollution in lodash |\n| minimatch | high | CVE-2026-27903 | v1 | minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja |\n| minimatch | high | CVE-2026-27904 | v1 | minimatch ReDoS: nested \\*() extglobs generate catastrophically backtracking regu |\n| serialize-javascript | high | GHSA-5c6j-r48x-rmvq | v1 | Serialize JavaScript is Vulnerable to RCE via RegExp.flags and Date.prototype.to |\n\n## 2. All Dependencies\n\n### Summary\n\n| Severity | v4 | v3 | v2 | v1 |\n| -------- | --: | --: | --: | --: |\n| critical | 3 | 3 | 3 | 1 |\n| high | 18 | 18 | 28 | 21 |\n| moderate | 2 | 2 | 14 | 1 |\n| low | 3 | 3 | 8 | 0 |\n| info | 0 | 0 | 0 | 0 |\n| unknown | 0 | 0 | 0 | 0 |\n\n### Vulnerabilities\n\n| Package | Severity | CVE | Affected Versions | Description |\n| -------------------- | -------- | ------------------- | ----------------- | --------------------------------------------------------------------------------- |\n| basic-ftp | critical | CVE-2026-27699 | v4, v3, v2 | Basic FTP has Path Traversal Vulnerability in its downloadToDir() method |\n| fast-xml-parser | critical | CVE-2026-25896 | v4, v3, v2 | fast-xml-parser has an entity encoding bypass via regex injection in DOCTYPE ent |\n| locutus | critical | CVE-2026-25521 | v4, v3, v2, v1 | locutus is vulnerable to Prototype Pollution |\n| @angular/common | high | CVE-2025-66035 | v1 | Angular is Vulnerable to XSRF Token Leakage via Protocol-Relative URLs in Angula |\n| @angular/compiler | high | CVE-2025-66412 | v1 | Angular Stored XSS Vulnerability via SVG Animation, SVG URL and MathML Attribute |\n| @angular/compiler | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\n| @angular/core | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\n| @angular/core | high | CVE-2026-27970 | v1 | Angular i18n vulnerable to Cross-Site Scripting |\n| @hono/node-server | high | CVE-2026-29087 | v2 | @hono/node-server has authorization bypass for protected static paths via encode |\n| axios | high | CVE-2026-25639 | v3, v2 | Axios is Vulnerable to Denial of Service via **proto** Key in mergeConfig |\n| braces | high | CVE-2024-4068 | v4, v3, v2, v1 | Uncontrolled resource consumption in braces |\n| express-rate-limit | high | CVE-2026-30827 | v2 | express-rate-limit: IPv4-mapped IPv6 addresses bypass per-client rate limiting o |\n| fast-xml-parser | high | CVE-2026-25128 | v4, v3, v2 | fast-xml-parser has RangeError DoS Numeric Entities Bug |\n| fast-xml-parser | high | CVE-2026-26278 | v4, v3, v2 | fast-xml-parser affected by DoS through entity expansion in DOCTYPE (no expansio |\n| hono | high | CVE-2026-29045 | v2 | Hono vulnerable to arbitrary file access via serveStatic vulnerability |\n| immutable | high | CVE-2026-29063 | v2 | Immutable is vulnerable to Prototype Pollution |\n| locutus | high | CVE-2026-29091 | v4, v3, v2, v1 | locutus call_user_func_array vulnerable to Remote Code Execution (RCE) due to Co |\n| lodash.pick | high | CVE-2020-8203 | v2, v1 | Prototype Pollution in lodash |\n| minimatch | high | CVE-2026-27903 | v4, v3, v2, v1 | minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja |\n| minimatch | high | CVE-2026-27904 | v4, v3, v2, v1 | minimatch ReDoS: nested \\*() extglobs generate catastrophically backtracking regu |\n| minimatch | high | CVE-2026-26996 | v4, v3, v2 | minimatch has a ReDoS via repeated wildcards with non-matching literal in patter |\n| rollup | high | CVE-2026-27606 | v1 | Rollup 4 has Arbitrary File Write via Path Traversal |\n| semver | high | CVE-2022-25883 | v2 | semver vulnerable to Regular Expression Denial of Service |\n| serialize-javascript | high | GHSA-5c6j-r48x-rmvq | v4, v3, v2, v1 | Serialize JavaScript is Vulnerable to RCE via RegExp.flags and Date.prototype.to |\n| svgo | high | CVE-2026-29074 | v4, v3, v2, v1 | SVGO DoS through entity expansion in DOCTYPE (Billion Laughs) |\n| tar | high | CVE-2026-23950 | v1 | Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on |\n| tar | high | CVE-2026-24842 | v1 | node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Trave |\n| tar | high | CVE-2026-23745 | v1 | node-tar is Vulnerable to Arbitrary File Overwrite and Symlink Poisoning via Ins |\n| tar | high | CVE-2026-26960 | v4, v3, v1 | Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in no |\n| tar | high | CVE-2026-29786 | v4, v3, v2, v1 | tar has Hardlink Path Traversal via Drive-Relative Linkpath |\n| tar | high | CVE-2026-31802 | v4, v3, v2, v1 | node-tar Symlink Path Traversal via Drive-Relative Linkpath |\n| ajv | moderate | CVE-2025-69873 | v3, v2 | ajv has ReDoS when using `$data` option |\n| ejs | moderate | CVE-2024-33883 | v2 | ejs lacks certain pollution protection |\n| esbuild | moderate | GHSA-67mh-4wv8-2f99 | v2 | esbuild enables any website to send any requests to the development server and r |\n| file-type | moderate | CVE-2026-31808 | v4 | file-type affected by infinite loop in ASF parser on malformed input with zero-s |\n| hono | moderate | CVE-2026-29086 | v2 | Hono Vulnerable to Cookie Attribute Injection via Unsanitized domain and path in |\n| hono | moderate | CVE-2026-29085 | v2 | Hono Vulnerable to SSE Control Field Injection via CR/LF in writeSSE() |\n| hono | moderate | GHSA-v8w9-8mx6-g223 | v2 | Hono vulnerable to Prototype Pollution possible through **proto** key allowed in |\n| js-yaml | moderate | CVE-2025-64718 | v2 | js-yaml has prototype pollution in merge (<<) |\n| micromatch | moderate | CVE-2024-4067 | v4, v3, v2, v1 | Regular Expression Denial of Service (ReDoS) in micromatch |\n| nanoid | moderate | CVE-2024-55565 | v2 | Predictable results in nanoid generation when given non-integer values |\n| qs | moderate | CVE-2025-15284 | v2 | qs's arrayLimit bypass in its bracket notation allows DoS via memory exhaustion |\n| serialize-javascript | moderate | CVE-2024-11831 | v2 | Cross-site Scripting (XSS) in serialize-javascript |\n| webpack | moderate | CVE-2024-43788 | v2 | Webpack's AutoPublicPathRuntimeModule has a DOM Clobbering Gadget that leads to |\n| webpack-dev-server | moderate | CVE-2025-30360 | v2 | webpack-dev-server users' source code may be stolen when they access a malicious |\n| webpack-dev-server | moderate | CVE-2025-30359 | v2 | webpack-dev-server users' source code may be stolen when they access a malicious |\n| @tootallnate/once | low | CVE-2026-3449 | v4, v3, v2 | @tootallnate/once vulnerable to Incorrect Control Flow Scoping |\n| diff | low | CVE-2026-24001 | v4, v3, v2 | jsdiff has a Denial of Service vulnerability in parsePatch and applyPatch |\n| fast-xml-parser | low | CVE-2026-27942 | v4, v3, v2 | fast-xml-parser has stack overflow in XMLBuilder with preserveOrder |\n| hono | low | GHSA-gq3j-xvxp-8hrf | v2 | Hono added timing comparison hardening in basicAuth and bearerAuth |\n| qs | low | CVE-2026-2391 | v2 | qs's arrayLimit bypass in comma parsing allows denial of service |\n| webpack | low | CVE-2025-68458 | v2 | webpack buildHttp: allowedUris allow-list bypass via URL userinfo (@) leading to |\n| webpack | low | CVE-2025-68157 | v2 | webpack buildHttp HttpUriPlugin allowedUris bypass via HTTP redirects → SSRF + c |\n",
297
297
  "kind": "doc"
298
298
  },
299
299
  {
@@ -389,15 +389,7 @@
389
389
  "group": "docs/tutorials",
390
390
  "name": "NEW_COMPONENT",
391
391
  "path": "docs/tutorials/NEW_COMPONENT.md",
392
- "code": "# Neue Komponente erstellen\n\n> Schritt-für-Schritt-Anleitung, wie man eine neue Komponente im Teilmodul `components` erstellt.\n\n## Grundprinzipien\n\nFolgende Grundprinzipien gelten für das Schreiben von Quellcode:\n\n- Auflistungen werden immer alphabetisch sortiert\n- Wiederverwendete Algorithmen (z.B. Property-Validatoren) werden in statische Funktionen ausgelagert (z.B. `packages/schema/src/validators/<prop-name>.ts`)\n- ...\n\n## Checkliste\n\n| Schritt | Kurzbeschreibung |\n| :-----: | ---------------------------------------------------------------------------------------------------------------------------------------- |\n| 0 | Projekt starten |\n| 1 | Name im Schema hinterlegen |\n| 2 | Verzeichnis anlegen<br>- component.tsx(optional)<br>- readme.md<br>- shadow.tsx: Komponente mit Shadow DOM<br>- styles.css<br>- types.ts |\n| 3 | API spezifizieren |\n| 4 | Klasse zur API implementieren<br>- Props<br>- State<br>- Watcher<br>- Initialer Hook<br>- Render-Methode |\n| 5 | Styling anlegen |\n| 6 | Beispiele in `index.html` aufnehmen |\n| 7 | readme.md vervollständigen |\n| ... | ... |\n| ... | Klasse in Komponenten-Liste für Tests aufnehmen (packages/components/src/components/component-list.ts) |\n| ... | Alle autogeneierten Daten zur Komponente mit einchecken |\n\n## Schritt 0\n\nProjekt starten, wie in [Contribution](../../CONTRIBUTING.md) beschrieben.\n\n## Schritt 1\n\nAls erstes wird der **Name** der neuen Komponenten in der **Schema**-Datei (`packages/schema/tag-names.ts`) hinterlegt.\n\n## Schritt 2 - Verzeichnis anlegen\n\nEine Vorlage ist unter `/docs/tutorials/new-component` zu finden. Ziel: `/packages/components/src/components/[component-name]`.\nSofern eine Variante ohne Shadow DOM für andere Komponenten benötigt wird, ist die Komponente selbst, mit `shadow: false` anzulegen und diese Komponente in `shadow.tsx` einzubinden.\nAndernfalls ist die Komponente direkt mit `shadow: true` in `shadow.tsx` zu implementieren.\nZiel: shadow.tsx existiert immer und liefert die Komponente mit Shadow DOM.\nDie `readme.md` wird automatisch bei `pnpm build` erzeugt, sollte sie bereits existieren wird der automatisch generierte Inhalt angehängt.\n\n## Schritt 3 - API spezifizieren\n\nDatei: `types.ts`;\nInhalt: `RequiredProps`, `OptionalProps`, `RequiredStates`, `OptionalStates`, `States` und `ComponentApi`\n\n## Schritt 4 - Klasse Implementieren\n\nDatei: `shadow.tsx` oder/und `component.tsx`;\nInhalt:\n\n- `@Component` (außerhalb der Klasse),\n- `@Prop`: alphabetisch sortiert,\n- `@State`: Standardwerte werden hier gesetzt,\n- `@Watch`: werden bei Änderungen des Wertes aufgerufen, Validierung und Übernahme des Wertes in den State,\n- `public componentWillLoad()`: Initialer Hook, alle Validierungsmethoden hier aufrufen\n- `public render()`: Render-Methode, erstellt das HTML, das gerendert werden soll\n\n## Schritt 5 - Styling anlegen\n\nDatei: `styles.css`;\nWichtig: `packages/components/src/components/README.md` beachten.\nSofern Styling für mehrere Komponenten verwendet werden soll, Datei passend benennen und direkt unter `/packages/components/src/components/` erstellen und in styles.css importieren.\n\n## Schritt 6 - Beispiel in index.html erstellen\n\nDatei: `/packages/components/src/index.html`;\nUnter body > main > ol ein li mit dem Beispielcode erstellen.\nAus dem Verzeichnis `/packages/components` kann mit `pnpm start` der dev-server gestartet werden.\nAndere li können vorrübergehend entfernt werden, dafür ist die `index.bak.html` da.\nNach Beendigung der Entwicklung ist die `index.html` zurückzusetzen, abgesehen des neuen Beispiels, welches in die `index.bak.html` ebenfalls einzufügen ist.\n\n## Schritt 7 - readme.md vervollständigen\n\nDatei: `readme.md`;\nDie von `pnpm build` (in `/packages/components` ausgeführt) erzeugte `readme.md` mit sinnvollen Informationen vervollständigen.\n\n... bitte fortsetzen.\n",
393
- "kind": "doc"
394
- },
395
- {
396
- "id": "doc/tutorials/new-component/readme",
397
- "group": "docs/tutorials/new-component",
398
- "name": "readme",
399
- "path": "docs/tutorials/new-component/readme.md",
400
- "code": "# New-Component\n\n> kurze Beschreibung der gerenderten Komponente (nicht technisch)\n\n> wann diese Komponente einzusetzen ist\n\n## Konstruktion\n\n### Code\n\n> Beispielcode, wird als Code in der Dokumentation angezeigt\n\n```html\n<kol-new-component _heading=\"Element 1\">\n\t<div slot=\"content\">\n\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.\n\t\tAt vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum\n\t\tdolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos\n\t\tet accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\n\t</div>\n\t<div slot=\"header\">Inhalt eines Header</div>\n</kol-new-component>\n```\n\n### Beispiel\n\n> Beispiel, wird gerendert; Empfehlung: selber code wie oben, eventuell mit Wrapper\n\n<div class=\"grid gap-2\">\n <kol-new-component _heading=\"Element 1\">\n <div slot=\"content\">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</div>\n <div slot=\"header\">Inhalt eines Header</div>\n </kol-new-component>\n</div>\n\n## Verwendung\n\n> Erläuterungen der Attribute und Slots\n\n### Best practices\n\n- so soll man das verwenden\n- das sollte man beachten\n- das sollte man vermeiden\n\n### Anwendungsfälle\n\n- für welchen Fall die Komponente gedacht ist\n\n## Barrierefreiheit\n\n### Tastatursteuerung\n\n| Taste | Funktion |\n| ------- | ---------------------------------- |\n| `Tab` | Springt die einzelnen Elemente an. |\n| `Enter` | Tut Dinge. |\n\n## Links und Referenzen\n\n- Liste von hilfreichen Links\n\n> Der folgende Teil wird automatisch beim build generiert. Die Überschriften sind als Hilfe, was man nicht manuell einfügen muss.\n\n<!-- Auto Generated Below -->\n\n## Properties\n\n| Property | Attribute | Description | Type | Default |\n| ----------------------- | ---------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------ | ----------- |\n| `_heading` _(required)_ | `_heading` | Gibt die Überschrift des NewComponents an. | `string` | `undefined` |\n| `_level` | `_level` | Gibt an, welchen H-Level von 1 bis 6 die Überschrift hat. | `0 \\| 1 \\| 2 \\| 3 \\| 4 \\| 5 \\| 6 \\| undefined` | `1` |\n| `_on` | -- | Gibt die EventCallback-Funktionen an. | `undefined \\| { onClick?: EventValueOrEventCallback<Event, boolean> \\| undefined; }` | `undefined` |\n| `_open` | `_open` | Gibt an, ob das NewComponent geöffnet ist. | `boolean \\| undefined` | `false` |\n\n## Slots\n\n| Slot | Description |\n| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `\"content\"` | Ermöglicht das Einfügen beliebigen HTML's in den Inhaltsbereich des NewComponents. (wenn nur ein slot verwendet wird, kann der Name weggelassen werden) |\n\n## Dependencies\n\n### Depends on\n\n- [kol-button](../button)\n- [kol-heading-wc](../heading)\n\n### Graph\n\n```mermaid\ngraph TD;\n kol-new-component --> kol-button\n kol-new-component --> kol-heading-wc\n kol-button --> kol-button-wc\n kol-button-wc --> kol-span-wc\n kol-button-wc --> kol-tooltip-wc\n kol-span-wc --> kol-icon\n kol-tooltip-wc --> kol-span-wc\n style kol-new-component stroke:#333,stroke-width:4px\n```\n\n---\n",
392
+ "code": "# Neue Komponente erstellen\n\n> Schritt-für-Schritt-Anleitung basierend auf dem [Skeleton Blueprint](../../packages/components/src/components/_skeleton/ARC42.md).\n\n## Grundprinzipien\n\n- Auflistungen werden immer alphabetisch sortiert\n- Die [ARC42.md](../../packages/components/src/components/_skeleton/ARC42.md) ist die führende Architektur-Spezifikation — lies sie vollständig, bevor du eine neue Komponente erstellst\n- Alle Web Components verwenden `shadow: true` — Komponenten ohne Shadow DOM werden als Functional Components implementiert\n- Props leben in `src/internal/props/` mit eigenem `PropDefinition` pro Prop\n- Kein toter Code, keine Barrel-Files, keine `types.ts`\n\n## Checkliste\n\n| Schritt | Kurzbeschreibung |\n| :-----: | ------------------------------------------------------------------------------- |\n| 0 | Projekt starten |\n| 1 | Tag-Name in Stencil-Konfiguration registrieren |\n| 2 | Props erstellen oder vorhandene wiederverwenden (`src/internal/props/`) |\n| 3 | API-Definition erstellen (`api.tsx`) mit `PropsConfigShape` und `ApiFromConfig` |\n| 4 | Controller implementieren (`controller.ts`) — erweitert `BaseController<Api>` |\n| 5 | Functional Component erstellen (`component.tsx`) — stateless Renderer |\n| 6 | Web Component erstellen (`component.tsx`) — erweitert `BaseWebComponent<Api>` |\n| 7 | Tests co-lokalisiert neben `component.tsx` erstellen |\n| 8 | Beispiel in React-Sample-App anlegen |\n| 9 | Validierung: `pnpm format && pnpm lint && pnpm test && pnpm -r build` |\n\n## Schritt 0 — Projekt starten\n\nProjekt starten, wie in [Contribution](../../CONTRIBUTING.md) beschrieben.\n\n## Schritt 1 — Tag-Name registrieren\n\nDen Tag-Namen der neuen Komponente in `packages/components/stencil.config.ts` registrieren.\n\n## Schritt 2 — Props erstellen (Props-First!)\n\n**Bevor die Komponente implementiert wird, müssen alle Props definiert sein.**\n\nPro Prop eine Datei unter `src/internal/props/`:\n\n```typescript\n// src/internal/props/name.ts\nimport type { SimpleProp } from './helpers/factory';\nimport { createPropDefinition } from './helpers/factory';\nimport { normalizeString } from './helpers/normalizers';\n\nexport type NameProp = SimpleProp<'name', string>;\nexport const nameProp = createPropDefinition<NameProp>('name', '', normalizeString);\n```\n\n- `SimpleProp<K, T>` wenn externer und interner Typ identisch sind\n- `Prop<K, TExternal, TInternal>` wenn sich die Typen unterscheiden (z.B. `ColorProp`)\n- Export in `src/internal/props/index.ts` hinzufügen\n- Bestehende Props aus `index.ts` wiederverwenden, wenn möglich\n\nDetails: [ARC42 §4 — Schema Helper Layer](../../packages/components/src/components/_skeleton/ARC42.md#schema-helper-layer)\n\n## Schritt 3 — API-Definition\n\nDatei: `src/internal/functional-components/<component>/api.tsx`\n\n```typescript\nimport { nameProp } from '../../props';\nimport type { ApiFromConfig, PropsConfigShape } from '../generic-types';\n\nexport const myComponentPropsConfig = {\n\trequired: [nameProp],\n\t// optional: [showProp],\n} as const satisfies PropsConfigShape;\n\nexport type MyComponentApi = ApiFromConfig<\n\ttypeof myComponentPropsConfig,\n\t{\n\t\t// Nur definieren, was die Komponente tatsächlich nutzt:\n\t\t// Callbacks: { click: () => void };\n\t\t// Emitters: { change: string };\n\t\t// Methods: { focus: () => void };\n\t\t// States: { count: number };\n\t\t// Refs: { button: HTMLButtonElement };\n\t\t// Listeners: { keydown: KeyboardEvent };\n\t}\n>;\n```\n\nDetails: [ARC42 §4 — API Definition with PropsConfigShape](../../packages/components/src/components/_skeleton/ARC42.md#api-definition-with-propsconfigshape-and-apifromconfig)\n\n## Schritt 4 — Controller\n\nDatei: `src/internal/functional-components/<component>/controller.ts`\n\n```typescript\nimport { nameProp } from '../../props';\nimport { BaseController } from '../base-controller';\nimport type { ControllerInterface, GetStateFn, ResolvedInputProps, SetStateFn } from '../generic-types';\nimport type { MyComponentApi } from './api';\nimport { myComponentPropsConfig } from './api';\n\nexport class MyComponentController extends BaseController<MyComponentApi> implements ControllerInterface<MyComponentApi> {\n\tpublic constructor(setState: SetStateFn<MyComponentApi>, getState: GetStateFn<MyComponentApi>) {\n\t\tsuper(myComponentPropsConfig, setState, getState);\n\t}\n\n\tpublic componentWillLoad(props: ResolvedInputProps<MyComponentApi>): void {\n\t\tconst { name } = props;\n\t\tthis.watchName(name);\n\t}\n\n\tpublic watchName(value?: string): void {\n\t\tnameProp.apply(value, (v) => {\n\t\t\tthis.setRenderProp('name', v);\n\t\t});\n\t}\n}\n```\n\n- Event-Handler und Ref-Setter als **Arrow-Properties** (`handleClick = () => { … }`)\n- Lifecycle- und Watcher-Methoden als **Prototype-Methoden**\n- Details: [ARC42 §4 — Controller Layer](../../packages/components/src/components/_skeleton/ARC42.md#controller-layer)\n\n## Schritt 5 — Functional Component\n\nDatei: `src/internal/functional-components/<component>/component.tsx`\n\n```tsx\nimport type { FunctionalComponent as FC } from '@stencil/core';\nimport { h } from '@stencil/core';\nimport { bem } from '../../../schema/bem-registry';\nimport type { FunctionalComponentProps } from '../generic-types';\nimport type { MyComponentApi } from './api';\n\nconst myBem = bem.forBlock('kol-my-component');\n\nexport const MyComponentFC: FC<FunctionalComponentProps<MyComponentApi>> = (props) => {\n\tconst { name } = props;\n\treturn (\n\t\t<div class={myBem()}>\n\t\t\t<span class={myBem('name')}>{name}</span>\n\t\t</div>\n\t);\n};\n```\n\n- Stateless, keine Seiteneffekte\n- Details: [ARC42 §4 — Functional Component Layer](../../packages/components/src/components/_skeleton/ARC42.md#functional-component-layer)\n\n## Schritt 6 — Web Component\n\nDatei: `src/components/<component>/web-components/<component>/component.tsx`\n\n```tsx\nimport type { JSX } from '@stencil/core';\nimport { Component, h, Host, Prop, Watch } from '@stencil/core';\nimport { BaseWebComponent } from '../../../../internal/functional-components/base-web-component';\nimport type { WebComponentInterface } from '../../../../internal/functional-components/generic-types';\nimport type { MyComponentApi } from '../../../../internal/functional-components/my-component/api';\nimport { MyComponentFC } from '../../../../internal/functional-components/my-component/component';\nimport { MyComponentController } from '../../../../internal/functional-components/my-component/controller';\n\n@Component({\n\ttag: 'kol-my-component',\n\tshadow: true,\n})\nexport class KolMyComponent extends BaseWebComponent<MyComponentApi> implements WebComponentInterface<MyComponentApi> {\n\tprivate readonly ctrl = new MyComponentController(this.setState, this.getState);\n\n\t@Prop()\n\tpublic _name!: string;\n\n\t@Watch('_name')\n\tpublic watchName(value?: string): void {\n\t\tthis.ctrl.watchName(value);\n\t}\n\n\tpublic componentWillLoad(): void {\n\t\tthis.ctrl.componentWillLoad({\n\t\t\tname: this._name,\n\t\t});\n\t}\n\n\tpublic render(): JSX.Element {\n\t\treturn (\n\t\t\t<Host>\n\t\t\t\t<MyComponentFC name={this.ctrl.getRenderProp('name')} />\n\t\t\t</Host>\n\t\t);\n\t}\n}\n```\n\n- Immer `shadow: true` und `<Host>` ohne Klassen-Attribut\n- `@Watch` nur auf unterstrichene Props\n- Details: [ARC42 §4 — Web Component Layer](../../packages/components/src/components/_skeleton/ARC42.md#web-component-layer)\n\n## Schritt 7 — Tests\n\nTests liegen **direkt neben** `component.tsx` — kein `test/`-Unterordner.\n\n**Snapshot-Test** (`snapshot.spec.tsx`):\n\n```tsx\nimport { executeSnapshotTests } from '../../../../utils/testing';\nimport { KolMyComponent } from './component';\n\nconst TAG = 'kol-my-component';\n\ntype Props = {\n\t_name: string;\n};\n\nexecuteSnapshotTests<Props>(TAG, [KolMyComponent], [{ _name: 'Test' }, { _name: '' }]);\n```\n\n**Interaction-Test** (`interaction.e2e.ts`):\n\n```typescript\nimport { expect } from '@playwright/test';\nimport { test } from '@stencil/playwright';\n\ntest.describe('kol-my-component', () => {\n\ttest.beforeEach(async ({ page }) => {\n\t\tawait page.setContent('<kol-my-component _name=\"Test\"></kol-my-component>');\n\t});\n\n\ttest('should render the name', async ({ page }) => {\n\t\tawait expect(page.locator('kol-my-component')).toBeVisible();\n\t});\n});\n```\n\nDetails: [ARC42 §9 — Design Decision 11](../../packages/components/src/components/_skeleton/ARC42.md#9-design-decisions)\n\n## Schritt 8 — Beispiel in React-Sample-App\n\nDatei: `packages/samples/react/src/scenarios/<component>.tsx`\n\nAnschließend die Route in `packages/samples/react/src/scenarios/routes.ts` registrieren.\n\nZum Testen:\n\n```bash\ncd packages/samples/react\npnpm start\n# Navigiere zu http://localhost:9191\n```\n\n## Schritt 9 — Validierung\n\n```bash\npnpm format # ~10 Sekunden\npnpm lint # ~1 Minute, NICHT abbrechen\npnpm test # ~2-3 Minuten, NICHT abbrechen\npnpm -r build # ~2 Minuten, NICHT abbrechen\n```\n\nAlle vier Befehle müssen fehlerfrei durchlaufen.\n\n## Referenz\n\nDie vollständige Referenzimplementierung findet sich im Skeleton Blueprint:\n\n- **Architektur**: [`_skeleton/ARC42.md`](../../packages/components/src/components/_skeleton/ARC42.md)\n- **Agent-Instruktionen**: [`_skeleton/AGENTS.md`](../../packages/components/src/components/_skeleton/AGENTS.md)\n- **Performance-Analyse**: [`_skeleton/PERFORMANCE_ANALYSIS.md`](../../packages/components/src/components/_skeleton/PERFORMANCE_ANALYSIS.md)\n- **Refactoring-Leitfaden**: [`_skeleton/REFACTORING_PROMPT.md`](../../packages/components/src/components/_skeleton/REFACTORING_PROMPT.md)\n",
401
393
  "kind": "doc"
402
394
  },
403
395
  {
@@ -1120,6 +1112,14 @@
1120
1112
  "code": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { KolImage, KolLink } from '@public-ui/react-v19';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const LinkImage: FC = () => (\n\t<>\n\t\t<SampleDescription>\n\t\t\t<p>KolLink can be used with slot-content instead of a label as well. This sample demonstrates the slot content used to display an image.</p>\n\t\t</SampleDescription>\n\n\t\t<div className=\"grid gap-4\">\n\t\t\t<KolLink _href=\"#/back-page\" _label=\"I am a link that is rendered as text\" />\n\t\t\t<KolLink _href=\"#/back-page\" _label=\"\">\n\t\t\t\t<KolImage\n\t\t\t\t\t_alt=\"KoliBri design system illustration showing three people working on laptops surrounded by UI components, charts, and the KoliBri hummingbird logo\"\n\t\t\t\t\t_src=\"sample-image.png\"\n\t\t\t\t\tclassName=\"w-image\"\n\t\t\t\t\tslot=\"expert\"\n\t\t\t\t/>\n\t\t\t</KolLink>\n\t\t</div>\n\t</>\n);\n",
1121
1113
  "kind": "sample"
1122
1114
  },
1115
+ {
1116
+ "id": "sample/link/link-variant",
1117
+ "group": "link",
1118
+ "name": "link-variant",
1119
+ "path": "packages/samples/react/src/components/link/variant.tsx",
1120
+ "code": "import type { FC } from 'react';\nimport React, { useEffect, useState } from 'react';\n\nimport { KolLink } from '@public-ui/react-v19';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const LinkVariant: FC = () => {\n\tconst [data, setData] = useState<Array<string>>([]);\n\tconst [loading, setLoading] = useState<boolean>(true);\n\n\tuseEffect(() => {\n\t\tconst theme = document.body.dataset.theme;\n\t\tif (!theme) {\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\t\tfetch('/assets/variants/inject-variants_' + theme + '.json')\n\t\t\t.then((response) => {\n\t\t\t\tif (response.status === 404) {\n\t\t\t\t\t// No variants file for this theme is an expected state.\n\t\t\t\t\tsetData([]);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconsole.info('Error fetching variants: HTTP ' + response.status);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn response.json();\n\t\t\t})\n\t\t\t.then((json) => {\n\t\t\t\tif (!json) {\n\t\t\t\t\tsetData([]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst linkVariants = (json as { linkVariants?: unknown }).linkVariants;\n\t\t\t\tif (Array.isArray(linkVariants)) {\n\t\t\t\t\tconst variants = linkVariants.filter((item): item is string => typeof item === 'string');\n\t\t\t\t\tsetData(variants);\n\t\t\t\t} else {\n\t\t\t\t\tsetData([]);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconsole.info('No theme variant file found or file could not be parsed', error);\n\t\t\t\tsetData([]);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tsetLoading(false);\n\t\t\t});\n\t}, []);\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This sample shows the theme specific variants of KolLink.</p>\n\t\t\t\t<p className={loading ? 'loading' : 'hidden'}>Loading Data</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t<KolLink _href=\"#/back-page\" _label=\"Normal link without a variant\" />\n\t\t\t\t{!Array.isArray(data) || data.length === 0 ? (\n\t\t\t\t\t<p>This theme has no variants for this component.</p>\n\t\t\t\t) : (\n\t\t\t\t\tdata.map((element) => {\n\t\t\t\t\t\treturn <KolLink _href=\"#/back-page\" _label={`Theme exclusive variant: ${element}`} _variant={element} key={element} />;\n\t\t\t\t\t})\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
1121
+ "kind": "sample"
1122
+ },
1123
1123
  {
1124
1124
  "id": "sample/link/linked-headline",
1125
1125
  "group": "link",
@@ -1320,6 +1320,14 @@
1320
1320
  "code": "import type { KoliBriTableDataType, KoliBriTableHeaderCellWithLogic } from '@public-ui/components';\nimport { KolTableStateful } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { SampleDescription } from '../SampleDescription';\n\nconst ROWS_COUNT = 50;\n\ntype DataRow = {\n\tid: number;\n\tname: string;\n\temail: string;\n\tstatus: string;\n};\n\nconst FIRST_NAMES = [\n\t'Max',\n\t'Erika',\n\t'John',\n\t'Jane',\n\t'Peter',\n\t'Anna',\n\t'Michael',\n\t'Sarah',\n\t'Thomas',\n\t'Lisa',\n\t'Daniel',\n\t'Maria',\n\t'Christian',\n\t'Laura',\n\t'Stefan',\n\t'Julia',\n\t'Andreas',\n\t'Sophie',\n\t'Markus',\n\t'Emma',\n];\nconst LAST_NAMES = [\n\t'Mustermann',\n\t'Musterfrau',\n\t'Doe',\n\t'Smith',\n\t'Schmidt',\n\t'Müller',\n\t'Weber',\n\t'Meyer',\n\t'Wagner',\n\t'Becker',\n\t'Fischer',\n\t'Schneider',\n\t'Hoffmann',\n\t'Koch',\n\t'Bauer',\n\t'Richter',\n\t'Klein',\n\t'Wolf',\n\t'Schröder',\n\t'Neumann',\n];\nconst STATUSES = ['active', 'inactive', 'pending'];\n\nconst generateData = (count: number): DataRow[] => {\n\treturn Array.from({ length: count }, (_, i) => {\n\t\tconst firstName = FIRST_NAMES[i % FIRST_NAMES.length];\n\t\tconst lastName = LAST_NAMES[Math.floor(i / FIRST_NAMES.length) % LAST_NAMES.length];\n\t\tconst status = STATUSES[i % STATUSES.length];\n\t\tconst id = i + 1;\n\n\t\treturn {\n\t\t\tid,\n\t\t\tname: `${firstName} ${lastName}`,\n\t\t\temail: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${id > 20 ? id : ''}@example.com`,\n\t\t\tstatus,\n\t\t};\n\t});\n};\n\nconst DATA: DataRow[] = generateData(ROWS_COUNT);\n\nconst HEADERS: { horizontal: KoliBriTableHeaderCellWithLogic[][] } = {\n\thorizontal: [\n\t\t[\n\t\t\t{\n\t\t\t\tkey: 'id',\n\t\t\t\tlabel: 'ID',\n\t\t\t\ttextAlign: 'left',\n\t\t\t\twidth: 60,\n\t\t\t\tcompareFn: (data0: KoliBriTableDataType, data1: KoliBriTableDataType) => (data0 as unknown as DataRow).id - (data1 as unknown as DataRow).id,\n\t\t\t\tsortDirection: 'ASC',\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'name',\n\t\t\t\tlabel: 'Name',\n\t\t\t\ttextAlign: 'left',\n\t\t\t\tcompareFn: (data0: KoliBriTableDataType, data1: KoliBriTableDataType) =>\n\t\t\t\t\t(data0 as unknown as DataRow).name.localeCompare((data1 as unknown as DataRow).name, 'de'),\n\t\t\t\tsortDirection: 'ASC',\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'email',\n\t\t\t\tlabel: 'E-Mail',\n\t\t\t\ttextAlign: 'left',\n\t\t\t\tcompareFn: (data0: KoliBriTableDataType, data1: KoliBriTableDataType) =>\n\t\t\t\t\t(data0 as unknown as DataRow).email.localeCompare((data1 as unknown as DataRow).email, 'de'),\n\t\t\t\tsortDirection: 'ASC',\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'status',\n\t\t\t\tlabel: 'Status',\n\t\t\t\ttextAlign: 'center',\n\t\t\t\twidth: 100,\n\t\t\t\tcompareFn: (data0: KoliBriTableDataType, data1: KoliBriTableDataType) =>\n\t\t\t\t\t(data0 as unknown as DataRow).status.localeCompare((data1 as unknown as DataRow).status, 'de'),\n\t\t\t\tsortDirection: 'ASC',\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'action',\n\t\t\t\tkey: 'actions',\n\t\t\t\tlabel: 'Aktionen',\n\t\t\t\ttextAlign: 'center',\n\t\t\t\twidth: 180,\n\t\t\t\tactions: (row) => {\n\t\t\t\t\tconst dataRow = row as unknown as DataRow;\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t_label: 'Bearbeiten',\n\t\t\t\t\t\t\t_icons: 'kolicon-eye',\n\t\t\t\t\t\t\t_hideLabel: true,\n\t\t\t\t\t\t\t_tooltipAlign: 'top',\n\t\t\t\t\t\t\t_variant: 'secondary',\n\t\t\t\t\t\t\t_on: {\n\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\tconsole.log('Edit clicked for:', dataRow);\n\t\t\t\t\t\t\t\t\talert(`Bearbeiten: ${dataRow.name}`);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t_label: 'Löschen',\n\t\t\t\t\t\t\t_icons: 'kolicon-alert-error',\n\t\t\t\t\t\t\t_hideLabel: true,\n\t\t\t\t\t\t\t_tooltipAlign: 'top',\n\t\t\t\t\t\t\t_variant: 'danger',\n\t\t\t\t\t\t\t_on: {\n\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\tconsole.log('Delete clicked for:', dataRow);\n\t\t\t\t\t\t\t\t\talert(`Löschen: ${dataRow.name}`);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t_label: 'Details anzeigen',\n\t\t\t\t\t\t\t_icons: 'kolicon-alert-info',\n\t\t\t\t\t\t\t_hideLabel: true,\n\t\t\t\t\t\t\t_tooltipAlign: 'top',\n\t\t\t\t\t\t\t_variant: 'normal',\n\t\t\t\t\t\t\t_on: {\n\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\tconsole.log('Details clicked for:', dataRow);\n\t\t\t\t\t\t\t\t\talert(`Details: ${JSON.stringify(dataRow, null, 2)}`);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t];\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t],\n};\n\nexport const TableActionColumnPerformance: FC = () => (\n\t<>\n\t\t<SampleDescription>\n\t\t\t<p>\n\t\t\t\tPerformance demo: {ROWS_COUNT} rows with action buttons defined once in the column header using the refactored approach. The factory function generates\n\t\t\t\tactions for each row on demand, eliminating redundant data and improving maintainability.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tActions stay type-safe with <code>ActionColumnPropType</code> (ButtonProps or LinkProps), and no custom render functions are needed.\n\t\t\t</p>\n\t\t</SampleDescription>\n\n\t\t<section className=\"w-full\">\n\t\t\t<KolTableStateful _label=\"Benutzerverwaltung mit Action-Spalte\" _headers={HEADERS} _data={DATA} className=\"block\" />\n\t\t</section>\n\t</>\n);\n",
1321
1321
  "kind": "sample"
1322
1322
  },
1323
+ {
1324
+ "id": "sample/table/big",
1325
+ "group": "table",
1326
+ "name": "big",
1327
+ "path": "packages/samples/react/src/components/table/big-table.tsx",
1328
+ "code": "import type { FC } from 'react';\nimport React, { useEffect, useState } from 'react';\n\nimport type { KoliBriTableHeaderCellWithLogic, KoliBriTableHeaders, KoliBriTableSelection } from '@public-ui/components';\nimport { KolHeading, KolTableStateful } from '@public-ui/react-v19';\nimport { useSearchParams } from 'react-router';\nimport { SampleDescription } from '../SampleDescription';\nimport { COMPLEX_DATA, configurableData } from './test-complex-data';\n\ntype Data = (typeof COMPLEX_DATA)[0];\n\nconst selection: KoliBriTableSelection = {\n\tlabel: (row) => `Selection for ${(row as Data).common_name}`,\n\tmultiple: true,\n\tkeyPropertyName: 'id',\n};\n\nconst defaultHeaders: KoliBriTableHeaderCellWithLogic[] = [\n\t{ label: 'ID', key: 'id', textAlign: 'right', width: 60 },\n\t{ label: 'Common name', key: 'common_name', textAlign: 'left', width: 250 },\n\t{ label: 'Scientific name', key: 'scientific_name', textAlign: 'left', width: 400 },\n\t{ label: 'Conservation status', key: 'conservation_status', textAlign: 'left', width: 250 },\n\t{ label: 'Habitat', key: 'habitat', textAlign: 'left', width: 400 },\n\t{ label: 'Diet', key: 'diet', textAlign: 'left', width: 200 },\n\t{ label: 'Geographic range', key: 'geographic_range', textAlign: 'left', width: 300 },\n];\n\nvar headers: KoliBriTableHeaderCellWithLogic[] = defaultHeaders;\n\nconst HEADERS_HORIZONTAL: KoliBriTableHeaders = {\n\thorizontal: [headers],\n};\n\nexport const TableBig: FC = () => {\n\tconst [searchParams, setSearchParams] = useSearchParams();\n\tconst [rows, setRows] = useState<number>(50);\n\tconst [fixedCols, setFixedCols] = useState<[number, number]>([0, 0]);\n\tvar loaded = false;\n\n\tfunction defineTable() {\n\t\tif (loaded) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rows = searchParams.get('rows');\n\t\tif (rows && +rows < 5000) {\n\t\t\tsetRows(+rows);\n\t\t} else {\n\t\t\tsetSearchParams((searchParams) => {\n\t\t\t\tsearchParams.append('rows', '50');\n\t\t\t\treturn searchParams;\n\t\t\t});\n\t\t}\n\n\t\tconst addCols = searchParams.get('addCols');\n\t\tif (addCols && +addCols < 5000) {\n\t\t\theaders = [...defaultHeaders];\n\t\t\tfor (let index = 0; index < +addCols; index++) {\n\t\t\t\theaders.push({ label: 'label' + index, key: 'key' + index, textAlign: 'left', width: 100 });\n\t\t\t}\n\t\t} else {\n\t\t\tsetSearchParams((searchParams) => {\n\t\t\t\tsearchParams.append('addCols', '0');\n\t\t\t\treturn searchParams;\n\t\t\t});\n\t\t}\n\n\t\tconst fixedCols = searchParams.get('fixedCols');\n\t\tif (fixedCols) {\n\t\t\tconst strings = fixedCols.split('.');\n\t\t\tsetFixedCols([+strings[0], +strings[1]]);\n\t\t} else {\n\t\t\tsetSearchParams((searchParams) => {\n\t\t\t\tsearchParams.append('fixedCols', '0.0');\n\t\t\t\treturn searchParams;\n\t\t\t});\n\t\t}\n\n\t\tloaded = true;\n\t}\n\n\tuseEffect(() => defineTable(), [searchParams]);\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>You can change what this examples shows with query parameters. Change the values as you like:</p>\n\t\t\t\t<ul>\n\t\t\t\t\t<li>rows=400 - loads 400 rows</li>\n\t\t\t\t\t<li>addCols=10 - adds 10 empty columns to the end</li>\n\t\t\t\t\t<li>fixedCols=2.1 - makes the first two and the last column sticky</li>\n\t\t\t\t</ul>\n\t\t\t</SampleDescription>\n\n\t\t\t<KolHeading _level={2} _label=\"Configurable table\" />\n\t\t\t<KolTableStateful\n\t\t\t\t_label=\"Animal species overview\"\n\t\t\t\t_data={configurableData(rows)}\n\t\t\t\t_headers={HEADERS_HORIZONTAL}\n\t\t\t\tclassName=\"block\"\n\t\t\t\t_selection={selection}\n\t\t\t\t_fixedCols={fixedCols}\n\t\t\t/>\n\t\t</>\n\t);\n};\n",
1329
+ "kind": "sample"
1330
+ },
1323
1331
  {
1324
1332
  "id": "sample/table/column-alignment",
1325
1333
  "group": "table",
@@ -1453,7 +1461,7 @@
1453
1461
  "group": "table",
1454
1462
  "name": "stateless-async",
1455
1463
  "path": "packages/samples/react/src/components/table/stateless-async-paging.tsx",
1456
- "code": "import type { KoliBriTableHeaders } from '@public-ui/components';\nimport { KolPagination, KolSpin, KolTableStateless } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useEffect, useState } from 'react';\nimport { SampleDescription } from '../SampleDescription';\n\nimport type { ComplexData } from './test-complex-data';\nimport { COMPLEX_DATA } from './test-complex-data';\n\nconst HEADERS_HORIZONTAL: KoliBriTableHeaders = {\n\thorizontal: [\n\t\t[\n\t\t\t{ label: 'ID', key: 'id', textAlign: 'right', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Common name', key: 'common_name', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Scientific name', key: 'scientific_name', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Conservation status', key: 'conservation_status', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Habitat', key: 'habitat', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Diet', key: 'diet', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Geographic range', key: 'geographic_range', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t],\n\t],\n};\n\nconst LoadingOverlayFC: FC<{\n\tlabel: string;\n\tshow: boolean;\n}> = ({ label, show }) => {\n\tif (show) {\n\t\treturn (\n\t\t\t<div className=\"loading-overlay\">\n\t\t\t\t<KolSpin\n\t\t\t\t\t_label={label}\n\t\t\t\t\t_show={show}\n\t\t\t\t\t_variant=\"cycle\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackgroundColor: 'transparent',\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t);\n\t} else {\n\t\treturn null;\n\t}\n};\n\nexport const TableStatelessAsync: FC = () => {\n\tconst getAsyncData = () => new Promise<{ COMPLEX_DATA: ComplexData[] }>((resolve) => setTimeout(() => resolve({ COMPLEX_DATA }), 3000));\n\tconst loadData = (action: 'sort' | 'paginate') => {\n\t\tsetLoading(true);\n\t\tsetCurrentAction(action);\n\t\tgetAsyncData().then((result: Awaited<ReturnType<typeof getAsyncData>>) => {\n\t\t\tsetComplexData(result.COMPLEX_DATA.slice(0, 15));\n\t\t\tsetLoading(false);\n\t\t});\n\t};\n\n\tconst [complexData, setComplexData] = useState<ComplexData[]>([]);\n\tconst [loading, setLoading] = useState<boolean>(true);\n\tconst [currentAction, setCurrentAction] = useState<'sort' | 'paginate'>('sort');\n\n\tuseEffect(() => loadData('sort'), []);\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis sample shows how KolTableStateless can be used async and with KolPagination. Paging and sorting are not functional here, because a backend would\n\t\t\t\t\toffer this in real life.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<section className=\"w-full relative\">\n\t\t\t\t<KolTableStateless\n\t\t\t\t\t_label=\"Table for demonstration purposes\"\n\t\t\t\t\t_headerCells={HEADERS_HORIZONTAL}\n\t\t\t\t\t_data={complexData}\n\t\t\t\t\t_on={{\n\t\t\t\t\t\tonSort: () => loadData('sort'),\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<KolPagination\n\t\t\t\t\t_max={200}\n\t\t\t\t\t_page={1}\n\t\t\t\t\t_siblingCount={0}\n\t\t\t\t\t_boundaryCount={2}\n\t\t\t\t\t_pageSize={15}\n\t\t\t\t\t_on={{\n\t\t\t\t\t\tonChangePage: () => loadData('paginate'),\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<LoadingOverlayFC label={currentAction === 'sort' ? 'Table is being sorted...' : 'Page is loading...'} show={loading} />\n\t\t\t</section>\n\t\t</>\n\t);\n};\n",
1464
+ "code": "import type { KoliBriTableHeaders } from '@public-ui/components';\nimport { KolPagination, KolSpin, KolTableStateless } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useEffect, useState } from 'react';\nimport { SampleDescription } from '../SampleDescription';\n\nimport type { ComplexData } from './test-complex-data';\nimport { COMPLEX_DATA } from './test-complex-data';\n\nconst HEADERS_HORIZONTAL: KoliBriTableHeaders = {\n\thorizontal: [\n\t\t[\n\t\t\t{ label: 'ID', key: 'id', textAlign: 'right', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Common name', key: 'common_name', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Scientific name', key: 'scientific_name', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Conservation status', key: 'conservation_status', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Habitat', key: 'habitat', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Diet', key: 'diet', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t\t{ label: 'Geographic range', key: 'geographic_range', textAlign: 'left', width: 160, sortDirection: 'NOS' },\n\t\t],\n\t],\n};\n\nconst LoadingOverlayFC: FC<{\n\tlabel: string;\n\tshow: boolean;\n}> = ({ label, show }) => {\n\tif (show) {\n\t\treturn (\n\t\t\t<div className=\"loading-overlay\">\n\t\t\t\t<KolSpin\n\t\t\t\t\t_label={label}\n\t\t\t\t\t_show={show}\n\t\t\t\t\t_variant=\"cycle\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackgroundColor: 'transparent',\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t);\n\t} else {\n\t\treturn null;\n\t}\n};\n\nexport const TableStatelessAsync: FC = () => {\n\tconst getAsyncData = () => new Promise<{ COMPLEX_DATA: ComplexData[] }>((resolve) => setTimeout(() => resolve({ COMPLEX_DATA }), 5000));\n\tconst loadData = (action: 'sort' | 'paginate') => {\n\t\tsetLoading(true);\n\t\tsetCurrentAction(action);\n\t\tgetAsyncData().then((result: Awaited<ReturnType<typeof getAsyncData>>) => {\n\t\t\tsetComplexData(result.COMPLEX_DATA.slice(0, 15));\n\t\t\tsetLoading(false);\n\t\t});\n\t};\n\n\tconst [complexData, setComplexData] = useState<ComplexData[]>([]);\n\tconst [loading, setLoading] = useState<boolean>(true);\n\tconst [currentAction, setCurrentAction] = useState<'sort' | 'paginate'>('sort');\n\n\tuseEffect(() => loadData('sort'), []);\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis sample shows how KolTableStateless can be used async and with KolPagination. Paging and sorting are not functional here, because a backend would\n\t\t\t\t\toffer this in real life.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<section className=\"w-full relative\">\n\t\t\t\t<KolTableStateless\n\t\t\t\t\t_label=\"Table for demonstration purposes\"\n\t\t\t\t\t_headerCells={HEADERS_HORIZONTAL}\n\t\t\t\t\t_data={complexData}\n\t\t\t\t\t_on={{\n\t\t\t\t\t\tonSort: () => loadData('sort'),\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<KolPagination\n\t\t\t\t\t_max={200}\n\t\t\t\t\t_page={1}\n\t\t\t\t\t_siblingCount={0}\n\t\t\t\t\t_boundaryCount={2}\n\t\t\t\t\t_pageSize={15}\n\t\t\t\t\t_on={{\n\t\t\t\t\t\tonChangePage: () => loadData('paginate'),\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<LoadingOverlayFC label={currentAction === 'sort' ? 'Table is being sorted...' : 'Page is loading...'} show={loading} />\n\t\t\t</section>\n\t\t</>\n\t);\n};\n",
1457
1465
  "kind": "sample"
1458
1466
  },
1459
1467
  {
@@ -1797,7 +1805,7 @@
1797
1805
  "group": "spec",
1798
1806
  "name": "_skeleton",
1799
1807
  "path": "packages/tools/mcp/node_modules/@public-ui/components/doc/_skeleton.md",
1800
- "code": "# Refactoring-Auftrag: Komponente auf Skeleton/Internals-Architektur migrieren\n\n## Rolle\n\nDu bist ein **Senior Software Architect und Developer** mit über 15 Jahren Erfahrung in komponentenbasierter Frontend-Architektur. Du legst höchsten Wert auf:\n\n- **Clean Architecture** — klare Schichtentrennung, Single Responsibility, Dependency Inversion.\n- **Wartbarkeit** — Code, der in 2 Jahren von einem neuen Teammitglied ohne Rückfragen verstanden wird.\n- **Lesbarkeit** — selbstdokumentierende Strukturen, konsistente Namensgebung, minimaler kognitiver Aufwand beim Lesen.\n- **Nachvollziehbarkeit** — jede Entscheidung folgt einem erkennbaren Pattern, keine Sonderfälle ohne Begründung.\n- **Reduktion** — du schreibst nicht mehr Code als nötig. Du löschst mutig, was nicht gebraucht wird.\n\nDu arbeitest methodisch: erst analysieren, dann planen, dann umsetzen, dann validieren. Du hinterlässt keinen toten Code, keine verwaisten Typen, keine Dateien ohne Referenz.\n\n---\n\n## Auftrag\n\nRefaktoriere die angegebene Komponente so, dass sie vollständig der Referenzimplementierung im Skeleton-Blueprint und der Internals-Schicht entspricht. Welche Komponente zu refaktorieren ist, wird dir zusammen mit diesem Prompt mitgeteilt.\n\n---\n\n## ⚠️ Arbeitsverzeichnis\n\n- **Skeleton** (`_skeleton/`) = **nur lesen**. Dient ausschließlich als Referenz und Vorlage.\n- **Komponentenverzeichnis** = **Arbeitsort**. Alle Änderungen finden in-place im bestehenden Ordner der Komponente statt.\n\n---\n\n## Verbindliche Spezifikation\n\nDie [ARC42.md](./ARC42.md) ist die **führende Architektur-Spezifikation**. Lies sie vollständig, bevor du mit dem Refactoring beginnst. Alle dort beschriebenen Patterns, Konventionen und Schichten sind einzuhalten — ohne Ausnahme.\n\nErgänzend gelten:\n\n- `AGENTS.md` (Repository-Root)\n- `.github/copilot-instructions.md`\n\nBei Widersprüchen hat die ARC42.md Vorrang.\n\n---\n\n## Vorgehen\n\n### 1. Analyse\n\n- Lies **alle** Dateien im Komponentenverzeichnis.\n- Lies die Skeleton-Referenzimplementierung (`_skeleton/web-components/`) und die Internals-Schicht (`src/internal/`).\n- Erstelle eine **Gap-Analyse**: Was weicht von der Skeleton-Architektur ab?\n\n### 2. Props-First: Struktur aufbauen (KRITISCH — ZUERST!)\n\n**Bevor du die Komponente implementierst, musst du alle Props migrieren:**\n\n1. **Props-Inventar**: Sammle alle vorhandenen `@Prop()` Deklarationen aus der aktuellen Komponente\n2. **Pro Prop eine Datei** unter `src/internal/props/`:\n - Dateiname: `<prop-name>.ts` (z.B. `label.ts`, `href.ts`, `disabled.ts`)\n - Nutze `Prop<K, TExternal, TInternal>` oder `SimpleProp<K, T>`\n - Implementiere `normalize()` und `validate()` via `createPropDefinition<P>()`\n3. **Props exportieren** in `src/internal/props/index.ts`\n4. **Props-Typen im Controller** verwenden (z.B. `InternalOf<P>`, `ExternalOf<P>`)\n\n**Warum Props-First?**\n\n- API-Verträge sind klar, bevor Implementation beginnt\n- Keine Props gehen verloren oder werden vergessen\n- Controller und Tests haben sichere Typen von Anfang an\n- Architektur muss nicht nachträglich angepasst werden\n\n### 3. Refactoring: Komponenten-Implementierung\n\nErstelle bzw. ersetze die Dateien im Komponentenverzeichnis gemäß der ARC42-Schichten:\n\n1. **API-Definition** (`api.tsx`) — Interface für die Komponente (nutzt Props-Typen aus Schritt 2)\n2. **Controller** — erweitert `BaseController`, nutzt normalisierte Props\n3. **Functional Component** — stateless Renderer\n4. **Web Component** — Stencil `@Component` mit Lifecycle, Watchers, Rendering\n5. **CSS/SCSS** — bestehende Styles beibehalten, bei Bedarf anpassen\n6. **Tests** — Testdateien **neben** `component.tsx` erstellen bzw. aktualisieren (kein `test/`-Unterordner, siehe ARC42 Design Decision 11):\n - `snapshot.spec.tsx` — Jest DOM-Snapshot-Tests (`executeSnapshotTests`)\n - `interaction.e2e.ts` — Playwright Interaction-Tests (Klick, Tastatur, Events)\n\n### 4. Dead Code eliminieren\n\nNach dem Refactoring darf **kein veralteter Code** zurückbleiben:\n\n- **Dateien löschen**: alte Type-/Interface-Dateien, alte Controller, verwaiste Module, leere Dateien.\n- **Code entfernen**: unused Types, Imports, auskommentierter Code, deprecated Wrapper.\n- **Prüfen**: Keine Datei ohne Referenz, keine Barrel-Files.\n\n### 5. Validierung\n\n```bash\npnpm format\npnpm lint\npnpm --filter @public-ui/components test:unit\npnpm --filter @public-ui/components build\n```\n\nAlle vier Befehle müssen fehlerfrei durchlaufen. **Kein Befehl darf vor dem Timeout abgebrochen werden.**\n\n---\n\n## Ausgabe\n\n1. **Gap-Analyse** — Abweichungen der bestehenden Komponente zur Skeleton-Architektur.\n2. **Gelöschte Dateien** — Liste mit Begründung pro Datei.\n3. **Neue/geänderte Dateien** — Verzeichnisstruktur mit Architektur-Layer pro Datei.\n4. **Validierungsergebnis** — Bestätigung, dass alle Befehle erfolgreich waren.\n",
1808
+ "code": "# Refactoring-Auftrag: Komponente auf Skeleton/Internals-Architektur migrieren\n\n## Rolle\n\nDu bist ein **Senior Software Architect und Developer** mit über 15 Jahren Erfahrung in komponentenbasierter Frontend-Architektur. Du legst höchsten Wert auf:\n\n- **Clean Architecture** — klare Schichtentrennung, Single Responsibility, Dependency Inversion.\n- **Wartbarkeit** — Code, der in 2 Jahren von einem neuen Teammitglied ohne Rückfragen verstanden wird.\n- **Lesbarkeit** — selbstdokumentierende Strukturen, konsistente Namensgebung, minimaler kognitiver Aufwand beim Lesen.\n- **Nachvollziehbarkeit** — jede Entscheidung folgt einem erkennbaren Pattern, keine Sonderfälle ohne Begründung.\n- **Reduktion** — du schreibst nicht mehr Code als nötig. Du löschst mutig, was nicht gebraucht wird.\n\nDu arbeitest methodisch: erst analysieren, dann planen, dann umsetzen, dann validieren. Du hinterlässt keinen toten Code, keine verwaisten Typen, keine Dateien ohne Referenz.\n\n---\n\n## Auftrag\n\nRefaktoriere die angegebene Komponente so, dass sie vollständig der Referenzimplementierung im Skeleton-Blueprint und der Internals-Schicht entspricht. Welche Komponente zu refaktorieren ist, wird dir zusammen mit diesem Prompt mitgeteilt.\n\n---\n\n## ⚠️ Arbeitsverzeichnis\n\n- **Skeleton** (`_skeleton/`) = **nur lesen**. Dient ausschließlich als Referenz und Vorlage.\n- **Komponentenverzeichnis** = **Arbeitsort**. Alle Änderungen finden in-place im bestehenden Ordner der Komponente statt.\n\n---\n\n## Verbindliche Spezifikation\n\nDie [ARC42.md](./ARC42.md) ist die **führende Architektur-Spezifikation**. Lies sie vollständig, bevor du mit dem Refactoring beginnst. Alle dort beschriebenen Patterns, Konventionen und Schichten sind einzuhalten — ohne Ausnahme.\n\nErgänzend gelten:\n\n- `AGENTS.md` (Repository-Root)\n- `.github/copilot-instructions.md`\n\nBei Widersprüchen hat die ARC42.md Vorrang.\n\n---\n\n## Vorgehen\n\n### 1. Analyse\n\n- Lies **alle** Dateien im Komponentenverzeichnis.\n- Lies die Skeleton-Referenzimplementierung (`_skeleton/web-components/`) und die Internals-Schicht (`src/internal/`).\n- Erstelle eine **Gap-Analyse**: Was weicht von der Skeleton-Architektur ab?\n\n### 2. Props-First: Struktur aufbauen (KRITISCH — ZUERST!)\n\n**Bevor du die Komponente implementierst, musst du alle Props migrieren:**\n\n1. **Props-Inventar**: Sammle alle vorhandenen `@Prop()` Deklarationen aus der aktuellen Komponente\n2. **Pro Prop eine Datei** unter `src/internal/props/`:\n - Dateiname: `<prop-name>.ts` (z.B. `label.ts`, `href.ts`, `disabled.ts`)\n - Nutze `Prop<K, TExternal, TInternal>` oder `SimpleProp<K, T>`\n - Implementiere `normalize()` und `validate()` via `createPropDefinition<P>()`\n3. **Props exportieren** in `src/internal/props/index.ts`\n4. **Props-Typen im Controller** verwenden (z.B. `InternalOf<P>`, `ExternalOf<P>`)\n\n**Warum Props-First?**\n\n- API-Verträge sind klar, bevor Implementation beginnt\n- Keine Props gehen verloren oder werden vergessen\n- Controller und Tests haben sichere Typen von Anfang an\n- Architektur muss nicht nachträglich angepasst werden\n\n### 3. Refactoring: Komponenten-Implementierung\n\nErstelle bzw. ersetze die Dateien im Komponentenverzeichnis gemäß der ARC42-Schichten:\n\n1. **API-Definition** (`api.tsx`) — Interface für die Komponente (nutzt Props-Typen aus Schritt 2)\n2. **Controller** — erweitert `BaseController`, nutzt normalisierte Props, empfängt `setState` und `getState` als Callbacks\n3. **Functional Component** — stateless Renderer\n4. **Web Component** — Stencil `@Component` mit Lifecycle, Watchers, Rendering; erweitert `BaseWebComponent<Api>` und übergibt `this.setState` und `this.getState` an den Controller\n5. **CSS/SCSS** — bestehende Styles beibehalten, bei Bedarf anpassen\n6. **Tests** — Testdateien **neben** `component.tsx` erstellen bzw. aktualisieren (kein `test/`-Unterordner, siehe ARC42 Design Decision 11):\n - `snapshot.spec.tsx` — Jest DOM-Snapshot-Tests (`executeSnapshotTests`)\n - `interaction.e2e.ts` — Playwright Interaction-Tests (Klick, Tastatur, Events)\n\n### 4. Dead Code eliminieren\n\nNach dem Refactoring darf **kein veralteter Code** zurückbleiben:\n\n- **Dateien löschen**: alte Type-/Interface-Dateien, alte Controller, verwaiste Module, leere Dateien.\n- **Code entfernen**: unused Types, Imports, auskommentierter Code, deprecated Wrapper.\n- **Prüfen**: Keine Datei ohne Referenz, keine Barrel-Files.\n\n### 5. Validierung\n\n```bash\npnpm format\npnpm lint\npnpm --filter @public-ui/components test:unit\npnpm --filter @public-ui/components build\n```\n\nAlle vier Befehle müssen fehlerfrei durchlaufen. **Kein Befehl darf vor dem Timeout abgebrochen werden.**\n\n---\n\n## Ausgabe\n\n1. **Gap-Analyse** — Abweichungen der bestehenden Komponente zur Skeleton-Architektur.\n2. **Gelöschte Dateien** — Liste mit Begründung pro Datei.\n3. **Neue/geänderte Dateien** — Verzeichnisstruktur mit Architektur-Layer pro Datei.\n4. **Validierungsergebnis** — Bestätigung, dass alle Befehle erfolgreich waren.\n",
1801
1809
  "kind": "spec"
1802
1810
  },
1803
1811
  {
@@ -1941,7 +1949,7 @@
1941
1949
  "group": "spec",
1942
1950
  "name": "icon",
1943
1951
  "path": "packages/tools/mcp/node_modules/@public-ui/components/doc/icon.md",
1944
- "code": "# kol-icon\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description | Type | Default |\n| --------------------- | --------- | ------------------------------------------------------------------------------------------------------------------ | -------- | ----------- |\n| `_icons` _(required)_ | `_icons` | Defines the icon classnames (e.g. `_icons=\"fa-solid fa-user\"`). | `string` | `undefined` |\n| `_label` _(required)_ | `_label` | Defines the visible or semantic label of the component (e.g. aria-label, label, headline, caption, summary, etc.). | `string` | `undefined` |\n\n\n## Shadow Parts\n\n| Part | Description |\n| -------- | ----------------------------------------- |\n| `\"icon\"` | Ermöglicht das Styling des inneren Icons. |\n\n\n----------------------------------------------\n\n\n",
1952
+ "code": "# kol-icon\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description | Type | Default |\n| --------------------- | --------- | ------------------------------------------------------------------------------------------------------------------ | -------- | ----------- |\n| `_icons` _(required)_ | `_icons` | Defines the icon classnames (e.g. `_icons=\"fa-solid fa-user\"`). | `string` | `undefined` |\n| `_label` _(required)_ | `_label` | Defines the visible or semantic label of the component (e.g. aria-label, label, headline, caption, summary, etc.). | `string` | `undefined` |\n\n\n----------------------------------------------\n\n\n",
1945
1953
  "kind": "spec"
1946
1954
  },
1947
1955
  {
@@ -2117,7 +2125,7 @@
2117
2125
  "group": "spec",
2118
2126
  "name": "single-select",
2119
2127
  "path": "packages/tools/mcp/node_modules/@public-ui/components/doc/single-select.md",
2120
- "code": "# kol-single-select\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description | Type | Default |\n| ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | ----------- |\n| `_accessKey` | `_access-key` | Defines the key combination that can be used to trigger or focus the component's interactive element. | `string \\| undefined` | `undefined` |\n| `_disabled` | `_disabled` | Makes the element not focusable and ignore all events. | `boolean \\| undefined` | `false` |\n| `_hasClearButton` | `_has-clear-button` | Shows the clear button if enabled. | `boolean \\| undefined` | `true` |\n| `_hideLabel` | `_hide-label` | Hides the caption by default and displays the caption text with a tooltip when the interactive element is focused or the mouse is over it. | `boolean \\| undefined` | `false` |\n| `_hideMsg` | `_hide-msg` | Hides the error message but leaves it in the DOM for the input's aria-describedby. | `boolean \\| undefined` | `false` |\n| `_hint` | `_hint` | Defines the hint text. | `string \\| undefined` | `''` |\n| `_icons` | `_icons` | Defines the icon classnames (e.g. `_icons=\"fa-solid fa-user\"`). | `string \\| undefined \\| { right?: IconOrIconClass \\| undefined; left?: IconOrIconClass \\| undefined; }` | `undefined` |\n| `_label` _(required)_ | `_label` | Defines the visible or semantic label of the component (e.g. aria-label, label, headline, caption, summary, etc.). Set to `false` to enable the expert slot. | `string` | `undefined` |\n| `_msg` | `_msg` | Defines the properties for a message rendered as Alert component. | `Omit<AlertProps, \"_on\" \\| \"_variant\" \\| \"_hasCloser\" \\| \"_label\" \\| \"_level\"> & { _description: string; } \\| string \\| undefined` | `undefined` |\n| `_name` | `_name` | Defines the technical name of an input field. | `string \\| undefined` | `undefined` |\n| `_on` | -- | Gibt die EventCallback-Funktionen für das Input-Event an. | `InputTypeOnBlur & InputTypeOnClick & InputTypeOnChange & InputTypeOnFocus & InputTypeOnInput & InputTypeOnKeyDown \\| undefined` | `undefined` |\n| `_options` _(required)_ | `_options` | Options the user can choose from. | `Option<StencilUnknown>[] \\| string` | `undefined` |\n| `_placeholder` | `_placeholder` | Defines the placeholder for input field. To be shown when there's no value. | `string \\| undefined` | `undefined` |\n| `_required` | `_required` | Makes the input element required. | `boolean \\| undefined` | `false` |\n| `_rows` | `_rows` | Maximum number of visible rows of the element. | `number \\| undefined` | `undefined` |\n| `_shortKey` | `_short-key` | Adds a visual shortcut hint after the label and instructs the screen reader to read the shortcut aloud. | `string \\| undefined` | `undefined` |\n| `_tooltipAlign` | `_tooltip-align` | Defines where to show the Tooltip preferably: top, right, bottom or left. | `\"bottom\" \\| \"left\" \\| \"right\" \\| \"top\" \\| undefined` | `'top'` |\n| `_touched` | `_touched` | Shows if the input was touched by a user. | `boolean \\| undefined` | `false` |\n| `_value` | `_value` | Defines the value of the element. | `boolean \\| null \\| number \\| object \\| string \\| undefined` | `null` |\n\n\n## Methods\n\n### `focus() => Promise<void>`\n\nSets focus on the internal element.\n\n#### Returns\n\nType: `Promise<void>`\n\n\n\n### `getValue() => Promise<StencilUnknown>`\n\nReturns the current value.\n\n#### Returns\n\nType: `Promise<StencilUnknown>`\n\n\n\n\n## Slots\n\n| Slot | Description |\n| ---- | ---------------------- |\n| | The input field label. |\n\n\n----------------------------------------------\n\n\n",
2128
+ "code": "# kol-single-select\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description | Type | Default |\n| ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | ----------- |\n| `_accessKey` | `_access-key` | Defines the key combination that can be used to trigger or focus the component's interactive element. | `string \\| undefined` | `undefined` |\n| `_disabled` | `_disabled` | Makes the element not focusable and ignore all events. | `boolean \\| undefined` | `false` |\n| `_hasClearButton` | `_has-clear-button` | Shows the clear button if enabled. | `boolean \\| undefined` | `true` |\n| `_hideLabel` | `_hide-label` | Hides the caption by default and displays the caption text with a tooltip when the interactive element is focused or the mouse is over it. | `boolean \\| undefined` | `false` |\n| `_hideMsg` | `_hide-msg` | Hides the error message but leaves it in the DOM for the input's aria-describedby. | `boolean \\| undefined` | `false` |\n| `_hint` | `_hint` | Defines the hint text. | `string \\| undefined` | `''` |\n| `_icons` | `_icons` | Defines the icon classnames (e.g. `icons=\"fa-solid fa-user\"`). | `string \\| undefined \\| { right?: IconOrIconClass \\| undefined; left?: IconOrIconClass \\| undefined; }` | `undefined` |\n| `_label` _(required)_ | `_label` | Defines the visible or semantic label of the component (e.g. aria-label, label, headline, caption, summary, etc.). Set to `false` to enable the expert slot. | `string` | `undefined` |\n| `_msg` | `_msg` | Defines the properties for a message rendered as Alert component. | `Omit<AlertProps, \"_on\" \\| \"_variant\" \\| \"_hasCloser\" \\| \"_label\" \\| \"_level\"> & { _description: string; } \\| string \\| undefined` | `undefined` |\n| `_name` | `_name` | Defines the technical name of an input field. | `string \\| undefined` | `undefined` |\n| `_on` | -- | Gibt die EventCallback-Funktionen für das Input-Event an. | `InputTypeOnBlur & InputTypeOnClick & InputTypeOnChange & InputTypeOnFocus & InputTypeOnInput & InputTypeOnKeyDown \\| undefined` | `undefined` |\n| `_options` _(required)_ | `_options` | Options the user can choose from. | `Option<StencilUnknown>[] \\| string` | `undefined` |\n| `_placeholder` | `_placeholder` | Defines the placeholder for input field. To be shown when there's no value. | `string \\| undefined` | `undefined` |\n| `_required` | `_required` | Makes the input element required. | `boolean \\| undefined` | `false` |\n| `_rows` | `_rows` | Maximum number of visible rows of the element. | `number \\| undefined` | `undefined` |\n| `_shortKey` | `_short-key` | Adds a visual shortcut hint after the label and instructs the screen reader to read the shortcut aloud. | `string \\| undefined` | `undefined` |\n| `_tooltipAlign` | `_tooltip-align` | Defines where to show the Tooltip preferably: top, right, bottom or left. | `\"bottom\" \\| \"left\" \\| \"right\" \\| \"top\" \\| undefined` | `'top'` |\n| `_touched` | `_touched` | Shows if the input was touched by a user. | `boolean \\| undefined` | `false` |\n| `_value` | `_value` | Defines the value of the element. | `boolean \\| null \\| number \\| object \\| string \\| undefined` | `null` |\n\n\n## Methods\n\n### `focus() => Promise<void>`\n\nSets focus on the internal element.\n\n#### Returns\n\nType: `Promise<void>`\n\n\n\n### `getValue() => Promise<StencilUnknown>`\n\nReturns the current value.\n\n#### Returns\n\nType: `Promise<StencilUnknown>`\n\n\n\n\n## Slots\n\n| Slot | Description |\n| ---- | ---------------------- |\n| | The input field label. |\n\n\n----------------------------------------------\n\n\n",
2121
2129
  "kind": "spec"
2122
2130
  },
2123
2131
  {