@public-ui/mcp 4.3.1-rc.5 ā 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/shared/sample-index.json +53 -37
- package/shared/template-index.json +79 -79
package/shared/sample-index.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"metadata": {
|
|
3
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"generatedAt": "2026-09-09T07:08:55.741Z",
|
|
4
4
|
"buildMode": "ci",
|
|
5
5
|
"counts": {
|
|
6
|
-
"total":
|
|
7
|
-
"totalDocs":
|
|
6
|
+
"total": 334,
|
|
7
|
+
"totalDocs": 63,
|
|
8
8
|
"totalSpecs": 53,
|
|
9
|
-
"totalSamples":
|
|
9
|
+
"totalSamples": 198,
|
|
10
10
|
"totalScenarios": 20
|
|
11
11
|
},
|
|
12
12
|
"repo": {
|
|
13
|
-
"commit": "
|
|
13
|
+
"commit": "9ac818e686a0ab8ef2d6e77598c2e576779cec15",
|
|
14
14
|
"branch": "develop",
|
|
15
15
|
"repoUrl": "https://github.com/public-ui/kolibri"
|
|
16
16
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"group": "docs",
|
|
22
22
|
"name": "AGENTS",
|
|
23
23
|
"path": "AGENTS.md",
|
|
24
|
-
"code": "# Agent Instructions\n\nThis repository is a monorepo managed with **pnpm** and **Nx**. It contains multiple packages under `packages/` such as web components, themes, adapters, samples and tooling.\n\n## Handling hints\n\nWe have a monorepo structure with multiple packages, each with its own `package.json`. The root `package.json` contains shared dependencies and scripts. Use `pnpm` commands to manage dependencies and run scripts across packages.\n\n- To install dependencies, use `pnpm i` at the root level. This will install all dependencies for all packages.\n- If you change a dependency in a package:\n - Use only exact version numbers in `package.json`. Other peers will not be able to use the package if you can use a range version.\n - You need to run `pnpm i` at the root level. This updates the lockfile and ensures all packages are using the correct versions.\n- Never add a `packageManager` field to any `package.json` file.\n- Avoid that branch name may contain hidden characters.\n- If something does not work, check in the event of an error whether all dependent submodules have been built.\n- To build a single package faster, run commands with downstream dependents using `pnpm --filter ...<package>` (e.g., `pnpm --filter ...@public-ui/sample-react build`).\n\n## šØ Format-first rule\n\n> **Stop before you commit:** run the formatter so CI never rejects your patch for style drift.\n\n1. Run `pnpm format` from the repo root whenever you change code, docs or configs.\n2. If you only touched one package, you may instead run `pnpm --filter <package> format` for a quicker pass.\n3. Re-stage the affected files (`git add -u`) so the formatted result is what lands in the commit.\n\nNo package scripts in this repo need extra flags such as `-- --write`; the scripts already know when to write changes versus just check.\n\n## Semantic Versioning\n\nThis repository follows **Semantic Versioning** (SemVer) for all packages. Each package version is defined in its own `package.json` file. The versioning scheme is as follows:\n\n- **Major version**: Incremented for incompatible API changes.\n- **Minor version**: Incremented for adding functionality in a backwards-compatible manner.\n- **Patch version**: Incremented for backwards-compatible bug fixes.\n\nIf we deprecate a feature, we will mark it as deprecated in the code and documentation, but we will not remove it immediately. Instead, we will provide a migration guide (migration\\*.md) for users to transition to the new feature. Also we provide a migration tool in the `packages/tools/kolibri-cli` package to help with the migration process. You have to add a migration task from the previous version to the new version in the `packages/tools/kolibri-cli/src/migrations` folder. In the migration package, are a lot of migration tasks already implemented, so you can use them as a reference.\n\n## Project Structure\n\n- `packages/components` ā Stencil based web components\n - `packages/components/src/component` ā components\n - `packages/components/src/schema` ā schema definitions for all components\n- `packages/samples` ā sample applications demonstrating usage\n - `packages/samples/angular` ā Angular sample app; do not edit\n - `packages/samples/react` ā React sample app; all samples; write component samples here\n- `packages/adapters/*` ā generated framework integration packages; do not edit\n- `packages/themes` ā style themes and assets\n - `packages/themes/default` ā primary maintained standard theme\n - All other themes are not actively maintained\n- `packages/tools/kolibri-cli` ā helper CLI for migration\n- Documentation lives in `docs/`.\n- Do always ignore and do not edit all `assets` folders in all packages, as these are generated by the build process and should not be edited manually. If you need to change something in the assets, you have to change it in the source code and rebuild the package.\n\n## Theming\n\nThe theming is realized with adopted style sheets on web components and will be adopted at the mounted hook of the components. All following styling rules are only relevant for the `components` and `themes` packages.\n\n### The 5 styling layers\n\n1. **A11y Preset layer**: This layer comes out of the `adopted-style-sheets` package and contains the basic styles for accessibility. It is applied to all components.\n2. **Basis Global layer**: This layer contains the basis global styles for all components and comes out of the `@public-ui/components` package. It is applied only component specific layout styles without margins and paddings. Generally, the styling works without colors, as the colors should only be set through the custom Theme Layer.\n3. **Basis Component layer**: This layer contains the basis styles for one component and comes out of the `@public-ui/components` package. It is applied only component specific layout styles without margins and paddings. Generally, the styling works without colors, as the colors should only be set through the custom Theme Layer.\n4. **Theme Global layer**: This layer contains the global styles for all components of a theme and comes out of a own theme package, like `@public-ui/theme-default`.\n5. **Theme Component layer**: This layer contains the component specific styles for one component of a theme and comes out of a own theme package, like `@public-ui/theme-default`.\n\n### Global accessibility styles\n\n```css\n/*\n * This file contains all rules for accessibility.\n */\n@layer kol-global {\n\t:host {\n\t\t/*\n\t\t * Minimum size of interactive elements.\n\t\t */\n\t\t--a11y-min-size: #{rem(44)};\n\t\t/*\n\t\t * No element should be used without a background and font color whose contrast ratio has\n\t\t * not been checked. By initially setting the background color to white and the font color\n\t\t * to black, the contrast ratio is ensured and explicit adjustment is forced.\n\t\t */\n\t\tbackground-color: white;\n\t\tcolor: black;\n\t}\n\n\t* {\n\t\t/*\n\t\t * This rule enables the word dividing for all texts. That is important for high zoom levels.\n\t\t */\n\t\thyphens: auto;\n\t\t/*\n\t\t * Verdana is an accessible font that can be used without requiring additional loading time.\n\t\t */\n\t\tfont-family: Verdana;\n\t\t/*\n\t\t * Letter spacing is required for all texts.\n\t\t */\n\t\tletter-spacing: inherit;\n\t\t/*\n\t\t * This rule enables the word dividing for all texts. That is important for high zoom levels.\n\t\t */\n\t\tword-break: break-word;\n\t\t/*\n\t\t * Word spacing is required for all texts.\n\t\t */\n\t\tword-spacing: inherit;\n\t}\n\n\t/*\n\t * All interactive elements should have a minimum size of rem(44).\n\t */\n\t/* input:not([type='checkbox'], [type='radio'], [type='range']), */\n\t/* option, */\n\t/* select, */\n\t/* textarea, */\n\t[role='button'],\n\tbutton:not([role='link']),\n\t.kol-input .input {\n\t\tmin-height: var(--a11y-min-size);\n\t\tmin-width: var(--a11y-min-size);\n\t}\n\n\t/*\n\t * Some interactive elements should not inherit the font-family and font-size.\n\t */\n\ta,\n\tbutton,\n\th1,\n\th2,\n\th3,\n\th4,\n\th5,\n\th6,\n\tinput,\n\toption,\n\tselect,\n\ttextarea {\n\t\t/*\n\t\t * All elements should inherit the font family from his parent element.\n\t\t */\n\t\tfont-family: inherit;\n\t\t/*\n\t\t * All elements should inherit the font size from his parent element.\n\t\t */\n\t\tfont-size: inherit;\n\t}\n}\n\n/**\n * Sometimes we need the semantic element for accessibility reasons,\n * but we don't want to show it.\n *\n * - https://www.a11yproject.com/posts/how-to-hide-content/\n */\n.visually-hidden {\n\tclip: rect(0 0 0 0);\n\tclip-path: inset(50%);\n\theight: 1px;\n\toverflow: hidden;\n\tposition: absolute;\n\twhite-space: nowrap;\n\twidth: 1px;\n}\n```\n\n### Styling rules\n\nThe basis global layer set the default font-size and box-sizing for all components.\n\n```css\n@layer kol-global {\n\t:host {\n\t\tfont-size: rem(16);\n\t\t/*\n\t\t * The max-width is needed to prevent the table from overflowing the\n\t\t * parent node, if the table is wider than the parent node.\n\t\t */\n\t\tmax-width: 100%;\n\t}\n\n\t* {\n\t\t/*\n\t\t * We prefer to box-sizing: border-box for all elements.\n\t\t */\n\t\tbox-sizing: border-box;\n\t}\n ...\n}\n```\n\n### Custom Theming rules\n\nThe custom theme layer is used to set the colors and other theme specific styles. The custom theme layer should not contain any layout styles, as these are already set in the basis global and component layers.\n\nFor example, generally the font-family is set in the theme global layer, on the `:host` element, so that all components inherit the font-family from the theme. The font-size is set in the basis global layer, so that all components inherit the font-size from the basis global layer. But it is possible to set a other base font-size in the theme global layer, if needed.\n\n```css\n@layer kol-theme-global {\n\t:host {\n\t\t--font-family: var(--kolibri-font-family, Verdana, Arial, Calibri, Helvetica, sans-serif);\n\t\t--font-size: var(--kolibri-font-size, #{rem(16)});\n ...\n\t}\n\n\t:host {\n\t\tfont-size: var(--font-size);\n\n\t\t* {\n\t\t\tfont-family: var(--font-family);\n\t\t}\n\t}\n ...\n}\n```\n\nIn the theme component layer, you can set what ever you need to realize your own custom style guidelines. For example, you can set the colors, borders, shadows, etc. for the component.\n\n```css\n@layer kol-theme-component {\n ...\n}\n```\n\n### CSS Custom Properties and SASS Variables\n\nCSS custom properties remain part of the global cascade and are not isolated by the Shadow DOM.\nOverusing them (in theme files as well as in component styles) can collide with variables defined\non a host page, and every custom property you declare is implicitly overridable from outside,\nwhether you intended that or not.\n\n**Prefer plain CSS over a custom property.** Before adding a custom property, check whether the\nplatform already gives the consumer a way to control it ā the standard box model (`width`,\n`height`), inherited properties (`color`, `font-size` via `em`), or relative units (`%`, container\nquery units). A component that simply fills its host (`width: 100%; height: 100%` inside, a sane\ndefault `width`/`height` on `:host`) can be resized with plain CSS, exactly like a native element ā\nno bespoke API, no documentation burden, nothing to keep in sync. Only reach for a custom property\nwhen the value genuinely cannot be derived this way (e.g. a semantic color token that isn't just\n`currentColor`, or a value with no corresponding native CSS mechanism).\n\n**Rule:** only declare a CSS custom property when it is a deliberate, documented customization\npoint (a `--kol-<component>-<name>` design token). For anything else ā internal aliases,\nintermediate values, ratios, or derived defaults ā use a SASS `$variable` instead. SASS variables\nare resolved at build time, can't leak into the global cascade, and can't be overridden from a host\npage, so they can't accidentally become part of the public API.\n\nDo not introduce a second, internal custom property just to make the code more readable:\n\n```scss\n// ā Bad: `--color-bar` is an unintended, additional public custom property.\n// It reacts to overrides from a host page exactly like `--kol-progress-color-bar`,\n// even though only the latter was meant to be part of the API.\n.kol-progress {\n\t--color-bar: var(--kol-progress-color-bar, #0075ff);\n\n\t&__bar-progress {\n\t\tfill: var(--color-bar);\n\t}\n}\n```\n\n```scss\n// ā
Good: the SASS variable holds the default value; the only custom property\n// is `--kol-progress-color-bar`, referenced directly wherever needed.\n$kol-progress-default-color-bar: #0075ff;\n\n.kol-progress {\n\t&__bar-progress {\n\t\tfill: var(--kol-progress-color-bar, #{$kol-progress-default-color-bar});\n\t}\n}\n```\n\nAny further unit conversion or math that doesn't depend on a runtime custom property (e.g. `to-rem()`,\nratios, breakpoints) belongs in SASS, not in an extra layer of `calc()`/custom-property indirection.\n\n`kol-avatar` is an example of preferring plain CSS: instead of a `--kol-avatar-size` custom property,\n`:host` gets a default `width` and an `aspect-ratio: 1`, and the inner element derives its size from the\nhost via container query units (`cqw`/`cqh`) instead of a separate ratio calculation. Consumers resize it\nthe same way they'd resize any block-level element ā with plain `width`/`height`.\n\nThe avatar must always stay square, even if `width` and `height` end up different (e.g. both are set\nexplicitly to different values), so the inner element uses `max(100cqw, 100cqh)` for both its own `width`\nand `height` ā the larger of the two wins, and `:host` centers it (`align-items`/`justify-content`), so it\nmay visually extend beyond the host on the smaller axis. Since CSS can't distinguish \"our default\" from\n\"an explicit author value\" on two independent properties, only setting `width` reliably resizes the avatar\nbelow its 100px default; setting only `height` below 100px does not shrink it, because our own default\n`width` is still in effect and wins the `max()`. This is a deliberate, documented trade-off, not a bug ā\nachieving full symmetry would require either a custom property or JavaScript, both of which cost more\nthan the trade-off is worth.\n\n### SCSS Architecture Guidelines: BEM with Smart Nesting\n\nWhen writing component theme styles, follow these principles for clean, maintainable SCSS:\n\n#### 1. **Flat BEM Structure (Root Level)**\n\nAll BEM modifiers and independent elements belong at **root level** of the mixin. Never nest BEM class names:\n\n```scss\n@mixin kol-alert-theme {\n\t// ā
All BEM selectors on root (flat)\n\t.kol-alert { ... }\n\t.kol-alert--variant-msg { ... }\n\t.kol-alert--variant-card { ... }\n\t.kol-alert--type-default { ... }\n\t.kol-alert__container { ... }\n\t.kol-alert__heading { ... }\n}\n```\n\n**Why?** BEM classnames are independent selectors. Each class should be predictable and flat.\n\n#### 2. **Contextual Nesting (When Variants Change Element Behavior)**\n\nNest **only when a modifier changes how a child element behaves**. Keep all rules for an element together:\n\n```scss\n.kol-alert__closer {\n\tplace-self: center;\n\n\t.kol-button {\n\t\tborder-radius: 50%;\n\t\twidth: var(--a11y-min-size);\n\t\theight: var(--a11y-min-size);\n\t\tcursor: pointer;\n\n\t\t// ā
Variant changes button styling - nest here\n\t\t.kol-alert--variant-msg & {\n\t\t\t--text-color: var(--alert-accent-color);\n\t\t}\n\n\t\t.kol-alert--variant-card & {\n\t\t\t--text-color: var(--color-light);\n\t\t}\n\t}\n}\n```\n\n**Rule of thumb**: All rules for `.kol-button` in `.kol-alert__closer` stay in one place. This keeps related styles together and makes maintenance easier.\n\n#### 3. **Never Use `$root` or `@at-root`**\n\nā **Outdated pattern (removed):**\n\n```scss\n.kol-alert {\n\t$root: &;\n\t&__closer {\n\t\t@at-root #{$root}--variant-msg & { ... }\n\t}\n}\n```\n\nā
**Modern pattern (direct nesting):**\n\n```scss\n.kol-alert__closer {\n\t.kol-button {\n\t\t.kol-alert--variant-msg & { ... }\n\t}\n}\n```\n\nThis is clearer and doesn't require Sass variable gymnastics.\n\n#### 4. **Structure Template**\n\n```scss\n@mixin kol-component-theme {\n\t// 1. Base component (no children)\n\t.kol-component {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t}\n\n\t// 2. All BEM modifiers at root (flat)\n\t.kol-component--variant-a {\n\t\t...\n\t}\n\n\t.kol-component--type-default {\n\t\t...\n\t}\n\n\t// 3. Elements with contextual nesting for variants\n\t.kol-component__heading {\n\t\tfont-weight: bold;\n\n\t\t.kol-component--variant-a & {\n\t\t\tcolor: red;\n\t\t}\n\t}\n\n\t.kol-component__content {\n\t\tpadding: 1rem;\n\n\t\t.kol-component--variant-a & {\n\t\t\tbackground: white;\n\t\t}\n\t}\n\n\t// 4. Child components with variant context\n\t.kol-component__button {\n\t\t.kol-button {\n\t\t\tcursor: pointer;\n\n\t\t\t.kol-component--variant-a & {\n\t\t\t\t--text-color: var(--accent);\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n### General rules for custom themes\n\n- Do not use `!important` in your styles, as this will override the styles of the basis global and component layers.\n- Do only overwrite styling definitions you will really customize. Do not set styling definitions that are already set (redundant) in the basis global and component layers, as this will override the styles of the basis global and component layers.\n- Do not `inherit` styles over the `:host` element, as this will override the styles of the basis global and component layers. This makes your component less robust from outside environment styles. Only the `kol-icon` inherits some specific styles, like `color`, `font-size`, `font-family` and `line-height`, as these are needed for the icon to be displayed correctly inline to this neighbored elements.\n- Do not set the default `font-family`, `font-size` or `box-sizing` in the basis or theme component layer (redundant), as these are already set in the basis global layers. If you need to set a different font-family or font-size, you can do this in the theme global layer.\n- Do not set `margin` or `padding` in the basis global and component layers. If you need to set a different margin or padding, you can do this in the theme global or component layers.\n- Do not use `overflow: hidden` in styling or theming, as it often causes issues for reuse and should be avoided.\n- **Do not use `@layer` declarations in utility files**: Helper files, mixin files, and partial files (starting with `_`) should not contain `@layer` declarations. These files are utilities and should be layer-agnostic. This is enforced by the custom Stylelint rule `kolibri/no-layer-in-utility-files`.\n- **Never use `$root` variables or `@at-root` in component mixins**: All selectors should be explicit. Use direct child/descendant nesting only when a modifier changes element behavior within a specific context.\n\n## Samples\n\nThe samples are located in `packages/samples/react` and demonstrate how to use the components in react. Each component has its own folder and the basic sample are in `basic.tsx`. Other stories can be added in the same folder. All samples of a component are registered in the `routes.ts` file.\n\n## Coding Conventions\n\n- Formatting is enforced via **Prettier** with settings defined in `prettier.config.js` (print width 160, single quotes, tabs).\n- `.editorconfig` sets `indent_style = tab` and `max_line_length = 160` for code files. Markdown and YAML files use spaces.\n- ESLint and Stylelint are run using `pnpm lint`. Lint rules should **not** be disabled via inline comments. Instead, describe the problem and work towards a clean solution.\n- Lists and enumerations in code should be kept in alphanumeric order. This also applies to import specifiers and union type literals.\n- Do not disable ESLint, Stylelint or TypeScript rules inline. Fix the code instead of turning such rules off.\n- ESLint and Stylelint are run using `pnpm lint`.\n- Lists and enumerations in code should be kept in alphabetical order (see `docs/tutorials/NEW_COMPONENT.md`).\n- Commit messages follow the **Conventional Commits** specification.\n- See also the [Contributing Guide](CONTRIBUTING.md) for more details on coding conventions and best practices.\n- Spell \"KoliBri\" with this casing in all documentation and code. The only exception is the component named KolKolibri.\n- Use ESM import syntax in browser code and scripts whenever supported, instead of `require` imports.\n- Do not create barrel files (e.g. `index.ts` that re-export modules). Import modules directly instead.\n- Do not place constant declarations before import statements; imports must always be at the very top of the file.\n- **Scripts must be platform-independent**: All scripts in the `scripts/` folder must work on Windows, macOS, and Linux without requiring external tools or platform-specific dependencies. Use Node.js built-in modules instead of external command-line tools like `rg`, `grep`, `find`, etc.\n\n## Linting and Formatting\n\n- Run `pnpm lint` to check for linting errors across all packages. This script runs ESLint, Stylelint and TypeScript checks.\n - ā ļø **Note**: TypeScript type checking in the lint script can require built artifacts. If you've made source code changes, lint will handle any necessary compilation. Explicit pre-build is typically unnecessary.\n - You can try to automatically fix linting issues with `pnpm lint:eslint --fix`, but this may not resolve all issues.\n- Run `pnpm format` to format all code files using Prettier. You can try to automatically fix linting issues with `pnpm format -w`, but this may not resolve all issues.\n- If your pull request only modifies Markdown files, skip `pnpm build`, `pnpm lint` and `pnpm test`. Just format the Markdown using `pnpm format` or Prettier.\n\n### Pre-commit checklist\n\n- **Always run `pnpm format` (or `pnpm --filter <package> format` for a single workspace) right before committing.** Formatting failures are one of the most common reasons for blocked quality gates, so make this the last step before `git commit` even for documentation-only changes.\n- **For SCSS changes**: Always run `pnpm lint:stylelint --fix` (or `pnpm --filter <package> lint:stylelint --fix`) to automatically correct formatting, property order, and selector structure rules before committing. This ensures compliance with BEM structure and style consistency.\n- After formatting, re-stage affected files with `git add -u` so the formatted content is what gets committed.\n\n## Testing\n\n- Run `pnpm test` from the repository root to execute all unit and integration tests.\n - ā ļø **Note**: Test runners (Vitest, Jest, Playwright, etc.) execute an implicit build automatically before running tests. **Do NOT run a separate `pnpm build` beforehand** ā this wastes time. The test scripts handle compilation and type checking internally.\n- Visual and snapshot tests can be updated with `pnpm test:update` or via the `update-snapshots.yml` GitHub workflow (see `CONTRIBUTING.md`).\n- Individual packages provide their own test scripts (e.g. `pnpm --filter @public-ui/components test:unit`).\n - These also perform implicit builds, so explicit pre-build is unnecessary.\n\n## Pull Request Guidelines\n\n- PR titles should be meaningful as they appear in the release notes.\n- Every PR must link to its issue and contain only changes related to that issue.\n- Ensure automated tests pass and manual testing is completed when required.\n- Update documentation or migration guides if your changes affect them.\n",
|
|
24
|
+
"code": "# Agent Instructions\n\nThis repository is a monorepo managed with **pnpm** and **Nx**. It contains multiple packages under `packages/` such as web components, themes, adapters, samples and tooling.\n\n## Handling hints\n\nWe have a monorepo structure with multiple packages, each with its own `package.json`. The root `package.json` contains shared dependencies and scripts. Use `pnpm` commands to manage dependencies and run scripts across packages.\n\n- To install dependencies, use `pnpm i` at the root level. This will install all dependencies for all packages.\n- If you change a dependency in a package:\n - Use only exact version numbers in `package.json`. Other peers will not be able to use the package if you can use a range version.\n - You need to run `pnpm i` at the root level. This updates the lockfile and ensures all packages are using the correct versions.\n- Never add a `packageManager` field to any `package.json` file.\n- Avoid that branch name may contain hidden characters.\n- If something does not work, check in the event of an error whether all dependent submodules have been built.\n- To build a single package faster, run commands with downstream dependents using `pnpm --filter ...<package>` (e.g., `pnpm --filter ...@public-ui/sample-react build`).\n\n## šØ Format-first rule\n\n> **Stop before you commit:** run the formatter so CI never rejects your patch for style drift.\n\n1. Run `pnpm format` from the repo root whenever you change code, docs or configs.\n2. If you only touched one package, you may instead run `pnpm --filter <package> format` for a quicker pass.\n3. Re-stage the affected files (`git add -u`) so the formatted result is what lands in the commit.\n\nNo package scripts in this repo need extra flags such as `-- --write`; the scripts already know when to write changes versus just check.\n\n## Semantic Versioning\n\nThis repository follows **Semantic Versioning** (SemVer) for all packages. Each package version is defined in its own `package.json` file. The versioning scheme is as follows:\n\n- **Major version**: Incremented for incompatible API changes.\n- **Minor version**: Incremented for adding functionality in a backwards-compatible manner.\n- **Patch version**: Incremented for backwards-compatible bug fixes.\n\nIf we deprecate a feature, we will mark it as deprecated in the code and documentation, but we will not remove it immediately. Instead, we will provide a migration guide (migration\\*.md) for users to transition to the new feature. Also we provide a migration tool in the `packages/tools/kolibri-cli` package to help with the migration process. You have to add a migration task from the previous version to the new version in the `packages/tools/kolibri-cli/src/migrations` folder. In the migration package, are a lot of migration tasks already implemented, so you can use them as a reference.\n\n## Project Structure\n\n- `packages/components` ā Stencil based web components\n - `packages/components/src/component` ā components\n - `packages/components/src/schema` ā schema definitions for all components\n- `packages/samples` ā sample applications demonstrating usage\n - `packages/samples/angular` ā Angular sample app; do not edit\n - `packages/samples/react` ā React sample app; all samples; write component samples here\n- `packages/adapters/*` ā generated framework integration packages; do not edit\n- `packages/themes` ā style themes and assets\n - `packages/themes/default` ā primary maintained standard theme\n - All other themes are not actively maintained\n- `packages/tools/kolibri-cli` ā helper CLI for migration\n- Documentation lives in `docs/`.\n- Do always ignore and do not edit all `assets` folders in all packages, as these are generated by the build process and should not be edited manually. If you need to change something in the assets, you have to change it in the source code and rebuild the package.\n\n## Theming\n\nThe theming is realized with adopted style sheets on web components and will be adopted at the mounted hook of the components. All following styling rules are only relevant for the `components` and `themes` packages.\n\n### The 5 styling layers\n\n1. **A11y Preset layer**: This layer comes out of the `adopted-style-sheets` package and contains the basic styles for accessibility. It is applied to all components.\n2. **Basis Global layer**: This layer contains the basis global styles for all components and comes out of the `@public-ui/components` package. It is applied only component specific layout styles without margins and paddings. Generally, the styling works without colors, as the colors should only be set through the custom Theme Layer.\n3. **Basis Component layer**: This layer contains the basis styles for one component and comes out of the `@public-ui/components` package. It is applied only component specific layout styles without margins and paddings. Generally, the styling works without colors, as the colors should only be set through the custom Theme Layer.\n4. **Theme Global layer**: This layer contains the global styles for all components of a theme and comes out of a own theme package, like `@public-ui/theme-default`.\n5. **Theme Component layer**: This layer contains the component specific styles for one component of a theme and comes out of a own theme package, like `@public-ui/theme-default`.\n\n### Global accessibility styles\n\n```css\n/*\n * This file contains all rules for accessibility.\n */\n@layer kol-global {\n\t:host {\n\t\t/*\n\t\t * Minimum size of interactive elements.\n\t\t */\n\t\t--a11y-min-size: #{rem(44)};\n\t\t/*\n\t\t * No element should be used without a background and font color whose contrast ratio has\n\t\t * not been checked. By initially setting the background color to white and the font color\n\t\t * to black, the contrast ratio is ensured and explicit adjustment is forced.\n\t\t */\n\t\tbackground-color: white;\n\t\tcolor: black;\n\t}\n\n\t* {\n\t\t/*\n\t\t * This rule enables the word dividing for all texts. That is important for high zoom levels.\n\t\t */\n\t\thyphens: auto;\n\t\t/*\n\t\t * Verdana is an accessible font that can be used without requiring additional loading time.\n\t\t */\n\t\tfont-family: Verdana;\n\t\t/*\n\t\t * Letter spacing is required for all texts.\n\t\t */\n\t\tletter-spacing: inherit;\n\t\t/*\n\t\t * This rule enables the word dividing for all texts. That is important for high zoom levels.\n\t\t */\n\t\tword-break: break-word;\n\t\t/*\n\t\t * Word spacing is required for all texts.\n\t\t */\n\t\tword-spacing: inherit;\n\t}\n\n\t/*\n\t * All interactive elements should have a minimum size of rem(44).\n\t */\n\t/* input:not([type='checkbox'], [type='radio'], [type='range']), */\n\t/* option, */\n\t/* select, */\n\t/* textarea, */\n\t[role='button'],\n\tbutton:not([role='link']),\n\t.kol-input .input {\n\t\tmin-height: var(--a11y-min-size);\n\t\tmin-width: var(--a11y-min-size);\n\t}\n\n\t/*\n\t * Some interactive elements should not inherit the font-family and font-size.\n\t */\n\ta,\n\tbutton,\n\th1,\n\th2,\n\th3,\n\th4,\n\th5,\n\th6,\n\tinput,\n\toption,\n\tselect,\n\ttextarea {\n\t\t/*\n\t\t * All elements should inherit the font family from his parent element.\n\t\t */\n\t\tfont-family: inherit;\n\t\t/*\n\t\t * All elements should inherit the font size from his parent element.\n\t\t */\n\t\tfont-size: inherit;\n\t}\n}\n\n/**\n * Sometimes we need the semantic element for accessibility reasons,\n * but we don't want to show it.\n *\n * - https://www.a11yproject.com/posts/how-to-hide-content/\n */\n.visually-hidden {\n\tclip: rect(0 0 0 0);\n\tclip-path: inset(50%);\n\theight: 1px;\n\toverflow: hidden;\n\tposition: absolute;\n\twhite-space: nowrap;\n\twidth: 1px;\n}\n```\n\n### Styling rules\n\nThe basis global layer set the default font-size and box-sizing for all components.\n\n```css\n@layer kol-global {\n\t:host {\n\t\tfont-size: rem(16);\n\t\t/*\n\t\t * The max-width is needed to prevent the table from overflowing the\n\t\t * parent node, if the table is wider than the parent node.\n\t\t */\n\t\tmax-width: 100%;\n\t}\n\n\t* {\n\t\t/*\n\t\t * We prefer to box-sizing: border-box for all elements.\n\t\t */\n\t\tbox-sizing: border-box;\n\t}\n ...\n}\n```\n\n### Custom Theming rules\n\nThe custom theme layer is used to set the colors and other theme specific styles. The custom theme layer should not contain any layout styles, as these are already set in the basis global and component layers.\n\nFor example, generally the font-family is set in the theme global layer, on the `:host` element, so that all components inherit the font-family from the theme. The font-size is set in the basis global layer, so that all components inherit the font-size from the basis global layer. But it is possible to set a other base font-size in the theme global layer, if needed.\n\n```css\n@layer kol-theme-global {\n\t:host {\n\t\t--font-family: var(--kolibri-font-family, Verdana, Arial, Calibri, Helvetica, sans-serif);\n\t\t--font-size: var(--kolibri-font-size, #{rem(16)});\n ...\n\t}\n\n\t:host {\n\t\tfont-size: var(--font-size);\n\n\t\t* {\n\t\t\tfont-family: var(--font-family);\n\t\t}\n\t}\n ...\n}\n```\n\nIn the theme component layer, you can set what ever you need to realize your own custom style guidelines. For example, you can set the colors, borders, shadows, etc. for the component.\n\n```css\n@layer kol-theme-component {\n ...\n}\n```\n\n### CSS Custom Properties and SASS Variables\n\nCSS custom properties remain part of the global cascade and are not isolated by the Shadow DOM.\nOverusing them (in theme files as well as in component styles) can collide with variables defined\non a host page, and every custom property you declare is implicitly overridable from outside,\nwhether you intended that or not.\n\n**Prefer plain CSS over a custom property.** Before adding a custom property, check whether the\nplatform already gives the consumer a way to control it ā the standard box model (`width`,\n`height`), inherited properties (`color`, `font-size` via `em`), or relative units (`%`, container\nquery units). A component that simply fills its host (`width: 100%; height: 100%` inside, a sane\ndefault `width`/`height` on `:host`) can be resized with plain CSS, exactly like a native element ā\nno bespoke API, no documentation burden, nothing to keep in sync. Only reach for a custom property\nwhen the value genuinely cannot be derived this way (e.g. a semantic color token that isn't just\n`currentColor`, or a value with no corresponding native CSS mechanism).\n\n**Rule:** only declare a CSS custom property when it is a deliberate, documented customization\npoint (a `--kol-<component>-<name>` design token). For anything else ā internal aliases,\nintermediate values, ratios, or derived defaults ā use a SASS `$variable` instead. SASS variables\nare resolved at build time, can't leak into the global cascade, and can't be overridden from a host\npage, so they can't accidentally become part of the public API.\n\nDo not introduce a second, internal custom property just to make the code more readable:\n\n```scss\n// ā Bad: `--color-bar` is an unintended, additional public custom property.\n// It reacts to overrides from a host page exactly like `--kol-progress-color-bar`,\n// even though only the latter was meant to be part of the API.\n.kol-progress {\n\t--color-bar: var(--kol-progress-color-bar, #0075ff);\n\n\t&__bar-progress {\n\t\tfill: var(--color-bar);\n\t}\n}\n```\n\n```scss\n// ā
Good: the SASS variable holds the default value; the only custom property\n// is `--kol-progress-color-bar`, referenced directly wherever needed.\n$kol-progress-default-color-bar: #0075ff;\n\n.kol-progress {\n\t&__bar-progress {\n\t\tfill: var(--kol-progress-color-bar, #{$kol-progress-default-color-bar});\n\t}\n}\n```\n\nAny further unit conversion or math that doesn't depend on a runtime custom property (e.g. `to-rem()`,\nratios, breakpoints) belongs in SASS, not in an extra layer of `calc()`/custom-property indirection.\n\n`kol-avatar` is an example of preferring plain CSS: instead of a `--kol-avatar-size` custom property,\n`:host` gets a default `width` and an `aspect-ratio: 1`, and the inner element derives its size from the\nhost via container query units (`cqw`/`cqh`) instead of a separate ratio calculation. Consumers resize it\nthe same way they'd resize any block-level element ā with plain `width`/`height`.\n\nThe avatar must always stay square, even if `width` and `height` end up different (e.g. both are set\nexplicitly to different values), so the inner element uses `max(100cqw, 100cqh)` for both its own `width`\nand `height` ā the larger of the two wins, and `:host` centers it (`align-items`/`justify-content`), so it\nmay visually extend beyond the host on the smaller axis. Since CSS can't distinguish \"our default\" from\n\"an explicit author value\" on two independent properties, only setting `width` reliably resizes the avatar\nbelow its 100px default; setting only `height` below 100px does not shrink it, because our own default\n`width` is still in effect and wins the `max()`. This is a deliberate, documented trade-off, not a bug ā\nachieving full symmetry would require either a custom property or JavaScript, both of which cost more\nthan the trade-off is worth.\n\n### SCSS Architecture Guidelines: BEM with Smart Nesting\n\nWhen writing component theme styles, follow these principles for clean, maintainable SCSS:\n\n#### 1. **Flat BEM Structure (Root Level)**\n\nAll BEM modifiers and independent elements belong at **root level** of the mixin. Never nest BEM class names:\n\n```scss\n@mixin kol-alert-theme {\n\t// ā
All BEM selectors on root (flat)\n\t.kol-alert { ... }\n\t.kol-alert--variant-msg { ... }\n\t.kol-alert--variant-card { ... }\n\t.kol-alert--type-default { ... }\n\t.kol-alert__container { ... }\n\t.kol-alert__heading { ... }\n}\n```\n\n**Why?** BEM classnames are independent selectors. Each class should be predictable and flat.\n\n#### 2. **Contextual Nesting (When Variants Change Element Behavior)**\n\nNest **only when a modifier changes how a child element behaves**. Keep all rules for an element together:\n\n```scss\n.kol-alert__closer {\n\tplace-self: center;\n\n\t.kol-button {\n\t\tborder-radius: 50%;\n\t\twidth: var(--a11y-min-size);\n\t\theight: var(--a11y-min-size);\n\t\tcursor: pointer;\n\n\t\t// ā
Variant changes button styling - nest here\n\t\t.kol-alert--variant-msg & {\n\t\t\t--text-color: var(--alert-accent-color);\n\t\t}\n\n\t\t.kol-alert--variant-card & {\n\t\t\t--text-color: var(--color-light);\n\t\t}\n\t}\n}\n```\n\n**Rule of thumb**: All rules for `.kol-button` in `.kol-alert__closer` stay in one place. This keeps related styles together and makes maintenance easier.\n\n#### 3. **Never Use `$root` or `@at-root`**\n\nā **Outdated pattern (removed):**\n\n```scss\n.kol-alert {\n\t$root: &;\n\t&__closer {\n\t\t@at-root #{$root}--variant-msg & { ... }\n\t}\n}\n```\n\nā
**Modern pattern (direct nesting):**\n\n```scss\n.kol-alert__closer {\n\t.kol-button {\n\t\t.kol-alert--variant-msg & { ... }\n\t}\n}\n```\n\nThis is clearer and doesn't require Sass variable gymnastics.\n\n#### 4. **Structure Template**\n\n```scss\n@mixin kol-component-theme {\n\t// 1. Base component (no children)\n\t.kol-component {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t}\n\n\t// 2. All BEM modifiers at root (flat)\n\t.kol-component--variant-a {\n\t\t...\n\t}\n\n\t.kol-component--type-default {\n\t\t...\n\t}\n\n\t// 3. Elements with contextual nesting for variants\n\t.kol-component__heading {\n\t\tfont-weight: bold;\n\n\t\t.kol-component--variant-a & {\n\t\t\tcolor: red;\n\t\t}\n\t}\n\n\t.kol-component__content {\n\t\tpadding: 1rem;\n\n\t\t.kol-component--variant-a & {\n\t\t\tbackground: white;\n\t\t}\n\t}\n\n\t// 4. Child components with variant context\n\t.kol-component__button {\n\t\t.kol-button {\n\t\t\tcursor: pointer;\n\n\t\t\t.kol-component--variant-a & {\n\t\t\t\t--text-color: var(--accent);\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n### General rules for custom themes\n\n- Do not use `!important` in your styles, as this will override the styles of the basis global and component layers.\n- Do only overwrite styling definitions you will really customize. Do not set styling definitions that are already set (redundant) in the basis global and component layers, as this will override the styles of the basis global and component layers.\n- Do not `inherit` styles over the `:host` element, as this will override the styles of the basis global and component layers. This makes your component less robust from outside environment styles. Only the `kol-icon` inherits some specific styles, like `color`, `font-size`, `font-family` and `line-height`, as these are needed for the icon to be displayed correctly inline to this neighbored elements.\n- Do not set the default `font-family`, `font-size` or `box-sizing` in the basis or theme component layer (redundant), as these are already set in the basis global layers. If you need to set a different font-family or font-size, you can do this in the theme global layer.\n- Do not set `margin` or `padding` in the basis global and component layers. If you need to set a different margin or padding, you can do this in the theme global or component layers.\n- Do not use `overflow: hidden` in styling or theming, as it often causes issues for reuse and should be avoided.\n- **Do not use `@layer` declarations in utility files**: Helper files, mixin files, and partial files (starting with `_`) should not contain `@layer` declarations. These files are utilities and should be layer-agnostic. This is enforced by the custom Stylelint rule `kolibri/no-layer-in-utility-files`.\n- **Never use `$root` variables or `@at-root` in component mixins**: All selectors should be explicit. Use direct child/descendant nesting only when a modifier changes element behavior within a specific context.\n\n## Samples\n\nThe samples are located in `packages/samples/react` and demonstrate how to use the components in react. Each component has its own folder and the basic sample are in `basic.tsx`. Other stories can be added in the same folder. All samples of a component are registered in the `routes.ts` file.\n\n## Coding Conventions\n\n- Formatting is enforced via **Prettier** with settings defined in `prettier.config.js` (print width 160, single quotes, tabs).\n- `.editorconfig` sets `indent_style = tab` and `max_line_length = 160` for code files. Markdown and YAML files use spaces.\n- ESLint and Stylelint are run using `pnpm lint`. Lint rules should **not** be disabled via inline comments. Instead, describe the problem and work towards a clean solution.\n- Lists and enumerations in code should be kept in alphanumeric order. This also applies to import specifiers and union type literals.\n- Do not disable ESLint, Stylelint or TypeScript rules inline. Fix the code instead of turning such rules off.\n- ESLint and Stylelint are run using `pnpm lint`.\n- Lists and enumerations in code should be kept in alphabetical order (see `docs/tutorials/NEW_COMPONENT.md`).\n- Commit messages follow the **Conventional Commits** specification.\n- See also the [Contributing Guide](CONTRIBUTING.md) for more details on coding conventions and best practices.\n- Spell \"KoliBri\" with this casing in all documentation and code. The only exception is the component named KolKolibri.\n- Use ESM import syntax in browser code and scripts whenever supported, instead of `require` imports.\n- Do not create barrel files (e.g. `index.ts` that re-export modules). Import modules directly instead.\n- Do not place constant declarations before import statements; imports must always be at the very top of the file.\n- **Scripts must be platform-independent**: All scripts in the `scripts/` folder must work on Windows, macOS, and Linux without requiring external tools or platform-specific dependencies. Use Node.js built-in modules instead of external command-line tools like `rg`, `grep`, `find`, etc.\n\n## Linting and Formatting\n\n- Run `pnpm lint` to check for linting errors across all packages. This script runs ESLint, Stylelint and TypeScript checks.\n - ā ļø **Note**: TypeScript type checking in the lint script can require built artifacts. If you've made source code changes, lint will handle any necessary compilation. Explicit pre-build is typically unnecessary.\n - You can try to automatically fix linting issues with `pnpm lint:eslint --fix`, but this may not resolve all issues.\n- Run `pnpm format` to format all code files using Prettier. You can try to automatically fix linting issues with `pnpm format -w`, but this may not resolve all issues.\n- If your pull request only modifies Markdown files, skip `pnpm build`, `pnpm lint` and `pnpm test`. Just format the Markdown using `pnpm format` or Prettier.\n\n### Pre-commit checklist\n\n- **Always run `pnpm format` (or `pnpm --filter <package> format` for a single workspace) right before committing.** Formatting failures are one of the most common reasons for blocked quality gates, so make this the last step before `git commit` even for documentation-only changes.\n- **For SCSS changes**: Always run `pnpm lint:stylelint --fix` (or `pnpm --filter <package> lint:stylelint --fix`) to automatically correct formatting, property order, and selector structure rules before committing. This ensures compliance with BEM structure and style consistency.\n- After formatting, re-stage affected files with `git add -u` so the formatted content is what gets committed.\n\n## Testing\n\n- Run `pnpm test` from the repository root to execute all unit and integration tests.\n - ā ļø **Note**: Test runners (Vitest, Jest, Playwright, etc.) execute an implicit build automatically before running tests. **Do NOT run a separate `pnpm build` beforehand** ā this wastes time. The test scripts handle compilation and type checking internally.\n- Text snapshots of the unit tests can be updated with `pnpm test:update:unit` or via the `update-snapshots.yml` GitHub workflow. Visual screenshots are **not** committed: differences are approved on the review page of the pull request (see `docs/visual-review.md`); `pnpm snapshots:pull` fetches the current baseline for local runs.\n- Individual packages provide their own test scripts (e.g. `pnpm --filter @public-ui/components test:unit`).\n - These also perform implicit builds, so explicit pre-build is unnecessary.\n\n## Pull Request Guidelines\n\n- PR titles should be meaningful as they appear in the release notes.\n- Every PR must link to its issue and contain only changes related to that issue.\n- Ensure automated tests pass and manual testing is completed when required.\n- Update documentation or migration guides if your changes affect them.\n",
|
|
25
25
|
"kind": "doc"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
"group": "docs",
|
|
334
334
|
"name": "CONTRIBUTING",
|
|
335
335
|
"path": "CONTRIBUTING.md",
|
|
336
|
-
"code": "# Contributing\n\nWe would love for you to contribute to **KoliBri**and help make it even better than it is today! As a contributor, we ask that you follow the following guidelines:\n\n- [Contributing](#contributing)\n - [Code of Conduct](#code-of-conduct)\n - [Questions and problems](#questions-and-problems)\n - [Report an error](#report-an-error)\n - [Further development](#further-development)\n - [Git flow](#git-flow)\n - [Pull Request Guidelines](#pull-request-guidelines)\n - [Developing](#developing)\n - [Develop new component](#develop-new-component)\n - [Switching between branches](#switching-between-branches)\n - [Back porting to older Major-Versions](#back-porting-to-older-major-versions)\n - [Snapshot Testing for Visual Changes](#snapshot-testing-for-visual-changes)\n - [How to Update Snapshots](#how-to-update-snapshots)\n\n## Code of Conduct\n\nHelp us keep **KoliBri** open and inclusive. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).\n\n## Questions and problems\n\nPlease do not create issue tickets for general support questions. We want to use the ticket system for tracking bug reports and feature requests.\n\nInstead, we recommend first checking [Stack Overflow](https://stackoverflow.com/questions/tagged/kolibri) to see whether someone else has already solved the question or problem. You can also create new questions with the tag āhummingbirdā.\nTo save your time and ours, we will close all general questions in the ticket system and redirect those asking to Stack Overflow.\n\nIf you would like to contact us, please send us an email to [kolibri@itzbund.de](mailto:kolibri@itzbund.de).\n\n## Report an error\n\nIf you find an error in the source code, you can report it to our ticket system.\n\nIt would be even better if you suggested a solution to us as a pull request.\n\n## Further development\n\nYou can request new features by submitting an issue to our ticket system. If you would like to implement a new function, please note the following steps for further action:\n\n- It is helpful to read the KoliBri [architecture concept](https://public-ui.github.io/docs/concepts/architecture) before implementing.\n- For major innovations, please create a ticket with the description of the new function.\n- For small innovations, you can offer and justify the implementation directly as a pull request.\n\n### Git flow\n\nWe work according to the Git flow: https://medium.com/android-news/gitflow-with-github-c675aa4f606a\n\n### Pull Request Guidelines\n\nWhen creating a pull request, please follow these guidelines:\n\n- **PR Title:** The pull request title must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. This is enforced by automated validation in our CI pipeline.\n- **PR Title Format:** `<type>: <description>` or `<type>(<scope>): <description>`\n- **Allowed Types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`\n- **Description:** The description should start with a lowercase letter and clearly explain the change.\n\n**Examples of valid PR titles:**\n\n- `feat: add new button component`\n- `fix: resolve navigation issue on mobile devices`\n- `docs: update installation instructions`\n- `refactor(components): simplify input validation logic`\n\n**Examples of invalid PR titles:**\n\n- `Add new feature` (missing type prefix)\n- `feat: Add feature` (description should start with lowercase)\n- `feature: add new button` (invalid type, should be `feat`)\n\n### Developing\n\n1. For contributing, you need a [GitHub account](https://github.com/login)\n2. Fork [our repository](https://github.com/public-ui/kolibri) on GitHub\n3. Open your preferred command line interface\n4. Clone the forked repository via HTTPS to your local machine. The VS Code GitHub extension can handle authentication.\n5. Navigate the project root directory\n6. Create a new branch for your changes\n7. Install Node.js version 22\n8. [Install PNPM](https://pnpm.io/installation) on you local machine\n9. Install all packages with `pnpm i`\n10. Build all packages within the mono repository `pnpm -r build`\n11. Navigate to the desired package in our monorepo\n12. When you want to start the project navigate to `packages/components/` and run `pnpm dev`\n13. To watch for changes navigate to `packages/samples/react/` and execute `pnpm start`. `http://localhost:8080/` will open automatically\n\nRun ESLint across the repository with `pnpm lint` (or `pnpm lint:eslint` to invoke ESLint directly); the configuration lives in `packages/*/eslint.config.cjs`. Formatting is handled by Prettier via `pnpm format`, so run format first to keep ESLint focused on code-quality rules rather than style drift.\n\n### VS Code Setup\n\nWe recommend using [Visual Studio Code](https://code.visualstudio.com/):\n\n- Install the Prettier and ESLint extensions.\n- Enable \"Format on Save\" in your settings.\n\n### Tests\n\nAll tests run via GitHub Actions when you open a pull request. Monitor them under the **Actions** tab.\n\n### Develop new component\n\nRefer to [new component](docs/tutorials/NEW_COMPONENT.md) tutorial.\n\n### Switching between branches\n\nWhen changing the current working branch, it is important to reinstall all dependencies, as these may have changed. It is very important that all packages are built when working on dependents. This is because the packages always use the built state of the referenced packages in the mono repo.\nTo avoid unexpected problems, it is therefore always advisable to build all packages once. This can be done with these steps:\n\n- Reinstall all dependencies: `pnpm i`\n- Build all packages: `pnpm -r build`\n- You can then switch to the package to be processed and start it with `pnpm start`.\n\nIf it is also necessary to edit dependent packages such as `@public-ui/components`, these must be rebuilt for each change. Such packages offer the `dev` script for this purpose. This automatically rebuilds the package after each change.\n\n### Back porting to older Major-Versions\n\nBy default, development is carried out in the `development` branch for the following version. However, if it becomes necessary to provide an issue for an older major release, such as version 1.x.x, the code change must also be merged into the corresponding release branch. In this case, it would be the `release/1` branch. It is important that the branch that was created from the `develop` is not merged into the release branch, as otherwise the next patch version will receive all the changes from the current development status.\nThe simplest procedure is therefore to create a new branch from the release branch (e.g. `release/1`) and transfer the individual commits of the feature branch from the `develop` to the new branch using cherry-picking. This branch can then be merged into the release branch as normal with a new pull request.\n\n###
|
|
336
|
+
"code": "# Contributing\n\nWe would love for you to contribute to **KoliBri**and help make it even better than it is today! As a contributor, we ask that you follow the following guidelines:\n\n- [Contributing](#contributing)\n - [Code of Conduct](#code-of-conduct)\n - [Questions and problems](#questions-and-problems)\n - [Report an error](#report-an-error)\n - [Further development](#further-development)\n - [Git flow](#git-flow)\n - [Pull Request Guidelines](#pull-request-guidelines)\n - [Developing](#developing)\n - [Develop new component](#develop-new-component)\n - [Switching between branches](#switching-between-branches)\n - [Back porting to older Major-Versions](#back-porting-to-older-major-versions)\n - [Snapshot Testing for Visual Changes](#snapshot-testing-for-visual-changes)\n - [How to Update Snapshots](#how-to-update-snapshots)\n\n## Code of Conduct\n\nHelp us keep **KoliBri** open and inclusive. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).\n\n## Questions and problems\n\nPlease do not create issue tickets for general support questions. We want to use the ticket system for tracking bug reports and feature requests.\n\nInstead, we recommend first checking [Stack Overflow](https://stackoverflow.com/questions/tagged/kolibri) to see whether someone else has already solved the question or problem. You can also create new questions with the tag āhummingbirdā.\nTo save your time and ours, we will close all general questions in the ticket system and redirect those asking to Stack Overflow.\n\nIf you would like to contact us, please send us an email to [kolibri@itzbund.de](mailto:kolibri@itzbund.de).\n\n## Report an error\n\nIf you find an error in the source code, you can report it to our ticket system.\n\nIt would be even better if you suggested a solution to us as a pull request.\n\n## Further development\n\nYou can request new features by submitting an issue to our ticket system. If you would like to implement a new function, please note the following steps for further action:\n\n- It is helpful to read the KoliBri [architecture concept](https://public-ui.github.io/docs/concepts/architecture) before implementing.\n- For major innovations, please create a ticket with the description of the new function.\n- For small innovations, you can offer and justify the implementation directly as a pull request.\n\n### Git flow\n\nWe work according to the Git flow: https://medium.com/android-news/gitflow-with-github-c675aa4f606a\n\n### Pull Request Guidelines\n\nWhen creating a pull request, please follow these guidelines:\n\n- **PR Title:** The pull request title must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. This is enforced by automated validation in our CI pipeline.\n- **PR Title Format:** `<type>: <description>` or `<type>(<scope>): <description>`\n- **Allowed Types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`\n- **Description:** The description should start with a lowercase letter and clearly explain the change.\n\n**Examples of valid PR titles:**\n\n- `feat: add new button component`\n- `fix: resolve navigation issue on mobile devices`\n- `docs: update installation instructions`\n- `refactor(components): simplify input validation logic`\n\n**Examples of invalid PR titles:**\n\n- `Add new feature` (missing type prefix)\n- `feat: Add feature` (description should start with lowercase)\n- `feature: add new button` (invalid type, should be `feat`)\n\n### Developing\n\n1. For contributing, you need a [GitHub account](https://github.com/login)\n2. Fork [our repository](https://github.com/public-ui/kolibri) on GitHub\n3. Open your preferred command line interface\n4. Clone the forked repository via HTTPS to your local machine. The VS Code GitHub extension can handle authentication.\n5. Navigate the project root directory\n6. Create a new branch for your changes\n7. Install Node.js version 22\n8. [Install PNPM](https://pnpm.io/installation) on you local machine\n9. Install all packages with `pnpm i`\n10. Build all packages within the mono repository `pnpm -r build`\n11. Navigate to the desired package in our monorepo\n12. When you want to start the project navigate to `packages/components/` and run `pnpm dev`\n13. To watch for changes navigate to `packages/samples/react/` and execute `pnpm start`. `http://localhost:8080/` will open automatically\n\nRun ESLint across the repository with `pnpm lint` (or `pnpm lint:eslint` to invoke ESLint directly); the configuration lives in `packages/*/eslint.config.cjs`. Formatting is handled by Prettier via `pnpm format`, so run format first to keep ESLint focused on code-quality rules rather than style drift.\n\n### VS Code Setup\n\nWe recommend using [Visual Studio Code](https://code.visualstudio.com/):\n\n- Install the Prettier and ESLint extensions.\n- Enable \"Format on Save\" in your settings.\n\n### Tests\n\nAll tests run via GitHub Actions when you open a pull request. Monitor them under the **Actions** tab.\n\n### Develop new component\n\nRefer to [new component](docs/tutorials/NEW_COMPONENT.md) tutorial.\n\n### Switching between branches\n\nWhen changing the current working branch, it is important to reinstall all dependencies, as these may have changed. It is very important that all packages are built when working on dependents. This is because the packages always use the built state of the referenced packages in the mono repo.\nTo avoid unexpected problems, it is therefore always advisable to build all packages once. This can be done with these steps:\n\n- Reinstall all dependencies: `pnpm i`\n- Build all packages: `pnpm -r build`\n- You can then switch to the package to be processed and start it with `pnpm start`.\n\nIf it is also necessary to edit dependent packages such as `@public-ui/components`, these must be rebuilt for each change. Such packages offer the `dev` script for this purpose. This automatically rebuilds the package after each change.\n\n### Back porting to older Major-Versions\n\nBy default, development is carried out in the `development` branch for the following version. However, if it becomes necessary to provide an issue for an older major release, such as version 1.x.x, the code change must also be merged into the corresponding release branch. In this case, it would be the `release/1` branch. It is important that the branch that was created from the `develop` is not merged into the release branch, as otherwise the next patch version will receive all the changes from the current development status.\nThe simplest procedure is therefore to create a new branch from the release branch (e.g. `release/1`) and transfer the individual commits of the feature branch from the `develop` to the new branch using cherry-picking. This branch can then be merged into the release branch as normal with a new pull request.\n\n### Visual Review for Visual Changes\n\nThe Continuous Integration (CI) pipeline takes screenshots of the React sample app in every theme and compares them with the baseline of the base branch. The screenshots are **not** stored in git: every push to `develop`, `main` and `release/*` publishes them as the artifact `visual-baseline-<package>`, and a pull request compares against the artifact of the commit it is merged with.\n\nWhen you introduce visual modifications to components, themes or the React sample app:\n\n1. The `visual-tests (<package>)` jobs report the differences. That is expected ā there is nothing to regenerate or commit.\n2. The bot comment **šø Visual Review** on the pull request links the review page (`https://public-ui.github.io/kolibri/visual/?pr=<number>`), where every changed, added and removed screenshot can be inspected side by side, with a slider, as onion skin or as diff.\n3. A reviewer with write access approves (or rejects) the screenshots there ā directly with a fine-grained GitHub token, or by pasting the generated comment on the pull request. The commit status **Visual Review** turns green once everything is approved; approvals are bound to the screenshot content and survive later pushes that do not change the screenshot again.\n\nThe full process is described in [docs/visual-review.md](docs/visual-review.md).\n\n#### Running the visual tests locally\n\n```bash\npnpm snapshots:pull # download the current develop baseline into the snapshot folders (needs `gh auth login`)\npnpm --filter @public-ui/theme-default test # compare; the result is written to packages/themes/default/visual-report/\npnpm test:update:docker default # regenerate a baseline locally in the pinned Playwright container\n```\n\nScreenshots are platform specific (font rendering), so only the Docker variant produces files that match the CI.\n\n#### Text snapshots of the unit tests\n\nThe `__snapshots__` files of the unit tests (components, hydrate, hydrate-server) stay in git. Update them with `pnpm test:update:unit`, or run the `03 - Update Snapshots` action on your branch:\n\n```bash\ngh workflow run update-snapshots.yml -r `git rev-parse --abbrev-ref HEAD`\n```\n",
|
|
337
337
|
"kind": "doc"
|
|
338
338
|
},
|
|
339
339
|
{
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
"group": "docs",
|
|
342
342
|
"name": "CVE_OVERVIEW",
|
|
343
343
|
"path": "docs/CVE_OVERVIEW.md",
|
|
344
|
-
"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 | 2 | 17 | 2 | 16 |\n| moderate | 0 | 12 | 0 | 5 |\n| low | 0 | 2 | 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| @angular/common | high | CVE-2026-68945 | v3 | Angular: Cache-Key Ambiguity in HttpTransferCache Leading to Cross-Request Respo |\n| @angular/compiler | high | CVE-2026-69151 | v3 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\n| @angular/core | high | CVE-2026-69151 | v3 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\n| brace-expansion | high | CVE-2026-13149 | v1 | brace-expansion: DoS via exponential-time expansion of consecutive non-expanding |\n| brace-expansion | high | CVE-2026-14257 | v1 | brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro |\n| brace-expansion | high | CVE-2026-69152 | v1 | brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-1 |\n| extract-zip | high | CVE-2026-56876 | v1 | extract-zip unvalidated symlink path traversal |\n| fast-uri | high | CVE-2026-18446 | v3, v1 | fast-uri vulnerable to host confusion via backslash authority introducer |\n| fast-uri | high | CVE-2026-16221 | v3 | fast-uri vulnerable to host confusion via literal backslash authority delimiter |\n| fast-uri | high | CVE-2026-13676 | v3 | fast-uri vulnerable to host confusion via failed IDN canonicalization |\n| find-my-way | high | CVE-2026-47219 | v3 | find-my-way: DDoS with HTTP2 |\n| image-size | high | CVE-2025-71330 | v4, v3, v2, v1 | image-size: ICNS parser allows denial of service through an infinite loop |\n| image-size | high | CVE-2025-71329 | v4, v3, v2, v1 | image-size: JXL and HEIF parsers allow denial of service through infinite loops |\n| immutable | high | CVE-2026-59879 | v3, v1 | Immutable.js `List` 32-bit trie overflow ā unrecoverable DoS |\n| immutable | high | CVE-2026-59880 | v3, v1 | Immutable: Hash-collision algorithmic complexity denial of service in Immutable. |\n| ip-address | high | CVE-2026-69192 | v3 | ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco |\n| js-yaml | high | GHSA-5p4m-2wfm-xmqj | v1 | JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) ā CVE-2026 |\n| linkify-it | high | CVE-2026-59887 | v3 | linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on at |\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| nanoid | high | CVE-2026-67213 | v3, v1 | nanoid: custom generators can loop indefinitely when size is zero |\n| nanoid | high | CVE-2026-67214 | v3 | nanoid: non-secure generators can loop indefinitely with negative size |\n| postcss | high | CVE-2026-73646 | v3 | PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) l |\n| react-router | high | GHSA-qwww-vcr4-c8h2 | v3 | React Router: RSC Mode CSRF Bypass Allows Action Execution Before 400 Response |\n| serialize-javascript | high | GHSA-5c6j-r48x-rmvq | v1 | Serialize JavaScript is Vulnerable to RCE via RegExp.flags and Date.prototype.to |\n| @hono/node-server | moderate | GHSA-frvp-7c67-39w9 | v3 | Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode |\n| brace-expansion | moderate | CVE-2026-45149 | v1 | brace-expansion: Large numeric range defeats documented `max` DoS protection |\n| dompurify | moderate | GHSA-55q2-fjhq-7xh7 | v1 | DOMPurify: IN_PLACE hook removal leaves a detached subtree executable, causing X |\n| hono | moderate | CVE-2026-59897 | v3 | Hono: API Gateway v1 adapter can drop a distinct repeated request header value d |\n| hono | moderate | CVE-2026-59896 | v3 | hono/jsx does not isolate context per request, leading to cross-request data dis |\n| hono | moderate | CVE-2026-59895 | v3 | Hono: Server-Side XSS via JSX Escaping Bypass in cx() Utility |\n| hono | moderate | CVE-2026-69207 | v3 | Hono: ReDoS in CORS middleware via Access-Control-Request-Headers |\n| hono | moderate | CVE-2026-71850 | v3 | Hono: `memo()` retains SSR output across requests, leading to cross-user data di |\n| hono | moderate | CVE-2026-71848 | v3 | Hono: Algorithmic Complexity DoS in Language Middleware |\n| ip-address | moderate | CVE-2026-69198 | v3 | ip-address: a CIDR suffix on the parsed address suppresses special-use classific |\n| ip-address | moderate | CVE-2026-54272 | v3 | ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSR |\n| postcss | moderate | CVE-2026-69153 | v3 | PostCSS: incomplete fix of GHSA-6g55-p6wh-862q ā attacker-controlled sourceMappi |\n| protobufjs | moderate | CVE-2026-59876 | v3 | protobufjs: Text Format string map parsing can mutate returned map object protot |\n| protobufjs | moderate | CVE-2026-59877 | v3 | protobufjs: Denial of Service via infinite loop in .proto option parsing |\n| qs | moderate | CVE-2026-8723 | v1 | qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/u |\n| react-router-dom | moderate | CVE-2026-53668 | v1 | React Router: Open redirect leading to XSS |\n| serialize-javascript | moderate | CVE-2026-34043 | v1 | Serialize JavaScript has CPU Exhaustion Denial of Service via crafted array-like |\n| body-parser | low | CVE-2026-12590 | v3 | body-parser vulnerable to denial of service when invalid limit value silently di |\n| hono | low | CVE-2026-71849 | v3 | Hono: Proxy Helper does not remove response headers listed in the `Connection` h |\n\n## 2. All Dependencies\n\n### Summary\n\n| Severity | v4 | v3 | v2 | v1 |\n| -------- | --: | --: | --: | --: |\n| critical | 0 | 9 | 4 | 5 |\n| high | 19 | 106 | 82 | 59 |\n| moderate | 16 | 74 | 65 | 23 |\n| low | 2 | 13 | 13 | 3 |\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 | v3 | Basic FTP has Path Traversal Vulnerability in its downloadToDir()Ā method |\n| fast-xml-parser | critical | CVE-2026-25896 | v3, v2 | fast-xml-parser has an entity encoding bypass via regex injection in DOCTYPE ent |\n| handlebars | critical | CVE-2026-33937 | v3, v1 | Handlebars.js has JavaScript Injection via AST Type Confusion |\n| locutus | critical | CVE-2026-25521 | v3, v1 | locutus is vulnerable to Prototype Pollution |\n| locutus | critical | CVE-2026-32304 | v3, v2, v1 | Locutus vulnerable to RCE via unsanitized input in create_function() |\n| seroval | critical | CVE-2026-59940 | v3, v2, v1 | seroval: `seroval.fromJSON()` Promise resolver type confusion invokes attacker-c |\n| shell-quote | critical | CVE-2026-9277 | v3 | shell-quote quote() does not escape newlines in object .op values |\n| tar | critical | CVE-2026-59873 | v3, v1 | node-tar: Decompression/parse DoS via unlimited input |\n| websocket-driver | critical | CVE-2026-54466 | v3, v2 | websocket-driver: Message corruption via abuse of protocol length headers |\n| @angular/common | high | CVE-2025-66035 | v1 | Angular is Vulnerable to XSRF Token Leakage via Protocol-Relative URLs in Angula |\n| @angular/common | high | CVE-2026-54268 | v4, v3, v2, v1 | @angular/common: Denial of Service (DoS) via OOM in Date Formatting (formatDate) |\n| @angular/common | high | CVE-2026-54266 | v4, v3, v2, v1 | @angular/common: Weak 32-Bit Cache Key Hashing in `HttpTransferCache` Leading to |\n| @angular/common | high | CVE-2026-50171 | v1 | @angular/common: Denial of Service (DoS) via OOM in Number Formatting (digitsInf |\n| @angular/common | high | CVE-2026-50170 | v1 | @angular/common: Information Leak via Default Caching of Credentialed Requests i |\n| @angular/common | high | CVE-2026-68945 | v4, v3, v2, v1 | Angular: Cache-Key Ambiguity in HttpTransferCache Leading to Cross-Request Respo |\n| @angular/compiler | high | CVE-2026-32635 | v1 | Angular vulnerable to XSS in i18n attribute bindings |\n| @angular/compiler | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\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-69151 | v4, v3, v2, v1 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\n| @angular/core | high | CVE-2026-27970 | v1 | Angular i18n vulnerable to Cross-Site Scripting |\n| @angular/core | high | CVE-2026-32635 | v1 | Angular vulnerable to XSS in i18n attribute bindings |\n| @angular/core | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\n| @angular/core | high | CVE-2026-54267 | v4, v3, v2, v1 | Angular Client Hydration DOM Clobbering & Response-Cache Poisoning |\n| @angular/core | high | CVE-2026-69151 | v4, v3, v2, v1 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\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-42043 | v3 | Axios: Incomplete Fix for CVE-2025-62718 ā NO_PROXY Protection Bypassed via RFC |\n| axios | high | CVE-2026-42033 | v3 | Axios: Prototype Pollution Gadgets - Response Tampering, Data Exfiltration, and |\n| axios | high | CVE-2026-42035 | v3 | Axios: Header Injection via Prototype Pollution |\n| axios | high | CVE-2026-25639 | v3 | Axios is Vulnerable to Denial of Service via **proto** Key in mergeConfig |\n| axios | high | CVE-2026-42264 | v3 | Axios has prototype pollution read-side gadgets in HTTP adapter that allow crede |\n| axios | high | CVE-2026-44496 | v3 | Axios: Regular Expression Denial of Service (ReDoS) via Cookie Name Injection |\n| axios | high | CVE-2026-44488 | v3 | Allocation of Resources Without Limits or Throttling in Axios |\n| axios | high | CVE-2026-44487 | v3 | Axios: Proxy-Authorization Credential Leak to Origin Server Across HTTP-to-HTTPS |\n| axios | high | CVE-2026-44486 | v3 | Axios: Proxy-Authorization header leaks to redirect target when proxy is re-eval |\n| axios | high | CVE-2026-44495 | v3 | axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut |\n| axios | high | CVE-2026-44494 | v3 | axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co |\n| basic-ftp | high | GHSA-6v7q-wjvx-w8wg | v3 | basic-ftp: Incomplete CRLF Injection Protection Allows Arbitrary FTP Command Exe |\n| basic-ftp | high | CVE-2026-41324 | v3 | basic-ftp vulnerable to denial of service via unbounded memory consumption in Cl |\n| basic-ftp | high | CVE-2026-44240 | v3 | basic-ftp allows a malicious FTP server to cause client-side denial of service v |\n| brace-expansion | high | CVE-2026-13149 | v3, v2, v1 | brace-expansion: DoS via exponential-time expansion of consecutive non-expanding |\n| brace-expansion | high | CVE-2026-14257 | v3, v2, v1 | brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro |\n| brace-expansion | high | CVE-2026-69152 | v3, v2, v1 | brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-1 |\n| braces | high | CVE-2024-4068 | v3, v2, v1 | Uncontrolled resource consumption in braces |\n| deepmerge-ts | high | CVE-2026-40345 | v4, v3, v2 | DeepmergeTS has stack exhaustion when merging recursive object graphs |\n| engine.io | high | CVE-2026-59725 | v3, v2 | Socket.IO: Engine.IO Polling Transport Connection Exhaustion |\n| express-rate-limit | high | CVE-2026-30827 | v2 | express-rate-limit: IPv4-mapped IPv6 addresses bypass per-client rate limiting o |\n| extract-zip | high | CVE-2026-56876 | v4, v3, v2, v1 | extract-zip unvalidated symlink path traversal |\n| fast-uri | high | CVE-2026-18446 | v3, v2, v1 | fast-uri vulnerable to host confusion via backslash authority introducer |\n| fast-uri | high | CVE-2026-16221 | v3, v2 | fast-uri vulnerable to host confusion via literal backslash authority delimiter |\n| fast-uri | high | CVE-2026-6321 | v2 | fast-uri vulnerable to path traversal via percent-encoded dot segments |\n| fast-uri | high | CVE-2026-13676 | v3, v2 | fast-uri vulnerable to host confusion via failed IDN canonicalization |\n| fast-uri | high | CVE-2026-6322 | v2 | fast-uri vulnerable to host confusion via percent-encoded authority delimiters |\n| fast-xml-parser | high | CVE-2026-25128 | v3, v2 | fast-xml-parser has RangeError DoS Numeric Entities Bug |\n| fast-xml-parser | high | CVE-2026-26278 | v3, v2 | fast-xml-parser affected by DoS through entity expansion in DOCTYPE (no expansio |\n| fast-xml-parser | high | CVE-2026-33036 | v3, v2 | fast-xml-parser affected by numeric entity expansion bypassing all entity expans |\n| find-my-way | high | CVE-2026-47219 | v3 | find-my-way: DDoS with HTTP2 |\n| flatted | high | CVE-2026-32141 | v3, v2 | flatted vulnerable to unbounded recursion DoS in parse() revive phase |\n| flatted | high | CVE-2026-33228 | v3, v2 | Prototype Pollution via parse() in NodeJS flatted |\n| form-data | high | CVE-2026-12143 | v3, v2, v1 | form-data: CRLF injection in form-data via unescaped multipart field names and f |\n| handlebars | high | CVE-2026-33938 | v3, v1 | Handlebars.js has JavaScript Injection via AST Type Confusion by tampering @part |\n| handlebars | high | CVE-2026-33940 | v3, v1 | Handlebars.js has JavaScript Injection via AST Type Confusion when passing an ob |\n| handlebars | high | CVE-2026-33939 | v3, v1 | Handlebars.js has Denial of Service via Malformed Decorator Syntax in Template C |\n| handlebars | high | CVE-2026-33941 | v3, v1 | Handlebars.js has JavaScript Injection in CLI Precompiler via Unescaped Names an |\n| hono | high | CVE-2026-29045 | v2 | Hono vulnerable to arbitrary file access via serveStatic vulnerability |\n| hono | high | CVE-2026-54290 | v2 | hono: CORS Middleware reflects any Origin with credentials when `origin` default |\n| http-proxy-middleware | high | CVE-2026-55603 | v3 | http-proxy-middleware: multipart/form-data field injection via unescaped CRLF in |\n| image-size | high | CVE-2025-71330 | v4, v3, v2, v1 | image-size: ICNS parser allows denial of service through an infinite loop |\n| image-size | high | CVE-2025-71329 | v4, v3, v2, v1 | image-size: JXL and HEIF parsers allow denial of service through infinite loops |\n| immutable | high | CVE-2026-59879 | v3, v2, v1 | Immutable.js `List` 32-bit trie overflow ā unrecoverable DoS |\n| immutable | high | CVE-2026-59880 | v3, v2, v1 | Immutable: Hash-collision algorithmic complexity denial of service in Immutable. |\n| immutable | high | CVE-2026-29063 | v2 | Immutable is vulnerable to Prototype Pollution |\n| ip-address | high | CVE-2026-69192 | v3, v2 | ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco |\n| js-yaml | high | GHSA-5p4m-2wfm-xmqj | v3, v2, v1 | JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) ā CVE-2026 |\n| js-yaml | high | CVE-2026-59869 | v3, v2 | js-yaml: YAML merge-key chains can force quadratic CPU consumption |\n| linkify-it | high | CVE-2026-59887 | v3 | linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on at |\n| locutus | high | CVE-2026-29091 | v3, v2, v1 | locutus call_user_func_array vulnerable to Remote Code Execution (RCE) due to Co |\n| lodash | high | CVE-2026-4800 | v3 | lodash vulnerable to Code Injection via `_.template` imports key names |\n| lodash.pick | high | CVE-2020-8203 | v2, v1 | Prototype Pollution in lodash |\n| minimatch | high | CVE-2026-27903 | v3, v2, v1 | minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja |\n| minimatch | high | CVE-2026-27904 | v3, v2, v1 | minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regu |\n| minimatch | high | CVE-2026-26996 | v3, v2 | minimatch has a ReDoS via repeated wildcards with non-matching literal in patter |\n| nanoid | high | CVE-2026-67213 | v3, v1 | nanoid: custom generators can loop indefinitely when size is zero |\n| nanoid | high | CVE-2026-67214 | v3 | nanoid: non-secure generators can loop indefinitely with negative size |\n| node-forge | high | CVE-2026-33896 | v2 | Forge has a basicConstraints bypass in its certificate chain verification (RFC 5 |\n| node-forge | high | CVE-2026-33895 | v2 | Forge has signature forgery in Ed25519 due to missing S > L check |\n| node-forge | high | CVE-2026-33891 | v2 | Forge has Denial of Service via Infinite Loop in BigInteger.modInverse() with Ze |\n| node-forge | high | CVE-2026-33894 | v2 | Forge has signature forgery in RSA-PKCS due to ASN.1 extra field |\n| nx | high | CVE-2026-71476 | v3, v1 | Nx: Zip-Slip in the self-hosted remote cache |\n| pacote | high | CVE-2026-9496 | v3, v2, v1 | pacote is vulnerable to Denial of Service (DoS) via the addGitSha function |\n| path-to-regexp | high | CVE-2026-4867 | v3, v2 | path-to-regexp vulnerable to Regular Expression Denial of Service via multiple r |\n| path-to-regexp | high | CVE-2026-4926 | v2 | path-to-regexp vulnerable to Denial of Service via sequential optional groups |\n| piscina | high | CVE-2026-55388 | v3 | piscina: Prototype Pollution Gadget ā RCE via inherited options.filename |\n| postcss | high | CVE-2026-45623 | v4, v3, v2 | PostCSS: Arbitrary file read and information disclosure via attacker-controlled |\n| postcss | high | CVE-2026-73646 | v4, v3, v2 | PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) l |\n| react-router | high | GHSA-qwww-vcr4-c8h2 | v3 | React Router: RSC Mode CSRF Bypass Allows Action Execution Before 400 Response |\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| shell-quote | high | CVE-2026-13311 | v3 | shell-quote: Quadratic-complexity Denial of Service in `parse()` (CWE-407) |\n| sigstore | high | CVE-2026-48815 | v3, v2, v1 | sigstore's `certificateOIDs` verification constraints are silently dropped and n |\n| socket.io-parser | high | CVE-2026-33151 | v3, v2 | socket.io allows an unbounded number of binary attachments |\n| socket.io-parser | high | CVE-2026-69185 | v3, v2 | Socket.IO: Zero-attachment Memory Exhaustion |\n| svgo | high | CVE-2026-29074 | v3, v2, v1 | SVGO DoS through entity expansion in DOCTYPE (Billion Laughs) |\n| svgo | high | CVE-2026-73650 | v3, v2, v1 | SVGO removeScripts plugin leaves some executable scripts intact |\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 | v1 | Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in no |\n| tar | high | CVE-2026-29786 | v1 | tar has Hardlink Path Traversal via Drive-Relative Linkpath |\n| tar | high | CVE-2026-31802 | v1 | node-tar Symlink Path Traversal via Drive-Relative Linkpath |\n| tar | high | CVE-2026-23950 | v1 | Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on |\n| tar | high | CVE-2026-59874 | v3, v1 | node-tar: Negative tar entry size causes infinite loop in archive replace |\n| tar | high | CVE-2026-73566 | v3, v2, v1 | node-tar: Uncontrolled recursion in mapHas/filesFilter allows uncatchable stack- |\n| tmp | high | CVE-2026-44705 | v3, v2 | tmp has Path Traversal via unsanitized prefix/postfix that enables directory esc |\n| undici | high | CVE-2026-1528 | v3 | Undici: Malicious WebSocket 64-bit length overflows parser and crashes the clien |\n| undici | high | CVE-2026-1526 | v3 | Undici has Unbounded Memory Consumption in WebSocket permessage-deflate Decompre |\n| undici | high | CVE-2026-2229 | v3 | Undici has Unhandled Exception in WebSocket Client Due to Invalid server_max_win |\n| undici | high | CVE-2026-9697 | v3 | undici vulnerable to TLS certificate validation bypass via dropped requestTls in |\n| undici | high | CVE-2026-12151 | v3 | undici WebSocket client vulnerable to denial of service via fragment count bypas |\n| undici | high | CVE-2026-6734 | v3 | undici vulnerable to cross-origin request routing via SOCKS5 proxy pool reuse |\n| undici | high | CVE-2026-13697 | v3 | undici vulnerable to cross-user information disclosure and parse-time crash via |\n| vite | high | CVE-2026-39364 | v1 | Vite: `server.fs.deny` bypassed with queries |\n| vite | high | CVE-2026-39363 | v1 | Vite Vulnerable to Arbitrary File Read via Vite Dev Server WebSocket |\n| vite | high | CVE-2026-53571 | v3, v1 | vite: `server.fs.deny` bypass on Windows alternate paths |\n| ws | high | CVE-2026-48779 | v3, v2, v1 | ws: Memory exhaustion DoS from tiny fragments and data chunks |\n| @angular/compiler | moderate | CVE-2026-54265 | v4, v3, v2, v1 | @angular/compiler: Two-Way Property Binding Sanitization Bypass (XSS) |\n| @angular/compiler | moderate | CVE-2026-50557 | v4, v1 | Angular: Template and Attribute Namespace Sanitization Bypass (XSS) |\n| @angular/core | moderate | CVE-2026-50557 | v4, v1 | Angular: Template and Attribute Namespace Sanitization Bypass (XSS) |\n| @angular/core | moderate | CVE-2026-52725 | v4, v1 | @angular/core: Angular Template and Dynamic Component Namespace Bypass leading t |\n| @hono/node-server | moderate | CVE-2026-39406 | v2 | @hono/node-server: Middleware bypass via repeated slashes in serveStatic |\n| @hono/node-server | moderate | GHSA-frvp-7c67-39w9 | v3, v2 | Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode |\n| @opentelemetry/core | moderate | CVE-2026-54285 | v1 | OpenTelemetry Core: Unbounded memory allocation in W3C Baggage propagation |\n| @sigstore/core | moderate | CVE-2026-48758 | v3, v2, v1 | @sigstore/core has DSSE payloadType type-binding failure |\n| ajv | moderate | CVE-2025-69873 | v3, v2 | ajv has ReDoS when using `$data` option |\n| axios | moderate | CVE-2025-62718 | v3 | Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF |\n| axios | moderate | CVE-2026-42041 | v3 | Axios: Authentication Bypass via Prototype Pollution Gadget in `validateStatus` |\n| axios | moderate | CVE-2026-42044 | v3 | Axios: Invisible JSON Response Tampering via Prototype Pollution Gadget in `pars |\n| axios | moderate | CVE-2026-42037 | v3 | Axios: CRLF Injection in multipart/form-data body via unsanitized blob.type in f |\n| axios | moderate | CVE-2026-42038 | v3 | Axios: no_proxy bypass via IP alias allows SSRF |\n| axios | moderate | CVE-2026-42034 | v3 | Axios' HTTP adapter-streamed uploads bypass maxBodyLength when maxRedirects: 0 |\n| axios | moderate | CVE-2026-42036 | v3 | Axios: HTTP adapter streamed responses bypass maxContentLength |\n| axios | moderate | CVE-2026-42042 | v3 | Axios: XSRF Token Cross-Origin Leakage via Prototype Pollution Gadget in `withXS |\n| axios | moderate | CVE-2026-40175 | v3 | Axios has Unrestricted Cloud Metadata Exfiltration via Header Injection Chain |\n| axios | moderate | CVE-2026-42039 | v3 | Axios: unbounded recursion in toFormData causes DoS via deeply nested request da |\n| axios | moderate | CVE-2026-44490 | v3 | axios has DoS & Header Injection via Prototype Pollution Read-Side Gadgets in ax |\n| axios | moderate | GHSA-42h9-826w-cgv3 | v3 | Axios: Excessive recursion in formDataToJSON can cause denial of service |\n| axios | moderate | GHSA-pmv8-rq9r-6j72 | v3 | Axios: Deep formToJSON Key Recursion Can Cause Denial of Service |\n| axios | moderate | GHSA-jqh4-m9w3-8hp9 | v3 | Axios: Fetch adapter `ReadableStream` uploads bypass `maxBodyLength` |\n| axios | moderate | GHSA-mmx7-hfxf-jppx | v3 | Axios: Prototype pollution gadgets can alter axios request construction |\n| axios | moderate | GHSA-7q8q-rj6j-mhjq | v3 | Axios: Nested axios option objects can consume polluted prototype values |\n| brace-expansion | moderate | CVE-2026-45149 | v3, v2, v1 | brace-expansion: Large numeric range defeats documented `max` DoS protection |\n| brace-expansion | moderate | CVE-2026-33750 | v3, v2 | brace-expansion: Zero-step sequence causes process hang and memory exhaustion |\n| dompurify | moderate | GHSA-55q2-fjhq-7xh7 | v1 | DOMPurify: IN_PLACE hook removal leaves a detached subtree executable, causing X |\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| fast-xml-parser | moderate | CVE-2026-33349 | v3, v2 | Entity Expansion Limits Bypassed When Set to Zero Due to JavaScript Falsy Evalua |\n| fast-xml-parser | moderate | CVE-2026-41650 | v3, v2 | fast-xml-parser XMLBuilder: XML Comment and CDATA Injection via Unescaped Delimi |\n| file-type | moderate | CVE-2026-31808 | v4 | file-type affected by infinite loop in ASF parser on malformed input with zero-s |\n| handlebars | moderate | CVE-2026-33916 | v3, v1 | Handlebars.js has Prototype Pollution Leading to XSS through Partial Template In |\n| handlebars | moderate | GHSA-7rx3-28cr-v5wh | v3, v1 | Handlebars.js has a Prototype Method Access Control Gap via Missing __lookupSett |\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| hono | moderate | GHSA-26pp-8wgv-hjvm | v2 | Hono missing validation of cookie name on write path in setCookie() |\n| hono | moderate | CVE-2026-39410 | v2 | Hono: Non-breaking space prefix bypass in cookie name handling in getCookie() |\n| hono | moderate | CVE-2026-39408 | v2 | Hono: Path traversal in toSSG() allows writing files outside the output director |\n| hono | moderate | CVE-2026-39407 | v2 | Hono: Middleware bypass via repeated slashes in serveStatic |\n| hono | moderate | CVE-2026-39409 | v2 | Hono has incorrect IP matching in ipRestriction() for IPv4-mapped IPv6 addresses |\n| hono | moderate | CVE-2026-44458 | v2 | Hono has CSS Declaration Injection via Style Object Values in JSX SSR |\n| hono | moderate | CVE-2026-44457 | v2 | Hono's Cache Middleware ignores Vary: Authorization / Vary: Cookie leading to cr |\n| hono | moderate | CVE-2026-44456 | v2 | Hono: bodyLimit() can be bypassed for chunked / unknown-length requests |\n| hono | moderate | CVE-2026-44455 | v2 | hono/jsx has Unvalidated JSX Tag Names that May Allow HTML Injection |\n| hono | moderate | CVE-2026-47674 | v2 | Hono: IP Restriction bypasses static deny rules for non-canonical IPv6 |\n| hono | moderate | CVE-2026-47675 | v2 | Hono: Cookie helper does not sanitize sameSite and priority, allowing Set-Cookie |\n| hono | moderate | CVE-2026-47673 | v2 | Hono: JWT middleware accepts any Authorization scheme, not only Bearer |\n| hono | moderate | CVE-2026-47676 | v2 | Hono: app.mount() strips mount prefix using undecoded path, causing incorrect ro |\n| hono | moderate | CVE-2026-56761 | v2 | hono Improperly Handles JSX Attribute Names Allows HTML Injection in hono/jsx SS |\n| hono | moderate | CVE-2026-54288 | v2 | hono: Body Limit Middleware can be bypassed on AWS Lambda by understating `Conte |\n| hono | moderate | CVE-2026-54289 | v2 | hono: Lambda@Edge adapter keeps only the last value of a repeated request header |\n| hono | moderate | CVE-2026-54286 | v2 | hono: Path traversal in `serve-static` on Windows via encoded backslash (`%5C`) |\n| hono | moderate | CVE-2026-54287 | v2 | hono: AWS Lambda adapter merges multiple `Set-Cookie` headers into one value, dr |\n| hono | moderate | CVE-2026-59897 | v3, v2 | Hono: API Gateway v1 adapter can drop a distinct repeated request header value d |\n| hono | moderate | CVE-2026-59895 | v3, v2 | Hono: Server-Side XSS via JSX Escaping Bypass in cx() Utility |\n| hono | moderate | CVE-2026-69207 | v3, v2 | Hono: ReDoS in CORS middleware via Access-Control-Request-Headers |\n| hono | moderate | CVE-2026-71850 | v3, v2 | Hono: `memo()` retains SSR output across requests, leading to cross-user data di |\n| hono | moderate | CVE-2026-59896 | v3 | hono/jsx does not isolate context per request, leading to cross-request data dis |\n| hono | moderate | CVE-2026-71848 | v3 | Hono: Algorithmic Complexity DoS in Language Middleware |\n| http-proxy-middleware | moderate | CVE-2026-55602 | v3, v2 | http-proxy-middleware `router` host+path substring matching allows Host-header-d |\n| ip-address | moderate | CVE-2026-42338 | v2 | ip-address has XSS in Address6 HTML-emitting methods |\n| ip-address | moderate | CVE-2026-69198 | v3 | ip-address: a CIDR suffix on the parsed address suppresses special-use classific |\n| ip-address | moderate | CVE-2026-54272 | v3 | ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSR |\n| js-yaml | moderate | CVE-2025-64718 | v2 | js-yaml has prototype pollution in merge (<<) |\n| js-yaml | moderate | CVE-2026-53550 | v3, v2 | JS-YAML: Quadratic-complexity DoS in merge key handling via repeated aliases |\n| launch-editor | moderate | CVE-2026-53632 | v3, v2 | launch-editor: NTLMv2 hash disclosure via UNC path handling on Windows |\n| locutus | moderate | CVE-2026-33993 | v3, v2, v1 | Locutus has Prototype Pollution via **proto** Key Injection in unserialize() |\n| locutus | moderate | CVE-2026-33994 | v2 | Locutus Prototype Pollution due to incomplete fix for CVE-2026-25521 |\n| lodash | moderate | CVE-2026-2950 | v3 | lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and |\n| micromatch | moderate | CVE-2024-4067 | v3, v2, v1 | Regular Expression Denial of Service (ReDoS) in micromatch |\n| nx | moderate | CVE-2026-54753 | v3, v1 | `nx graph` dev server permissive CORS policy |\n| path-to-regexp | moderate | CVE-2026-4923 | v2 | path-to-regexp vulnerable to Regular Expression Denial of Service via multiple w |\n| postcss | moderate | CVE-2026-41305 | v4, v3, v2 | PostCSS has XSS via Unescaped </style> in its CSS Stringify Output |\n| postcss | moderate | CVE-2026-69153 | v4, v3, v2 | PostCSS: incomplete fix of GHSA-6g55-p6wh-862q ā attacker-controlled sourceMappi |\n| protobufjs | moderate | CVE-2026-59876 | v3 | protobufjs: Text Format string map parsing can mutate returned map object protot |\n| protobufjs | moderate | CVE-2026-59877 | v3 | protobufjs: Denial of Service via infinite loop in .proto option parsing |\n| qs | moderate | CVE-2026-8723 | v3, v2, v1 | qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/u |\n| qs | moderate | CVE-2025-15284 | v2 | qs's arrayLimit bypass in its bracket notation allows DoS via memory exhaustion |\n| react-router-dom | moderate | CVE-2026-53668 | v1 | React Router: Open redirect leading to XSS |\n| serialize-javascript | moderate | CVE-2026-34043 | v4, v3, v2, v1 | Serialize JavaScript has CPU Exhaustion Denial of Service via crafted array-like |\n| serialize-javascript | moderate | CVE-2024-11831 | v2 | Cross-site Scripting (XSS) in serialize-javascript |\n| smol-toml | moderate | GHSA-v3rj-xjv7-4jmq | v3, v1 | smol-toml: Denial of Service via TOML documents containing thousands of consecut |\n| tar | moderate | CVE-2026-53655 | v3, v1 | node-tar applies PAX size override to intermediary GNU long-name/long-link heade |\n| tar | moderate | CVE-2026-59871 | v3, v1 | node-tar: Process crash via PAX numeric path type confusion |\n| tar | moderate | CVE-2026-59875 | v3, v1 | node-tar: Uncaught Exception DoS via NUL byte in PAX path/linkpath records |\n| undici | moderate | CVE-2026-1525 | v3 | Undici has an HTTP Request/Response Smuggling issue |\n| undici | moderate | CVE-2026-1527 | v3 | Undici has CRLF Injection in undici via `upgrade` option |\n| undici | moderate | CVE-2026-9679 | v3 | undici vulnerable to HTTP header injection via Set-Cookie percent-decoding |\n| undici | moderate | CVE-2026-9678 | v3 | undici vulnerable to cross-user information disclosure via shared cache whitespa |\n| undici | moderate | CVE-2026-16728 | v3 | undici vulnerable to downstream response desynchronization via retry interceptor |\n| undici | moderate | CVE-2026-15157 | v3 | undici vulnerable to CRLF Injection via blob-like body 'type' property |\n| undici | moderate | CVE-2026-14643 | v3 | undici vulnerable to cross-user information disclosure via whitespace around equ |\n| undici | moderate | CVE-2026-16729 | v3 | undici vulnerable to cookie attribute injection via unsanitized domain and unpar |\n| uuid | moderate | CVE-2026-41907 | v4, v3, v2 | uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided |\n| vite | moderate | CVE-2026-39365 | v1 | Vite Vulnerable to Path Traversal in Optimized Deps `.map` Handling |\n| vite | moderate | CVE-2026-53632 | v3, v1 | launch-editor: NTLMv2 hash disclosure via UNC path handling on Windows |\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| webpack-dev-server | moderate | CVE-2026-6402 | v2 | webpack-dev-server vulnerable to cross-origin source code exposure on non-HTTPS |\n| webpack-dev-server | moderate | CVE-2026-9595 | v2 | webpack-dev-server vulnerable to HMR WebSocket interception via permissive user |\n| webpack-dev-server | moderate | CVE-2026-14620 | v3, v2 | webpack-dev-server vulnerable to cross-site request forgery via internal develop |\n| webpack-dev-server | moderate | CVE-2026-14631 | v3, v2 | webpack-dev-server vulnerable to denial of service via a malformed Host or Origi |\n| websocket-driver | moderate | CVE-2026-54490 | v3, v2 | websocket-driver: Resource limit bypass via message compression |\n| ws | moderate | CVE-2026-45736 | v3, v2 | ws: Uninitialized memory disclosure |\n| yaml | moderate | CVE-2026-33532 | v3, v2, v1 | yaml is vulnerable to Stack Overflow via deeply nested YAML collections |\n| @babel/core | low | CVE-2026-49356 | v4, v3, v2, v1 | @babel/core: Arbitrary File Read via sourceMappingURL Comment |\n| @tootallnate/once | low | CVE-2026-3449 | v3, v2, v1 | @tootallnate/once vulnerable to Incorrect Control Flow Scoping |\n| axios | low | CVE-2026-42040 | v3 | Axios: Null Byte Injection via Reverse-Encoding in AxiosURLSearchParams |\n| body-parser | low | CVE-2026-12590 | v3, v2 | body-parser vulnerable to denial of service when invalid limit value silently di |\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 | v3, v2 | fast-xml-parser has stack overflow in XMLBuilder with preserveOrder |\n| handlebars | low | GHSA-442j-39wm-28r2 | v3, v1 | Handlebars.js has a Property Access Validation Bypass in container.lookup |\n| hono | low | GHSA-gq3j-xvxp-8hrf | v2 | Hono added timing comparison hardening in basicAuth and bearerAuth |\n| hono | low | CVE-2026-44459 | v2 | Hono has improper validation of NumericDate claims (exp, nbf, iat) in JWT verify |\n| hono | low | CVE-2026-71849 | v3, v2 | Hono: Proxy Helper does not remove response headers listed in the `Connection` h |\n| qs | low | CVE-2026-2391 | v2 | qs's arrayLimit bypass in comma parsing allows denial of service |\n| undici | low | CVE-2026-11525 | v3 | undici vulnerable to Set-Cookie SameSite attribute downgrade via permissive subs |\n| undici | low | CVE-2026-6733 | v3 | undici vulnerable to HTTP response queue poisoning via keep-alive socket reuse |\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",
|
|
344
|
+
"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 | 10 | 20 | 2 | 22 |\n| moderate | 2 | 16 | 2 | 7 |\n| low | 0 | 2 | 0 | 1 |\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| @angular/common | high | CVE-2026-68945 | v3 | Angular: Cache-Key Ambiguity in HttpTransferCache Leading to Cross-Request Respo |\n| @angular/compiler | high | CVE-2026-69151 | v3 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\n| @angular/core | high | CVE-2026-69151 | v3 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\n| brace-expansion | high | CVE-2026-13149 | v1 | brace-expansion: DoS via exponential-time expansion of consecutive non-expanding |\n| brace-expansion | high | CVE-2026-14257 | v1 | brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro |\n| brace-expansion | high | CVE-2026-69152 | v1 | brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-1 |\n| browserslist | high | CVE-2026-73089 | v1 | Browserslist: Unbounded memory growth (no cache eviction) via distinct query res |\n| browserslist | high | CVE-2026-73088 | v1 | Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats. |\n| extract-zip | high | CVE-2026-56876 | v1 | extract-zip unvalidated symlink path traversal |\n| fast-uri | high | CVE-2026-18446 | v3, v1 | fast-uri vulnerable to host confusion via backslash authority introducer |\n| fast-uri | high | CVE-2026-75931 | v4, v1 | fast-uri vulnerable to host confusion via skipped IDN canonicalization on scheme |\n| fast-uri | high | CVE-2026-75975 | v4, v3, v1 | fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat |\n| fast-uri | high | CVE-2026-75899 | v4, v3, v1 | fast-uri vulnerable to server-side request forgery via repeated hostname percent |\n| fast-uri | high | CVE-2026-76172 | v4, v3, v1 | fast-uri vulnerable to host confusion via percent-encoded scheme normalization |\n| fast-uri | high | CVE-2026-16221 | v3 | fast-uri vulnerable to host confusion via literal backslash authority delimiter |\n| fast-uri | high | CVE-2026-13676 | v3 | fast-uri vulnerable to host confusion via failed IDN canonicalization |\n| find-my-way | high | CVE-2026-47219 | v3 | find-my-way: DDoS with HTTP2 |\n| image-size | high | CVE-2025-71330 | v4, v3, v2, v1 | image-size: ICNS parser allows denial of service through an infinite loop |\n| image-size | high | CVE-2025-71329 | v4, v3, v2, v1 | image-size: JXL and HEIF parsers allow denial of service through infinite loops |\n| immutable | high | CVE-2026-59879 | v3, v1 | Immutable.js `List` 32-bit trie overflow ā unrecoverable DoS |\n| immutable | high | CVE-2026-59880 | v3, v1 | Immutable: Hash-collision algorithmic complexity denial of service in Immutable. |\n| ip-address | high | CVE-2026-69192 | v3 | ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco |\n| js-yaml | high | GHSA-5p4m-2wfm-xmqj | v1 | JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) ā CVE-2026 |\n| linkify-it | high | CVE-2026-59887 | v3 | linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on at |\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| nanoid | high | CVE-2026-67213 | v3, v1 | nanoid: custom generators can loop indefinitely when size is zero |\n| nanoid | high | CVE-2026-67214 | v3 | nanoid: non-secure generators can loop indefinitely with negative size |\n| postcss | high | CVE-2026-73646 | v3 | PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) l |\n| react-router | high | GHSA-qwww-vcr4-c8h2 | v3 | React Router: RSC Mode CSRF Bypass Allows Action Execution Before 400 Response |\n| serialize-javascript | high | GHSA-5c6j-r48x-rmvq | v1 | Serialize JavaScript is Vulnerable to RCE via RegExp.flags and Date.prototype.to |\n| @hono/node-server | moderate | GHSA-frvp-7c67-39w9 | v3 | Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode |\n| brace-expansion | moderate | CVE-2026-45149 | v1 | brace-expansion: Large numeric range defeats documented `max` DoS protection |\n| dompurify | moderate | GHSA-55q2-fjhq-7xh7 | v1 | DOMPurify: IN_PLACE hook removal leaves a detached subtree executable, causing X |\n| fastify | moderate | CVE-2026-18504 | v3 | fastify vulnerable to schema validation bypass via root primitive coercion misma |\n| fastify | moderate | CVE-2026-16732 | v3 | fastify vulnerable to X-Forwarded-* spoofing under trustProxy hop-count |\n| hono | moderate | CVE-2026-59897 | v3 | Hono: API Gateway v1 adapter can drop a distinct repeated request header value d |\n| hono | moderate | CVE-2026-59896 | v3 | hono/jsx does not isolate context per request, leading to cross-request data dis |\n| hono | moderate | CVE-2026-59895 | v3 | Hono: Server-Side XSS via JSX Escaping Bypass in cx() Utility |\n| hono | moderate | CVE-2026-69207 | v3 | Hono: ReDoS in CORS middleware via Access-Control-Request-Headers |\n| hono | moderate | CVE-2026-71850 | v3 | Hono: `memo()` retains SSR output across requests, leading to cross-user data di |\n| hono | moderate | CVE-2026-71848 | v3 | Hono: Algorithmic Complexity DoS in Language Middleware |\n| ip-address | moderate | CVE-2026-69198 | v3 | ip-address: a CIDR suffix on the parsed address suppresses special-use classific |\n| ip-address | moderate | CVE-2026-54272 | v3 | ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSR |\n| postcss | moderate | CVE-2026-69153 | v3 | PostCSS: incomplete fix of GHSA-6g55-p6wh-862q ā attacker-controlled sourceMappi |\n| protobufjs | moderate | CVE-2026-59876 | v3 | protobufjs: Text Format string map parsing can mutate returned map object protot |\n| protobufjs | moderate | CVE-2026-59877 | v3 | protobufjs: Denial of Service via infinite loop in .proto option parsing |\n| qs | moderate | CVE-2026-8723 | v1 | qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/u |\n| qs | moderate | CVE-2026-82562 | v4, v3, v2, v1 | qs array-limit bypass via bracket-key comma parsing |\n| qs | moderate | CVE-2026-82417 | v4, v3, v2, v1 | qs: Denial of Service via Attacker Controlled isBuffer |\n| react-router-dom | moderate | CVE-2026-53668 | v1 | React Router: Open redirect leading to XSS |\n| serialize-javascript | moderate | CVE-2026-34043 | v1 | Serialize JavaScript has CPU Exhaustion Denial of Service via crafted array-like |\n| body-parser | low | CVE-2026-12590 | v3 | body-parser vulnerable to denial of service when invalid limit value silently di |\n| hono | low | CVE-2026-71849 | v3 | Hono: Proxy Helper does not remove response headers listed in the `Connection` h |\n| postcss-selector-parser | low | CVE-2026-9358 | v1 | postcss-selector-parser allows denial of service through uncontrolled AST recurs |\n\n## 2. All Dependencies\n\n### Summary\n\n| Severity | v4 | v3 | v2 | v1 |\n| -------- | --: | --: | --: | --: |\n| critical | 1 | 9 | 4 | 5 |\n| high | 29 | 113 | 87 | 65 |\n| moderate | 19 | 80 | 68 | 26 |\n| low | 2 | 15 | 15 | 5 |\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 | v3 | Basic FTP has Path Traversal Vulnerability in its downloadToDir()Ā method |\n| fast-xml-parser | critical | CVE-2026-25896 | v3, v2 | fast-xml-parser has an entity encoding bypass via regex injection in DOCTYPE ent |\n| handlebars | critical | CVE-2026-33937 | v3, v1 | Handlebars.js has JavaScript Injection via AST Type Confusion |\n| happy-dom | critical | CVE-2025-61927 | v4 | Happy DOM: VM Context Escape can lead to Remote Code Execution |\n| locutus | critical | CVE-2026-25521 | v3, v1 | locutus is vulnerable to Prototype Pollution |\n| locutus | critical | CVE-2026-32304 | v3, v2, v1 | Locutus vulnerable to RCE via unsanitized input in create_function() |\n| seroval | critical | CVE-2026-59940 | v3, v2, v1 | seroval: `seroval.fromJSON()` Promise resolver type confusion invokes attacker-c |\n| shell-quote | critical | CVE-2026-9277 | v3 | shell-quote quote() does not escape newlines in object .op values |\n| tar | critical | CVE-2026-59873 | v3, v1 | node-tar: Decompression/parse DoS via unlimited input |\n| websocket-driver | critical | CVE-2026-54466 | v3, v2 | websocket-driver: Message corruption via abuse of protocol length headers |\n| @angular/common | high | CVE-2025-66035 | v1 | Angular is Vulnerable to XSRF Token Leakage via Protocol-Relative URLs in Angula |\n| @angular/common | high | CVE-2026-54268 | v4, v3, v2, v1 | @angular/common: Denial of Service (DoS) via OOM in Date Formatting (formatDate) |\n| @angular/common | high | CVE-2026-54266 | v4, v3, v2, v1 | @angular/common: Weak 32-Bit Cache Key Hashing in `HttpTransferCache` Leading to |\n| @angular/common | high | CVE-2026-50171 | v1 | @angular/common: Denial of Service (DoS) via OOM in Number Formatting (digitsInf |\n| @angular/common | high | CVE-2026-50170 | v1 | @angular/common: Information Leak via Default Caching of Credentialed Requests i |\n| @angular/common | high | CVE-2026-68945 | v4, v3, v2, v1 | Angular: Cache-Key Ambiguity in HttpTransferCache Leading to Cross-Request Respo |\n| @angular/compiler | high | CVE-2026-32635 | v1 | Angular vulnerable to XSS in i18n attribute bindings |\n| @angular/compiler | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\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-69151 | v4, v3, v2, v1 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\n| @angular/core | high | CVE-2026-27970 | v1 | Angular i18n vulnerable to Cross-Site Scripting |\n| @angular/core | high | CVE-2026-32635 | v1 | Angular vulnerable to XSS in i18n attribute bindings |\n| @angular/core | high | CVE-2026-22610 | v1 | Angular has XSS Vulnerability via Unsanitized SVG Script Attributes |\n| @angular/core | high | CVE-2026-54267 | v4, v3, v2, v1 | Angular Client Hydration DOM Clobbering & Response-Cache Poisoning |\n| @angular/core | high | CVE-2026-69151 | v4, v3, v2, v1 | Angular i18n: Cross-Site Scripting (XSS) via event-handler attributes |\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-42043 | v3 | Axios: Incomplete Fix for CVE-2025-62718 ā NO_PROXY Protection Bypassed via RFC |\n| axios | high | CVE-2026-42033 | v3 | Axios: Prototype Pollution Gadgets - Response Tampering, Data Exfiltration, and |\n| axios | high | CVE-2026-42035 | v3 | Axios: Header Injection via Prototype Pollution |\n| axios | high | CVE-2026-25639 | v3 | Axios is Vulnerable to Denial of Service via **proto** Key in mergeConfig |\n| axios | high | CVE-2026-42264 | v3 | Axios has prototype pollution read-side gadgets in HTTP adapter that allow crede |\n| axios | high | CVE-2026-44496 | v3 | Axios: Regular Expression Denial of Service (ReDoS) via Cookie Name Injection |\n| axios | high | CVE-2026-44488 | v3 | Allocation of Resources Without Limits or Throttling in Axios |\n| axios | high | CVE-2026-44487 | v3 | Axios: Proxy-Authorization Credential Leak to Origin Server Across HTTP-to-HTTPS |\n| axios | high | CVE-2026-44486 | v3 | Axios: Proxy-Authorization header leaks to redirect target when proxy is re-eval |\n| axios | high | CVE-2026-44495 | v3 | axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut |\n| axios | high | CVE-2026-44494 | v3 | axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co |\n| basic-ftp | high | GHSA-6v7q-wjvx-w8wg | v3 | basic-ftp: Incomplete CRLF Injection Protection Allows Arbitrary FTP Command Exe |\n| basic-ftp | high | CVE-2026-41324 | v3 | basic-ftp vulnerable to denial of service via unbounded memory consumption in Cl |\n| basic-ftp | high | CVE-2026-44240 | v3 | basic-ftp allows a malicious FTP server to cause client-side denial of service v |\n| brace-expansion | high | CVE-2026-13149 | v3, v2, v1 | brace-expansion: DoS via exponential-time expansion of consecutive non-expanding |\n| brace-expansion | high | CVE-2026-14257 | v3, v2, v1 | brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro |\n| brace-expansion | high | CVE-2026-69152 | v3, v2, v1 | brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-1 |\n| braces | high | CVE-2024-4068 | v3, v2, v1 | Uncontrolled resource consumption in braces |\n| browserslist | high | CVE-2026-73089 | v3, v2, v1 | Browserslist: Unbounded memory growth (no cache eviction) via distinct query res |\n| browserslist | high | CVE-2026-73088 | v3, v2, v1 | Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats. |\n| deepmerge-ts | high | CVE-2026-40345 | v4, v3, v2 | DeepmergeTS has stack exhaustion when merging recursive object graphs |\n| engine.io | high | CVE-2026-59725 | v3, v2 | Socket.IO: Engine.IO Polling Transport Connection Exhaustion |\n| engine.io | high | CVE-2026-59724 | v3, v2 | Socket.IO: Engine.IO WebTransport SID DoS |\n| express-rate-limit | high | CVE-2026-30827 | v2 | express-rate-limit: IPv4-mapped IPv6 addresses bypass per-client rate limiting o |\n| extract-zip | high | CVE-2026-56876 | v4, v3, v2, v1 | extract-zip unvalidated symlink path traversal |\n| fast-uri | high | CVE-2026-18446 | v3, v2, v1 | fast-uri vulnerable to host confusion via backslash authority introducer |\n| fast-uri | high | CVE-2026-75931 | v4, v1 | fast-uri vulnerable to host confusion via skipped IDN canonicalization on scheme |\n| fast-uri | high | CVE-2026-75975 | v4, v3, v2, v1 | fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat |\n| fast-uri | high | CVE-2026-75899 | v4, v3, v1 | fast-uri vulnerable to server-side request forgery via repeated hostname percent |\n| fast-uri | high | CVE-2026-76172 | v4, v3, v2, v1 | fast-uri vulnerable to host confusion via percent-encoded scheme normalization |\n| fast-uri | high | CVE-2026-16221 | v3, v2 | fast-uri vulnerable to host confusion via literal backslash authority delimiter |\n| fast-uri | high | CVE-2026-6321 | v2 | fast-uri vulnerable to path traversal via percent-encoded dot segments |\n| fast-uri | high | CVE-2026-13676 | v3, v2 | fast-uri vulnerable to host confusion via failed IDN canonicalization |\n| fast-uri | high | CVE-2026-6322 | v2 | fast-uri vulnerable to host confusion via percent-encoded authority delimiters |\n| fast-xml-parser | high | CVE-2026-25128 | v3, v2 | fast-xml-parser has RangeError DoS Numeric Entities Bug |\n| fast-xml-parser | high | CVE-2026-26278 | v3, v2 | fast-xml-parser affected by DoS through entity expansion in DOCTYPE (no expansio |\n| fast-xml-parser | high | CVE-2026-33036 | v3, v2 | fast-xml-parser affected by numeric entity expansion bypassing all entity expans |\n| find-my-way | high | CVE-2026-47219 | v3 | find-my-way: DDoS with HTTP2 |\n| flatted | high | CVE-2026-32141 | v3, v2 | flatted vulnerable to unbounded recursion DoS in parse() revive phase |\n| flatted | high | CVE-2026-33228 | v3, v2 | Prototype Pollution via parse() in NodeJS flatted |\n| form-data | high | CVE-2026-12143 | v3, v2, v1 | form-data: CRLF injection in form-data via unescaped multipart field names and f |\n| handlebars | high | CVE-2026-33938 | v3, v1 | Handlebars.js has JavaScript Injection via AST Type Confusion by tampering @part |\n| handlebars | high | CVE-2026-33940 | v3, v1 | Handlebars.js has JavaScript Injection via AST Type Confusion when passing an ob |\n| handlebars | high | CVE-2026-33939 | v3, v1 | Handlebars.js has Denial of Service via Malformed Decorator Syntax in Template C |\n| handlebars | high | CVE-2026-33941 | v3, v1 | Handlebars.js has JavaScript Injection in CLI Precompiler via Unescaped Names an |\n| happy-dom | high | CVE-2026-34226 | v4 | Happy DOM's fetch credentials include uses page-origin cookies instead of target |\n| happy-dom | high | CVE-2026-33943 | v4 | Happy DOM ECMAScriptModuleCompiler: unsanitized export names are interpolated as |\n| hono | high | CVE-2026-29045 | v2 | Hono vulnerable to arbitrary file access via serveStatic vulnerability |\n| hono | high | CVE-2026-54290 | v2 | hono: CORS Middleware reflects any Origin with credentials when `origin` default |\n| http-proxy-middleware | high | CVE-2026-55603 | v3 | http-proxy-middleware: multipart/form-data field injection via unescaped CRLF in |\n| image-size | high | CVE-2025-71330 | v4, v3, v2, v1 | image-size: ICNS parser allows denial of service through an infinite loop |\n| image-size | high | CVE-2025-71329 | v4, v3, v2, v1 | image-size: JXL and HEIF parsers allow denial of service through infinite loops |\n| immutable | high | CVE-2026-59879 | v3, v2, v1 | Immutable.js `List` 32-bit trie overflow ā unrecoverable DoS |\n| immutable | high | CVE-2026-59880 | v3, v2, v1 | Immutable: Hash-collision algorithmic complexity denial of service in Immutable. |\n| immutable | high | CVE-2026-29063 | v2 | Immutable is vulnerable to Prototype Pollution |\n| ip-address | high | CVE-2026-69192 | v3, v2 | ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco |\n| js-yaml | high | GHSA-5p4m-2wfm-xmqj | v3, v2, v1 | JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) ā CVE-2026 |\n| js-yaml | high | CVE-2026-59869 | v3, v2 | js-yaml: YAML merge-key chains can force quadratic CPU consumption |\n| linkify-it | high | CVE-2026-59887 | v3 | linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on at |\n| locutus | high | CVE-2026-29091 | v3, v2, v1 | locutus call_user_func_array vulnerable to Remote Code Execution (RCE) due to Co |\n| lodash | high | CVE-2026-4800 | v3 | lodash vulnerable to Code Injection via `_.template` imports key names |\n| lodash.pick | high | CVE-2020-8203 | v2, v1 | Prototype Pollution in lodash |\n| minimatch | high | CVE-2026-27903 | v3, v2, v1 | minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja |\n| minimatch | high | CVE-2026-27904 | v3, v2, v1 | minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regu |\n| minimatch | high | CVE-2026-26996 | v3, v2 | minimatch has a ReDoS via repeated wildcards with non-matching literal in patter |\n| nanoid | high | CVE-2026-67213 | v3, v1 | nanoid: custom generators can loop indefinitely when size is zero |\n| nanoid | high | CVE-2026-67214 | v3 | nanoid: non-secure generators can loop indefinitely with negative size |\n| nanoid | high | CVE-2026-73086 | v3 | nanoid: Integer Overflow or Wraparound |\n| node-forge | high | CVE-2026-33896 | v2 | Forge has a basicConstraints bypass in its certificate chain verification (RFC 5 |\n| node-forge | high | CVE-2026-33895 | v2 | Forge has signature forgery in Ed25519 due to missing S > L check |\n| node-forge | high | CVE-2026-33891 | v2 | Forge has Denial of Service via Infinite Loop in BigInteger.modInverse() with Ze |\n| node-forge | high | CVE-2026-33894 | v2 | Forge has signature forgery in RSA-PKCS due to ASN.1 extra field |\n| nx | high | CVE-2026-71476 | v3, v1 | Nx: Zip-Slip in the self-hosted remote cache |\n| pacote | high | CVE-2026-9496 | v3, v2, v1 | pacote is vulnerable to Denial of Service (DoS) via the addGitSha function |\n| path-to-regexp | high | CVE-2026-4867 | v3, v2 | path-to-regexp vulnerable to Regular Expression Denial of Service via multiple r |\n| path-to-regexp | high | CVE-2026-4926 | v2 | path-to-regexp vulnerable to Denial of Service via sequential optional groups |\n| piscina | high | CVE-2026-55388 | v3 | piscina: Prototype Pollution Gadget ā RCE via inherited options.filename |\n| postcss | high | CVE-2026-45623 | v4, v3, v2 | PostCSS: Arbitrary file read and information disclosure via attacker-controlled |\n| postcss | high | CVE-2026-73646 | v4, v3, v2 | PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) l |\n| react-router | high | GHSA-qwww-vcr4-c8h2 | v3 | React Router: RSC Mode CSRF Bypass Allows Action Execution Before 400 Response |\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| shell-quote | high | CVE-2026-13311 | v3 | shell-quote: Quadratic-complexity Denial of Service in `parse()` (CWE-407) |\n| sigstore | high | CVE-2026-48815 | v3, v2, v1 | sigstore's `certificateOIDs` verification constraints are silently dropped and n |\n| socket.io-parser | high | CVE-2026-33151 | v3, v2 | socket.io allows an unbounded number of binary attachments |\n| socket.io-parser | high | CVE-2026-69185 | v3, v2 | Socket.IO: Zero-attachment Memory Exhaustion |\n| svgo | high | CVE-2026-29074 | v3, v2, v1 | SVGO DoS through entity expansion in DOCTYPE (Billion Laughs) |\n| svgo | high | CVE-2026-73650 | v3, v2, v1 | SVGO removeScripts plugin leaves some executable scripts intact |\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 | v1 | Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in no |\n| tar | high | CVE-2026-29786 | v1 | tar has Hardlink Path Traversal via Drive-Relative Linkpath |\n| tar | high | CVE-2026-31802 | v1 | node-tar Symlink Path Traversal via Drive-Relative Linkpath |\n| tar | high | CVE-2026-23950 | v1 | Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on |\n| tar | high | CVE-2026-59874 | v3, v1 | node-tar: Negative tar entry size causes infinite loop in archive replace |\n| tar | high | CVE-2026-73566 | v3, v2, v1 | node-tar: Uncontrolled recursion in mapHas/filesFilter allows uncatchable stack- |\n| tmp | high | CVE-2026-44705 | v3, v2 | tmp has Path Traversal via unsanitized prefix/postfix that enables directory esc |\n| undici | high | CVE-2026-1528 | v3 | Undici: Malicious WebSocket 64-bit length overflows parser and crashes the clien |\n| undici | high | CVE-2026-1526 | v3 | Undici has Unbounded Memory Consumption in WebSocket permessage-deflate Decompre |\n| undici | high | CVE-2026-2229 | v3 | Undici has Unhandled Exception in WebSocket Client Due to Invalid server_max_win |\n| undici | high | CVE-2026-9697 | v3 | undici vulnerable to TLS certificate validation bypass via dropped requestTls in |\n| undici | high | CVE-2026-12151 | v3 | undici WebSocket client vulnerable to denial of service via fragment count bypas |\n| undici | high | CVE-2026-6734 | v3 | undici vulnerable to cross-origin request routing via SOCKS5 proxy pool reuse |\n| undici | high | CVE-2026-13697 | v3 | undici vulnerable to cross-user information disclosure and parse-time crash via |\n| vite | high | CVE-2026-39364 | v1 | Vite: `server.fs.deny` bypassed with queries |\n| vite | high | CVE-2026-39363 | v1 | Vite Vulnerable to Arbitrary File Read via Vite Dev Server WebSocket |\n| vite | high | CVE-2026-53571 | v3, v1 | vite: `server.fs.deny` bypass on Windows alternate paths |\n| ws | high | CVE-2026-48779 | v3, v2, v1 | ws: Memory exhaustion DoS from tiny fragments and data chunks |\n| @angular/compiler | moderate | CVE-2026-54265 | v4, v3, v2, v1 | @angular/compiler: Two-Way Property Binding Sanitization Bypass (XSS) |\n| @angular/compiler | moderate | CVE-2026-50557 | v4, v1 | Angular: Template and Attribute Namespace Sanitization Bypass (XSS) |\n| @angular/core | moderate | CVE-2026-50557 | v4, v1 | Angular: Template and Attribute Namespace Sanitization Bypass (XSS) |\n| @angular/core | moderate | CVE-2026-52725 | v4, v1 | @angular/core: Angular Template and Dynamic Component Namespace Bypass leading t |\n| @hono/node-server | moderate | CVE-2026-39406 | v2 | @hono/node-server: Middleware bypass via repeated slashes in serveStatic |\n| @hono/node-server | moderate | GHSA-frvp-7c67-39w9 | v3, v2 | Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode |\n| @humanfs/node | moderate | GHSA-p498-v437-472g | v3 | humanfs: Recursive copy follows symlinked files and copies data from outside the |\n| @opentelemetry/core | moderate | CVE-2026-54285 | v1 | OpenTelemetry Core: Unbounded memory allocation in W3C Baggage propagation |\n| @sigstore/core | moderate | CVE-2026-48758 | v3, v2, v1 | @sigstore/core has DSSE payloadType type-binding failure |\n| @xmldom/xmldom | moderate | CVE-2026-83610 | v4 | xmldom: XML fragment injection via invalid EntityReference.nodeName during requi |\n| ajv | moderate | CVE-2025-69873 | v3, v2 | ajv has ReDoS when using `$data` option |\n| axios | moderate | CVE-2025-62718 | v3 | Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF |\n| axios | moderate | CVE-2026-42041 | v3 | Axios: Authentication Bypass via Prototype Pollution Gadget in `validateStatus` |\n| axios | moderate | CVE-2026-42044 | v3 | Axios: Invisible JSON Response Tampering via Prototype Pollution Gadget in `pars |\n| axios | moderate | CVE-2026-42037 | v3 | Axios: CRLF Injection in multipart/form-data body via unsanitized blob.type in f |\n| axios | moderate | CVE-2026-42038 | v3 | Axios: no_proxy bypass via IP alias allows SSRF |\n| axios | moderate | CVE-2026-42034 | v3 | Axios' HTTP adapter-streamed uploads bypass maxBodyLength when maxRedirects: 0 |\n| axios | moderate | CVE-2026-42036 | v3 | Axios: HTTP adapter streamed responses bypass maxContentLength |\n| axios | moderate | CVE-2026-42042 | v3 | Axios: XSRF Token Cross-Origin Leakage via Prototype Pollution Gadget in `withXS |\n| axios | moderate | CVE-2026-40175 | v3 | Axios has Unrestricted Cloud Metadata Exfiltration via Header Injection Chain |\n| axios | moderate | CVE-2026-42039 | v3 | Axios: unbounded recursion in toFormData causes DoS via deeply nested request da |\n| axios | moderate | CVE-2026-44490 | v3 | axios has DoS & Header Injection via Prototype Pollution Read-Side Gadgets in ax |\n| axios | moderate | CVE-2026-67316 | v3 | Axios: Prototype pollution gadgets can alter axios request construction |\n| axios | moderate | CVE-2026-67312 | v3 | Axios: Deep formToJSON Key Recursion Can Cause Denial of Service |\n| axios | moderate | CVE-2026-67319 | v3 | Axios: Nested axios option objects can consume polluted prototype values |\n| axios | moderate | CVE-2026-67317 | v3 | Axios: Fetch adapter `ReadableStream` uploads bypass `maxBodyLength` |\n| axios | moderate | CVE-2026-67313 | v3 | Axios: Excessive recursion in formDataToJSON can cause denial of service |\n| brace-expansion | moderate | CVE-2026-45149 | v3, v2, v1 | brace-expansion: Large numeric range defeats documented `max` DoS protection |\n| brace-expansion | moderate | CVE-2026-33750 | v3, v2 | brace-expansion: Zero-step sequence causes process hang and memory exhaustion |\n| decode-uri-component | moderate | CVE-2026-45822 | v3, v2, v1 | decode-uri-component: Denial of service via exponential decoding of malformed pe |\n| dompurify | moderate | GHSA-55q2-fjhq-7xh7 | v1 | DOMPurify: IN_PLACE hook removal leaves a detached subtree executable, causing X |\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| fast-xml-parser | moderate | CVE-2026-33349 | v3, v2 | Entity Expansion Limits Bypassed When Set to Zero Due to JavaScript Falsy Evalua |\n| fast-xml-parser | moderate | CVE-2026-41650 | v3, v2 | fast-xml-parser XMLBuilder: XML Comment and CDATA Injection via Unescaped Delimi |\n| fastify | moderate | CVE-2026-18504 | v3 | fastify vulnerable to schema validation bypass via root primitive coercion misma |\n| fastify | moderate | CVE-2026-16732 | v3 | fastify vulnerable to X-Forwarded-* spoofing under trustProxy hop-count |\n| file-type | moderate | CVE-2026-31808 | v4 | file-type affected by infinite loop in ASF parser on malformed input with zero-s |\n| handlebars | moderate | CVE-2026-33916 | v3, v1 | Handlebars.js has Prototype Pollution Leading to XSS through Partial Template In |\n| handlebars | moderate | GHSA-7rx3-28cr-v5wh | v3, v1 | Handlebars.js has a Prototype Method Access Control Gap via Missing __lookupSett |\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| hono | moderate | GHSA-26pp-8wgv-hjvm | v2 | Hono missing validation of cookie name on write path in setCookie() |\n| hono | moderate | CVE-2026-39410 | v2 | Hono: Non-breaking space prefix bypass in cookie name handling in getCookie() |\n| hono | moderate | CVE-2026-39408 | v2 | Hono: Path traversal in toSSG() allows writing files outside the output director |\n| hono | moderate | CVE-2026-39407 | v2 | Hono: Middleware bypass via repeated slashes in serveStatic |\n| hono | moderate | CVE-2026-39409 | v2 | Hono has incorrect IP matching in ipRestriction() for IPv4-mapped IPv6 addresses |\n| hono | moderate | CVE-2026-44458 | v2 | Hono has CSS Declaration Injection via Style Object Values in JSX SSR |\n| hono | moderate | CVE-2026-44457 | v2 | Hono's Cache Middleware ignores Vary: Authorization / Vary: Cookie leading to cr |\n| hono | moderate | CVE-2026-44456 | v2 | Hono: bodyLimit() can be bypassed for chunked / unknown-length requests |\n| hono | moderate | CVE-2026-44455 | v2 | hono/jsx has Unvalidated JSX Tag Names that May Allow HTML Injection |\n| hono | moderate | CVE-2026-47674 | v2 | Hono: IP Restriction bypasses static deny rules for non-canonical IPv6 |\n| hono | moderate | CVE-2026-47675 | v2 | Hono: Cookie helper does not sanitize sameSite and priority, allowing Set-Cookie |\n| hono | moderate | CVE-2026-47673 | v2 | Hono: JWT middleware accepts any Authorization scheme, not only Bearer |\n| hono | moderate | CVE-2026-47676 | v2 | Hono: app.mount() strips mount prefix using undecoded path, causing incorrect ro |\n| hono | moderate | CVE-2026-56761 | v2 | hono Improperly Handles JSX Attribute Names Allows HTML Injection in hono/jsx SS |\n| hono | moderate | CVE-2026-54288 | v2 | hono: Body Limit Middleware can be bypassed on AWS Lambda by understating `Conte |\n| hono | moderate | CVE-2026-54289 | v2 | hono: Lambda@Edge adapter keeps only the last value of a repeated request header |\n| hono | moderate | CVE-2026-54286 | v2 | hono: Path traversal in `serve-static` on Windows via encoded backslash (`%5C`) |\n| hono | moderate | CVE-2026-54287 | v2 | hono: AWS Lambda adapter merges multiple `Set-Cookie` headers into one value, dr |\n| hono | moderate | CVE-2026-59897 | v3, v2 | Hono: API Gateway v1 adapter can drop a distinct repeated request header value d |\n| hono | moderate | CVE-2026-59895 | v3, v2 | Hono: Server-Side XSS via JSX Escaping Bypass in cx() Utility |\n| hono | moderate | CVE-2026-69207 | v3, v2 | Hono: ReDoS in CORS middleware via Access-Control-Request-Headers |\n| hono | moderate | CVE-2026-71850 | v3, v2 | Hono: `memo()` retains SSR output across requests, leading to cross-user data di |\n| hono | moderate | CVE-2026-59896 | v3 | hono/jsx does not isolate context per request, leading to cross-request data dis |\n| hono | moderate | CVE-2026-71848 | v3 | Hono: Algorithmic Complexity DoS in Language Middleware |\n| http-proxy-middleware | moderate | CVE-2026-55602 | v3, v2 | http-proxy-middleware `router` host+path substring matching allows Host-header-d |\n| ip-address | moderate | CVE-2026-42338 | v2 | ip-address has XSS in Address6 HTML-emitting methods |\n| ip-address | moderate | CVE-2026-69198 | v3 | ip-address: a CIDR suffix on the parsed address suppresses special-use classific |\n| ip-address | moderate | CVE-2026-54272 | v3 | ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSR |\n| js-yaml | moderate | CVE-2025-64718 | v2 | js-yaml has prototype pollution in merge (<<) |\n| js-yaml | moderate | CVE-2026-53550 | v3, v2 | JS-YAML: Quadratic-complexity DoS in merge key handling via repeated aliases |\n| launch-editor | moderate | CVE-2026-53632 | v3, v2 | launch-editor: NTLMv2 hash disclosure via UNC path handling on Windows |\n| locutus | moderate | CVE-2026-33993 | v3, v2, v1 | Locutus has Prototype Pollution via **proto** Key Injection in unserialize() |\n| locutus | moderate | CVE-2026-33994 | v2 | Locutus Prototype Pollution due to incomplete fix for CVE-2026-25521 |\n| lodash | moderate | CVE-2026-2950 | v3 | lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and |\n| micromatch | moderate | CVE-2024-4067 | v3, v2, v1 | Regular Expression Denial of Service (ReDoS) in micromatch |\n| nx | moderate | CVE-2026-54753 | v3, v1 | `nx graph` dev server permissive CORS policy |\n| path-to-regexp | moderate | CVE-2026-4923 | v2 | path-to-regexp vulnerable to Regular Expression Denial of Service via multiple w |\n| postcss | moderate | CVE-2026-41305 | v4, v3, v2 | PostCSS has XSS via Unescaped </style> in its CSS Stringify Output |\n| postcss | moderate | CVE-2026-69153 | v4, v3, v2 | PostCSS: incomplete fix of GHSA-6g55-p6wh-862q ā attacker-controlled sourceMappi |\n| protobufjs | moderate | CVE-2026-59876 | v3 | protobufjs: Text Format string map parsing can mutate returned map object protot |\n| protobufjs | moderate | CVE-2026-59877 | v3 | protobufjs: Denial of Service via infinite loop in .proto option parsing |\n| qs | moderate | CVE-2026-8723 | v3, v2, v1 | qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/u |\n| qs | moderate | CVE-2026-82562 | v4, v3, v2, v1 | qs array-limit bypass via bracket-key comma parsing |\n| qs | moderate | CVE-2026-82417 | v4, v3, v2, v1 | qs: Denial of Service via Attacker Controlled isBuffer |\n| qs | moderate | CVE-2025-15284 | v2 | qs's arrayLimit bypass in its bracket notation allows DoS via memory exhaustion |\n| react-router-dom | moderate | CVE-2026-53668 | v1 | React Router: Open redirect leading to XSS |\n| serialize-javascript | moderate | CVE-2026-34043 | v4, v3, v2, v1 | Serialize JavaScript has CPU Exhaustion Denial of Service via crafted array-like |\n| serialize-javascript | moderate | CVE-2024-11831 | v2 | Cross-site Scripting (XSS) in serialize-javascript |\n| smol-toml | moderate | GHSA-v3rj-xjv7-4jmq | v3, v1 | smol-toml: Denial of Service via TOML documents containing thousands of consecut |\n| tar | moderate | CVE-2026-53655 | v3, v1 | node-tar applies PAX size override to intermediary GNU long-name/long-link heade |\n| tar | moderate | CVE-2026-59871 | v3, v1 | node-tar: Process crash via PAX numeric path type confusion |\n| tar | moderate | CVE-2026-59875 | v3, v1 | node-tar: Uncaught Exception DoS via NUL byte in PAX path/linkpath records |\n| undici | moderate | CVE-2026-1525 | v3 | Undici has an HTTP Request/Response Smuggling issue |\n| undici | moderate | CVE-2026-1527 | v3 | Undici has CRLF Injection in undici via `upgrade` option |\n| undici | moderate | CVE-2026-9679 | v3 | undici vulnerable to HTTP header injection via Set-Cookie percent-decoding |\n| undici | moderate | CVE-2026-9678 | v3 | undici vulnerable to cross-user information disclosure via shared cache whitespa |\n| undici | moderate | CVE-2026-16728 | v3 | undici vulnerable to downstream response desynchronization via retry interceptor |\n| undici | moderate | CVE-2026-15157 | v3 | undici vulnerable to CRLF Injection via blob-like body 'type' property |\n| undici | moderate | CVE-2026-14643 | v3 | undici vulnerable to cross-user information disclosure via whitespace around equ |\n| undici | moderate | CVE-2026-16729 | v3 | undici vulnerable to cookie attribute injection via unsanitized domain and unpar |\n| uuid | moderate | CVE-2026-41907 | v4, v3, v2 | uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided |\n| vite | moderate | CVE-2026-39365 | v1 | Vite Vulnerable to Path Traversal in Optimized Deps `.map` Handling |\n| vite | moderate | CVE-2026-53632 | v3, v1 | launch-editor: NTLMv2 hash disclosure via UNC path handling on Windows |\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| webpack-dev-server | moderate | CVE-2026-6402 | v2 | webpack-dev-server vulnerable to cross-origin source code exposure on non-HTTPS |\n| webpack-dev-server | moderate | CVE-2026-9595 | v2 | webpack-dev-server vulnerable to HMR WebSocket interception via permissive user |\n| webpack-dev-server | moderate | CVE-2026-14620 | v3, v2 | webpack-dev-server vulnerable to cross-site request forgery via internal develop |\n| webpack-dev-server | moderate | CVE-2026-14631 | v3, v2 | webpack-dev-server vulnerable to denial of service via a malformed Host or Origi |\n| websocket-driver | moderate | CVE-2026-54490 | v3, v2 | websocket-driver: Resource limit bypass via message compression |\n| ws | moderate | CVE-2026-45736 | v3, v2 | ws: Uninitialized memory disclosure |\n| yaml | moderate | CVE-2026-33532 | v3, v2, v1 | yaml is vulnerable to Stack Overflow via deeply nested YAML collections |\n| @babel/core | low | CVE-2026-49356 | v4, v3, v2, v1 | @babel/core: Arbitrary File Read via sourceMappingURL Comment |\n| @tootallnate/once | low | CVE-2026-3449 | v3, v2, v1 | @tootallnate/once vulnerable to Incorrect Control Flow Scoping |\n| axios | low | CVE-2026-42040 | v3 | Axios: Null Byte Injection via Reverse-Encoding in AxiosURLSearchParams |\n| body-parser | low | CVE-2026-12590 | v3, v2 | body-parser vulnerable to denial of service when invalid limit value silently di |\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 | v3, v2 | fast-xml-parser has stack overflow in XMLBuilder with preserveOrder |\n| handlebars | low | GHSA-442j-39wm-28r2 | v3, v1 | Handlebars.js has a Property Access Validation Bypass in container.lookup |\n| hono | low | GHSA-gq3j-xvxp-8hrf | v2 | Hono added timing comparison hardening in basicAuth and bearerAuth |\n| hono | low | CVE-2026-44459 | v2 | Hono has improper validation of NumericDate claims (exp, nbf, iat) in JWT verify |\n| hono | low | CVE-2026-71849 | v3, v2 | Hono: Proxy Helper does not remove response headers listed in the `Connection` h |\n| postcss-selector-parser | low | CVE-2026-9358 | v3, v2, v1 | postcss-selector-parser allows denial of service through uncontrolled AST recurs |\n| qs | low | CVE-2026-2391 | v2 | qs's arrayLimit bypass in comma parsing allows denial of service |\n| undici | low | CVE-2026-11525 | v3 | undici vulnerable to Set-Cookie SameSite attribute downgrade via permissive subs |\n| undici | low | CVE-2026-6733 | v3 | undici vulnerable to HTTP response queue poisoning via keep-alive socket reuse |\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",
|
|
345
345
|
"kind": "doc"
|
|
346
346
|
},
|
|
347
347
|
{
|
|
@@ -453,7 +453,7 @@
|
|
|
453
453
|
"group": "docs",
|
|
454
454
|
"name": "RENOVATE",
|
|
455
455
|
"path": "docs/RENOVATE.md",
|
|
456
|
-
"code": "# Renovate ā Automated Dependency Updates\n\nThis document is the outcome of issue [#10270](https://github.com/public-ui/kolibri/issues/10270)\n(_renovate vs npm-check-updates vs dependabot_). It contains:\n\n1. a comparison of the three candidate tools,\n2. a description of the exemplary [`renovate.json`](../renovate.json) that ships with this repo,\n3. how to enable Renovate, and\n4. the migration checklist for retiring the current tooling.\n\n> **Status:** The `renovate.json` and a self-hosted runner workflow\n> ([`.github/workflows/renovate.yml`](../.github/workflows/renovate.yml)) are committed as an\n> **exemplary, ready-to-run setup**. Renovate stays **idle** until that workflow runs ā either on its\n> weekly schedule or via the manual **Run workflow** button (see [Enabling Renovate](#enabling-renovate)).\n> Until then the existing Dependabot + npm-check-updates automation stays in charge.\n\n---\n\n## 1. Tool comparison\n\nKoliBri is a **pnpm-workspace monorepo** with 30+ packages, several intentionally pinned major\nlines (Angular `v19`/`v20`/`v21`, React 18/19, Stencil 4, ESLint 9) and four maintained branches\n(`develop`, `release/3`, `release/2`, `release/1`). That shapes the comparison:\n\n| Capability | **Renovate** | Dependabot | npm-check-updates (ncu) |\n| -------------------------------------------- | :----------------------: | :---------------------------------: | :-----------------------: |\n| pnpm-workspace aware | ā
native | ā ļø partial | ā manual (per-package) |\n| One PR grouping related packages | ā
fully configurable | ā ļø `groups:` only | ā none |\n| Hold a package on a specific major line | ā
per-folder rules | ā ļø `ignore` (global) | ā ļø `-x` exclude (global) |\n| GitHub Actions updates | ā
| ā
| ā |\n| Lockfile-only refresh | ā
`lockFileMaintenance` | ā ļø limited | ā (needs `pnpm install`) |\n| Automerge (per update type) | ā
| ā ļø limited | ā |\n| Multi-base-branch (release/\\*) support | ā
`baseBranchPatterns` | ā
`target-branch` (one entry each) | ā ļø matrix in a workflow |\n| Security / vulnerability remediation | ā
OSV + GitHub alerts | ā
GitHub alerts | ā |\n| Dependency Dashboard (single overview issue) | ā
| ā | ā |\n| Schedule / batching | ā
| ā ļø basic | ā ļø via cron workflow |\n| Self-hostable (no third-party app) | ā
(official Action) | ā
(GitHub-native) | ā
(CLI) |\n| Config surface | medium | low | minimal |\n| Cost for open source | free | free | free |\n\n### Verdict\n\n- **Renovate ā recommended.** It is the only option that models KoliBri's reality in _one_ config:\n group the Angular/React/Stencil families, hold each adapter folder on its pinned major, automerge\n the safe stuff (GitHub Actions, `@types/*`), and route everything risky to a review queue (the\n Dependency Dashboard). It also folds in what we currently split across **two** systems\n (Dependabot for Actions + a daily `ncu` workflow for npm).\n- **Dependabot ā viable fallback.** Now supports `groups:`, but every package directory needs its\n own `updates:` entry (ā30 for this monorepo Ć 4 branches) and it cannot hold a dependency on a\n specific major _per folder_ ā exactly what the `angular/v19|v20|v21` and `react*` adapters need.\n- **npm-check-updates ā not an automation tool.** It is a CLI that rewrites version ranges; it has\n no PR/grouping/scheduling of its own. We only use it _inside_ a hand-written workflow\n (`.github/workflows/auto-dependency-updater.yml`). Renovate makes that workflow redundant.\n\n---\n\n## 2. What the exemplary `renovate.json` does\n\nThe committed [`renovate.json`](../renovate.json) is tailored to this repo. Highlights:\n\n### Global behaviour\n\n- **`extends: [\"config:recommended\", \"security:openssf-scorecard\"]`** ā sensible defaults plus\n OpenSSF Scorecard badges on PRs.\n- **Conventional Commits** ā `chore(deps): ā¦` titles so PRs pass `pr-title-validation.yml`.\n- **`labels: [\"dependencies\", \"renovate\", \"release:engineering\"]`** ā the `release:*` label is\n **required** by `pr-release-label-validation.yml`; `release:engineering` files dependency PRs\n under _š§ Engineering_ in the changelog (see `.github/release.yml`).\n- **Weekly schedule** (`before 6am on monday`, `Europe/Berlin`) with `prConcurrentLimit: 10` /\n `prHourlyLimit: 4` so the first run does **not** flood the repo with PRs.\n- **`baseBranchPatterns`** ā runs on `develop` **and** `release/3|2|1`; the maintenance branches are\n restricted to security + patch npm updates so released majors stay stable.\n- **`lockFileMaintenance`** ā weekly `pnpm-lock.yaml` refresh (replaces the manual\n `04 - Update pnpm Lock` workflow runs).\n- **`postUpdateOptions: [\"pnpmDedupe\"]`** ā keeps the pnpm lockfile tidy.\n\n### Grouping & guard-rails (the important part for this monorepo)\n\n| Rule | Effect |\n| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **All majors** | Require manual approval via the Dependency Dashboard ā KoliBri pins majors deliberately. |\n| **Angular `@angular/*`, `zone.js`, `ng-packagr`** | Major updates **disabled** entirely; within-major updates grouped per adapter folder (_Angular 19/20/21_). A new Angular major = a new adapter folder, never an auto-bump. |\n| **React `react`, `react-dom`, `@types/react*`** | Major updates **disabled**; within-major React updates of the `react*` adapters grouped and reviewed (not automerged). |\n| **Stencil `@stencil/*`, `@stencil-community/*`** | **All** updates require dashboard approval ā every 4.39+ release currently breaks the Popover API, tooltips and visual tests (see [`UPGRADEABLE_DEPENDENCIES.md`](./UPGRADEABLE_DEPENDENCIES.md)). |\n| **`@kern-ux/*`** | Dashboard approval only ā upgraded by hand together with theming work. |\n| **`@typescript-eslint/*`, ESLint core + plugins** | Minor/major require approval (9 ā 10 is a breaking migration). |\n| **`jest*`, `typescript`** | Majors/non-patch require approval. |\n| **`github-actions`, `@types/*`** | Grouped **and automerged** for low-risk update types. |\n| **Stylelint, Playwright** | Grouped into single PRs. |\n\n> The pins above mirror exactly what the current `ncu:*` scripts exclude\n> (`@kern-ux/*`, `@stencil/*`, `@typescript-eslint/*`) and what `UPGRADEABLE_DEPENDENCIES.md`\n> documents as breaking ā so behaviour is preserved, just expressed declaratively.\n\n### Validate the config locally\n\n```sh\nnpx --yes --package renovate renovate-config-validator renovate.json\n```\n\n---\n\n## 3. Enabling Renovate\n\nTwo ways to run it; **this repo is wired for Option A**.\n\n### Option A ā Self-hosted via GitHub Actions (committed in this repo)\n\nThis repo ships [`.github/workflows/renovate.yml`](../.github/workflows/renovate.yml). It runs Renovate\non a weekly schedule (Mondays 04:00 UTC) **and** on demand via the **Run workflow** button\n(`workflow_dispatch`, with an optional `dry_run` preview). It authenticates through the existing GitHub\nApp (`APP_ID` / `PRIVATE_KEY` secrets, shared with _04 - Update pnpm Lock_).\n\nTo activate it:\n\n1. Ensure that GitHub App installation grants **contents: write**, **pull-requests: write**,\n **issues: write** (for the Dependency Dashboard) and **workflows: write** (so the `github-actions`\n manager may update `.github/workflows/*`). _Alternative:_ replace the app-token step with a\n `RENOVATE_TOKEN` PAT/fine-grained token carrying the same scopes.\n2. Trigger the workflow once via **Run workflow** (optionally with `dry_run` enabled) to verify it, then\n let the weekly schedule take over.\n\n> **Tip:** The `dry_run` input maps to `RENOVATE_DRY_RUN=full`, so the first manual run previews every PR\n> Renovate _would_ open without creating anything.\n\n### Option B ā Mend-hosted GitHub App (alternative, zero maintenance)\n\nIf you would rather not self-host, delete `.github/workflows/renovate.yml` and instead:\n\n1. Have an **org admin** install the [Renovate GitHub App](https://github.com/apps/renovate) on\n `public-ui` (or just on `public-ui/kolibri`).\n2. Renovate detects `renovate.json` and opens a Dependency Dashboard issue.\n3. Review the dashboard, then let it run on the weekly schedule.\n\n---\n\n## 4. Migration checklist (do this only after Renovate is verified)\n\nOnce Renovate runs green for a cycle, retire the overlapping automation to avoid **duplicate PRs**:\n\n- [ ] Remove `.github/dependabot.yml` (Renovate now manages GitHub Actions ā see the\n `github-actions` group).\n- [ ] Remove `.github/workflows/auto-dependency-updater.yml` (the daily `ncu` PR job).\n- [ ] Drop the `ncu:*` / `update` scripts and the `npm-check-updates` devDependency from the root\n `package.json`, plus `.ncurc.json` (optional ā `ncu` is still handy for manual ad-hoc checks).\n- [ ] Keep `04 - Update pnpm Lock` if you still want a manual lockfile-refresh button; otherwise\n Renovate's `lockFileMaintenance` covers it.\n\nUntil every box is ticked, **leave the existing tooling in place** ā Renovate only acts once the\nworkflow (or app) from [§3](#3-enabling-renovate) actually runs, so there is no conflict in the meantime.\n\n---\n\n## š©šŖ Zusammenfassung\n\n**Empfehlung: Renovate.** Es ist die einzige Lƶsung, die das KoliBri-Monorepo in _einer_ Konfiguration\nabbildet ā verwandte Pakete gruppieren (z. B. alle `@angular/*`), jeden Adapter-Ordner auf seiner\nfixierten Major-Version halten (`angular/v19|v20|v21`, `react*`), sichere Updates automatisch mergen\n(GitHub Actions, `@types/*`) und alles Riskante (Stencil, kern-ux, ESLint-/Angular-Majors) über das\n**Dependency Dashboard** zur manuellen Freigabe leiten.\n\n- **Dependabot** kann zwar gruppieren, braucht aber pro Paketverzeichnis einen eigenen Eintrag\n (ā30 Ć 4 Branches) und kann ein Paket nicht _pro Ordner_ auf einer Major-Version halten.\n- **npm-check-updates** ist nur ein CLI ohne eigene Automatisierung (lƤuft heute im Workflow\n `auto-dependency-updater.yml`).\n\nDie fertige [`renovate.json`](../renovate.json) liegt im Repo-Root (geprüft mit dem offiziellen\n`renovate-config-validator`), und der self-hosted Runner-Workflow\n[`.github/workflows/renovate.yml`](../.github/workflows/renovate.yml) ist ebenfalls committet.\n**Renovate lƤuft**, sobald der Workflow startet ā wƶchentlich per Zeitplan oder manuell über den\n**Run workflow**-Button (Option A); alternativ kann ein Org-Admin die\n[Renovate-GitHub-App](https://github.com/apps/renovate) installieren (Option B). Bis dahin bleibt die\nbestehende Dependabot-/ncu-Automatisierung zustƤndig; danach greift die Migrations-Checkliste oben.\n",
|
|
456
|
+
"code": "# Renovate ā Automated Dependency Updates\n\nThis document is the outcome of issue [#10270](https://github.com/public-ui/kolibri/issues/10270)\n(_renovate vs npm-check-updates vs dependabot_). It contains:\n\n1. a comparison of the three candidate tools,\n2. a description of the exemplary [`renovate.json`](../renovate.json) that ships with this repo,\n3. how to enable Renovate, and\n4. the migration checklist for retiring the current tooling.\n\n> **Status:** The `renovate.json` and a self-hosted runner workflow\n> ([`.github/workflows/renovate.yml`](../.github/workflows/renovate.yml)) are committed as an\n> **exemplary, ready-to-run setup**. Renovate stays **idle** until that workflow runs ā either on its\n> every-4-hours schedule or via the manual **Run workflow** button (see [Enabling Renovate](#enabling-renovate)).\n> Until then the existing Dependabot + npm-check-updates automation stays in charge.\n\n---\n\n## 1. Tool comparison\n\nKoliBri is a **pnpm-workspace monorepo** with 30+ packages, several intentionally pinned major\nlines (Angular `v19`/`v20`/`v21`, React 18/19, Stencil 4, ESLint 9) and four maintained branches\n(`develop`, `release/3`, `release/2`, `release/1`). That shapes the comparison:\n\n| Capability | **Renovate** | Dependabot | npm-check-updates (ncu) |\n| -------------------------------------------- | :----------------------: | :---------------------------------: | :-----------------------: |\n| pnpm-workspace aware | ā
native | ā ļø partial | ā manual (per-package) |\n| One PR grouping related packages | ā
fully configurable | ā ļø `groups:` only | ā none |\n| Hold a package on a specific major line | ā
per-folder rules | ā ļø `ignore` (global) | ā ļø `-x` exclude (global) |\n| GitHub Actions updates | ā
| ā
| ā |\n| Lockfile-only refresh | ā
`lockFileMaintenance` | ā ļø limited | ā (needs `pnpm install`) |\n| Automerge (per update type) | ā
| ā ļø limited | ā |\n| Multi-base-branch (release/\\*) support | ā
`baseBranchPatterns` | ā
`target-branch` (one entry each) | ā ļø matrix in a workflow |\n| Security / vulnerability remediation | ā
OSV + GitHub alerts | ā
GitHub alerts | ā |\n| Dependency Dashboard (single overview issue) | ā
| ā | ā |\n| Schedule / batching | ā
| ā ļø basic | ā ļø via cron workflow |\n| Self-hostable (no third-party app) | ā
(official Action) | ā
(GitHub-native) | ā
(CLI) |\n| Config surface | medium | low | minimal |\n| Cost for open source | free | free | free |\n\n### Verdict\n\n- **Renovate ā recommended.** It is the only option that models KoliBri's reality in _one_ config:\n group the Angular/React/Stencil families, hold each adapter folder on its pinned major, automerge\n the safe stuff (GitHub Actions, `@types/*`), and route everything risky to a review queue (the\n Dependency Dashboard). It also folds in what we currently split across **two** systems\n (Dependabot for Actions + a daily `ncu` workflow for npm).\n- **Dependabot ā viable fallback.** Now supports `groups:`, but every package directory needs its\n own `updates:` entry (ā30 for this monorepo Ć 4 branches) and it cannot hold a dependency on a\n specific major _per folder_ ā exactly what the `angular/v19|v20|v21` and `react*` adapters need.\n- **npm-check-updates ā not an automation tool.** It is a CLI that rewrites version ranges; it has\n no PR/grouping/scheduling of its own. We only use it _inside_ a hand-written workflow\n (`.github/workflows/auto-dependency-updater.yml`). Renovate makes that workflow redundant.\n\n---\n\n## 2. What the exemplary `renovate.json` does\n\nThe committed [`renovate.json`](../renovate.json) is tailored to this repo. Highlights:\n\n### Global behaviour\n\n- **`extends: [\"config:recommended\", \"security:openssf-scorecard\"]`** ā sensible defaults plus\n OpenSSF Scorecard badges on PRs.\n- **Conventional Commits** ā `chore(deps): ā¦` titles so PRs pass `pr-title-validation.yml`.\n- **`labels: [\"dependencies\", \"renovate\", \"release:engineering\"]`** ā the `release:*` label is\n **required** by `pr-release-label-validation.yml`; `release:engineering` files dependency PRs\n under _š§ Engineering_ in the changelog (see `.github/release.yml`).\n- **Every-4-hours cadence** ā the workflow cron runs Renovate every 4 hours; `renovate.json` itself\n allows PR creation `at any time`, so the workflow schedule governs. `prConcurrentLimit: 5` /\n `prHourlyLimit: 5` cap the number of open PRs **per base branch** (so `develop` and each\n `release/*` branch have their own budget).\n- **`minimumReleaseAge: \"3 days\"`** ā all updates (npm, Actions, ā¦, including security fixes)\n are held back for three days after release before a PR is opened or auto-merged. This protects\n against compromised or quickly-revoked releases.\n- **Automerge all non-major updates (squash)** ā the first package rule enables `automerge` for\n `patch`/`minor`/`digest`/`pin`/lockfile updates; `automergeStrategy: squash` means each\n dependency bump becomes a single commit. Known-risky rules below (Stencil, kern-ux, ESLint,\n TypeScript, typescript-eslint) override it back to manual. Majors always keep dashboard approval.\n Prerequisites: repo setting **Allow auto-merge** enabled, green pipelines enforced via required\n status checks on `develop`, and the runner GitHub App listed in the branch-protection bypass\n (see [Enabling Renovate](#enabling-renovate)).\n- **`baseBranchPatterns`** ā runs on `develop` **and** `release/3|2|1`; the maintenance branches are\n **security-only** (all regular npm and GitHub Actions updates are disabled) so released majors stay\n stable. Security PRs still automerge when non-major; major security updates require dashboard\n approval.\n- **`lockFileMaintenance`** ā weekly `pnpm-lock.yaml` refresh (replaces the manual\n `04 - Update pnpm Lock` workflow runs).\n- **`configMigration: true`** ā Renovate keeps `renovate.json` itself up to date when built-in\n presets or options change.\n- **`dependencyDashboardOSVVulnerabilitySummary: \"all\"`** ā adds an OSV vulnerability table\n directly to the Dependency Dashboard issue.\n- **`postUpdateOptions: [\"pnpmDedupe\"]`** ā keeps the pnpm lockfile tidy.\n\n### Grouping & guard-rails (the important part for this monorepo)\n\n| Rule | Effect |\n| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **All majors** | Require manual approval via the Dependency Dashboard ā KoliBri pins majors deliberately. |\n| **Angular `@angular/*`, `zone.js`, `ng-packagr`** | Major updates **disabled** entirely; within-major updates grouped per adapter folder (_Angular 19/20/21_). A new Angular major = a new adapter folder, never an auto-bump. |\n| **React `react`, `react-dom`, `@types/react*`** | Major updates **disabled**; within-major React updates of the `react*` adapters grouped and automerged once green. |\n| **Stencil `@stencil/*`, `@stencil-community/*`** | **All** updates require dashboard approval ā every 4.39+ release currently breaks the Popover API, tooltips and visual tests (see [`UPGRADEABLE_DEPENDENCIES.md`](./UPGRADEABLE_DEPENDENCIES.md)). |\n| **`@kern-ux/*`** | Dashboard approval only ā upgraded by hand together with theming work. |\n| **`@typescript-eslint/*`, ESLint core + plugins** | Minor/major require approval (9 ā 10 is a breaking migration). |\n| **`jest*`, `typescript`** | Majors/non-patch require approval. |\n| **`github-actions`, `@types/*`** | Grouped; automerged like every other non-major update. |\n| **Stylelint, Playwright** | Grouped into single PRs. |\n\n> The pins above mirror exactly what the current `ncu:*` scripts exclude\n> (`@kern-ux/*`, `@stencil/*`, `@typescript-eslint/*`) and what `UPGRADEABLE_DEPENDENCIES.md`\n> documents as breaking ā so behaviour is preserved, just expressed declaratively.\n\n### Validate the config locally\n\n```sh\nnpx --yes --package renovate renovate-config-validator renovate.json\n```\n\n---\n\n## 3. Enabling Renovate\n\nTwo ways to run it; **this repo is wired for Option A**.\n\n### Option A ā Self-hosted via GitHub Actions (committed in this repo)\n\nThis repo ships [`.github/workflows/renovate.yml`](../.github/workflows/renovate.yml). It runs Renovate\n**every 4 hours** (`0 */4 * * *` UTC) **and** on demand via the **Run workflow** button\n(`workflow_dispatch`, with an optional `dry_run` preview). It authenticates through the existing GitHub\nApp (`APP_ID` / `PRIVATE_KEY` secrets, shared with _04 - Update pnpm Lock_).\n\nTo activate it:\n\n1. Ensure that GitHub App installation grants **contents: write**, **pull-requests: write**,\n **issues: write** (for the Dependency Dashboard) and **workflows: write** (so the `github-actions`\n manager may update `.github/workflows/*`). _Alternative:_ replace the app-token step with a\n `RENOVATE_TOKEN` PAT/fine-grained token carrying the same scopes.\n2. For automerge to work end to end, check three repository settings:\n - **Settings ā General ā Pull Requests ā Allow auto-merge**: enabled (Renovate uses\n `platformAutomerge`, i.e. GitHub's native auto-merge).\n - **Branch protection for `develop` (and `release/2`, `release/1`, `release/3`) ā required status\n checks**: add the CI gate jobs (`check-results`, `validate-pr-title`) so a PR is only merged\n when the pipelines are green.\n - **Branch protection for `develop` (and `release/*`) ā bypass pull request allowances**: the\n runner App (`publicuibot`) must be listed there, so its PRs can merge without a human\n code-owner review.\n3. Trigger the workflow once via **Run workflow** (optionally with `dry_run` enabled) to verify it, then\n let the 4-hours schedule take over.\n\n> **Tip:** The `dry_run` input maps to `RENOVATE_DRY_RUN=full`, so the first manual run previews every PR\n> Renovate _would_ open without creating anything.\n\n### Option B ā Mend-hosted GitHub App (alternative, zero maintenance)\n\nIf you would rather not self-host, delete `.github/workflows/renovate.yml` and instead:\n\n1. Have an **org admin** install the [Renovate GitHub App](https://github.com/apps/renovate) on\n `public-ui` (or just on `public-ui/kolibri`).\n2. Renovate detects `renovate.json` and opens a Dependency Dashboard issue.\n3. Review the dashboard, then let it run on the weekly schedule.\n\n---\n\n## 4. Migration checklist (do this only after Renovate is verified)\n\nOnce Renovate runs green for a cycle, retire the overlapping automation to avoid **duplicate PRs**.\nStatus as of the Renovate activation for `develop`:\n\n- [x] Removed `.github/dependabot.yml` (Renovate now manages GitHub Actions ā see the\n `github-actions` group).\n- [x] Removed `.github/workflows/auto-dependency-updater.yml` (the daily `ncu` PR job).\n- [x] Dropped the `ncu:*` / `update` scripts and the `npm-check-updates` devDependency from the root\n `package.json`, plus `.ncurc.json`.\n- [ ] Keep `04 - Update pnpm Lock` if you still want a manual lockfile-refresh button; otherwise\n Renovate's `lockFileMaintenance` covers it.\n\nUntil every box is ticked, **leave the existing tooling in place** ā Renovate only acts once the\nworkflow (or app) from [§3](#3-enabling-renovate) actually runs, so there is no conflict in the meantime.\n\n---\n\n## š©šŖ Zusammenfassung\n\n**Empfehlung: Renovate.** Es ist die einzige Lƶsung, die das KoliBri-Monorepo in _einer_ Konfiguration\nabbildet ā verwandte Pakete gruppieren (z. B. alle `@angular/*`), jeden Adapter-Ordner auf seiner\nfixierten Major-Version halten (`angular/v19|v20|v21`, `react*`), sichere Updates automatisch mergen\n(GitHub Actions, `@types/*`) und alles Riskante (Stencil, kern-ux, ESLint-/Angular-Majors) über das\n**Dependency Dashboard** zur manuellen Freigabe leiten.\n\n- **Dependabot** kann zwar gruppieren, braucht aber pro Paketverzeichnis einen eigenen Eintrag\n (ā30 Ć 4 Branches) und kann ein Paket nicht _pro Ordner_ auf einer Major-Version halten.\n- **npm-check-updates** ist nur ein CLI ohne eigene Automatisierung (lƤuft heute im Workflow\n `auto-dependency-updater.yml`).\n\nNeu hinzugekommen: `minimumReleaseAge: \"3 Tage\"` schützt vor kompromittierten Releases\n(inklusive Security-Updates), `automergeStrategy: squash` sorgt für saubere Commit-Historie,\nund die `release/*`-Branches werden auf **Security-only** umgestellt ā regulƤre npm- und\nGitHub-Actions-Updates werden dort komplett deaktiviert, wƤhrend Vulnerability-Alert-PRs\nweiterhin (bei Nicht-Major) automatisch mergen.\n\nDie fertige [`renovate.json`](../renovate.json) liegt im Repo-Root (geprüft mit dem offiziellen\n`renovate-config-validator`), und der self-hosted Runner-Workflow\n[`.github/workflows/renovate.yml`](../.github/workflows/renovate.yml) ist ebenfalls committet.\n**Renovate lƤuft**, sobald der Workflow startet ā alle 4 Stunden per Zeitplan oder manuell über den\n**Run workflow**-Button (Option A); alternativ kann ein Org-Admin die\n[Renovate-GitHub-App](https://github.com/apps/renovate) installieren (Option B). Bis dahin bleibt die\nbestehende Dependabot-/ncu-Automatisierung zustƤndig; danach greift die Migrations-Checkliste oben.\n",
|
|
457
457
|
"kind": "doc"
|
|
458
458
|
},
|
|
459
459
|
{
|
|
@@ -504,6 +504,14 @@
|
|
|
504
504
|
"code": "# Upgradeable Dependencies ā Major Versions Available\n\n**Analysis Date:** 2026-03-31 \n**Scope:** Root package.json + all packages in `packages/*/` \n**Method:** npm-check-updates with `--target greatest`\n\n---\n\n## š“ Critical (Breaking Changes ā Manual Work Required)\n\n### 1. **@stencil/core** | 4.38.3 (pinned) ā 4.43.5 (patch, BLOCKED) / 5.0.0-alpha.7 (major)\n\n- **Status:** ā ļø Pinned to 4.38.3 ā every newer 4.x release changes runtime behavior\n (verified 2026-06-11 by E2E A/B bisect on this codebase):\n - 4.39.0 / 4.40.0: build fails (SCSS parse error in input-date; fixed in 4.40.1)\n - 4.40.1: tooltip no longer hides when a popover opens\n (popover-button.e2e.ts:41 fails consistently); CI visual tests fail across all\n themes; hydrate output differs (e.g. kol-input-file browse button renders\n `kol-button--normal` ā behavior drift in SSR output)\n - 4.41.0 ā 4.43.5: native Popover API broken ā `showPopover()` elements stay\n hidden (kol-popover, kol-popover-button, kol-split-button, table settings)\n- **Breaking Changes (v5):**\n - v5.0.0-alpha.7 is not production-ready (alpha channel)\n - Multiple output-target packages block v5 upgrade:\n - @public-ui/stencil-angular-output-target\n - @public-ui/stencil-react-output-target\n - @public-ui/stencil-solid-output-target\n - @public-ui/stencil-vue-output-target\n - @stencil/playwright requires >=4.13.0, conflicts with 5.x\n- **Risk:** VERY HIGH ā Core platform dependency\n- **Recommendation:** Stay on 4.38.3; before any future bump, run the popover/tooltip\n E2E suites and the visual tests against the candidate version\n- **Effort:** Would require coordinating 4+ downstream packages plus resolving the\n popover/tooltip regressions (upstream fix or component-side adaptation)\n\n### 2. **eslint** | 9.39.4 ā 10.1.0\n\n- **Breaking Changes:**\n - Legacy `.eslintrc.json` configuration is no longer supported; must migrate to flat config (`eslint.config.js`)\n - Node.js < v20.19.0 no longer supported\n - Config file lookup now starts from linted file's directory (beneficial for monorepos)\n - Formatter output depends on Node.js native `styleText()` API\n - NO_COLOR and NODE_DISABLE_COLORS environment variables now affect color output\n - FlatESLint and LegacyESLint deprecated APIs removed\n - JSX reference tracking improved (may affect scope-dependent rules)\n- **Peer Dependencies:** Requires @eslint/js ^10.0.0 and eslint-plugin-jsx-a11y compatibility\n- **Config Changes:** Must convert `.eslintrc.json` to `eslint.config.js` (tool available: `eslint --init`)\n- **Risk:** HIGH ā Affects all linting configuration\n- **Effort:** MEDIUM ā Config migration required but automation tools available\n- **Roadmap:** [Migrate to v10.x](https://eslint.org/docs/latest/use/migrate-to-10.0.0)\n\n### 3. **jest** | 26.6.3 ā 30.3.0\n\n- **Breaking Changes:**\n - Node.js 14, 16, 19, 21 no longer supported (require >=18.x, >=20.x)\n - Minimum TypeScript now 5.4+\n - jest-environment-jsdom upgraded from jsdom 21 ā jsdom 26 (spec compliance changes)\n - Mocking `window.location` behavior may change\n - Deprecated alias methods removed (e.g., `toBeTruthy()` aliases)\n - Non-enumerable object properties excluded from matchers by default\n - `jest.mock()` now case-sensitive (affects Windows edge cases)\n - `jest.genMockFromModule()` removed (use `jest.createMockFromModule()`)\n - `--testPathPattern` renamed to `--testPathPatterns`\n - Performance: Real-world speedups from optimizations\n- **Risk:** HIGH ā Core testing framework with wide breaking surface\n- **Effort:** MEDIUM ā HIGH ā Will require test review and fixes\n- **Migration:** [Jest 30 Migration Guide](https://jestjs.io/docs/upgrading-to-jest30)\n\n### 4. **TypeScript** | 5.9.3 ā 6.0.2\n\n- **Breaking Changes:**\n - `moduleResolution: classic` removed (only nodenext, bundler supported)\n - AMD, UMD, SystemJS modules removed (ESM only)\n - `esModuleInterop` and `allowSyntheticDefaultImports` cannot be set to false\n - `target: es5` deprecated; minimum ES2015\n - All code treated as strict mode (automatic \"use strict\" emission)\n- **Config Migration:** Migration CLI available: `npx @andrewbranch/ts5to6`\n- **Impact:** May be low if tsconfig.json is explicit and uses modern settings\n- **Peer:** @stencil-community/eslint-plugin requires ^4.9.4 || ^5.0.0 (blocks 6.0+)\n- **Risk:** MEDIUM ā Language compiler fundamental shift\n- **Effort:** LOW ā MEDIUM ā Config migration mostly automatic\n- **Roadmap:** [TypeScript 5.x to 6.0 Migration Guide](https://gist.github.com/privatenumber/3d2e80da28f84ee30b77d53e1693378f)\n\n### 5. **@angular/core** | 19.2.20 ā 22.0.0-next.5 (Angular v19, v20, v21 adapters)\n\n- **Packages Affected:**\n - `/packages/adapters/angular/v19/`: 19.2.20 ā 22.0.0-next.5\n - `/packages/adapters/angular/v20/`: 20.3.18 ā 22.0.0-next.5\n - `/packages/adapters/angular/v21/`: 21.2.6 ā 22.0.0-next.5\n- **Breaking Changes (v20+):**\n - Node.js >=22.22.0 required (v24.13.1+) ā v20 no longer supported\n - TypeScript >=5.8 required\n - Zoneless applications now stable (Zone.js side effects deprecated)\n - Ivy strict mode enabled by default\n - ViewEngine completely removed\n - NgModules support deprecated in favor of standalone components\n- **Complexity:** Enterprise applications can take weeks to migrate\n- **Related:** Also affects @angular/compiler, @angular/compiler-cli, zone.js, @angular/common\n- **Risk:** VERY HIGH ā Multi-framework adapter dependencies\n- **Effort:** HIGH ā Complete architectural review needed\n- **Roadmap:** [Angular Update Guide](https://angular.dev/update-guide)\n\n---\n\n## š” High (Test-Intensive Upgrades)\n\n### 1. **jest** (component package) | 26.6.3 ā 30.3.0\n\n- **Location:** `/packages/components/`\n- **Risk:** Same as critical jest (see above), but scoped to component tests\n- **Effort:** MEDIUM\n- **Testing:** All component unit tests must run and pass\n\n### 2. **@types/jest** | 26.0.24 ā 30.0.0\n\n- **Breaking:** TypeScript types for jest@30 (follows jest breaking changes)\n- **Dependency:** Must upgrade together with jest\n- **Risk:** MEDIUM\n- **Effort:** LOW ā Automatic with jest upgrade\n\n### 3. **knip** | 5.88.1 ā 6.1.0 (components, stylelint-rules)\n\n- **Breaking Changes:**\n - Node.js <v20.19.0 no longer supported\n - Issue type `classMembers` removed\n - `--include-libs` and `--isolate-workspaces` flags removed (now default)\n - `--experimental-tags` renamed to `--tags`\n - `issues.files` structure changes in reporters\n - `issues._files` removed\n - Root files removed\n- **Packages:** tools/stylelint-rules, components\n- **Risk:** MEDIUM ā Unused-code detection configuration changes\n- **Effort:** LOW ā MEDIUM ā Config review needed\n- **Roadmap:** [knip v6 Releases](https://github.com/webpro-nl/knip/releases)\n\n### 4. **@types/color-convert** | 2.0.4 ā 3.0.1 + **color-rgba** | 2.4.0 ā 3.0.0\n\n- **Location:** `/packages/components/`\n- **Breaking Changes:** Major version bump on color-rgba (internal API changes likely)\n- **Risk:** MEDIUM ā Type definitions and color processing\n- **Effort:** LOW ā Likely compatible\n- **Notes:** These are typically non-breaking for consumers\n\n### 5. **@typescript-eslint/eslint-plugin** & **@typescript-eslint/parser** | 8.57.2 ā 8.58.0 (patch)\n\n- **Note:** ncu shows 8.58.1-alpha.0 as \"greatest\" but 8.58.0 is stable latest\n- **Peer:** @stencil-community/eslint-plugin requires ^7.0.0 || ^8.0.0\n- **Risk:** LOW\n- **Effort:** LOW ā Patch upgrade\n\n### 6. **cssnano** | 7.1.3 ā 7.1.4\n\n- **Risk:** LOW ā Patch-level CSS minifier\n- **Effort:** LOW\n\n### 7. **postcss-sorting** | 9.1.0 ā 10.0.0\n\n- **Location:** `/packages/components/`\n- **Breaking Changes:** Likely minor API changes (changelog not specific in v9āv10)\n- **Risk:** MEDIUM ā CSS property ordering configuration\n- **Effort:** LOW ā MEDIUM\n- **Roadmap:** [postcss-sorting CHANGELOG](https://github.com/hudochenkov/postcss-sorting/blob/master/CHANGELOG.md)\n\n### 8. **mocha** | 11.7.5 ā 12.0.0-beta-9\n\n- **Status:** Beta release only\n- **Breaking:** Likely breaking changes in beta\n- **Risk:** MEDIUM\n- **Effort:** MEDIUM ā Wait for stable v12.0.0 release\n- **Recommendation:** Defer until stable release\n\n### 9. **cpy-cli** | 6.0.0 ā 7.0.0 (themes package)\n\n- **Breaking:** Major file copy utility version\n- **Risk:** MEDIUM ā Copy script behavior changes likely\n- **Effort:** LOW ā MEDIUM\n- **Testing:** Verify theme build output\n\n---\n\n## š¢ Low (Safe Upgrades)\n\n### 1. **@eslint/js** | 9.39.4 ā 10.0.1 (themes, stylelint-rules, components)\n\n- **Peer Dependency:** Requires eslint ^10.0.0 (blocks eslint upgrade dependency)\n- **Risk:** LOW ā Language rule sets\n- **Effort:** LOW\n- **Upgrade Path:** Do together with eslint v10.0.0\n\n### 2. **minimatch** | 10.2.4 ā 10.2.5 (React, Vue, Svelte, Angular v19/v20/v21)\n\n- **Type:** Patch-level glob matching utility\n- **Risk:** VERY LOW\n- **Effort:** TRIVIAL\n\n### 3. **rollup** | 4.60.0 ā 4.60.1 (themes)\n\n- **Type:** Patch-level bundler\n- **Risk:** VERY LOW\n- **Effort:** TRIVIAL\n\n### 4. **npm-run-all2** | 8.0.4 ā 8.1.0-beta.0 (root)\n\n- **Note:** Beta version only\n- **Risk:** LOW (beta)\n- **Recommendation:** Wait for stable 8.1.0\n\n### 5. **stylelint-order** | 7.0.1 ā 8.1.1 (root)\n\n- **Type:** CSS plugin\n- **Risk:** LOW ā Property ordering\n- **Effort:** LOW\n\n### 6. **svelte** | ^5.55.0 ā ^5.55.1 (svelte adapter)\n\n- **Type:** Patch-level framework\n- **Risk:** VERY LOW\n- **Effort:** TRIVIAL\n\n### 7. **@babel/types** | 7.29.0 ā 8.0.0-rc.3 (Vue, Svelte adapters)\n\n- **Status:** Release candidate\n- **Risk:** MEDIUM (RC stage)\n- **Effort:** LOW\n- **Recommendation:** Wait for stable 8.0.0 release\n\n### 8. **zone.js** | 0.15.1 ā 0.16.1 (Angular adapters v19-v21)\n\n- **Type:** Angular zone management\n- **Dependency:** Follows Angular major versions\n- **Risk:** LOW (if upgrading Angular)\n- **Effort:** LOW\n\n---\n\n## Summary\n\n### Upgrade Statistics\n\n| Category | Count | Total Packages Affected |\n| --------------------------------- | ------- | ---------------------------- |\n| š“ Critical | 5 | 9 packages (with variations) |\n| š” High | 9 | 7 unique packages |\n| š¢ Low | 8 | 15 unique packages |\n| **Total Unique Upgradeable Deps** | **~22** | **Across entire monorepo** |\n\n### Critical Blockers & Interdependencies\n\n```\n1. @stencil/core@5 BLOCKED by:\n - @public-ui/stencil-angular-output-target (requires >=4)\n - @public-ui/stencil-react-output-target (requires >=4)\n - @public-ui/stencil-solid-output-target (requires >=2.17.2)\n - @public-ui/stencil-vue-output-target (requires >=4)\n - @stencil/playwright (requires >=4.13.0)\n ACTION: Keep on 4.38.3 ā 4.39+ regresses popover/tooltip behavior (see Critical #1);\n v5 additionally blocked until output-targets are v5-compatible\n\n2. eslint@10.0.0 blocks:\n - @stencil-community/eslint-plugin (requires ^8.0.0 || ^9.0.0)\n - eslint-plugin-jsx-a11y (requires ^8.0.0 || ^9.0.0)\n ACTION: Coordinate multi-package eslint migration\n\n3. prettier@3.8.1 blocked by:\n - prettier-plugin-organize-imports (requires >=2.0)\n ACTION: prettier@4.0.0-alpha.13 incompatible; stay on v3\n\n4. TypeScript@6.0.2 blocked by:\n - @stencil-community/eslint-plugin (requires ^4.9.4 || ^5.0.0)\n ACTION: Stay on TypeScript 5.x for now\n\n5. Angular@22 (next.5) not stable:\n - v20: Angular-specific adapters only\n - Migration complex: weeks for enterprise apps\n ACTION: Keep Angular adapters on current major versions\n```\n\n### Recommended Upgrade Priority\n\n#### Phase 1 (Immediate ā Low Risk)\n\n- ā
minimatch (10.2.4 ā 10.2.5) ā patch only\n- ā
rollup (4.60.0 ā 4.60.1) ā patch only\n- ā
stylelint-order (7.0.1 ā 8.1.1) ā CSS plugin\n- ā
cssnano (7.1.3 ā 7.1.4) ā patch only\n\n#### Phase 2 (Short-term ā High Effort)\n\n- ā ļø jest@30 + @types/jest@30 ā test suite migration (2-5 days)\n - Scoped start: `/packages/components/` component tests\n - Follow with root/adapters test suites\n- ā ļø eslint@10 + @eslint/js@10 ā config migration (1-3 days)\n - Convert `.eslintrc.json` ā `eslint.config.js`\n - Test all lint rules\n - Update CI/CD pipelines\n\n#### Phase 3 (Medium-term ā Coordinate)\n\n- ā ļø TypeScript@6 ā only after reviewing @stencil-community/eslint-plugin compatibility\n- ā ļø knip@6 ā unused-code detection, config review (0.5-1 day)\n\n#### Phase 4 (Blocked ā Wait for Stable)\n\n- ā prettier@4.0.0-alpha ā keep v3 until stable (blocked by prettier-plugin-organize-imports)\n- ā @stencil/core@5 ā wait for output-target compatibility\n- ā Angular@22 ā stay on v19/v20/v21 adapter versions (production-critical)\n- ā mocha@12, @babel/types@8 ā wait for stable releases (beta only)\n\n### Estimated Overall Effort\n\n| Phase | Effort | Timeline | Risk |\n| -------------------------- | ------------- | ------------- | ----------- |\n| Phase 1 | LOW | 0.5-1 hour | VERY LOW |\n| Phase 2 | HIGH | 3-5 days | MEDIUM-HIGH |\n| Phase 3 | MEDIUM | 1-2 days | MEDIUM |\n| Phase 4 | BLOCKED | N/A | BLOCKED |\n| **Total (if all applied)** | **VERY HIGH** | **2-3 weeks** | **HIGH** |\n\n---\n\n## Research Sources\n\n- [Migrate to ESLint v10.x](https://eslint.org/docs/latest/use/migrate-to-10.0.0)\n- [Jest 30 Migration Guide](https://jestjs.io/docs/upgrading-to-jest30)\n- [TypeScript 5.x to 6.0 Migration Guide](https://gist.github.com/privatenumber/3d2e80da28f84ee30b77d53e1693378f)\n- [Angular Update Guide](https://angular.dev/update-guide)\n- [Knip v6 Releases](https://github.com/webpro-nl/knip/releases)\n- [Stencil Releases](https://github.com/ionic-team/stencil/releases)\n- [postcss-sorting CHANGELOG](https://github.com/hudochenkov/postcss-sorting/blob/master/CHANGELOG.md)\n",
|
|
505
505
|
"kind": "doc"
|
|
506
506
|
},
|
|
507
|
+
{
|
|
508
|
+
"id": "doc/visual-review",
|
|
509
|
+
"group": "docs",
|
|
510
|
+
"name": "visual-review",
|
|
511
|
+
"path": "docs/visual-review.md",
|
|
512
|
+
"code": "# Visual Review\n\nHow screenshot changes of the KoliBri themes are detected, published and approved.\n\n## In one picture\n\n```\npush to develop āāāŗ Visual Baseline workflow āāāŗ artifact visual-baseline-<package> (per commit, 90 days)\n\npull request push āāāŗ CI-Pipeline, job visual-tests (<package>)\n compares against the baseline of the base commit\n āāāŗ artifact visual-review-<package> (report.json + changed images)\n ā\n ā¼\n Visual Review workflow (base repository context)\n publishes visual/pr-<n>/ on GitHub Pages\n reads the reviewers' comments\n sets the commit status \"Visual Review\"\n ā\n ā¼\nreviewer āāāŗ https://public-ui.github.io/kolibri/visual/?pr=<n>\n inspects baseline / actual / diff, approves or rejects, leaves notes\n saves the review as a pull-request comment (directly with a token, or by pasting it)\n```\n\n## What a contributor sees\n\n- The job `visual-tests (<package>)` of the CI-Pipeline fails when screenshots differ ā that is\n expected and not something to \"fix\" by regenerating snapshots. The job summary lists what changed.\n- The bot comment **šø Visual Review** on the pull request links the review page and shows the counts\n per package.\n- The commit status **Visual Review** stays `pending` until a reviewer with write access approved every\n changed, added and removed screenshot, turns `success` then, and `failure` when a screenshot was\n rejected or a route could not be compared at all (missing block, timeout).\n- Docs-only pull requests get `success` immediately; nothing to review.\n\nNothing has to be committed: the baseline is regenerated from `develop` after the merge.\n\n## What a reviewer does\n\n1. Open the review page from the bot comment (or the status link).\n2. Walk through the changed, added and removed snapshots (`j`/`k` or the list). Compare with\n _side by side_, _slider_, _onion skin_, _diff_ or _blink_; zoom in for subpixel changes.\n3. Approve (`a`), reject or annotate each one ā or **Approve all open changes** for an intentional\n sweep such as a browser upgrade.\n4. Save the review:\n - **with a token**: enter a fine-grained personal access token with _Pull requests: read and write_\n for `public-ui/kolibri` at the bottom of the page. The page posts (and later edits) one comment\n in your name. The token stays in this browser session unless you tick \"remember\".\n - **without a token**: click _Copy comment for the pull request_ and paste it as a comment on the\n pull request. To change your verdict later, edit that comment or post a new one ā only your\n newest comment counts.\n\nThe comment carries a machine-readable block, for example:\n\n```markdown\n<!-- visual-review:v1\n{\"approveAll\":{\"digest\":\"sha256:ā¦\"},\"approvals\":[{\"item\":\"theme-default/button-basic--variants\",\"hash\":\"sha256:ā¦\"}],\"rejects\":[],\"notes\":[]}\n-->\n\n**Visual Review** ā all changes approved ([review page](ā¦))\n```\n\nApprovals bind to the **content hash** of a screenshot, not to a commit: a later push that leaves an\napproved screenshot untouched keeps its approval, a push that changes it again reopens exactly that\none. `approveAll` binds to the digest of the whole report and therefore expires with the next change.\n\nOnly comments of users with write access count. Bots are ignored. A rejection wins over an approval.\n\n## Where things live\n\n| What | Where |\n| -------------------------------- | ------------------------------------------------------------------------------------- |\n| Report per package (CI artifact) | `visual-review-<package>` ā `report.json` + PNGs of changed items, 14 days |\n| Baseline per base commit | `visual-baseline-<package>` ā snapshots + `meta.json`, 90 days |\n| Published review data | `gh-pages`: `visual/pr-<n>/report.json`, `status.json`, `<package>/<name>.<kind>.png` |\n| Review page | `gh-pages`: `visual/` (built from `packages/tools/visual-tests/review-ui`) |\n| Reporter | `packages/tools/visual-tests/src/visual-reporter.js` |\n| Workflow scripts | `scripts/visual-review/` (see `scripts/README.md`) |\n| Workflows | `visual-baseline.yml`, `visual-review.yml`, `visual-review-ui.yml`, job in `ci.yml` |\n\nThe folder `visual/pr-<n>/` is removed when the pull request closes (`pr-preview-cleanup.yml`).\n\n## Trust boundary\n\nThe reports come from the pull request's own CI run, i.e. from code the pull request controls. The\nVisual Review workflow never executes that code: it downloads the artifacts, validates every field and\nfile name (`merge-reports.mjs`) and publishes only what passes. A pull request could still upload a\nreport that claims \"no changes\" ā the human review of the code and the branch protection remain the\nactual safeguard; the visual review makes intentional changes visible and reviewable, it does not\nreplace code review.\n\n## Local work\n\n```bash\npnpm snapshots:pull # fetch the current develop baseline into the snapshot folders\npnpm --filter @public-ui/theme-default test\npnpm --filter @public-ui/visual-tests review-ui:dev # the review page against a local report: ?src=<folder>\n```\n\n`pnpm test:update:docker <theme>` regenerates a baseline locally in the pinned Playwright container.\n",
|
|
513
|
+
"kind": "doc"
|
|
514
|
+
},
|
|
507
515
|
{
|
|
508
516
|
"id": "doc/WORKFLOW_OPTIMIZATION_PLAN",
|
|
509
517
|
"group": "docs",
|
|
@@ -605,7 +613,7 @@
|
|
|
605
613
|
"group": "button-link",
|
|
606
614
|
"name": "basic",
|
|
607
615
|
"path": "packages/samples/react/src/components/button-link/basic.tsx",
|
|
608
|
-
"code": "import
|
|
616
|
+
"code": "import { KolButtonLink, KolHeading } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonLinkBasic: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tKolButtonLink shows an element, that behaves like a button but looks like a link. The sample illustrates KolButtonLink with different\n\t\t\t\t\tdisplay-properties such as <code>block</code>, <code>inline-block</code> and <code>inline</code>. It also demonstrates the disabled-state.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\t\t\t<KolHeading _level={2} _label=\"Button-Link with _inline\" />\n\n\t\t\t<p>\n\t\t\t\tIn this paragraph, a link is inserted that contains no additional attributes. <KolButtonLink _label=\"Simple Link\" /> It is rendered by default as an{' '}\n\t\t\t\t<strong>inline element</strong>.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tIn this paragraph, a link is inserted that is rendered as an inline-block element.\n\t\t\t\t<KolButtonLink className=\"m-4\" style={{ display: 'inline-block', border: '1px dotted' }} _label=\"Simple Link\" />. This allows you to assign width,\n\t\t\t\theight, and other properties to it using CSS styles.\n\t\t\t\t<br />\n\t\t\t\t<br />\n\t\t\t\tAfter that, there is a link that is rendered as a block element.\n\t\t\t\t<KolButtonLink style={{ display: 'block' }} _label=\"Simple Link\" />\n\t\t\t\tTherefore, I go over the entire width of the parent element to create a line break.\n\t\t\t</p>\n\n\t\t\t<KolHeading _level={2} _label=\"Button-Link with _inline={false}\" />\n\n\t\t\t<p>Use the boolean _inline property to render the link inline (default) or standalone.</p>\n\n\t\t\t<SampleBlock id=\"basic\" className=\"flex flex-col gap-2\" fitContent>\n\t\t\t\t<KolButtonLink _label=\"Standalone ButtonLink\" _inline={false} _on={dummyEventHandler} />\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"disabled\" className=\"flex flex-col gap-2\" fitContent>\n\t\t\t\t<KolButtonLink _label=\"Disabled ButtonLink\" _disabled _inline={false} />\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"access-key\" className=\"flex flex-col gap-2\" fitContent>\n\t\t\t\t<KolButtonLink _label=\"With access key\" _accessKey=\"c\" _inline={false} _on={dummyEventHandler} />\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"short-key\" className=\"flex flex-col gap-2\" fitContent>\n\t\t\t\t<KolButtonLink _label=\"With short key\" _shortKey=\"s\" _inline={false} _on={dummyEventHandler} />\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"variant\" className=\"flex flex-col gap-2\" fitContent>\n\t\t\t\t<KolButtonLink _label=\"Special Variant ButtonLink\" _variant=\"theme-link\" />\n\t\t\t</SampleBlock>\n\t\t</>\n\t);\n};\n",
|
|
609
617
|
"kind": "sample"
|
|
610
618
|
},
|
|
611
619
|
{
|
|
@@ -629,7 +637,7 @@
|
|
|
629
637
|
"group": "button",
|
|
630
638
|
"name": "access-key",
|
|
631
639
|
"path": "packages/samples/react/src/components/button/access-key.tsx",
|
|
632
|
-
"code": "import { KolButton, KolLink } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
640
|
+
"code": "import { KolButton, KolLink } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonAccessKey: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates buttons with{' '}\n\t\t\t\t\t<KolLink _label=\"access keys\" _href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/accesskey\" _target=\"blank\" />. Access keys\n\t\t\t\t\tallow users to trigger buttons using keyboard shortcuts.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"buttons-access-keys\" heading=\"Buttons with Access Keys\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _label=\"With S access key\" _accessKey=\"S\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _label=\"Very small b\" _accessKey=\"b\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _label=\"Access key does not appear in label\" _accessKey=\"x\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"access-key-hidden-label\" heading=\"Access Key with Hidden Label\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _label=\"access key without label\" _hideLabel _accessKey=\"a\" _icons=\"kolicon-cogwheel\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"access-key-inline-icons\" heading=\"Access Key with Inline Icons\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_label=\"with inline icons\"\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t\tright: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_accessKey=\"n\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
633
641
|
"kind": "sample"
|
|
634
642
|
},
|
|
635
643
|
{
|
|
@@ -637,7 +645,7 @@
|
|
|
637
645
|
"group": "button",
|
|
638
646
|
"name": "aria-description",
|
|
639
647
|
"path": "packages/samples/react/src/components/button/aria-description.tsx",
|
|
640
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
648
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonAriaDescription: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates buttons with ARIA descriptions. The aria-description attribute provides additional descriptive text for screen readers,\n\t\t\t\t\thelping users understand the button's purpose or action in more detail.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"buttons-aria-description\" heading=\"Buttons with and without ARIA Description\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _label=\"Button without ARIA description\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _label=\"Button with ARIA description\" _ariaDescription=\"This button performs an important action\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
641
649
|
"kind": "sample"
|
|
642
650
|
},
|
|
643
651
|
{
|
|
@@ -645,7 +653,7 @@
|
|
|
645
653
|
"group": "button",
|
|
646
654
|
"name": "baselined",
|
|
647
655
|
"path": "packages/samples/react/src/components/button/baselined.tsx",
|
|
648
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
656
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonBaselined: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates button baseline alignment. It shows multiple buttons with and without icons that are vertically aligned, useful for testing\n\t\t\t\t\tlayout consistency.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"vertically-aligned-buttons\" heading=\"Vertically Aligned Buttons\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-2\">\n\t\t\t\t\t\t<KolButton _label=\"Label-Text\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-cogwheel\" _label=\"Label-Text with Icon\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
649
657
|
"kind": "sample"
|
|
650
658
|
},
|
|
651
659
|
{
|
|
@@ -653,7 +661,7 @@
|
|
|
653
661
|
"group": "button",
|
|
654
662
|
"name": "basic",
|
|
655
663
|
"path": "packages/samples/react/src/components/button/basic.tsx",
|
|
656
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
664
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonBasic: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates the most important features of the KolButton component. It showcases the different button variants, icons, disabled state, and\n\t\t\t\t\thidden labels.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"variants\" heading=\"Button Variants\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-house\" _label=\"Primary\" _variant=\"primary\" onClick={dummyClickEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-kolibri\" _label=\"Secondary\" _variant=\"secondary\" onClick={dummyClickEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-cogwheel\" _label=\"Tertiary\" _variant=\"tertiary\" onClick={dummyClickEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-cogwheel\" _label=\"Normal\" _variant=\"normal\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-alert-warning\" _label=\"Danger\" _variant=\"danger\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-eye-closed\" _label=\"Ghost\" _variant=\"ghost\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"disabled\" heading=\"Disabled State\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-house\" _label=\"Primary\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-kolibri\" _label=\"Secondary\" _variant=\"secondary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-alert-warning\" _label=\"Danger\" _variant=\"danger\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"hide-label\" heading=\"Hidden Label (Icon Only)\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-house\" _label=\"Primary\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-kolibri\" _label=\"Secondary\" _variant=\"secondary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-alert-warning\" _label=\"Danger\" _variant=\"danger\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"icon-positions\" heading=\"Icon Positions\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-chevron-left',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Icon Left\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tright: 'kolicon-chevron-right',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Icon Right\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-chevron-left',\n\t\t\t\t\t\t\t\tright: 'kolicon-chevron-right',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Icons Both Sides\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
657
665
|
"kind": "sample"
|
|
658
666
|
},
|
|
659
667
|
{
|
|
@@ -661,7 +669,7 @@
|
|
|
661
669
|
"group": "button",
|
|
662
670
|
"name": "disabled",
|
|
663
671
|
"path": "packages/samples/react/src/components/button/disabled.tsx",
|
|
664
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
672
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonDisabled: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This story demonstrates the disabled state of buttons. Disabled buttons are not clickable and appear visually dimmed.</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"disabled\" heading=\"Disabled Buttons\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-house\" _label=\"Primary\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-kolibri\" _label=\"Secondary\" _variant=\"secondary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-cogwheel\" _label=\"Tertiary\" _variant=\"tertiary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-cogwheel\" _label=\"Normal\" _variant=\"normal\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-alert-warning\" _label=\"Danger\" _variant=\"danger\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-eye-closed\" _label=\"Ghost\" _variant=\"ghost\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"comparison\" heading=\"Comparison: Enabled vs Disabled\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-house\" _label=\"Enabled\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-house\" _label=\"Disabled\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
665
673
|
"kind": "sample"
|
|
666
674
|
},
|
|
667
675
|
{
|
|
@@ -669,7 +677,7 @@
|
|
|
669
677
|
"group": "button",
|
|
670
678
|
"name": "expert-slot",
|
|
671
679
|
"path": "packages/samples/react/src/components/button/expert-slot.tsx",
|
|
672
|
-
"code": "import { KolButton, KolIcon } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
680
|
+
"code": "import { KolButton, KolIcon } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nimport './expert-slot.tooltip.scss';\n\nconst KolTooltip = 'kol-tooltip-wc' as unknown as React.FC<{ _label: string }>;\n\nexport const ButtonExpertSlot: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates the expert slot feature of KolButton. The expert slot allows you to insert custom content into the button, providing advanced\n\t\t\t\t\tcustomization options beyond the standard label and icon properties.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"buttons-expert-slot-content\" heading=\"Buttons with Expert Slot Content\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-house\" _label=\"\" _variant=\"primary\" _on={dummyEventHandler}>\n\t\t\t\t\t\t\t<span slot=\"expert\">I am more than just a button</span>\n\t\t\t\t\t\t</KolButton>\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-kolibri\" _label=\"\" _variant=\"secondary\" _on={dummyEventHandler}>\n\t\t\t\t\t\t\t<span slot=\"expert\">Custom content here</span>\n\t\t\t\t\t\t</KolButton>\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-alert-warning\" _label=\"\" _variant=\"danger\" _on={dummyEventHandler}>\n\t\t\t\t\t\t\t<span slot=\"expert\">Delete with custom text</span>\n\t\t\t\t\t\t</KolButton>\n\t\t\t\t\t\t<KolButton _label=\"\" _variant=\"danger\" _on={dummyEventHandler}>\n\t\t\t\t\t\t\t<KolIcon _icons=\"kolicon-alert-warning\" _label=\"Delete with custom text\" slot=\"expert\" />\n\t\t\t\t\t\t</KolButton>\n\t\t\t\t\t\t<KolTooltip _label=\"Delete with custom text\" />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"disabled-buttons-expert-slot\" heading=\"Disabled Buttons with Expert Slot\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-house\" _label=\"\" _variant=\"primary\" _on={dummyEventHandler}>\n\t\t\t\t\t\t\t<span slot=\"expert\">Disabled expert slot</span>\n\t\t\t\t\t\t</KolButton>\n\t\t\t\t\t\t<KolButton _disabled _icons=\"kolicon-eye-closed\" _label=\"\" _variant=\"ghost\" _on={dummyEventHandler}>\n\t\t\t\t\t\t\t<span slot=\"expert\">Another disabled one</span>\n\t\t\t\t\t\t</KolButton>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
673
681
|
"kind": "sample"
|
|
674
682
|
},
|
|
675
683
|
{
|
|
@@ -677,7 +685,7 @@
|
|
|
677
685
|
"group": "button",
|
|
678
686
|
"name": "fixed-grid",
|
|
679
687
|
"path": "packages/samples/react/src/components/button/buttons-in-fixed-grid.tsx",
|
|
680
|
-
"code": "import { KolButton, KolLinkButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
688
|
+
"code": "import { KolButton, KolLinkButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonInFixedGrid: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>All this buttons are in a grid with fixed height (60px) and width (25% of screen) and should accept this dimensions.</p>\n\t\t\t</SampleDescription>\n\t\t\t<div className=\"grid gap-4 fixed-height-grid\">\n\t\t\t\t<KolButton _variant=\"primary\" _icons=\"kolicon-house\" _label=\"Button\" _on={dummyEventHandler} />\n\t\t\t\t<KolButton _variant=\"primary\" _hideLabel _icons=\"kolicon-house\" _label=\"Button\" _on={dummyEventHandler} />\n\t\t\t\t<KolLinkButton _variant=\"primary\" _href=\"#\" _icons=\"kolicon-house\" _label=\"Link-Button\" _on={dummyEventHandler} />\n\t\t\t\t<KolLinkButton _variant=\"primary\" _hideLabel _href=\"#\" _icons=\"kolicon-house\" _label=\"Link-Button\" _on={dummyEventHandler} />\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
681
689
|
"kind": "sample"
|
|
682
690
|
},
|
|
683
691
|
{
|
|
@@ -693,7 +701,7 @@
|
|
|
693
701
|
"group": "button",
|
|
694
702
|
"name": "hide-label",
|
|
695
703
|
"path": "packages/samples/react/src/components/button/hide-label.tsx",
|
|
696
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
704
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonHideLabel: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates buttons with hidden labels. The label is still accessible to screen readers but visually hidden, showing only the icon. This\n\t\t\t\t\tis useful for icon-only buttons.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"hide-label\" heading=\"Buttons with Hidden Labels\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-house\" _label=\"Home\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-kolibri\" _label=\"Like\" _variant=\"secondary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-cogwheel\" _label=\"Subscribe\" _variant=\"tertiary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-cogwheel\" _label=\"Buy me a coffee\" _variant=\"normal\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-alert-warning\" _label=\"Delete\" _variant=\"danger\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-eye-closed\" _label=\"Settings\" _variant=\"ghost\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"comparison\" heading=\"Comparison: With and Without Hidden Label\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-house\" _label=\"Home\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-house\" _label=\"Home\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"disabled\" heading=\"Disabled with Hidden Label\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _disabled _hideLabel _icons=\"kolicon-house\" _label=\"Home\" _variant=\"primary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _hideLabel _icons=\"kolicon-kolibri\" _label=\"Like\" _variant=\"secondary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _hideLabel _icons=\"kolicon-cogwheel\" _label=\"Subscribe\" _variant=\"tertiary\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _hideLabel _icons=\"kolicon-cogwheel\" _label=\"Buy me a coffee\" _variant=\"normal\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _hideLabel _icons=\"kolicon-alert-warning\" _label=\"Delete\" _variant=\"danger\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
697
705
|
"kind": "sample"
|
|
698
706
|
},
|
|
699
707
|
{
|
|
@@ -701,7 +709,7 @@
|
|
|
701
709
|
"group": "button",
|
|
702
710
|
"name": "icons",
|
|
703
711
|
"path": "packages/samples/react/src/components/button/icons.tsx",
|
|
704
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
712
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonIcons: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story showcases buttons with icons in various positions and configurations. Icons can be placed on the left, right, top, bottom, or in multiple\n\t\t\t\t\tpositions at once.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"basic-positions\" heading=\"Basic Icon Positions\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-chevron-left',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Icon Left\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tright: 'kolicon-chevron-right',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Icon Right\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\ttop: 'kolicon-chevron-up',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Icon Top\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tbottom: 'kolicon-chevron-down',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Icon Bottom\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"multiple-positions\" heading=\"Multiple Icon Positions\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-chevron-left',\n\t\t\t\t\t\t\t\tright: 'kolicon-chevron-right',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Left & Right\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\ttop: 'kolicon-chevron-up',\n\t\t\t\t\t\t\t\tbottom: 'kolicon-chevron-down',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Top & Bottom\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"all-positions\" heading=\"All Icon Positions\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\ttop: 'kolicon-chevron-up',\n\t\t\t\t\t\t\t\tbottom: 'kolicon-chevron-down',\n\t\t\t\t\t\t\t\tleft: 'kolicon-chevron-left',\n\t\t\t\t\t\t\t\tright: 'kolicon-chevron-right',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"All Directions\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"icon-string\" heading=\"Simple Icon String\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-house\" _label=\"Home Icon\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-kolibri\" _label=\"Heart Icon\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _icons=\"kolicon-alert-warning\" _label=\"Trash Icon\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"large-icon\" heading=\"Large Icon on Top\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\ttop: {\n\t\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\t'font-size': '400%',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\ticon: 'kolicon-house',\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Home\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
705
713
|
"kind": "sample"
|
|
706
714
|
},
|
|
707
715
|
{
|
|
@@ -717,7 +725,7 @@
|
|
|
717
725
|
"group": "button",
|
|
718
726
|
"name": "short-key",
|
|
719
727
|
"path": "packages/samples/react/src/components/button/short-key.tsx",
|
|
720
|
-
"code": "import { KolAlert, KolButton, KolLink } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
728
|
+
"code": "import { KolAlert, KolButton, KolLink } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonShortKey: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\t// The short key announced via `_shortKey` is purely visual/assistive ā it does NOT\n\t// wire up a keyboard handler. The example below shows how to make it interactive by\n\t// registering a matching `keydown` listener yourself.\n\tconst interactiveShortKey = 'm';\n\t// Keep a stable reference to the (per-render) handler so the global listener is\n\t// registered only once instead of on every render.\n\tconst dummyClickEventHandlerRef = React.useRef(dummyClickEventHandler);\n\tReact.useEffect(() => {\n\t\tdummyClickEventHandlerRef.current = dummyClickEventHandler;\n\t}, [dummyClickEventHandler]);\n\tReact.useEffect(() => {\n\t\tconst handleKeyDown = (event: KeyboardEvent) => {\n\t\t\t// Match on `event.code` (layout-independent): on macOS, Alt + M emits a special\n\t\t\t// character, so `event.key` would not equal \"m\".\n\t\t\tif (event.altKey && event.code === 'KeyM') {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdummyClickEventHandlerRef.current();\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener('keydown', handleKeyDown);\n\t\treturn () => document.removeEventListener('keydown', handleKeyDown);\n\t}, []);\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates buttons with short keys. The short key is displayed as a visual indicator within the button label to communicate a recommended\n\t\t\t\t\tkeyboard shortcut to the user.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<KolAlert _label=\"Short keys are display-only\" _type=\"info\" _variant=\"card\">\n\t\t\t\t<p>\n\t\t\t\t\t<code>_shortKey</code> is <strong>purely visual and assistive</strong>: it renders the badge and announces the shortcut via{' '}\n\t\t\t\t\t<code>aria-keyshortcuts</code>, but it does <strong>not</strong> bind a keyboard handler. Pressing the displayed combination on its own does nothing ā\n\t\t\t\t\tyou have to register the listener yourself (see the interactive example below).\n\t\t\t\t</p>\n\t\t\t\t<p>\n\t\t\t\t\tIf you need a native, browser-handled shortcut instead, use{' '}\n\t\t\t\t\t<KolLink _label=\"_accessKey\" _href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/accesskey\" _target=\"_blank\" />. Note that\n\t\t\t\t\tnative access keys are triggered in a browser-specific way (e.g. <kbd>Alt</kbd> + <kbd>Shift</kbd> + key in Chrome on Windows).\n\t\t\t\t</p>\n\t\t\t</KolAlert>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"short-keys\" heading=\"Buttons with Short Keys\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _label=\"With S short key\" _shortKey=\"S\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _label=\"Very small b\" _shortKey=\"b\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _label=\"Short key does not appear in label\" _shortKey=\"x\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"hide-label\" heading=\"Short Key with Hidden Label\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _label=\"short key without label\" _hideLabel _shortKey=\"k\" _icons=\"kolicon-cogwheel\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"inline-icons\" heading=\"Short Key with Inline Icons\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\t_label=\"with inline icons\"\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t\tright: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_shortKey=\"n\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<p>\n\t\t\t\t\tThis button wires the announced short key up manually: a <code>keydown</code> listener triggers the same action as a click. Press <kbd>Alt</kbd> +{' '}\n\t\t\t\t\t<kbd>M</kbd> (or click the button) to open the toast.\n\t\t\t\t</p>\n\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t<KolButton _label=\"With working M short key\" _shortKey={interactiveShortKey} _on={dummyEventHandler} />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
721
729
|
"kind": "sample"
|
|
722
730
|
},
|
|
723
731
|
{
|
|
@@ -725,7 +733,7 @@
|
|
|
725
733
|
"group": "button",
|
|
726
734
|
"name": "spinner",
|
|
727
735
|
"path": "packages/samples/react/src/components/button/spinner.tsx",
|
|
728
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
736
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonSpinner: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story demonstrates icon-only buttons with an animated spinning loader icon. The animation is applied using CSS parts to target the icon element\n\t\t\t\t\tdirectly.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"animated-spinner-icon-css-part\" heading=\"Animated Spinner Icon via CSS Part\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\tclassName=\"spinner-button\"\n\t\t\t\t\t\t\t_hideLabel\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Loading\"\n\t\t\t\t\t\t\t_variant=\"primary\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\tclassName=\"spinner-button spinner-slow\"\n\t\t\t\t\t\t\t_hideLabel\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Syncing\"\n\t\t\t\t\t\t\t_variant=\"secondary\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\tclassName=\"spinner-button spinner-slower\"\n\t\t\t\t\t\t\t_hideLabel\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Processing\"\n\t\t\t\t\t\t\t_variant=\"tertiary\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"spinner-label\" heading=\"Spinner with Label\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\tclassName=\"spinner-button\"\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Loading...\"\n\t\t\t\t\t\t\t_variant=\"primary\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<KolButton\n\t\t\t\t\t\t\tclassName=\"spinner-button\"\n\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\tleft: 'kolicon-cogwheel',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t_label=\"Syncing...\"\n\t\t\t\t\t\t\t_variant=\"secondary\"\n\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\n\t\t\t<style>\n\t\t\t\t{`\n\t\t\t\t\t@keyframes spin {\n\t\t\t\t\t\tfrom {\n\t\t\t\t\t\t\ttransform: rotate(0deg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tto {\n\t\t\t\t\t\t\ttransform: rotate(360deg);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Target the icon part inside the button */\n\t\t\t\t\t.spinner-button::part(icon) {\n\t\t\t\t\t\tanimation: spin 1s linear infinite;\n\t\t\t\t\t}\n\n\t\t\t\t\t.spinner-slow::part(icon) {\n\t\t\t\t\t\tanimation-duration: 1.5s;\n\t\t\t\t\t}\n\n\t\t\t\t\t.spinner-slower::part(icon) {\n\t\t\t\t\t\tanimation-duration: 2s;\n\t\t\t\t\t}\n\n\t\t\t\t\t@media (prefers-reduced-motion) {\n\t\t\t\t\t\t.spinner-button::part(icon){\n\t\t\t\t\t\t\tanimation-duration: 10s;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t`}\n\t\t\t</style>\n\t\t</>\n\t);\n};\n",
|
|
729
737
|
"kind": "sample"
|
|
730
738
|
},
|
|
731
739
|
{
|
|
@@ -733,7 +741,7 @@
|
|
|
733
741
|
"group": "button",
|
|
734
742
|
"name": "variants",
|
|
735
743
|
"path": "packages/samples/react/src/components/button/variants.tsx",
|
|
736
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useMemo } from 'react';\nimport { useSearchParams } from 'react-router';\nimport {
|
|
744
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useMemo } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { useAlert } from '../../hooks/useAlert';\nimport { fetchVariantData } from '../../shares/fetchVariantData';\nimport { getTheme } from '../../shares/store';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonVariants: FC = () => {\n\tconst [searchParams] = useSearchParams();\n\tconst theme = searchParams.get('theme') ?? getTheme();\n\tconst data = useMemo(() => (theme ? fetchVariantData(theme, 'buttonVariants') : []), [theme]);\n\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis story showcases all available button variants for this theme. You can import <code>ButtonVariantsEnum</code> from your theme to always use the\n\t\t\t\t\tright variants.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"variants\" heading=\"All theme exclusive button variants\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4 items-center\">\n\t\t\t\t\t\t{!Array.isArray(data) || data.length === 0 ? (\n\t\t\t\t\t\t\t<p>This theme has no variants for this component.</p>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tdata.map((element) => {\n\t\t\t\t\t\t\t\treturn <KolButton _icons=\"kolicon-house\" _label={`${element}`} _variant={element} key={element} _on={dummyEventHandler} />;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4 items-center\">\n\t\t\t\t\t\t{!Array.isArray(data) || data.length === 0 ? (\n\t\t\t\t\t\t\t<p>This theme has no variants for this component.</p>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tdata.map((element) => {\n\t\t\t\t\t\t\t\treturn <KolButton _hideLabel _icons=\"kolicon-settings\" _label={`${element}`} _variant={element} key={element} _on={dummyEventHandler} />;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
737
745
|
"kind": "sample"
|
|
738
746
|
},
|
|
739
747
|
{
|
|
@@ -741,7 +749,7 @@
|
|
|
741
749
|
"group": "button",
|
|
742
750
|
"name": "width",
|
|
743
751
|
"path": "packages/samples/react/src/components/button/width.tsx",
|
|
744
|
-
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport {
|
|
752
|
+
"code": "import { KolButton } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const ButtonWidth: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst ARGS = {\n\t\tclassName: 'w-8rem',\n\t\t_on: {\n\t\t\tonClick: dummyClickEventHandler,\n\t\t},\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This story demonstrates buttons with custom widths. You can control the button width using CSS classes.</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"fixed-width-buttons-8rem\" heading=\"Fixed Width Buttons (8rem)\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _label=\"Primary\" _variant=\"primary\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _label=\"Secondary\" _variant=\"secondary\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _label=\"Normal\" _variant=\"normal\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _label=\"Danger\" _variant=\"danger\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _label=\"Ghost\" _variant=\"ghost\" {...ARGS} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\n\t\t\t\t<SampleBlock id=\"fixed-width-disabled-buttons\" heading=\"Fixed Width Disabled Buttons (8rem)\" fitContent>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _disabled _label=\"Primary\" _variant=\"primary\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _disabled _label=\"Secondary\" _variant=\"secondary\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _disabled _label=\"Normal\" _variant=\"normal\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _disabled _label=\"Danger\" _variant=\"danger\" {...ARGS} />\n\t\t\t\t\t\t<KolButton _disabled _label=\"Ghost\" _variant=\"ghost\" {...ARGS} />\n\t\t\t\t\t</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
745
753
|
"kind": "sample"
|
|
746
754
|
},
|
|
747
755
|
{
|
|
@@ -885,7 +893,7 @@
|
|
|
885
893
|
"group": "handout",
|
|
886
894
|
"name": "basic",
|
|
887
895
|
"path": "packages/samples/react/src/components/handout/basic.tsx",
|
|
888
|
-
"code": "import type { KoliBriTableCell, KoliBriTableHeaders } from '@public-ui/components';\nimport {\n\tKolAbbr,\n\tKolAccordion,\n\tKolAlert,\n\tKolBadge,\n\tKolBreadcrumb,\n\tKolButton,\n\tKolButtonLink,\n\tKolCard,\n\tKolDetails,\n\tKolForm,\n\tKolHeading,\n\tKolInputCheckbox,\n\tKolInputColor,\n\tKolInputDate,\n\tKolInputEmail,\n\tKolInputFile,\n\tKolInputNumber,\n\tKolInputPassword,\n\tKolInputRadio,\n\tKolInputRange,\n\tKolInputText,\n\tKolKolibri,\n\tKolLink,\n\tKolLinkButton,\n\tKolNav,\n\tKolProgress,\n\tKolSelect,\n\tKolTableStateful,\n\tKolTabs,\n\tKolTextarea,\n\tKolVersion,\n} from '@public-ui/react-v19';\nimport type { ComponentProps, FC } from 'react';\nimport React from 'react';\n\nimport { useToasterService } from '../../hooks/useToasterService';\nimport { getRoot } from '../../shares/react-roots';\nimport { getTheme, getThemeName } from '../../shares/store';\nimport { TABLE_DATA, type TableDataType } from './table-data';\n\ntype KolButtonProps = ComponentProps<typeof KolButton>;\n\nfunction KolButtonWrapper(props: KolButtonProps & { style: Record<string, unknown> }) {\n\tconst { dummyClickEventHandler } = useToasterService();\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\treturn <KolButton {...props} _on={dummyEventHandler} />;\n}\n\nconst TABLE_HEADERS: KoliBriTableHeaders = {\n\thorizontal: [\n\t\t[\n\t\t\t{\n\t\t\t\tlabel: 'Workdays',\n\t\t\t\tcolSpan: 5,\n\t\t\t\twidth: 500,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Weekend',\n\t\t\t\tcolSpan: 2,\n\t\t\t\twidth: 200,\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tkey: 'monday',\n\t\t\t\tlabel: 'Monday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolButtonWrapper _label={label} style={{ fontSize: '75%' }} />);\n\t\t\t\t},\n\t\t\t\tcompareFn: (first, second) => {\n\t\t\t\t\tif ((first as TableDataType).monday < (second as TableDataType).monday) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\tif ((first as TableDataType).monday > (second as TableDataType).monday) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t},\n\t\t\t\tsortDirection: 'ASC',\n\t\t\t\ttextAlign: 'right',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'tuesday',\n\t\t\t\tlabel: 'Tuesday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#060\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\tcompareFn: (first, second) => {\n\t\t\t\t\tif ((first as TableDataType).tuesday < (second as TableDataType).tuesday) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\tif ((first as TableDataType).tuesday > (second as TableDataType).tuesday) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t},\n\t\t\t\tsortDirection: 'DESC',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'wednesday',\n\t\t\t\tlabel: 'Wednesday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#006\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 110,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'thursday',\n\t\t\t\tlabel: 'Thursday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#600\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'friday',\n\t\t\t\tlabel: 'Friday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#303\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'saturday',\n\t\t\t\tlabel: 'Saturday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#330\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'sunday',\n\t\t\t\tlabel: 'Sunday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#033\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t],\n\t],\n\tvertical: [\n\t\t[\n\t\t\t{\n\t\t\t\tlabel: 'Early',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Noon',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Evening',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Night',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t],\n\t],\n};\n\nconst renderCellContent = (element: HTMLElement, content: React.ReactNode) => {\n\tconst renderElement = document.createElement('div');\n\trenderElement.setAttribute('role', 'presentation');\n\telement.innerHTML = '';\n\telement.appendChild(renderElement);\n\tgetRoot(renderElement).render(content);\n};\n\nexport const HandoutBasic: FC = () => {\n\tconst { dummyClickEventHandler } = useToasterService();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<div className=\"grid gap-4\">\n\t\t\t<div className=\"grid gap-4 md:grid-cols-[auto_1fr_1fr] items-center\">\n\t\t\t\t<KolKolibri className=\"block w-75px\" _labeled={false}></KolKolibri>\n\t\t\t\t<KolHeading _label=\"\" _level={1}>\n\t\t\t\t\t<span slot=\"expert\">\n\t\t\t\t\t\tKolibri-Handout <small>for {getThemeName(getTheme())}</small>\n\t\t\t\t\t</span>\n\t\t\t\t</KolHeading>\n\t\t\t\t<KolDetails _label=\"Abstract\" _open>\n\t\t\t\t\tThe handout shows a selection of KoliBri components in the style of <strong>{getThemeName(getTheme())}</strong>. Since KoliBri offers self-contained,\n\t\t\t\t\taccessible web components that can be customized to your own corporate design using theming, you don't have to develop these components yourself.\n\t\t\t\t\tFor more information read our documentation and follow us (\n\t\t\t\t\t<KolLink _label=\"https://github.com/public-ui/kolibri\" _href=\"https://github.com/public-ui/kolibri\" _target=\"_blank\" />\n\t\t\t\t\t).\n\t\t\t\t</KolDetails>\n\t\t\t</div>\n\t\t\t<div className=\"grid gap-4 sm:grid-cols-6 md:grid-cols-6 xl:grid-cols-12\">\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-3 xl:col-span-2\" _label=\"Heading\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 1\" _level={1}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 2\" _level={2}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 3\" _level={3}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 4\" _level={4}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 5\" _level={5}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 6\" _level={6}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 6\" _secondaryHeadline=\"Lessons\" _level={6}></KolHeading>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t{/* <KolCard className=\"col-span-3\" _label=\"Accordion\" _level={2}>\n\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 1\" _level={1} _open>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 1</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 2\" _level={2}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 2</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 3\" _level={3}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 3</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 4\" _level={4}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 4</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 5\" _level={5}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 5</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 6\" _level={6}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 6</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t</div>\n\t\t\t</KolCard> */}\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-3 xl:col-span-2\" _label=\"Abbreviation and Progress\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tI am <KolAbbr>e.g.</KolAbbr> an abbreviation.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<KolProgress _variant=\"bar\" _max={100} _value={33} _label=\"Progress\" />\n\t\t\t\t\t\t<KolProgress _variant=\"cycle\" _max={100} _value={66} _label=\"Progress\" />\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-6 xl:col-span-3\" _label=\"Button, LinkButton and Tab\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolTabs _label=\"\" _selected={0} _tabs={[{ _label: 'Button' }, { _label: 'LinkButton' }, { _label: 'Disabled Tab', _disabled: true }]}>\n\t\t\t\t\t\t\t<div className=\"grid gap-2 py-2\">\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-left\" _label=\"primary\" _variant=\"primary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-right\" _label=\"secondary\" _variant=\"secondary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-up\" _label=\"danger\" _variant=\"danger\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-down\" _label=\"normal\" _variant=\"normal\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _label=\"ghost\" _variant=\"ghost\"></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _label=\"ghost\" _variant=\"ghost\"></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _icons=\"kolicon-house\" _hideLabel _label=\"ghost\" _variant=\"ghost\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"grid gap-2 py-2\">\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-left\" _label=\"primary\" _variant=\"primary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-right\" _label=\"secondary\" _variant=\"secondary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-up\" _label=\"danger\" _variant=\"danger\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-down\" _label=\"normal\" _variant=\"normal\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _label=\"ghost\" _variant=\"ghost\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _label=\"ghost\" _variant=\"ghost\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons=\"kolicon-house\" _hideLabel _label=\"ghost\" _variant=\"ghost\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</KolTabs>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-2 xl:col-span-2\" _label=\"Accordion, Link and ButtonLink\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolAccordion _label=\"Links\" _level={3} _open>\n\t\t\t\t\t\t\t<div className=\"grid gap-2\" slot=\"\">\n\t\t\t\t\t\t\t\t<KolLink _href=\"#/back-page\" _label=\"Link text\"></KolLink>\n\t\t\t\t\t\t\t\t<KolLink _href=\"#/back-page\" _icons=\"kolicon-house\" _label=\"Link text with icon\"></KolLink>\n\t\t\t\t\t\t\t\t<KolLink _href=\"#/back-page\" _icons=\"kolicon-house\" _hideLabel _label=\"Link text with icon only\"></KolLink>\n\t\t\t\t\t\t\t\t<KolLink _href=\"/\" _label=\"Visited link\"></KolLink>\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tI am a <KolLink _href=\"#/back-page\" _label=\"externer Link\" _target=\"w3c\"></KolLink> in the running text.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t\t<KolAccordion _label=\"ButtonLinks\" _level={3}>\n\t\t\t\t\t\t\t<div className=\"grid gap-2\" slot=\"\">\n\t\t\t\t\t\t\t\t<KolButtonLink _label=\"Link text\"></KolButtonLink>\n\t\t\t\t\t\t\t\t<KolButtonLink _icons=\"kolicon-house\" _label=\"Link text with icon\"></KolButtonLink>\n\t\t\t\t\t\t\t\t<KolButtonLink _icons=\"kolicon-house\" _hideLabel _label=\"Link text with icon only\"></KolButtonLink>\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tI am a <KolButtonLink _label=\"Link\"></KolButtonLink> in the running text.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t<KolButtonLink\n\t\t\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\t\t\tleft: 'kolicon-chevron-left',\n\t\t\t\t\t\t\t\t\t\tright: 'kolicon-chevron-right',\n\t\t\t\t\t\t\t\t\t\ttop: 'kolicon-chevron-up',\n\t\t\t\t\t\t\t\t\t\tbottom: 'kolicon-chevron-down',\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t_label=\"Icons\"\n\t\t\t\t\t\t\t\t></KolButtonLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-4 xl:col-span-3\" _label=\"Alert\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolAlert _label=\"Default message\" _type=\"default\">\n\t\t\t\t\t\t\tThis is the text of the alert.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t\t<KolAlert _type=\"success\">Success message text</KolAlert>\n\t\t\t\t\t\t<KolAlert _type=\"error\" _hasCloser>\n\t\t\t\t\t\t\tThis is a error message text.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t\t<KolAlert _label=\"Info card\" _type=\"info\" _variant=\"card\">\n\t\t\t\t\t\t\tThis is the text of the alert.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t\t<KolAlert _label=\"Warning card\" _type=\"warning\" _hasCloser _variant=\"card\">\n\t\t\t\t\t\t\tThis is the text of the alert.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-2 xl:col-span-2\" _label=\"Nav and Breadcrumb\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<KolNav\n\t\t\t\t\t\t\t\t_label=\"Main navigation\"\n\t\t\t\t\t\t\t\t_links={[\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_label: 'Homepage',\n\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_label: '2 Navigation point',\n\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_active: true,\n\t\t\t\t\t\t\t\t\t\t_label: '3 Navigation point',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t_children: [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.1 Navigation point',\n\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.2 External navigation point',\n\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t\t_target: '_blank',\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.3 Navigation point',\n\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t_children: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_active: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.3.1 Navigation point (active)',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ _label: '3.3.2 Navigation point', _icons: 'kolicon-house', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{ _label: '3 Navigation point', _icons: 'kolicon-house', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t]}\n\t\t\t\t\t\t\t\t_hasCompactButton\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{/* <KolSkipNav></KolSkipNav> */}\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<KolBreadcrumb\n\t\t\t\t\t\t\t\t_label=\"Breadcrumb aus Text-Links\"\n\t\t\t\t\t\t\t\t_links={[\n\t\t\t\t\t\t\t\t\t{ _label: 'Homepage', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t\t{ _label: 'Bottom of the homepage', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_label: 'Underside of the underside',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t]}\n\t\t\t\t\t\t\t></KolBreadcrumb>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-4 xl:col-span-5\" _label=\"Input\" _level={2}>\n\t\t\t\t\t<KolForm slot=\"\">\n\t\t\t\t\t\t<div className=\"grid gap-4 sm:grid-cols-2 md:grid-cols-3 p-2\">\n\t\t\t\t\t\t\t<KolInputColor _label={`Color`} />\n\t\t\t\t\t\t\t<KolInputFile _label={`Upload file`} />\n\t\t\t\t\t\t\t<KolInputNumber _label={`Number input`} />\n\t\t\t\t\t\t\t<KolInputDate _type=\"date\" _label={`Date`} />\n\t\t\t\t\t\t\t<KolInputEmail\n\t\t\t\t\t\t\t\t_icons=\"{'left': 'kolicon-house'}\"\n\t\t\t\t\t\t\t\t_msg={{ _type: 'error', _description: 'Test of an error message' }}\n\t\t\t\t\t\t\t\t_touched\n\t\t\t\t\t\t\t\t_label={`E-mail address`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<KolInputText _hint=\"I am a hint.\" _label={`First name`} />\n\t\t\t\t\t\t\t<KolInputPassword _label={`password`} />\n\t\t\t\t\t\t\t<KolSelect _options=\"[{'label':'Mr.','value':0},{'label':'Mrs.','value':1}]\" _label={`Stimmung`} />\n\t\t\t\t\t\t\t<KolInputRange _min={0} _max={50} _value={25} _label={`Slider`} />\n\t\t\t\t\t\t\t<KolInputRadio className=\"herr-frau\" _options=\"[{'label':'Mr.','value':0},{'label':'Mrs.','value':1}]\" _value=\"1\" _label={`Salutation`} />\n\t\t\t\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t\t\t\t<KolInputRadio _orientation=\"horizontal\" _options=\"[{'label':'Mr.','value':0},{'label':'Mrs.','value':1}]\" _value=\"0\" _label={`Salutation`} />\n\t\t\t\t\t\t\t\t<KolInputCheckbox _label=\"\">\n\t\t\t\t\t\t\t\t\t<span slot=\"expert\">\n\t\t\t\t\t\t\t\t\t\tI accept the <KolAbbr>AGB</KolAbbr>.\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</KolInputCheckbox>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<KolTextarea _rows={4} _label={`Textarea`} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</KolForm>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-4 xl:col-span-5\" _label=\"Table with Pagination\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"gap-2 p-2 flex flex-col\">\n\t\t\t\t\t\t<KolTableStateful _label=\"Table\" _headers={TABLE_HEADERS} _data={TABLE_DATA} _pagination></KolTableStateful>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t</div>\n\t\t\t<KolVersion _label=\"5.0.2-test.2\"></KolVersion>\n\t\t\t{/* <KolImage _src=\"abgrenzung.jpg\" _alt=\"KoliBri Darstellung\"></KolImage> */}\n\t\t\t{/* <KolIndentedText></KolIndentedText> */}\n\t\t\t{/* <KolQuote></KolQuote> */}\n\t\t</div>\n\t);\n};\n",
|
|
896
|
+
"code": "import type { KoliBriTableCell, KoliBriTableHeaders } from '@public-ui/components';\nimport {\n\tKolAbbr,\n\tKolAccordion,\n\tKolAlert,\n\tKolBadge,\n\tKolBreadcrumb,\n\tKolButton,\n\tKolButtonLink,\n\tKolCard,\n\tKolDetails,\n\tKolForm,\n\tKolHeading,\n\tKolInputCheckbox,\n\tKolInputColor,\n\tKolInputDate,\n\tKolInputEmail,\n\tKolInputFile,\n\tKolInputNumber,\n\tKolInputPassword,\n\tKolInputRadio,\n\tKolInputRange,\n\tKolInputText,\n\tKolKolibri,\n\tKolLink,\n\tKolLinkButton,\n\tKolNav,\n\tKolProgress,\n\tKolSelect,\n\tKolTableStateful,\n\tKolTabs,\n\tKolTextarea,\n\tKolVersion,\n} from '@public-ui/react-v19';\nimport type { ComponentProps, FC } from 'react';\nimport React from 'react';\n\nimport { useAlert } from '../../hooks/useAlert';\nimport { getRoot } from '../../shares/react-roots';\nimport { getTheme, getThemeName } from '../../shares/store';\nimport { TABLE_DATA, type TableDataType } from './table-data';\n\ntype KolButtonProps = ComponentProps<typeof KolButton>;\n\nfunction KolButtonWrapper(props: KolButtonProps & { style: Record<string, unknown> }) {\n\tconst { dummyClickEventHandler } = useAlert();\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\treturn <KolButton {...props} _on={dummyEventHandler} />;\n}\n\nconst TABLE_HEADERS: KoliBriTableHeaders = {\n\thorizontal: [\n\t\t[\n\t\t\t{\n\t\t\t\tlabel: 'Workdays',\n\t\t\t\tcolSpan: 5,\n\t\t\t\twidth: 500,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Weekend',\n\t\t\t\tcolSpan: 2,\n\t\t\t\twidth: 200,\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tkey: 'monday',\n\t\t\t\tlabel: 'Monday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolButtonWrapper _label={label} style={{ fontSize: '75%' }} />);\n\t\t\t\t},\n\t\t\t\tcompareFn: (first, second) => {\n\t\t\t\t\tif ((first as TableDataType).monday < (second as TableDataType).monday) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\tif ((first as TableDataType).monday > (second as TableDataType).monday) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t},\n\t\t\t\tsortDirection: 'ASC',\n\t\t\t\ttextAlign: 'right',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'tuesday',\n\t\t\t\tlabel: 'Tuesday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#060\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\tcompareFn: (first, second) => {\n\t\t\t\t\tif ((first as TableDataType).tuesday < (second as TableDataType).tuesday) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\tif ((first as TableDataType).tuesday > (second as TableDataType).tuesday) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t},\n\t\t\t\tsortDirection: 'DESC',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'wednesday',\n\t\t\t\tlabel: 'Wednesday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#006\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 110,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'thursday',\n\t\t\t\tlabel: 'Thursday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#600\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'friday',\n\t\t\t\tlabel: 'Friday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#303\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'saturday',\n\t\t\t\tlabel: 'Saturday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#330\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: 'sunday',\n\t\t\t\tlabel: 'Sunday',\n\t\t\t\trender: (el: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\trenderCellContent(el, <KolBadge _color=\"#033\" _label={label}></KolBadge>);\n\t\t\t\t},\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t],\n\t],\n\tvertical: [\n\t\t[\n\t\t\t{\n\t\t\t\tlabel: 'Early',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Noon',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Evening',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Night',\n\t\t\t\twidth: 100,\n\t\t\t},\n\t\t],\n\t],\n};\n\nconst renderCellContent = (element: HTMLElement, content: React.ReactNode) => {\n\tconst renderElement = document.createElement('div');\n\trenderElement.setAttribute('role', 'presentation');\n\telement.innerHTML = '';\n\telement.appendChild(renderElement);\n\tgetRoot(renderElement).render(content);\n};\n\nexport const HandoutBasic: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<div className=\"grid gap-4\">\n\t\t\t<div className=\"grid gap-4 md:grid-cols-[auto_1fr_1fr] items-center\">\n\t\t\t\t<KolKolibri className=\"block w-75px\" _labeled={false}></KolKolibri>\n\t\t\t\t<KolHeading _label=\"\" _level={1}>\n\t\t\t\t\t<span slot=\"expert\">\n\t\t\t\t\t\tKolibri-Handout <small>for {getThemeName(getTheme())}</small>\n\t\t\t\t\t</span>\n\t\t\t\t</KolHeading>\n\t\t\t\t<KolDetails _label=\"Abstract\" _open>\n\t\t\t\t\tThe handout shows a selection of KoliBri components in the style of <strong>{getThemeName(getTheme())}</strong>. Since KoliBri offers self-contained,\n\t\t\t\t\taccessible web components that can be customized to your own corporate design using theming, you don't have to develop these components yourself.\n\t\t\t\t\tFor more information read our documentation and follow us (\n\t\t\t\t\t<KolLink _label=\"https://github.com/public-ui/kolibri\" _href=\"https://github.com/public-ui/kolibri\" _target=\"_blank\" />\n\t\t\t\t\t).\n\t\t\t\t</KolDetails>\n\t\t\t</div>\n\t\t\t<div className=\"grid gap-4 sm:grid-cols-6 md:grid-cols-6 xl:grid-cols-12\">\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-3 xl:col-span-2\" _label=\"Heading\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 1\" _level={1}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 2\" _level={2}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 3\" _level={3}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 4\" _level={4}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 5\" _level={5}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 6\" _level={6}></KolHeading>\n\t\t\t\t\t\t<KolHeading _label=\"Heading Level 6\" _secondaryHeadline=\"Lessons\" _level={6}></KolHeading>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t{/* <KolCard className=\"col-span-3\" _label=\"Accordion\" _level={2}>\n\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 1\" _level={1} _open>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 1</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 2\" _level={2}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 2</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 3\" _level={3}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 3</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 4\" _level={4}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 4</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 5\" _level={5}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 5</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t<KolAccordion _label=\"Ćberschrift Level 6\" _level={6}>\n\t\t\t\t\t\t<div slot=\"\">Inhalt Accordion Tab 6</div>\n\t\t\t\t\t</KolAccordion>\n\t\t\t\t</div>\n\t\t\t</KolCard> */}\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-3 xl:col-span-2\" _label=\"Abbreviation and Progress\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tI am <KolAbbr>e.g.</KolAbbr> an abbreviation.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<KolProgress _variant=\"bar\" _max={100} _value={33} _label=\"Progress\" />\n\t\t\t\t\t\t<KolProgress _variant=\"cycle\" _max={100} _value={66} _label=\"Progress\" />\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-6 xl:col-span-3\" _label=\"Button, LinkButton and Tab\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolTabs _label=\"\" _selected={0} _tabs={[{ _label: 'Button' }, { _label: 'LinkButton' }, { _label: 'Disabled Tab', _disabled: true }]}>\n\t\t\t\t\t\t\t<div className=\"grid gap-2 py-2\">\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-left\" _label=\"primary\" _variant=\"primary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-right\" _label=\"secondary\" _variant=\"secondary\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-up\" _label=\"danger\" _variant=\"danger\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-chevron-down\" _label=\"normal\" _variant=\"normal\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolButton _label=\"ghost\" _variant=\"ghost\"></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _disabled _label=\"ghost\" _variant=\"ghost\"></KolButton>\n\t\t\t\t\t\t\t\t\t<KolButton _icons=\"kolicon-house\" _hideLabel _label=\"ghost\" _variant=\"ghost\" _on={dummyEventHandler}></KolButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"grid gap-2 py-2\">\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ left: 'kolicon-chevron-left' }} _label=\"primary\" _variant=\"primary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-left\" _label=\"primary\" _variant=\"primary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ right: 'kolicon-chevron-right' }} _label=\"secondary\" _variant=\"secondary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-right\" _label=\"secondary\" _variant=\"secondary\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ top: 'kolicon-chevron-up' }} _label=\"danger\" _variant=\"danger\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-up\" _label=\"danger\" _variant=\"danger\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons={{ bottom: 'kolicon-chevron-down' }} _label=\"normal\" _variant=\"normal\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _hideLabel _icons=\"kolicon-chevron-down\" _label=\"normal\" _variant=\"normal\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-2 grid-cols-[4fr_4fr_1fr] justify-items-center\">\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _label=\"ghost\" _variant=\"ghost\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _label=\"ghost\" _variant=\"ghost\"></KolLinkButton>\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons=\"kolicon-house\" _hideLabel _label=\"ghost\" _variant=\"ghost\"></KolLinkButton>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</KolTabs>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-2 xl:col-span-2\" _label=\"Accordion, Link and ButtonLink\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolAccordion _label=\"Links\" _level={3} _open>\n\t\t\t\t\t\t\t<div className=\"grid gap-2\" slot=\"\">\n\t\t\t\t\t\t\t\t<KolLink _href=\"#/back-page\" _label=\"Link text\"></KolLink>\n\t\t\t\t\t\t\t\t<KolLink _href=\"#/back-page\" _icons=\"kolicon-house\" _label=\"Link text with icon\"></KolLink>\n\t\t\t\t\t\t\t\t<KolLink _href=\"#/back-page\" _icons=\"kolicon-house\" _hideLabel _label=\"Link text with icon only\"></KolLink>\n\t\t\t\t\t\t\t\t<KolLink _href=\"/\" _label=\"Visited link\"></KolLink>\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tI am a <KolLink _href=\"#/back-page\" _label=\"externer Link\" _target=\"w3c\"></KolLink> in the running text.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t\t<KolAccordion _label=\"ButtonLinks\" _level={3}>\n\t\t\t\t\t\t\t<div className=\"grid gap-2\" slot=\"\">\n\t\t\t\t\t\t\t\t<KolButtonLink _label=\"Link text\"></KolButtonLink>\n\t\t\t\t\t\t\t\t<KolButtonLink _icons=\"kolicon-house\" _label=\"Link text with icon\"></KolButtonLink>\n\t\t\t\t\t\t\t\t<KolButtonLink _icons=\"kolicon-house\" _hideLabel _label=\"Link text with icon only\"></KolButtonLink>\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tI am a <KolButtonLink _label=\"Link\"></KolButtonLink> in the running text.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t<KolButtonLink\n\t\t\t\t\t\t\t\t\t_icons={{\n\t\t\t\t\t\t\t\t\t\tleft: 'kolicon-chevron-left',\n\t\t\t\t\t\t\t\t\t\tright: 'kolicon-chevron-right',\n\t\t\t\t\t\t\t\t\t\ttop: 'kolicon-chevron-up',\n\t\t\t\t\t\t\t\t\t\tbottom: 'kolicon-chevron-down',\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t_label=\"Icons\"\n\t\t\t\t\t\t\t\t></KolButtonLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-4 xl:col-span-3\" _label=\"Alert\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<KolAlert _label=\"Default message\" _type=\"default\">\n\t\t\t\t\t\t\tThis is the text of the alert.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t\t<KolAlert _type=\"success\">Success message text</KolAlert>\n\t\t\t\t\t\t<KolAlert _type=\"error\" _hasCloser>\n\t\t\t\t\t\t\tThis is a error message text.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t\t<KolAlert _label=\"Info card\" _type=\"info\" _variant=\"card\">\n\t\t\t\t\t\t\tThis is the text of the alert.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t\t<KolAlert _label=\"Warning card\" _type=\"warning\" _hasCloser _variant=\"card\">\n\t\t\t\t\t\t\tThis is the text of the alert.\n\t\t\t\t\t\t</KolAlert>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-2 xl:col-span-2\" _label=\"Nav and Breadcrumb\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"grid gap-2 p-2\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<KolNav\n\t\t\t\t\t\t\t\t_label=\"Main navigation\"\n\t\t\t\t\t\t\t\t_links={[\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_label: 'Homepage',\n\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_label: '2 Navigation point',\n\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_active: true,\n\t\t\t\t\t\t\t\t\t\t_label: '3 Navigation point',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t_children: [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.1 Navigation point',\n\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.2 External navigation point',\n\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t\t_target: '_blank',\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.3 Navigation point',\n\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t_children: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_active: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_label: '3.3.1 Navigation point (active)',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_icons: 'kolicon-house',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ _label: '3.3.2 Navigation point', _icons: 'kolicon-house', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{ _label: '3 Navigation point', _icons: 'kolicon-house', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t]}\n\t\t\t\t\t\t\t\t_hasCompactButton\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{/* <KolSkipNav></KolSkipNav> */}\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<KolBreadcrumb\n\t\t\t\t\t\t\t\t_label=\"Breadcrumb aus Text-Links\"\n\t\t\t\t\t\t\t\t_links={[\n\t\t\t\t\t\t\t\t\t{ _label: 'Homepage', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t\t{ _label: 'Bottom of the homepage', _href: '#/back-page' },\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t_label: 'Underside of the underside',\n\t\t\t\t\t\t\t\t\t\t_href: '#/back-page',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t]}\n\t\t\t\t\t\t\t></KolBreadcrumb>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-4 xl:col-span-5\" _label=\"Input\" _level={2}>\n\t\t\t\t\t<KolForm slot=\"\">\n\t\t\t\t\t\t<div className=\"grid gap-4 sm:grid-cols-2 md:grid-cols-3 p-2\">\n\t\t\t\t\t\t\t<KolInputColor _label={`Color`} />\n\t\t\t\t\t\t\t<KolInputFile _label={`Upload file`} />\n\t\t\t\t\t\t\t<KolInputNumber _label={`Number input`} />\n\t\t\t\t\t\t\t<KolInputDate _type=\"date\" _label={`Date`} />\n\t\t\t\t\t\t\t<KolInputEmail\n\t\t\t\t\t\t\t\t_icons=\"{'left': 'kolicon-house'}\"\n\t\t\t\t\t\t\t\t_msg={{ _type: 'error', _description: 'Test of an error message' }}\n\t\t\t\t\t\t\t\t_touched\n\t\t\t\t\t\t\t\t_label={`E-mail address`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<KolInputText _hint=\"I am a hint.\" _label={`First name`} />\n\t\t\t\t\t\t\t<KolInputPassword _label={`password`} />\n\t\t\t\t\t\t\t<KolSelect _options=\"[{'label':'Mr.','value':0},{'label':'Mrs.','value':1}]\" _label={`Stimmung`} />\n\t\t\t\t\t\t\t<KolInputRange _min={0} _max={50} _value={25} _label={`Slider`} />\n\t\t\t\t\t\t\t<KolInputRadio className=\"herr-frau\" _options=\"[{'label':'Mr.','value':0},{'label':'Mrs.','value':1}]\" _value=\"1\" _label={`Salutation`} />\n\t\t\t\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t\t\t\t<KolInputRadio _orientation=\"horizontal\" _options=\"[{'label':'Mr.','value':0},{'label':'Mrs.','value':1}]\" _value=\"0\" _label={`Salutation`} />\n\t\t\t\t\t\t\t\t<KolInputCheckbox _label=\"\">\n\t\t\t\t\t\t\t\t\t<span slot=\"expert\">\n\t\t\t\t\t\t\t\t\t\tI accept the <KolAbbr>AGB</KolAbbr>.\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</KolInputCheckbox>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<KolTextarea _rows={4} _label={`Textarea`} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</KolForm>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard className=\"col-span-6 sm:col-span-6 md:col-span-4 xl:col-span-5\" _label=\"Table with Pagination\" _level={2}>\n\t\t\t\t\t<div slot=\"\" className=\"gap-2 p-2 flex flex-col\">\n\t\t\t\t\t\t<KolTableStateful _label=\"Table\" _headers={TABLE_HEADERS} _data={TABLE_DATA} _pagination></KolTableStateful>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t</div>\n\t\t\t<KolVersion _label=\"5.0.2-test.2\"></KolVersion>\n\t\t\t{/* <KolImage _src=\"abgrenzung.jpg\" _alt=\"KoliBri Darstellung\"></KolImage> */}\n\t\t\t{/* <KolIndentedText></KolIndentedText> */}\n\t\t\t{/* <KolQuote></KolQuote> */}\n\t\t</div>\n\t);\n};\n",
|
|
889
897
|
"kind": "sample"
|
|
890
898
|
},
|
|
891
899
|
{
|
|
@@ -1245,7 +1253,7 @@
|
|
|
1245
1253
|
"group": "input-text",
|
|
1246
1254
|
"name": "expert-slot",
|
|
1247
1255
|
"path": "packages/samples/react/src/components/input-text/expert-slot.tsx",
|
|
1248
|
-
"code": "import { KolBadge, KolIcon, KolInputText, KolPopoverButton } from '@public-ui/react-v19';\nimport * as React from 'react';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const InputTextExpertSlot = () => {\n\treturn (\n\t\t<div className=\"grid gap-4\">\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This sample shows KolInputText with expert slot. The expert slot allows for complex custom content beyond simple text inputs.</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<SampleBlock id=\"text\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\">\n\t\t\t\t\t<span slot=\"expert\">I am more than just a input field</span>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"badge\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _value=\"Complex example\">\n\t\t\t\t\t<div slot=\"expert\" className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<KolBadge _label=\"Premium\" _color=\"#1a73e8\" />\n\t\t\t\t\t\t<KolIcon _icons=\"kolicon-check\" _label=\"\" />\n\t\t\t\t\t\t<span>Verified account with premium features</span>\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"note\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _placeholder=\"Enter your email\">\n\t\t\t\t\t<div slot=\"expert\" style={{ padding: '0.5rem', backgroundColor: '#f0f0f0', borderRadius: '4px' }}>\n\t\t\t\t\t\t<strong>Note:</strong> This email will be used for account recovery and notifications.\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"required\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _required>\n\t\t\t\t\t<div slot=\"expert\" className=\"inline-block\">\n\t\t\t\t\t\t<span className=\"expert-slot-required-label\">Username</span>\n\t\t\t\t\t\t<KolPopoverButton _label=\"Help\" _icons=\"kolicon-alert-info\" _variant=\"ghost\" _hideLabel _inline>\n\t\t\t\t\t\t\t<div className=\"w-sm p-2 border border-solid border-gray\">You have to take care of the asterics on your own!</div>\n\t\t\t\t\t\t</KolPopoverButton>\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"readonly\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _readOnly _value=\"(read only) is also not appended\">\n\t\t\t\t\t<div slot=\"expert\" className=\"inline-block\">\n\t\t\t\t\t\t<span className=\"expert-slot-required-label\">Username</span>\n\t\t\t\t\t\t<KolPopoverButton _label=\"Help\" _icons=\"kolicon-alert-info\" _variant=\"ghost\" _hideLabel _inline>\n\t\t\t\t\t\t\t<div className=\"w-sm p-2 border border-solid border-gray\">Readonly is also not appended</div>\n\t\t\t\t\t\t</KolPopoverButton>\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t</div>\n\t);\n};\n",
|
|
1256
|
+
"code": "import { KolBadge, KolIcon, KolInputText, KolPopoverButton } from '@public-ui/react-v19';\nimport * as React from 'react';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const InputTextExpertSlot = () => {\n\treturn (\n\t\t<div className=\"grid gap-4\">\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This sample shows KolInputText with expert slot. The expert slot allows for complex custom content beyond simple text inputs.</p>\n\t\t\t\t<p>\n\t\t\t\t\tFor further information on the expert slot see its <a href=\"https://public-ui.github.io/docs/concepts/expert-slot\">documentation</a>\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<SampleBlock id=\"text\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\">\n\t\t\t\t\t<span slot=\"expert\">I am more than just a input field</span>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"badge\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _value=\"Complex example\">\n\t\t\t\t\t<div slot=\"expert\" className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<KolBadge _label=\"Premium\" _color=\"#1a73e8\" />\n\t\t\t\t\t\t<KolIcon _icons=\"kolicon-check\" _label=\"\" />\n\t\t\t\t\t\t<span>Verified account with premium features</span>\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"note\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _placeholder=\"Enter your email\">\n\t\t\t\t\t<div slot=\"expert\" style={{ padding: '0.5rem', backgroundColor: '#f0f0f0', borderRadius: '4px' }}>\n\t\t\t\t\t\t<strong>Note:</strong> This email will be used for account recovery and notifications.\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"required\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _required>\n\t\t\t\t\t<div slot=\"expert\" className=\"inline-block\">\n\t\t\t\t\t\t<span className=\"expert-slot-required-label\">Username</span>\n\t\t\t\t\t\t<KolPopoverButton _label=\"Help\" _icons=\"kolicon-alert-info\" _variant=\"ghost\" _hideLabel _inline>\n\t\t\t\t\t\t\t<div className=\"w-sm p-2 border border-solid border-gray\">You have to take care of the asterics on your own!</div>\n\t\t\t\t\t\t</KolPopoverButton>\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t\t<SampleBlock id=\"readonly\">\n\t\t\t\t<KolInputText _label=\"\" _type=\"text\" _readOnly _value=\"(read only) is also not appended\">\n\t\t\t\t\t<div slot=\"expert\" className=\"inline-block\">\n\t\t\t\t\t\t<span className=\"expert-slot-required-label\">Username</span>\n\t\t\t\t\t\t<KolPopoverButton _label=\"Help\" _icons=\"kolicon-alert-info\" _variant=\"ghost\" _hideLabel _inline>\n\t\t\t\t\t\t\t<div className=\"w-sm p-2 border border-solid border-gray\">Readonly is also not appended</div>\n\t\t\t\t\t\t</KolPopoverButton>\n\t\t\t\t\t</div>\n\t\t\t\t</KolInputText>\n\t\t\t</SampleBlock>\n\t\t</div>\n\t);\n};\n",
|
|
1249
1257
|
"kind": "sample"
|
|
1250
1258
|
},
|
|
1251
1259
|
{
|
|
@@ -1365,7 +1373,7 @@
|
|
|
1365
1373
|
"group": "link-button",
|
|
1366
1374
|
"name": "basic",
|
|
1367
1375
|
"path": "packages/samples/react/src/components/link-button/basic.tsx",
|
|
1368
|
-
"code": "import React, { useMemo } from 'react';\n\nimport { KolLinkButton } from '@public-ui/react-v19';\n\nimport type { FC } from 'react';\nimport { useSearchParams } from 'react-router';\nimport {
|
|
1376
|
+
"code": "import React, { useMemo } from 'react';\n\nimport { KolLinkButton } from '@public-ui/react-v19';\n\nimport type { FC } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { useAlert } from '../../hooks/useAlert';\nimport { fetchVariantData } from '../../shares/fetchVariantData';\nimport { getTheme } from '../../shares/store';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const LinkButtonBasic: FC = () => {\n\tconst [searchParams] = useSearchParams();\n\tconst theme = searchParams.get('theme') ?? getTheme();\n\tconst data = useMemo(() => (theme ? fetchVariantData(theme, 'buttonVariants') : []), [theme]);\n\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>KolLinkButton renders a link that looks like a button. The sample shows the different theme exclusive styling variants.</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"grid gap-8\">\n\t\t\t\t<SampleBlock id=\"variants\">\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4 items-center\">\n\t\t\t\t\t\t{!Array.isArray(data) || data.length === 0 ? (\n\t\t\t\t\t\t\t<p>This theme has no variants for this component.</p>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tdata.map((element) => {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<KolLinkButton _href=\"#/back-page\" _icons=\"kolicon-house\" _label={`${element}`} _variant={element} key={element} _on={dummyEventHandler} />\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</div>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4 items-center\">\n\t\t\t\t\t\t{!Array.isArray(data) || data.length === 0 ? (\n\t\t\t\t\t\t\t<p>This theme has no variants for this component.</p>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tdata.map((element) => {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<KolLinkButton\n\t\t\t\t\t\t\t\t\t\t_href=\"#/back-page\"\n\t\t\t\t\t\t\t\t\t\t_hideLabel\n\t\t\t\t\t\t\t\t\t\t_icons=\"kolicon-settings\"\n\t\t\t\t\t\t\t\t\t\t_label={`${element}`}\n\t\t\t\t\t\t\t\t\t\t_variant={element}\n\t\t\t\t\t\t\t\t\t\tkey={element}\n\t\t\t\t\t\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t\t\t\t\t\t/>\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</div>\n\t\t\t\t</SampleBlock>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
1369
1377
|
"kind": "sample"
|
|
1370
1378
|
},
|
|
1371
1379
|
{
|
|
@@ -1432,6 +1440,14 @@
|
|
|
1432
1440
|
"code": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { KolHeading, KolLink } from '@public-ui/react-v19';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const LinkHeadline: FC = () => (\n\t<>\n\t\t<SampleDescription>\n\t\t\t<p>This sample shows a linked headline with anchor.</p>\n\t\t</SampleDescription>\n\n\t\t<div className=\"grid gap-4\">\n\t\t\t<KolLink _href=\"/#/link/linked-headline#headline1\" _label=\"\">\n\t\t\t\t<KolHeading _label=\"I'm H2-heading number one\" _level={2} slot=\"expert\" id=\"headline1\" />\n\t\t\t</KolLink>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<KolLink _href=\"/#/link/linked-headline#headline2\" _label=\"\">\n\t\t\t\t<KolHeading _label=\"I'm H2-heading number two\" _level={2} slot=\"expert\" id=\"headline2\" />\n\t\t\t</KolLink>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<KolLink _href=\"/#/link/linked-headline#headline3\" _label=\"\">\n\t\t\t\t<KolHeading _label=\"I'm H2-heading number three\" _level={2} slot=\"expert\" id=\"headline3\" />\n\t\t\t</KolLink>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t\tLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n\t\t\t\tvoluptua. 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.\n\t\t\t</p>\n\t\t</div>\n\t</>\n);\n",
|
|
1433
1441
|
"kind": "sample"
|
|
1434
1442
|
},
|
|
1443
|
+
{
|
|
1444
|
+
"id": "sample/link/on-click",
|
|
1445
|
+
"group": "link",
|
|
1446
|
+
"name": "on-click",
|
|
1447
|
+
"path": "packages/samples/react/src/components/link/on-click.tsx",
|
|
1448
|
+
"code": "import type { FC } from 'react';\nimport React, { useState } from 'react';\n\nimport { KolLink } from '@public-ui/react-v19';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const LinkOnClick: FC = () => {\n\tconst [clickCount, setClickCount] = useState(0);\n\n\t// Test 1: onClick ohne preventDefault - sollte navigieren UND onClick ausführen\n\tconst onClickWithoutPrevent = {\n\t\tonClick: (event: Event, href: string) => {\n\t\t\tconsole.log('Test 1: onClick ohne preventDefault', { event, href });\n\t\t\tsetClickCount((c) => c + 1);\n\t\t\t// Kein preventDefault - Navigation sollte stattfinden\n\t\t},\n\t};\n\n\t// Test 2: onClick mit preventDefault - sollte NUR onClick ausführen, NICHT navigieren\n\tconst onClickWithPrevent = {\n\t\tonClick: (event: Event, href: string) => {\n\t\t\tconsole.log('Test 2: onClick mit preventDefault', { event, href });\n\t\t\tsetClickCount((c) => c + 1);\n\t\t\tevent.preventDefault();\n\t\t\t// Navigation sollte blockiert sein\n\t\t},\n\t};\n\n\t// Test 3: onClick mit return false - sollte NUR onClick ausführen, NICHT navigieren\n\tconst onClickWithReturnFalse = {\n\t\tonClick: (event: Event, href: string) => {\n\t\t\tconsole.log('Test 3: onClick mit return false', { event, href });\n\t\t\tsetClickCount((c) => c + 1);\n\t\t\treturn false;\n\t\t\t// Navigation sollte blockiert sein\n\t\t},\n\t};\n\n\t// Test 4: onClick mit useNavigate (React Router Pattern)\n\t// Dies ist der Use-Case aus Issue #10726\n\tconst onClickWithNavigate = {\n\t\tonClick: (event: Event, href: string) => {\n\t\t\tconsole.log('Test 4: onClick mit simulate navigate', { event, href });\n\t\t\tsetClickCount((c) => c + 1);\n\t\t\tevent.preventDefault();\n\t\t\t// Simuliere useNavigate.navigate(\"/home\") - sollte NICHT zu href navigieren\n\t\t\tconsole.log('Simulated navigate to:', href);\n\t\t},\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis sample demonstrates the issue described in{' '}\n\t\t\t\t\t<a href=\"https://github.com/public-ui/kolibri/issues/10726\" target=\"_blank\" rel=\"noopener noreferrer\">\n\t\t\t\t\t\t#10726\n\t\t\t\t\t</a>\n\t\t\t\t\t.\n\t\t\t\t\t<br />\n\t\t\t\t\tTest the behavior of KolLink with onClick handlers and compare it to native <a> tags.\n\t\t\t\t</p>\n\t\t\t\t<p>\n\t\t\t\t\t<strong>Expected behavior (like native <a> tag):</strong>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>onClick without preventDefault: Execute onClick AND navigate to href</li>\n\t\t\t\t\t\t<li>onClick with preventDefault: Execute onClick, BLOCK navigation</li>\n\t\t\t\t\t\t<li>onClick returning false: Execute onClick, BLOCK navigation</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</p>\n\t\t\t\t<p>\n\t\t\t\t\t<strong>Current behavior (Issue #10726):</strong>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>ā onClick with preventDefault: Still navigates to href (should only execute onClick)</li>\n\t\t\t\t\t\t<li>ā onClick returning false: Still navigates to href (should only execute onClick)</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<SampleBlock id=\"on-click\">\n\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t{/* Info Panel */}\n\t\t\t\t\t<div className=\"bg-gray-100 p-4 rounded\">\n\t\t\t\t\t\t<h2 className=\"h3 mb-2\">Test Results</h2>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t<strong>onClick executions:</strong> {clickCount}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p className=\"text-sm text-gray-600\">(Open browser console to see detailed logs)</p>\n\t\t\t\t\t\t<p className=\"text-sm text-gray-600\">\n\t\t\t\t\t\t\tNote: This demo uses href="#test" to avoid actual page reloads. Check the URL hash and console output.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{/* Test 1: onClick ohne preventDefault */}\n\t\t\t\t\t<div className=\"bg-white p-4 rounded border\">\n\t\t\t\t\t\t<h3 className=\"h4 mb-2\">Test 1: onClick ohne preventDefault</h3>\n\t\t\t\t\t\t<p className=\"text-sm text-gray-600 mb-2\">Expected: Click increments counter AND adds #test-1 to URL</p>\n\t\t\t\t\t\t<KolLink _href=\"#test-1\" _label=\"Click me (no preventDefault)\" _on={onClickWithoutPrevent} _inline={false} />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{/* Test 2: onClick mit preventDefault */}\n\t\t\t\t\t<div className=\"bg-white p-4 rounded border\">\n\t\t\t\t\t\t<h3 className=\"h4 mb-2\">Test 2: onClick mit preventDefault()</h3>\n\t\t\t\t\t\t<p className=\"text-sm text-gray-600 mb-2\">Expected: Click increments counter but does NOT add #test-2 to URL</p>\n\t\t\t\t\t\t<KolLink _href=\"#test-2\" _label=\"Click me (with preventDefault)\" _on={onClickWithPrevent} _inline={false} />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{/* Test 3: onClick mit return false */}\n\t\t\t\t\t<div className=\"bg-white p-4 rounded border\">\n\t\t\t\t\t\t<h3 className=\"h4 mb-2\">Test 3: onClick returning false</h3>\n\t\t\t\t\t\t<p className=\"text-sm text-gray-600 mb-2\">Expected: Click increments counter but does NOT add #test-3 to URL</p>\n\t\t\t\t\t\t<KolLink _href=\"#test-3\" _label=\"Click me (return false)\" _on={onClickWithReturnFalse} _inline={false} />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{/* Test 4: useNavigate Pattern (Issue #10726) */}\n\t\t\t\t\t<div className=\"bg-white p-4 rounded border\">\n\t\t\t\t\t\t<h3 className=\"h4 mb-2\">Test 4: useNavigate Pattern (Issue #10726)</h3>\n\t\t\t\t\t\t<p className=\"text-sm text-gray-600 mb-2\">Expected: Click logs navigate action but does NOT add #test-4 to URL</p>\n\t\t\t\t\t\t<KolLink _href=\"#test-4\" _label=\"Click me (simulate useNavigate)\" _on={onClickWithNavigate} _inline={false} />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{/* Vergleich: Natives <a>-Tag */}\n\t\t\t\t\t<div className=\"bg-white p-4 rounded border\">\n\t\t\t\t\t\t<h3 className=\"h4 mb-2\">Reference: Native <a> Tag</h3>\n\t\t\t\t\t\t<p className=\"text-sm text-gray-600 mb-2\">Test native <a> tag behavior for comparison</p>\n\t\t\t\t\t\t<div className=\"grid gap-2\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref=\"#native-test-1\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tconsole.log('Native a: onClick ohne preventDefault');\n\t\t\t\t\t\t\t\t\tsetClickCount((c) => c + 1);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tclassName=\"btn btn-primary\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tNative: No preventDefault\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref=\"#native-test-2\"\n\t\t\t\t\t\t\t\tonClick={(event: React.MouseEvent) => {\n\t\t\t\t\t\t\t\t\tconsole.log('Native a: onClick mit preventDefault');\n\t\t\t\t\t\t\t\t\tsetClickCount((c) => c + 1);\n\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tclassName=\"btn btn-primary\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tNative: With preventDefault\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref=\"#native-test-3\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tconsole.log('Native a: onClick mit return false');\n\t\t\t\t\t\t\t\t\tsetClickCount((c) => c + 1);\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tclassName=\"btn btn-primary\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tNative: Return false\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</SampleBlock>\n\t\t</>\n\t);\n};\n",
|
|
1449
|
+
"kind": "sample"
|
|
1450
|
+
},
|
|
1435
1451
|
{
|
|
1436
1452
|
"id": "sample/link/react-router",
|
|
1437
1453
|
"group": "link",
|
|
@@ -1541,7 +1557,7 @@
|
|
|
1541
1557
|
"group": "popover-button",
|
|
1542
1558
|
"name": "basic",
|
|
1543
1559
|
"path": "packages/samples/react/src/components/popover-button/basic.tsx",
|
|
1544
|
-
"code": "import type { ToolbarItemsPropType } from '@public-ui/components';\nimport { KolHeading, KolPopoverButton, KolToolbar } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useEffect } from 'react';\nimport {
|
|
1560
|
+
"code": "import type { ToolbarItemsPropType } from '@public-ui/components';\nimport { KolHeading, KolPopoverButton, KolToolbar } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useEffect } from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { SampleDescription } from '../SampleDescription';\n\nexport const PopoverButtonBasic: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\tconst buttonRef = React.useRef<HTMLKolPopoverButtonElement | null>(null);\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\tconst TOOLBAR_ITEMS: ToolbarItemsPropType = [\n\t\t{\n\t\t\ttype: 'button',\n\t\t\t_label: 'Show',\n\t\t\t_icons: 'kolicon-eye',\n\t\t\t_on: dummyEventHandler,\n\t\t},\n\t\t{\n\t\t\ttype: 'button',\n\t\t\t_label: 'Delete',\n\t\t\t_icons: 'kolicon-minus',\n\t\t\t_on: dummyEventHandler,\n\t\t},\n\t\t{\n\t\t\ttype: 'button',\n\t\t\t_label: 'Add',\n\t\t\t_icons: 'kolicon-plus',\n\t\t\t_on: dummyEventHandler,\n\t\t},\n\t];\n\n\tuseEffect(() => {\n\t\t// Ensure the popover is closed on initial render\n\t\tif (buttonRef.current) {\n\t\t\tbuttonRef.current.showPopover();\n\t\t\tbuttonRef.current.focus();\n\t\t}\n\t}, []);\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThe PopoverButton component combines a button with a popover that appears when clicked. The popover can be positioned in different directions (top,\n\t\t\t\t\tright, bottom, left) using the <code>_popoverAlign</code> prop.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\t\t\t<div className=\"flex flex-col gap-4 items-center\">\n\t\t\t\t<KolPopoverButton _label={'Actions'} _variant=\"primary\" _icons={{ right: 'kolicon-chevron-down' }} ref={buttonRef}>\n\t\t\t\t\t<KolToolbar _label=\"Action toolbar\" _items={TOOLBAR_ITEMS} _orientation=\"vertical\" />\n\t\t\t\t</KolPopoverButton>\n\t\t\t\t<KolPopoverButton _label=\"Help\" _icons=\"kolicon-alert-info\" _popoverAlign=\"right\" _tooltipAlign=\"bottom\" _hideLabel>\n\t\t\t\t\t<div className=\"w-sm p-2 border border-solid border-gray bg-white\">\n\t\t\t\t\t\t<KolHeading _label=\"Help Information\" _level={0}></KolHeading>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t<u>Lorem ipsum dolor sit amet</u>, consectetur adipisicing elit. Aspernatur aut dolore dolores itaque praesentium reprehenderit sed voluptatum!\n\t\t\t\t\t\t\tExercitationem ipsa magni maiores modi, placeat quas quos reprehenderit rerum sit veniam vitae.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</KolPopoverButton>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
1545
1561
|
"kind": "sample"
|
|
1546
1562
|
},
|
|
1547
1563
|
{
|
|
@@ -1653,7 +1669,7 @@
|
|
|
1653
1669
|
"group": "split-button",
|
|
1654
1670
|
"name": "basic",
|
|
1655
1671
|
"path": "packages/samples/react/src/components/split-button/basic.tsx",
|
|
1656
|
-
"code": "import React from 'react';\n\nimport type { ToolbarItemsPropType } from '@public-ui/components';\nimport { KolSplitButton, KolToolbar } from '@public-ui/react-v19';\nimport {
|
|
1672
|
+
"code": "import React from 'react';\n\nimport type { ToolbarItemsPropType } from '@public-ui/components';\nimport { KolSplitButton, KolToolbar } from '@public-ui/react-v19';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\nimport type { FC } from 'react';\nimport { useAlert } from '../../hooks/useAlert';\n\nexport const SplitButtonBasic: FC = () => {\n\tconst { buttonWithTextClickEventHandler } = useAlert();\n\tconst dummyEventHandler = {\n\t\tonClick: buttonWithTextClickEventHandler,\n\t};\n\tconst TOOLBAR_ITEMS: ToolbarItemsPropType = [\n\t\t{\n\t\t\ttype: 'button',\n\t\t\t_label: 'Save',\n\t\t\t_icons: 'kolicon-check',\n\t\t\t_on: dummyEventHandler,\n\t\t},\n\t\t{\n\t\t\ttype: 'button',\n\t\t\t_label: 'Move Up',\n\t\t\t_icons: 'kolicon-chevron-up',\n\t\t\t_on: dummyEventHandler,\n\t\t},\n\t\t{\n\t\t\ttype: 'button',\n\t\t\t_label: 'Delete',\n\t\t\t_icons: 'kolicon-minus',\n\t\t\t_on: dummyEventHandler,\n\t\t},\n\t];\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThe <code>SplitButton</code> component combines a primary action button with a context menu. Clicking the main button triggers the\n\t\t\t\t\t<strong> Edit</strong> action. The context menu opens a vertical list of additional actions:\n\t\t\t\t\t<strong> Save</strong>, <strong>Move</strong>, and <strong>Delete</strong>.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<SampleBlock id=\"basic\" className=\"flex flex-col gap-4\">\n\t\t\t\t<KolSplitButton _label=\"Edit\" _on={dummyEventHandler}>\n\t\t\t\t\t<KolToolbar _label=\"Action toolbar\" _items={TOOLBAR_ITEMS} _orientation=\"vertical\" />\n\t\t\t\t</KolSplitButton>\n\t\t\t</SampleBlock>\n\t\t</>\n\t);\n};\n",
|
|
1657
1673
|
"kind": "sample"
|
|
1658
1674
|
},
|
|
1659
1675
|
{
|
|
@@ -1677,7 +1693,7 @@
|
|
|
1677
1693
|
"group": "table",
|
|
1678
1694
|
"name": "action-columns",
|
|
1679
1695
|
"path": "packages/samples/react/src/components/table/action-columns.tsx",
|
|
1680
|
-
"code": "import type { KoliBriTableHeaderCellWithLogic } from '@public-ui/components';\nimport { KolTableStateful } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\ntype ProjectTask = {\n\tid: string;\n\tproject: string;\n\towner: string;\n};\n\nconst HEADERS: { horizontal: KoliBriTableHeaderCellWithLogic[][] } = {\n\thorizontal: [\n\t\t[\n\t\t\t{ key: 'id', label: 'ID', width: 80 },\n\t\t\t{ key: 'project', label: 'Project' },\n\t\t\t{ key: 'owner', label: 'Owner', width: 140 },\n\t\t\t{\n\t\t\t\ttype: 'action',\n\t\t\t\tkey: 'actions',\n\t\t\t\tlabel: 'Actions',\n\t\t\t\twidth: 250,\n\t\t\t\tactions: (row) => {\n\t\t\t\t\tconst simpleRow = row as ProjectTask;\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: 'Details',\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_on: {\n\t\t\t\t\t\t\t\tonClick: () => alert(`Details: ${simpleRow.id} - ${simpleRow.project}`),\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: 'Start',\n\t\t\t\t\t\t\t_icons: 'kolicon-chevron-right',\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: () => alert(`Start task ${simpleRow.id}`),\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: 'link',\n\t\t\t\t\t\t\t_label: 'View',\n\t\t\t\t\t\t\t_href: `#/back-page?taskId=${simpleRow.id}`,\n\t\t\t\t\t\t\t_target: '_blank',\n\t\t\t\t\t\t\t_icons: 'kolicon-external-link',\n\t\t\t\t\t\t\t_hideLabel: false,\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\t{\n\t\t\t\ttype: 'action',\n\t\t\t\tkey: 'externalActions',\n\t\t\t\tlabel: 'External Actions',\n\t\t\t\twidth: 280,\n\t\t\t\tactions: (row) => {\n\t\t\t\t\tconst simpleRow = row as ProjectTask;\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'link',\n\t\t\t\t\t\t\t_label: 'View on Dashboard',\n\t\t\t\t\t\t\t_href: `#/back-page?taskId=${simpleRow.id}`,\n\t\t\t\t\t\t\t_target: '_blank',\n\t\t\t\t\t\t\t_icons: 'kolicon-external-link',\n\t\t\t\t\t\t\t_hideLabel: false,\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\nconst DATA: ProjectTask[] = [\n\t{\n\t\tid: 'T-01',\n\t\tproject: 'Onboarding checklist',\n\t\towner: 'Alex Rivera',\n\t},\n\t{\n\t\tid: 'T-02',\n\t\tproject: 'Accessibility audit',\n\t\towner: 'Jamie Chen',\n\t},\n];\n\nexport const TableActionColumns: FC = () => (\n\t<>\n\t\t<SampleDescription>\n\t\t\t<p>\n\t\t\t\tSimple example using the refactored action column: Actions are defined once in the column header definition using a factory function. Two rows with\n\t\t\t\tinline action buttons demonstrate clean separation between data and UI behavior.\n\t\t\t</p>\n\t\t</SampleDescription>\n\n\t\t<SampleBlock id=\"action-columns\" className=\"w-full\">\n\t\t\t<KolTableStateful _label=\"Tasks with action buttons\" _headers={HEADERS} _data={DATA} className=\"block\" />\n\t\t</SampleBlock>\n\t</>\n);\n",
|
|
1696
|
+
"code": "import type { KoliBriTableHeaderCellWithLogic } from '@public-ui/components';\nimport { KolTableStateful } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\ntype ProjectTask = {\n\tid: string;\n\tproject: string;\n\towner: string;\n};\n\nconst HEADERS: { horizontal: KoliBriTableHeaderCellWithLogic[][] } = {\n\thorizontal: [\n\t\t[\n\t\t\t{ key: 'id', label: 'ID', width: 80 },\n\t\t\t{ key: 'project', label: 'Project' },\n\t\t\t{ key: 'owner', label: 'Owner', width: 140 },\n\t\t\t{\n\t\t\t\ttype: 'action',\n\t\t\t\tkey: 'actions',\n\t\t\t\tlabel: 'Actions',\n\t\t\t\ttextAlign: 'left',\n\t\t\t\twidth: 250,\n\t\t\t\tactions: (row) => {\n\t\t\t\t\tconst simpleRow = row as ProjectTask;\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: 'Details',\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_on: {\n\t\t\t\t\t\t\t\tonClick: () => alert(`Details: ${simpleRow.id} - ${simpleRow.project}`),\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: 'Start',\n\t\t\t\t\t\t\t_icons: 'kolicon-chevron-right',\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: () => alert(`Start task ${simpleRow.id}`),\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: 'link',\n\t\t\t\t\t\t\t_label: 'View',\n\t\t\t\t\t\t\t_href: `#/back-page?taskId=${simpleRow.id}`,\n\t\t\t\t\t\t\t_target: '_blank',\n\t\t\t\t\t\t\t_icons: 'kolicon-external-link',\n\t\t\t\t\t\t\t_hideLabel: false,\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\t{\n\t\t\t\ttype: 'action',\n\t\t\t\tkey: 'externalActions',\n\t\t\t\tlabel: 'External Actions',\n\t\t\t\ttextAlign: 'right',\n\t\t\t\twidth: 280,\n\t\t\t\tactions: (row) => {\n\t\t\t\t\tconst simpleRow = row as ProjectTask;\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'link',\n\t\t\t\t\t\t\t_label: 'View on Dashboard',\n\t\t\t\t\t\t\t_href: `#/back-page?taskId=${simpleRow.id}`,\n\t\t\t\t\t\t\t_target: '_blank',\n\t\t\t\t\t\t\t_icons: 'kolicon-external-link',\n\t\t\t\t\t\t\t_hideLabel: false,\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\nconst DATA: ProjectTask[] = [\n\t{\n\t\tid: 'T-01',\n\t\tproject: 'Onboarding checklist',\n\t\towner: 'Alex Rivera',\n\t},\n\t{\n\t\tid: 'T-02',\n\t\tproject: 'Accessibility audit',\n\t\towner: 'Jamie Chen',\n\t},\n];\n\nexport const TableActionColumns: FC = () => (\n\t<>\n\t\t<SampleDescription>\n\t\t\t<p>\n\t\t\t\tSimple example using the refactored action column: Actions are defined once in the column header definition using a factory function. Two rows with\n\t\t\t\tinline action buttons demonstrate clean separation between data and UI behavior.\n\t\t\t</p>\n\t\t</SampleDescription>\n\n\t\t<SampleBlock id=\"action-columns\" className=\"w-full\">\n\t\t\t<KolTableStateful _label=\"Tasks with action buttons\" _headers={HEADERS} _data={DATA} className=\"block\" />\n\t\t</SampleBlock>\n\t</>\n);\n",
|
|
1681
1697
|
"kind": "sample"
|
|
1682
1698
|
},
|
|
1683
1699
|
{
|
|
@@ -1757,7 +1773,7 @@
|
|
|
1757
1773
|
"group": "table",
|
|
1758
1774
|
"name": "interactive-child-elements",
|
|
1759
1775
|
"path": "packages/samples/react/src/components/table/interactive-child-elements.tsx",
|
|
1760
|
-
"code": "import type { KoliBriTableCell, KoliBriTableHeaderCell, VariantClassNamePropType } from '@public-ui/components';\nimport { createReactRenderElement, KolButton, KolButtonLink, KolLink, KolLinkButton, KolTableStateless } from '@public-ui/react-v19';\nimport type { ComponentProps, FC } from 'react';\nimport React from 'react';\nimport {
|
|
1776
|
+
"code": "import type { KoliBriTableCell, KoliBriTableHeaderCell, VariantClassNamePropType } from '@public-ui/components';\nimport { createReactRenderElement, KolButton, KolButtonLink, KolLink, KolLinkButton, KolTableStateless } from '@public-ui/react-v19';\nimport type { ComponentProps, FC } from 'react';\nimport React from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { getRoot } from '../../shares/react-roots';\nimport { SampleDescription } from '../SampleDescription';\n\ntype KolButtonProps = ComponentProps<typeof KolButton>;\n\nfunction KolButtonWrapper(props: KolButtonProps) {\n\tconst { dummyClickEventHandler } = useAlert();\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\treturn <KolButton {...props} _on={dummyEventHandler} />;\n}\n\nconst getButtonHeaderCell = (variant: VariantClassNamePropType): KoliBriTableHeaderCell => {\n\tconst variantLabel = `${variant}`;\n\tconst capitalizedVariant = variantLabel.charAt(0).toUpperCase() + variantLabel.slice(1);\n\treturn {\n\t\tlabel: capitalizedVariant,\n\t\tkey: variantLabel,\n\t\ttextAlign: 'left',\n\t\twidth: 160,\n\t\trender: (element: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\tconst { label } = cell as { label: string };\n\t\t\tconst commonProps = {\n\t\t\t\t_label: capitalizedVariant,\n\t\t\t\t_variant: variant,\n\t\t\t\t_icons: { right: 'kolicon-kolibri' },\n\t\t\t};\n\t\t\tgetRoot(createReactRenderElement(element)).render(\n\t\t\t\tlabel === 'button' ? <KolButtonWrapper {...commonProps} /> : <KolLinkButton _href=\"#/back-page\" {...commonProps} />,\n\t\t\t);\n\t\t},\n\t};\n};\n\nexport const InteractiveChildElements: FC = () => (\n\t<>\n\t\t<SampleDescription>\n\t\t\t<p>\n\t\t\t\tThis sample shows a KolTableStateless with different interactive child elements. It can be used to assure themes show these child elements correctly.\n\t\t\t</p>\n\t\t</SampleDescription>\n\n\t\t<section className=\"w-full flex flex-col\">\n\t\t\t<KolTableStateless\n\t\t\t\t_label=\"Button styles\"\n\t\t\t\t_headerCells={{\n\t\t\t\t\thorizontal: [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\tgetButtonHeaderCell('primary'),\n\t\t\t\t\t\t\tgetButtonHeaderCell('secondary'),\n\t\t\t\t\t\t\tgetButtonHeaderCell('normal'),\n\t\t\t\t\t\t\tgetButtonHeaderCell('danger'),\n\t\t\t\t\t\t\tgetButtonHeaderCell('ghost'),\n\t\t\t\t\t\t],\n\t\t\t\t\t],\n\t\t\t\t\tvertical: [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ label: 'Button', width: 120 },\n\t\t\t\t\t\t\t{ label: 'Link-Button', width: 120 },\n\t\t\t\t\t\t],\n\t\t\t\t\t],\n\t\t\t\t}}\n\t\t\t\t_data={[\n\t\t\t\t\t{\n\t\t\t\t\t\tprimary: 'button',\n\t\t\t\t\t\tsecondary: 'button',\n\t\t\t\t\t\tnormal: 'button',\n\t\t\t\t\t\tdanger: 'button',\n\t\t\t\t\t\tghost: 'button',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tprimary: 'link-button',\n\t\t\t\t\t\tsecondary: 'link-button',\n\t\t\t\t\t\tnormal: 'link-button',\n\t\t\t\t\t\tdanger: 'link-button',\n\t\t\t\t\t\tghost: 'link-button',\n\t\t\t\t\t},\n\t\t\t\t]}\n\t\t\t\tclassName=\"block\"\n\t\t\t/>\n\n\t\t\t<KolTableStateless\n\t\t\t\t_label=\"Link styles\"\n\t\t\t\t_headerCells={{\n\t\t\t\t\thorizontal: [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: 'regular',\n\t\t\t\t\t\t\t\tlabel: 'Regular',\n\t\t\t\t\t\t\t\ttextAlign: 'left',\n\t\t\t\t\t\t\t\twidth: 180,\n\t\t\t\t\t\t\t\trender: (element: HTMLElement, cell: KoliBriTableCell) => {\n\t\t\t\t\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\t\t\t\t\tconst commonProps = {\n\t\t\t\t\t\t\t\t\t\t_label: label,\n\t\t\t\t\t\t\t\t\t\t_icons: { right: 'kolicon-kolibri' },\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\tgetRoot(createReactRenderElement(element)).render(\n\t\t\t\t\t\t\t\t\t\tlabel === 'button-link' ? <KolButtonLink {...commonProps} /> : <KolLink _href=\"#/back-page\" {...commonProps} />,\n\t\t\t\t\t\t\t\t\t);\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\tvertical: [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ label: 'Link', width: 140 },\n\t\t\t\t\t\t\t{ label: 'Button-Link', width: 140 },\n\t\t\t\t\t\t],\n\t\t\t\t\t],\n\t\t\t\t}}\n\t\t\t\t_data={[\n\t\t\t\t\t{\n\t\t\t\t\t\tregular: 'link',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tregular: 'button-link',\n\t\t\t\t\t},\n\t\t\t\t]}\n\t\t\t\tclassName=\"block mt\"\n\t\t\t/>\n\t\t</section>\n\t</>\n);\n",
|
|
1761
1777
|
"kind": "sample"
|
|
1762
1778
|
},
|
|
1763
1779
|
{
|
|
@@ -1797,7 +1813,7 @@
|
|
|
1797
1813
|
"group": "table",
|
|
1798
1814
|
"name": "render-cell",
|
|
1799
1815
|
"path": "packages/samples/react/src/components/table/render-cell.tsx",
|
|
1800
|
-
"code": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { createReactRenderElement, KolButton, KolInputText, KolTableStateful } from '@public-ui/react-v19';\n\nimport { getRoot } from '../../shares/react-roots';\nimport { SampleDescription } from '../SampleDescription';\nimport { DATE_FORMATTER } from './formatter';\n\nimport type { IconsPropType, KoliBriTableCell, KoliBriTableHeaders } from '@public-ui/components';\nimport {
|
|
1816
|
+
"code": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { createReactRenderElement, KolButton, KolInputText, KolTableStateful } from '@public-ui/react-v19';\n\nimport { getRoot } from '../../shares/react-roots';\nimport { SampleDescription } from '../SampleDescription';\nimport { DATE_FORMATTER } from './formatter';\n\nimport type { IconsPropType, KoliBriTableCell, KoliBriTableHeaders } from '@public-ui/components';\nimport { useAlert } from '../../hooks/useAlert';\n\ntype Data = {\n\torder: number;\n\tdate: Date;\n\tshipped: boolean;\n};\n\n/**\n * Generates n data entries with random dates and shipping status\n * @param n - Number of data entries to generate\n * @returns Array of Data objects\n */\nfunction generateDataEntries(n: number): Data[] {\n\tconst entries: Data[] = [];\n\tconst startDate = new Date('1970-01-01').getTime();\n\tconst endDate = new Date('2025-12-31').getTime();\n\n\tfor (let i = 0; i < n; i++) {\n\t\tconst randomTimestamp = startDate + Math.random() * (endDate - startDate);\n\t\tentries.push({\n\t\t\torder: i,\n\t\t\tshipped: Math.random() > 0.5,\n\t\t\tdate: new Date(randomTimestamp),\n\t\t});\n\t}\n\n\treturn entries;\n}\n\nconst DATA: Data[] = generateDataEntries(100);\n\nfunction KolButtonWrapper({ label, icons }: { label: string; icons: IconsPropType }) {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn <KolButton _label={label} _icons={icons} _on={dummyEventHandler} />;\n}\n\nconst HEADERS: KoliBriTableHeaders = {\n\thorizontal: [\n\t\t[\n\t\t\t{\n\t\t\t\tlabel: '#',\n\t\t\t\tkey: 'order',\n\t\t\t\ttextAlign: 'center',\n\t\t\t\twidth: 100,\n\n\t\t\t\t/* Example 1: Use render return value to format data */\n\t\t\t\trender: (_el, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\treturn `Index: ${label}`;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Status',\n\t\t\t\tkey: 'shipped',\n\t\t\t\ttextAlign: 'center',\n\t\t\t\twidth: 100,\n\n\t\t\t\t/* Example 2: Simple render function using textContent */\n\t\t\t\trender: (el, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\tconst element = el as HTMLElement;\n\t\t\t\t\tif (label) {\n\t\t\t\t\t\telement.textContent = `Order has been dispatched š`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\telement.textContent = `Order pending š¦`;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Date (string)',\n\t\t\t\tkey: 'date',\n\t\t\t\twidth: 200,\n\t\t\t\ttextAlign: 'center',\n\n\t\t\t\t/* Example 3: Render function using innerHTML. ā ļøMake sure to sanitize data to avoid XSS. */\n\t\t\t\trender: (el, cell: KoliBriTableCell) => {\n\t\t\t\t\tconst { label } = cell as { label: string };\n\t\t\t\t\t(el as HTMLElement).innerHTML = `<strong>${DATE_FORMATTER.format(label as unknown as Date)}</strong>`;\n\t\t\t\t},\n\t\t\t\tcompareFn: (data0, data1) => (data0 as Data).date.getTime() - (data1 as Data).date.getTime(),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Action (react)',\n\t\t\t\tkey: 'action',\n\t\t\t\twidth: 200,\n\n\t\t\t\t/* Example 4: Render function using React */\n\t\t\t\trender: (el) => {\n\t\t\t\t\tgetRoot(createReactRenderElement(el)).render(\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tdisplay: `grid`,\n\t\t\t\t\t\t\t\tgridAutoFlow: `column`,\n\t\t\t\t\t\t\t\talignItems: `end`,\n\t\t\t\t\t\t\t\tgap: `1rem`,\n\t\t\t\t\t\t\t\tmaxWidth: `400px`,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<KolInputText _label=\"Input\" />\n\t\t\t\t\t\t\t<KolButtonWrapper label=\"Save\" icons={{ left: 'kolicon-check' }} />\n\t\t\t\t\t\t</div>,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t],\n};\n\nexport const TableRenderCell: FC = () => (\n\t<>\n\t\t<SampleDescription>\n\t\t\t<p>This sample shows KolTableStateful using React render functions for the cell contents.</p>\n\t\t</SampleDescription>\n\n\t\t<KolTableStateful _label=\"Sort by date column\" _data={DATA} _headers={HEADERS} className=\"w-full\" _hasSettingsMenu />\n\t</>\n);\n",
|
|
1801
1817
|
"kind": "sample"
|
|
1802
1818
|
},
|
|
1803
1819
|
{
|
|
@@ -1885,7 +1901,7 @@
|
|
|
1885
1901
|
"group": "table",
|
|
1886
1902
|
"name": "stateless-with-selection",
|
|
1887
1903
|
"path": "packages/samples/react/src/components/table/stateless-with-selection.tsx",
|
|
1888
|
-
"code": "import type { KoliBriTableCell, KoliBriTableSelection, KoliBriTableSelectionKeys } from '@public-ui/components';\nimport { createReactRenderElement, KolButton, KolTableStateless } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\nimport {
|
|
1904
|
+
"code": "import type { KoliBriTableCell, KoliBriTableSelection, KoliBriTableSelectionKeys } from '@public-ui/components';\nimport { createReactRenderElement, KolButton, KolTableStateless } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { getRoot } from '../../shares/react-roots';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\ntype SelectionValue = string | number;\ntype KolTableStatelessElement = {\n\taddEventListener: (type: string, listener: (event: CustomEvent<SelectionValue[]>) => void) => void;\n\tremoveEventListener: (type: string, listener: (event: CustomEvent<SelectionValue[]>) => void) => void;\n};\n\nconst DATA = [\n\t{ id: '1001', name: 'Foo Bar', internalIdentifier: `AAA1001` },\n\t{ id: '1002', name: 'Foo Baz', internalIdentifier: `AAA1002` },\n\t{ id: '1003', name: 'This row is always unchecked', internalIdentifier: `AAA1003` },\n\t{ id: '1004', name: 'This row is always checked', internalIdentifier: `AAA1004` },\n];\ntype Data = (typeof DATA)[0];\n\nfunction KolButtonWrapper({ label }: { label: string }) {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn <KolButton _label={label} _on={dummyEventHandler} />;\n}\n\nexport const TableStatelessWithSelection: FC = () => {\n\tconst [selectedKeys, setSelectedKeys] = useState<KoliBriTableSelectionKeys>(['AAA1002', 'AAA1004']);\n\n\tconst selection: KoliBriTableSelection = {\n\t\tlabel: (row) => `Selection for ${(row as Data).name}`,\n\t\tselectedKeys,\n\t\tkeyPropertyName: 'internalIdentifier',\n\t\tdisabledKeys: ['AAA1003', 'AAA1004'],\n\t};\n\n\tconst kolTableStatelessRef = useRef<HTMLKolTableStatelessElement>(null);\n\n\tconst handleSelectionChangeEvent = ({ detail: selection }: CustomEvent<SelectionValue[]>) => {\n\t\tconsole.log('Selection change via event', selection);\n\t};\n\tconst handleSelectionChangeCallback = (_event: Event, selection: SelectionValue[]) => {\n\t\tconsole.log('Selection change via callback', selection);\n\t\tsetSelectedKeys(selection);\n\t};\n\n\tuseEffect(() => {\n\t\tconst tableElement = kolTableStatelessRef.current as unknown as KolTableStatelessElement | null;\n\t\tconst selectionChangeEvent = 'kolSelectionChange';\n\t\ttableElement?.addEventListener(selectionChangeEvent, handleSelectionChangeEvent);\n\n\t\treturn () => {\n\t\t\ttableElement?.removeEventListener(selectionChangeEvent, handleSelectionChangeEvent);\n\t\t};\n\t}, [kolTableStatelessRef]);\n\n\tconst renderButton = (element: HTMLElement, cell: KoliBriTableCell) => {\n\t\tconst data = (cell as { data?: Data }).data;\n\t\tconst id = data?.id;\n\t\tgetRoot(createReactRenderElement(element)).render(<KolButtonWrapper label={`Click ${id}`} />);\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This sample shows KolTableStateless with checkboxes for selection enabled.</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<SampleBlock id=\"selection\" className=\"w-full\">\n\t\t\t\t<KolTableStateless\n\t\t\t\t\t_label=\"Table with selection checkboxes\"\n\t\t\t\t\t_headerCells={{\n\t\t\t\t\t\thorizontal: [\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t{ key: 'id', label: '#ID', textAlign: 'left' },\n\t\t\t\t\t\t\t\t{ key: 'name', label: 'Name', textAlign: 'left' },\n\t\t\t\t\t\t\t\t{ key: 'action', label: 'Action', textAlign: 'left', render: renderButton },\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\t_data={DATA}\n\t\t\t\t\t_selection={selection}\n\t\t\t\t\t_on={{ onSelectionChange: handleSelectionChangeCallback }}\n\t\t\t\t\tclassName=\"block\"\n\t\t\t\t\tstyle={{ maxWidth: '600px' }}\n\t\t\t\t\tref={kolTableStatelessRef}\n\t\t\t\t/>\n\t\t\t</SampleBlock>\n\t\t</>\n\t);\n};\n",
|
|
1889
1905
|
"kind": "sample"
|
|
1890
1906
|
},
|
|
1891
1907
|
{
|
|
@@ -1901,7 +1917,7 @@
|
|
|
1901
1917
|
"group": "table",
|
|
1902
1918
|
"name": "stateless-with-single-selection",
|
|
1903
1919
|
"path": "packages/samples/react/src/components/table/stateless-with-single-selection.tsx",
|
|
1904
|
-
"code": "import type { KoliBriTableCell, KoliBriTableSelection, KoliBriTableSelectionKeys } from '@public-ui/components';\nimport { createReactRenderElement, KolButton, KolTableStateless } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport {
|
|
1920
|
+
"code": "import type { KoliBriTableCell, KoliBriTableSelection, KoliBriTableSelectionKeys } from '@public-ui/components';\nimport { createReactRenderElement, KolButton, KolTableStateless } from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { useAlert } from '../../hooks/useAlert';\nimport { getRoot } from '../../shares/react-roots';\nimport { SampleBlock } from '../SampleBlock';\nimport { SampleDescription } from '../SampleDescription';\n\ntype SelectionValue = string | number;\ntype KolTableStatelessElement = {\n\taddEventListener: (type: string, listener: (event: CustomEvent<SelectionValue[]>) => void) => void;\n\tremoveEventListener: (type: string, listener: (event: CustomEvent<SelectionValue[]>) => void) => void;\n};\n\nconst DATA = [\n\t{ id: '1001', name: 'Foo Bar', internalIdentifier: `AAA1001` },\n\t{ id: '1002', name: 'Foo Baz', internalIdentifier: `AAA1002` },\n\t{ id: '1003', name: 'Foo Disabled', internalIdentifier: `AAA1003` },\n];\ntype Data = (typeof DATA)[0];\n\nfunction KolButtonWrapper({ label }: { label: string }) {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn <KolButton _label={label} _on={dummyEventHandler} />;\n}\n\nexport const TableStatelessWithSingleSelection: FC = () => {\n\tconst [selectedKeys, setSelectedKeys] = useState<KoliBriTableSelectionKeys>(['1002']);\n\n\tconst selection: KoliBriTableSelection = {\n\t\tlabel: (row) => `Selection for ${(row as Data).name}`,\n\t\tmultiple: false,\n\t\tselectedKeys,\n\t\tdisabledKeys: ['AAA1003'],\n\t\tkeyPropertyName: 'internalIdentifier',\n\t};\n\n\tconst kolTableStatelessRef = useRef<HTMLKolTableStatelessElement>(null);\n\n\tconst handleSelectionChangeEvent = useCallback(({ detail: selection }: CustomEvent<SelectionValue[]>) => {\n\t\tconsole.log('Selection change via event', selection);\n\t}, []);\n\tconst handleSelectionChangeCallback = useCallback((_event: Event, selection: SelectionValue[]) => {\n\t\tconsole.log('Selection change via callback', selection);\n\t\tsetSelectedKeys(selection);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tconst tableElement = kolTableStatelessRef.current as unknown as KolTableStatelessElement | null;\n\t\tconst selectionChangeEvent = 'kolSelectionChange';\n\t\ttableElement?.addEventListener(selectionChangeEvent, handleSelectionChangeEvent);\n\n\t\treturn () => {\n\t\t\ttableElement?.removeEventListener(selectionChangeEvent, handleSelectionChangeEvent);\n\t\t};\n\t}, [kolTableStatelessRef, handleSelectionChangeEvent]);\n\n\tconst renderButton = useCallback((element: HTMLElement, cell: KoliBriTableCell) => {\n\t\tconst data = (cell as { data?: Data }).data;\n\t\tconst id = data?.id;\n\t\tgetRoot(createReactRenderElement(element)).render(<KolButtonWrapper label={`Click ${id}`} />);\n\t}, []);\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This sample shows KolTableStateless with checkboxes for selection enabled.</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<SampleBlock id=\"single-selection\" className=\"w-full\" fitContent>\n\t\t\t\t<KolTableStateless\n\t\t\t\t\t_label=\"Table with selection checkboxes\"\n\t\t\t\t\t_headerCells={{\n\t\t\t\t\t\thorizontal: [\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t{ key: 'id', label: '#ID', textAlign: 'left' },\n\t\t\t\t\t\t\t\t{ key: 'name', label: 'Name', textAlign: 'left' },\n\t\t\t\t\t\t\t\t{ key: 'action', label: 'Action', textAlign: 'left', render: renderButton },\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\t_data={DATA}\n\t\t\t\t\t_selection={selection}\n\t\t\t\t\t_on={{ onSelectionChange: handleSelectionChangeCallback }}\n\t\t\t\t\tclassName=\"block\"\n\t\t\t\t\tstyle={{ maxWidth: '600px' }}\n\t\t\t\t\tref={kolTableStatelessRef}\n\t\t\t\t/>\n\t\t\t</SampleBlock>\n\t\t</>\n\t);\n};\n",
|
|
1905
1921
|
"kind": "sample"
|
|
1906
1922
|
},
|
|
1907
1923
|
{
|
|
@@ -2117,7 +2133,7 @@
|
|
|
2117
2133
|
"group": "scenarios",
|
|
2118
2134
|
"name": "custom-tooltip-css-properties",
|
|
2119
2135
|
"path": "packages/samples/react/src/scenarios/custom-tooltip-css-properties.tsx",
|
|
2120
|
-
"code": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { KolButton } from '@public-ui/react-v19';\nimport { SampleDescription } from '../components/SampleDescription';\nimport {
|
|
2136
|
+
"code": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { KolButton } from '@public-ui/react-v19';\nimport { SampleDescription } from '../components/SampleDescription';\nimport { useAlert } from '../hooks/useAlert';\n\nexport const CustomTooltipCssProperties: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis sample demonstrates how tooltip animation duration and width can be customized via\n\t\t\t\t\t<code>--kolibri-tooltip-animation-duration</code> and <code>--kol-tooltip-width</code>.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"flex justify-center items-center gap-4\">\n\t\t\t\t<KolButton\n\t\t\t\t\t_label=\"Custom duration\"\n\t\t\t\t\t_hideLabel\n\t\t\t\t\tstyle={{ '--kolibri-tooltip-animation-duration': '2500ms' }}\n\t\t\t\t\t_icons=\"fa-solid fa-clock\"\n\t\t\t\t\t_on={dummyEventHandler}\n\t\t\t\t></KolButton>\n\t\t\t\t<KolButton _label=\"Custom width\" _hideLabel style={{ '--kol-tooltip-width': '400px' }} _icons=\"kolicon-chevron-up\" _on={dummyEventHandler}></KolButton>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
2121
2137
|
"kind": "scenario"
|
|
2122
2138
|
},
|
|
2123
2139
|
{
|
|
@@ -2133,7 +2149,7 @@
|
|
|
2133
2149
|
"group": "scenarios",
|
|
2134
2150
|
"name": "disabled-interactive-scenario",
|
|
2135
2151
|
"path": "packages/samples/react/src/scenarios/disabled-interactive-elements.tsx",
|
|
2136
|
-
"code": "import {\n\tKolAccordion,\n\tKolButton,\n\tKolButtonLink,\n\tKolCard,\n\tKolDetails,\n\tKolInputCheckbox,\n\tKolInputColor,\n\tKolInputDate,\n\tKolInputEmail,\n\tKolInputFile,\n\tKolInputNumber,\n\tKolInputPassword,\n\tKolInputRadio,\n\tKolInputRange,\n\tKolInputText,\n\tKolLink,\n\tKolLinkButton,\n\tKolSelect,\n\tKolTextarea,\n} from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { SampleDescription } from '../components/SampleDescription';\nimport {
|
|
2152
|
+
"code": "import {\n\tKolAccordion,\n\tKolButton,\n\tKolButtonLink,\n\tKolCard,\n\tKolDetails,\n\tKolInputCheckbox,\n\tKolInputColor,\n\tKolInputDate,\n\tKolInputEmail,\n\tKolInputFile,\n\tKolInputNumber,\n\tKolInputPassword,\n\tKolInputRadio,\n\tKolInputRange,\n\tKolInputText,\n\tKolLink,\n\tKolLinkButton,\n\tKolSelect,\n\tKolTextarea,\n} from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { SampleDescription } from '../components/SampleDescription';\nimport { useAlert } from '../hooks/useAlert';\n\nconst OPTIONS = [\n\t{\n\t\tlabel: 'Option A',\n\t\tvalue: 'A',\n\t},\n\t{\n\t\tlabel: 'Option B',\n\t\tvalue: 'B',\n\t},\n];\n\nexport const DisabledInteractiveElements: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>This example shows how deactivated interactive elements are displayed.</p>\n\t\t\t\t<ul>\n\t\t\t\t\t<li>Deactivated interactive elements pose a particular challenge for accessibility.</li>\n\t\t\t\t\t<li>It must not be possible to focus on deactivated interactive elements, otherwise the tab paths will be unnecessarily extended.</li>\n\t\t\t\t\t<li>Deactivated interactive elements should be labelled clearly and legibly.</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\tDeactivated interactive elements have a tooltip for sighted people and aria labelling for the screen readers reading mode if they are represented by\n\t\t\t\t\t\tan interpretable graphic.\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<p>This implementation ensures standardized use for all users.</p>\n\t\t\t</SampleDescription>\n\n\t\t\t<div className=\"w-full grid gap-4\">\n\t\t\t\t<KolCard _label=\"Button\" _level={0}>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButton _label=\"Label\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _label=\"Label\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _hideLabel _icons=\"fa-solid fa-house\" _label=\"Label\" _on={dummyEventHandler} />\n\t\t\t\t\t\t<KolButton _disabled _hideLabel _icons=\"fa-solid fa-house\" _label=\"Label\" _on={dummyEventHandler} />\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard _label=\"ButtonLink\" _level={0}>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolButtonLink _label=\"Label\" />\n\t\t\t\t\t\t<KolButtonLink _disabled _label=\"Label\" />\n\t\t\t\t\t\t<KolButtonLink _hideLabel _icons=\"fa-solid fa-house\" _label=\"Label\" />\n\t\t\t\t\t\t<KolButtonLink _hideLabel _icons=\"fa-solid fa-house\" _disabled _label=\"Label\" />\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard _label=\"Link\" _level={0}>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolLink _href=\"#\" _label=\"Label\" />\n\t\t\t\t\t\t<KolLink _disabled _href=\"#\" _label=\"Label\" />\n\t\t\t\t\t\t<KolLink _hideLabel _href=\"#\" _icons=\"fa-solid fa-house\" _label=\"Label\" />\n\t\t\t\t\t\t<KolLink _disabled _hideLabel _href=\"#\" _icons=\"fa-solid fa-house\" _label=\"Label\" />\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard _label=\"LinkButton\" _level={0}>\n\t\t\t\t\t<div className=\"flex flex-wrap gap-4\">\n\t\t\t\t\t\t<KolLinkButton _href=\"#\" _label=\"Label\" />\n\t\t\t\t\t\t<KolLinkButton _disabled _href=\"#\" _label=\"Label\" />\n\t\t\t\t\t\t<KolLinkButton _hideLabel _href=\"#\" _icons=\"fa-solid fa-house\" _label=\"Label\" />\n\t\t\t\t\t\t<KolLinkButton _disabled _hideLabel _href=\"#\" _icons=\"fa-solid fa-house\" _label=\"Label\" />\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard _label=\"Accordion\" _level={0}>\n\t\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t\t<KolAccordion _label=\"Label\">Content</KolAccordion>\n\t\t\t\t\t\t<KolAccordion _disabled _label=\"Label\">\n\t\t\t\t\t\t\tContent\n\t\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t\t<KolAccordion _label=\"Label (open)\" _open>\n\t\t\t\t\t\t\tContent\n\t\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t\t<KolAccordion _disabled _label=\"Label (open)\" _open>\n\t\t\t\t\t\t\tContent\n\t\t\t\t\t\t</KolAccordion>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t<KolCard _label=\"Details\" _level={0}>\n\t\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t\t<KolDetails _label=\"Label\">Content</KolDetails>\n\t\t\t\t\t\t<KolDetails _disabled _label=\"Label\">\n\t\t\t\t\t\t\tContent\n\t\t\t\t\t\t</KolDetails>\n\t\t\t\t\t\t<KolDetails _label=\"Label (open)\" _open>\n\t\t\t\t\t\t\tContent\n\t\t\t\t\t\t</KolDetails>\n\t\t\t\t\t\t<KolDetails _disabled _label=\"Label (open)\" _open>\n\t\t\t\t\t\t\tContent\n\t\t\t\t\t\t</KolDetails>\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t\t{[KolInputCheckbox, KolInputColor, KolInputDate, KolInputEmail, KolInputFile, KolInputNumber, KolInputPassword, KolInputRange, KolInputText].map(\n\t\t\t\t\t(Input) => {\n\t\t\t\t\t\tconst render = (\n\t\t\t\t\t\t\tInput as typeof KolInputCheckbox & {\n\t\t\t\t\t\t\t\trender: { displayName: string };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t).render;\n\t\t\t\t\t\tconst name = render.displayName;\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<KolCard key={name} _label={name} _level={0}>\n\t\t\t\t\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t\t\t\t\t<Input _label=\"Label\" />\n\t\t\t\t\t\t\t\t\t<Input _disabled _label=\"Label\" />\n\t\t\t\t\t\t\t\t\t<Input _hideLabel _label=\"Label\" />\n\t\t\t\t\t\t\t\t\t<Input _disabled _hideLabel _label=\"Label\" />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</KolCard>\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t)}\n\t\t\t\t{[KolInputRadio, KolSelect].map((Input) => {\n\t\t\t\t\tconst render = (\n\t\t\t\t\t\tInput as typeof KolInputRadio & {\n\t\t\t\t\t\t\trender: { displayName: string };\n\t\t\t\t\t\t}\n\t\t\t\t\t).render;\n\t\t\t\t\tconst name = render.displayName;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<KolCard key={name} _label={name} _level={0}>\n\t\t\t\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t\t\t\t<Input _label=\"Label\" _options={OPTIONS} />\n\t\t\t\t\t\t\t\t<Input _disabled _label=\"Label\" _options={OPTIONS} />\n\t\t\t\t\t\t\t\t<Input _hideLabel _label=\"Label\" _options={OPTIONS} />\n\t\t\t\t\t\t\t\t<Input _disabled _hideLabel _label=\"Label\" _options={OPTIONS} />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</KolCard>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t<KolCard _label=\"KolTextarea\" _level={0}>\n\t\t\t\t\t<div className=\"grid gap-4\">\n\t\t\t\t\t\t<KolTextarea _label=\"Label\" _rows={3} />\n\t\t\t\t\t\t<KolTextarea _disabled _label=\"Label\" _rows={3} />\n\t\t\t\t\t\t<KolTextarea _hideLabel _label=\"Label\" _rows={3} />\n\t\t\t\t\t\t<KolTextarea _disabled _hideLabel _label=\"Label\" _rows={3} />\n\t\t\t\t\t</div>\n\t\t\t\t</KolCard>\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
2137
2153
|
"kind": "scenario"
|
|
2138
2154
|
},
|
|
2139
2155
|
{
|
|
@@ -2197,7 +2213,7 @@
|
|
|
2197
2213
|
"group": "scenarios",
|
|
2198
2214
|
"name": "same-height-of-all-interactive-elements",
|
|
2199
2215
|
"path": "packages/samples/react/src/scenarios/same-height-of-all-interactive-elements.tsx",
|
|
2200
|
-
"code": "import {\n\tKolButton,\n\tKolCombobox,\n\tKolInputColor,\n\tKolInputDate,\n\tKolInputEmail,\n\tKolInputFile,\n\tKolInputNumber,\n\tKolInputPassword,\n\tKolInputRange,\n\tKolInputText,\n\tKolLinkButton,\n\tKolSelect,\n\tKolSingleSelect,\n\tKolTextarea,\n} from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { SampleDescription } from '../components/SampleDescription';\nimport {
|
|
2216
|
+
"code": "import {\n\tKolButton,\n\tKolCombobox,\n\tKolInputColor,\n\tKolInputDate,\n\tKolInputEmail,\n\tKolInputFile,\n\tKolInputNumber,\n\tKolInputPassword,\n\tKolInputRange,\n\tKolInputText,\n\tKolLinkButton,\n\tKolSelect,\n\tKolSingleSelect,\n\tKolTextarea,\n} from '@public-ui/react-v19';\nimport type { FC } from 'react';\nimport React from 'react';\nimport { SampleDescription } from '../components/SampleDescription';\nimport { useAlert } from '../hooks/useAlert';\n\nexport const SameHeightOfAllInteractiveElements: FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\n\tconst dummyEventHandler = {\n\t\tonClick: dummyClickEventHandler,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tAll interactive elements, such as buttons and input fields, should have the same height to ensure a consistent and visually balanced user interface.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\t\t\t<div className=\"w-full flex flex-wrap gap-4\">\n\t\t\t\t<KolButton _icons=\"kolicon-house\" _label=\"Button\" _on={dummyEventHandler} />\n\t\t\t\t<KolButton _hideLabel _icons=\"kolicon-house\" _label=\"Button\" _on={dummyEventHandler} />\n\t\t\t\t<KolLinkButton _href=\"#\" _icons=\"kolicon-house\" _label=\"Link-Button\" _on={dummyEventHandler} />\n\t\t\t\t<KolLinkButton _hideLabel _href=\"#\" _icons=\"kolicon-house\" _label=\"Link-Button\" _on={dummyEventHandler} />\n\t\t\t\t<KolCombobox _hideLabel _icons=\"kolicon-house\" _label=\"Combobox\" _suggestions={[]} />\n\t\t\t\t<KolInputColor\n\t\t\t\t\t_hideLabel\n\t\t\t\t\t_icons={{\n\t\t\t\t\t\tleft: 'kolicon-house',\n\t\t\t\t\t}}\n\t\t\t\t\t_label=\"Input-Color\"\n\t\t\t\t/>\n\t\t\t\t<KolInputFile _hideLabel _icons=\"kolicon-house\" _label=\"Input-File\" />\n\t\t\t\t<KolInputDate _hideLabel _icons=\"kolicon-house\" _label=\"Input-Date\" />\n\t\t\t\t<KolInputEmail _hideLabel _icons=\"kolicon-house\" _label=\"Input-Email\" />\n\t\t\t\t<KolInputNumber _hideLabel _icons=\"kolicon-house\" _label=\"Input-Number\" />\n\t\t\t\t<KolInputPassword _hideLabel _icons=\"kolicon-house\" _label=\"Input-Password\" />\n\t\t\t\t<KolInputRange _hideLabel _icons=\"kolicon-house\" _label=\"Input-Range\" />\n\t\t\t\t<KolInputText _hideLabel _icons=\"kolicon-house\" _label=\"Input-Text\" />\n\t\t\t\t<KolSelect _hideLabel _icons=\"kolicon-house\" _label=\"Select\" _options={[]} />\n\t\t\t\t<KolSingleSelect _hideLabel _icons=\"kolicon-house\" _label=\"Single Select\" _options={[]} />\n\t\t\t\t<KolTextarea _hideLabel _icons=\"kolicon-house\" _label=\"Textarea\" />\n\t\t\t</div>\n\t\t</>\n\t);\n};\n",
|
|
2201
2217
|
"kind": "scenario"
|
|
2202
2218
|
},
|
|
2203
2219
|
{
|
|
@@ -2205,7 +2221,7 @@
|
|
|
2205
2221
|
"group": "scenarios",
|
|
2206
2222
|
"name": "sample-form-with-validation",
|
|
2207
2223
|
"path": "packages/samples/react/src/scenarios/sample-form-with-validation.tsx",
|
|
2208
|
-
"code": "import { zodResolver } from '@hookform/resolvers/zod';\nimport {\n\tKolComboboxController,\n\tKolInputCheckboxController,\n\tKolInputColorController,\n\tKolInputDateController,\n\tKolInputEmailController,\n\tKolInputNumberController,\n\tKolInputPasswordController,\n\tKolInputRadioController,\n\tKolInputRangeController,\n\tKolInputTextController,\n\tKolSelectController,\n\tKolSingleSelectController,\n\tKolTextareaController,\n} from '@public-ui/react-hook-form-adapter';\nimport { KolAlert, KolButton, KolHeading, KolLink } from '@public-ui/react-v19';\nimport React from 'react';\nimport type { FieldError } from 'react-hook-form';\nimport { useForm } from 'react-hook-form';\nimport { z } from 'zod';\n\nimport { SampleDescription } from '../components/SampleDescription';\nimport {
|
|
2224
|
+
"code": "import { zodResolver } from '@hookform/resolvers/zod';\nimport {\n\tKolComboboxController,\n\tKolInputCheckboxController,\n\tKolInputColorController,\n\tKolInputDateController,\n\tKolInputEmailController,\n\tKolInputNumberController,\n\tKolInputPasswordController,\n\tKolInputRadioController,\n\tKolInputRangeController,\n\tKolInputTextController,\n\tKolSelectController,\n\tKolSingleSelectController,\n\tKolTextareaController,\n} from '@public-ui/react-hook-form-adapter';\nimport { KolAlert, KolButton, KolHeading, KolLink } from '@public-ui/react-v19';\nimport React from 'react';\nimport type { FieldError } from 'react-hook-form';\nimport { useForm } from 'react-hook-form';\nimport { z } from 'zod';\n\nimport { SampleDescription } from '../components/SampleDescription';\nimport { useAlert } from '../hooks/useAlert';\nimport { COUNTRY_SUGGESTIONS } from '../shares/country';\n\nconst formSchema = z.object({\n\tdate: z.preprocess(\n\t\t(val) => (typeof val === 'string' || val instanceof Date ? new Date(val) : undefined),\n\t\tz.date({ message: 'Date is required' }).refine((d) => !isNaN(d.getTime()), { message: 'Invalid date' }),\n\t),\n\n\ttext: z.string({ message: 'Please enter text.' }).min(10, 'Text must be at least 10 characters long.'),\n\temail: z.string({ message: 'Please enter your email.' }).min(1, 'Please enter your email.').email('Invalid email address.'),\n\tpassword: z\n\t\t.string({ message: 'Please enter a password.' })\n\t\t.min(8, 'Password must be at least 8 characters.')\n\t\t.regex(/[A-Z]/, 'Password must include at least one uppercase letter.')\n\t\t.regex(/[0-9]/, 'Password must include at least one number.'),\n\trange: z.number({ message: 'Please select a range.' }).min(30, 'Minimum value is 30.'),\n\tnumber: z.number({ message: 'Please enter a number.' }).min(1, 'Minimum is 1.').max(10, 'Maximum is 10.'),\n\tcheckbox: z.boolean().refine((val: boolean) => val === true, {\n\t\tmessage: 'You must accept the terms and conditions.',\n\t}),\n\n\tradio: z.string({ message: 'Please select a gender.' }).min(1, 'Please select a gender.'),\n\tcolor: z.string({ message: 'Please select a color.' }).min(1, 'Please select a color.'),\n\tselect: z.string({ message: 'Please select a value.' }).min(1, 'Please select a value.'),\n\tsingleSelect: z.string({ message: 'Please select a single option.' }).min(1, 'Please select a single option.'),\n\tcombobox: z.string({ message: 'Please select a country.' }).min(1, 'Please select a country.'),\n\ttextarea: z.string({ message: 'Please enter a message.' }).min(1, 'Please enter a message.'),\n});\n\nexport const SampleFormWithValidation: React.FC = () => {\n\tconst { dummyClickEventHandler } = useAlert();\n\tconst {\n\t\thandleSubmit,\n\t\tformState: { errors },\n\t\treset,\n\t\tcontrol,\n\t} = useForm({\n\t\tmode: 'onBlur',\n\t\treValidateMode: 'onChange',\n\t\tresolver: zodResolver(formSchema),\n\t\tdefaultValues: {\n\t\t\trange: 30,\n\t\t\tnumber: 5,\n\t\t},\n\t});\n\n\tconst onReset = () => {\n\t\treset(undefined, {\n\t\t\tkeepErrors: false,\n\t\t\tkeepTouched: false,\n\t\t\tkeepDirty: false,\n\t\t});\n\t};\n\n\tconst allErrors = Object.entries(errors)\n\t\t.map(([key, value]) => [key, (value as FieldError).message] as const)\n\t\t.filter(([, msg]) => Boolean(msg));\n\n\treturn (\n\t\t<section className=\"w-full max-w-3xl mx-auto p-6\">\n\t\t\t<KolHeading _level={2} _label=\"Sample Form with Validation (Zod)\" />\n\t\t\t<SampleDescription>\n\t\t\t\t<p>\n\t\t\t\t\tThis example shows validation with <code>react-hook-form</code>, <code>Zod</code>, and an error list.\n\t\t\t\t</p>\n\t\t\t</SampleDescription>\n\n\t\t\t{allErrors.length > 0 && (\n\t\t\t\t<KolAlert _type=\"error\" _label=\"Please fix the following:\" _alert _variant=\"card\">\n\t\t\t\t\t<ul className=\"list-disc pl-5\">\n\t\t\t\t\t\t{allErrors.map(([key, msg], i) => (\n\t\t\t\t\t\t\t<li key={i}>\n\t\t\t\t\t\t\t\t<KolLink\n\t\t\t\t\t\t\t\t\t_label={msg}\n\t\t\t\t\t\t\t\t\t_href={`#field-${key}`}\n\t\t\t\t\t\t\t\t\t_on={{\n\t\t\t\t\t\t\t\t\t\tonClick: (e: Event) => {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tconst input = document.getElementById(`field-${key}`);\n\t\t\t\t\t\t\t\t\t\t\tinput?.focus();\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</KolAlert>\n\t\t\t)}\n\n\t\t\t<form onSubmit={handleSubmit(dummyClickEventHandler)} noValidate className=\"grid gap-4 mt-6\">\n\t\t\t\t<KolInputDateController control={control as any} name=\"date\" _label=\"Date\" />\n\t\t\t\t<KolInputTextController control={control as any} name=\"text\" _label=\"Text (ā„ 10 chars)\" />\n\t\t\t\t<KolInputEmailController control={control as any} name=\"email\" _label=\"Email\" />\n\t\t\t\t<KolInputPasswordController control={control as any} name=\"password\" _label=\"Password\" />\n\t\t\t\t<KolInputRangeController control={control as any} name=\"range\" _label=\"Range (ā„ 30)\" _min={0} _max={100} />\n\t\t\t\t<KolInputNumberController control={control as any} name=\"number\" _label=\"Number (1 ā 10)\" />\n\t\t\t\t<KolInputCheckboxController control={control as any} name=\"checkbox\" _label=\"Accept terms\" />\n\t\t\t\t<KolInputRadioController\n\t\t\t\t\tcontrol={control as any}\n\t\t\t\t\tname=\"radio\"\n\t\t\t\t\t_label=\"Gender\"\n\t\t\t\t\t_options={[\n\t\t\t\t\t\t{ label: 'Female', value: 'f' },\n\t\t\t\t\t\t{ label: 'Male', value: 'm' },\n\t\t\t\t\t]}\n\t\t\t\t/>\n\t\t\t\t<KolInputColorController control={control as any} name=\"color\" _label=\"Favorite Color\" />\n\t\t\t\t<KolSelectController\n\t\t\t\t\tcontrol={control as any}\n\t\t\t\t\tname=\"select\"\n\t\t\t\t\t_label=\"Select\"\n\t\t\t\t\t_options={[\n\t\t\t\t\t\t{ label: 'Option A', value: 'A' },\n\t\t\t\t\t\t{ label: 'Option B', value: 'B' },\n\t\t\t\t\t]}\n\t\t\t\t/>\n\t\t\t\t<KolSingleSelectController\n\t\t\t\t\tcontrol={control as any}\n\t\t\t\t\tname=\"singleSelect\"\n\t\t\t\t\t_label=\"Single Select\"\n\t\t\t\t\t_options={[\n\t\t\t\t\t\t{ label: 'Option A', value: 'A' },\n\t\t\t\t\t\t{ label: 'Option B', value: 'B' },\n\t\t\t\t\t]}\n\t\t\t\t/>\n\t\t\t\t<KolComboboxController control={control as any} name=\"combobox\" _label=\"Country\" _suggestions={COUNTRY_SUGGESTIONS} />\n\t\t\t\t<KolTextareaController control={control as any} name=\"textarea\" _label=\"Message\" _rows={4} />\n\n\t\t\t\t<div className=\"flex gap-4 mt-4\">\n\t\t\t\t\t<KolButton _label=\"Submit\" _type=\"submit\" _variant=\"primary\" />\n\t\t\t\t\t<KolButton _label=\"Reset\" _type=\"reset\" onClick={onReset} />\n\t\t\t\t</div>\n\t\t\t</form>\n\t\t</section>\n\t);\n};\n",
|
|
2209
2225
|
"kind": "scenario"
|
|
2210
2226
|
},
|
|
2211
2227
|
{
|