@design-system-rte/angular 0.1.1-rc1

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.
Files changed (36) hide show
  1. package/.editorconfig +15 -0
  2. package/.storybook/main.ts +25 -0
  3. package/.storybook/preview.scss +10 -0
  4. package/.storybook/preview.ts +27 -0
  5. package/.storybook/tsconfig.doc.json +7 -0
  6. package/.storybook/tsconfig.json +11 -0
  7. package/.storybook/typings.d.ts +4 -0
  8. package/.vscode/extensions.json +4 -0
  9. package/.vscode/launch.json +20 -0
  10. package/.vscode/tasks.json +42 -0
  11. package/angular.json +127 -0
  12. package/package.json +55 -0
  13. package/src/assets/.gitkeep +0 -0
  14. package/src/components/button/button.component.html +7 -0
  15. package/src/components/button/button.component.scss +156 -0
  16. package/src/components/button/button.component.spec.ts +23 -0
  17. package/src/components/button/button.component.stories.ts +103 -0
  18. package/src/components/button/button.component.ts +25 -0
  19. package/src/components/grid/col/col.directive.ts +37 -0
  20. package/src/components/grid/grid.directive.stories.ts +149 -0
  21. package/src/components/grid/grid.directive.ts +24 -0
  22. package/src/components/link/link.component.html +5 -0
  23. package/src/components/link/link.component.scss +108 -0
  24. package/src/components/link/link.component.stories.ts +61 -0
  25. package/src/components/link/link.component.ts +19 -0
  26. package/src/components/radio-button/radio-button.component.html +24 -0
  27. package/src/components/radio-button/radio-button.component.scss +140 -0
  28. package/src/components/radio-button/radio-button.component.stories.ts +75 -0
  29. package/src/components/radio-button/radio-button.component.ts +23 -0
  30. package/src/components/radio-button-group/radio-button-group.component.html +45 -0
  31. package/src/components/radio-button-group/radio-button-group.component.scss +82 -0
  32. package/src/components/radio-button-group/radio-button-group.component.stories.ts +124 -0
  33. package/src/components/radio-button-group/radio-button-group.component.ts +30 -0
  34. package/tsconfig.app.json +14 -0
  35. package/tsconfig.json +32 -0
  36. package/tsconfig.spec.json +14 -0
package/.editorconfig ADDED
@@ -0,0 +1,15 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ indent_style = space
6
+ indent_size = 2
7
+ insert_final_newline = true
8
+ trim_trailing_whitespace = true
9
+
10
+ [*.ts]
11
+ quote_type = single
12
+
13
+ [*.md]
14
+ max_line_length = off
15
+ trim_trailing_whitespace = false
@@ -0,0 +1,25 @@
1
+ import type { StorybookConfig } from '@storybook/angular';
2
+
3
+ import { join, dirname } from "path"
4
+
5
+ function getAbsolutePath(value: string): any {
6
+ return dirname(require.resolve(join(value, 'package.json')))
7
+ }
8
+ const config: StorybookConfig = {
9
+ "stories": [
10
+ "../src/**/*.mdx",
11
+ "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
12
+ ],
13
+ "addons": [
14
+ getAbsolutePath('@storybook/addon-essentials'),
15
+ getAbsolutePath('@storybook/addon-onboarding'),
16
+ getAbsolutePath('@chromatic-com/storybook'),
17
+ getAbsolutePath('@storybook/addon-interactions'),
18
+ getAbsolutePath("@storybook/addon-a11y")
19
+ ],
20
+ "framework": {
21
+ "name": getAbsolutePath('@storybook/angular'),
22
+ "options": {}
23
+ }
24
+ };
25
+ export default config;
@@ -0,0 +1,10 @@
1
+ @use "@design-system-rte/core/tokens/_mixins.scss" as *;
2
+ @use "@design-system-rte/core/components/grid/grid.stories.scss" as *;
3
+ @use "@design-system-rte/core/components/grid/grid.scss" as *;
4
+
5
+ @include theme-selector('bleu_iceberg');
6
+ @include theme-selector('bleu_iceberg', 'dark');
7
+ @include theme-selector('violet');
8
+ @include theme-selector('violet', 'dark');
9
+ @include theme-selector('vert_foret');
10
+ @include theme-selector('vert_foret', 'dark');
@@ -0,0 +1,27 @@
1
+ import type { Preview } from '@storybook/angular'
2
+ import { setCompodocJson } from "@storybook/addon-docs/angular";
3
+ import docJson from "../documentation.json";
4
+ setCompodocJson(docJson);
5
+
6
+ import { addons } from '@storybook/preview-api';
7
+
8
+ const preview: Preview = {
9
+ parameters: {
10
+ controls: {
11
+ matchers: {
12
+ color: /(background|color)$/i,
13
+ date: /Date$/i,
14
+ },
15
+ },
16
+ },
17
+ };
18
+
19
+ addons.getChannel().on('THEME_CHANGED', (theme) => {
20
+ document.querySelector("html")?.setAttribute("data-mode", theme.theme);
21
+ document.querySelector("html")?.setAttribute("data-theme", theme.color);
22
+ })
23
+
24
+ document.querySelector("html")?.setAttribute("data-theme", "bleu_iceberg");
25
+ document.querySelector("html")?.setAttribute("data-mode", "light");
26
+
27
+ export default preview;
@@ -0,0 +1,7 @@
1
+
2
+ {
3
+ "extends": "./tsconfig.json",
4
+ "exclude": ["../src/test.ts", "../src/**/*.spec.ts", "../src/**/*.stories.ts"],
5
+ "include": ["../src/**/*"],
6
+ "files": ["./typings.d.ts"]
7
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../tsconfig.app.json",
3
+ "compilerOptions": {
4
+ "types": ["node"],
5
+ "allowSyntheticDefaultImports": true,
6
+ "resolveJsonModule": true
7
+ },
8
+ "exclude": ["../src/test.ts", "../src/**/*.spec.ts"],
9
+ "include": ["../src/**/*.stories.*", "./preview.ts"],
10
+ "files": ["./typings.d.ts"]
11
+ }
@@ -0,0 +1,4 @@
1
+ declare module '*.md' {
2
+ const content: string;
3
+ export default content;
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3
+ "recommendations": ["angular.ng-template"]
4
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3
+ "version": "0.2.0",
4
+ "configurations": [
5
+ {
6
+ "name": "ng serve",
7
+ "type": "chrome",
8
+ "request": "launch",
9
+ "preLaunchTask": "npm: start",
10
+ "url": "http://localhost:4200/"
11
+ },
12
+ {
13
+ "name": "ng test",
14
+ "type": "chrome",
15
+ "request": "launch",
16
+ "preLaunchTask": "npm: test",
17
+ "url": "http://localhost:9876/debug.html"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3
+ "version": "2.0.0",
4
+ "tasks": [
5
+ {
6
+ "type": "npm",
7
+ "script": "start",
8
+ "isBackground": true,
9
+ "problemMatcher": {
10
+ "owner": "typescript",
11
+ "pattern": "$tsc",
12
+ "background": {
13
+ "activeOnStart": true,
14
+ "beginsPattern": {
15
+ "regexp": "(.*?)"
16
+ },
17
+ "endsPattern": {
18
+ "regexp": "bundle generation complete"
19
+ }
20
+ }
21
+ }
22
+ },
23
+ {
24
+ "type": "npm",
25
+ "script": "test",
26
+ "isBackground": true,
27
+ "problemMatcher": {
28
+ "owner": "typescript",
29
+ "pattern": "$tsc",
30
+ "background": {
31
+ "activeOnStart": true,
32
+ "beginsPattern": {
33
+ "regexp": "(.*?)"
34
+ },
35
+ "endsPattern": {
36
+ "regexp": "bundle generation complete"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ]
42
+ }
package/angular.json ADDED
@@ -0,0 +1,127 @@
1
+ {
2
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3
+ "version": 1,
4
+ "newProjectRoot": "projects",
5
+ "projects": {
6
+ "angular": {
7
+ "projectType": "library",
8
+ "schematics": {},
9
+ "root": "",
10
+ "sourceRoot": "src",
11
+ "prefix": "app",
12
+ "architect": {
13
+ "build": {
14
+ "builder": "@angular-devkit/build-angular:application",
15
+ "options": {
16
+ "outputPath": "dist/angular",
17
+ "index": "src/index.html",
18
+ "browser": "src/main.ts",
19
+ "polyfills": [
20
+ "zone.js"
21
+ ],
22
+ "tsConfig": "tsconfig.app.json",
23
+ "assets": [
24
+ "src/assets"
25
+ ],
26
+ "styles": [],
27
+ "scripts": [],
28
+ "stylePreprocessorOptions": {
29
+ "includePaths": ["../"]
30
+ }
31
+ },
32
+ "configurations": {
33
+ "production": {
34
+ "budgets": [
35
+ {
36
+ "type": "initial",
37
+ "maximumWarning": "500kb",
38
+ "maximumError": "1mb"
39
+ },
40
+ {
41
+ "type": "anyComponentStyle",
42
+ "maximumWarning": "2kb",
43
+ "maximumError": "4kb"
44
+ }
45
+ ],
46
+ "outputHashing": "all"
47
+ },
48
+ "development": {
49
+ "optimization": false,
50
+ "extractLicenses": false,
51
+ "sourceMap": true
52
+ }
53
+ },
54
+ "defaultConfiguration": "production"
55
+ },
56
+ "serve": {
57
+ "builder": "@angular-devkit/build-angular:dev-server",
58
+ "configurations": {
59
+ "production": {
60
+ "buildTarget": "angular:build:production"
61
+ },
62
+ "development": {
63
+ "buildTarget": "angular:build:development"
64
+ }
65
+ },
66
+ "defaultConfiguration": "development"
67
+ },
68
+ "extract-i18n": {
69
+ "builder": "@angular-devkit/build-angular:extract-i18n",
70
+ "options": {
71
+ "buildTarget": "angular:build"
72
+ }
73
+ },
74
+ "test": {
75
+ "builder": "@angular-devkit/build-angular:karma",
76
+ "options": {
77
+ "polyfills": [
78
+ "zone.js",
79
+ "zone.js/testing"
80
+ ],
81
+ "tsConfig": "tsconfig.spec.json",
82
+ "assets": [
83
+ "src/assets"
84
+ ],
85
+ "styles": [],
86
+ "scripts": []
87
+ }
88
+ },
89
+ "storybook": {
90
+ "builder": "@storybook/angular:start-storybook",
91
+ "options": {
92
+ "configDir": ".storybook",
93
+ "browserTarget": "angular:build",
94
+ "compodoc": true,
95
+ "compodocArgs": [
96
+ "-e",
97
+ "json",
98
+ "-d",
99
+ "."
100
+ ],
101
+ "styles": ["@design-system-rte/core/tokens/main.scss", ".storybook/preview.scss"],
102
+ "port": 6006
103
+ }
104
+ },
105
+ "build-storybook": {
106
+ "builder": "@storybook/angular:build-storybook",
107
+ "options": {
108
+ "configDir": ".storybook",
109
+ "browserTarget": "angular:build",
110
+ "styles": ["@design-system-rte/core/tokens/main.scss", ".storybook/preview.scss"],
111
+ "compodoc": true,
112
+ "compodocArgs": [
113
+ "-e",
114
+ "json",
115
+ "-d",
116
+ "."
117
+ ],
118
+ "outputDir": "storybook-static"
119
+ }
120
+ }
121
+ }
122
+ }
123
+ },
124
+ "cli": {
125
+ "analytics": "9019dcae-6ff4-41d3-acb7-b8e169519772"
126
+ }
127
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@design-system-rte/angular",
3
+ "version": "0.1.1-rc1",
4
+ "scripts": {
5
+ "ng": "ng",
6
+ "build": "echo \"No build for Angular package\" && exit 0",
7
+ "storybook": "ng run angular:storybook --port 7007",
8
+ "build-storybook": "ng run angular:build-storybook --output-dir ../design-docs/storybook-static/angular --config-dir .storybook",
9
+ "test:ci": "npx playwright install && npx start-server-and-test storybook http://localhost:7007 test",
10
+ "test": "test-storybook --url http://localhost:7007"
11
+ },
12
+ "description": "Angular components for the Design System RTE",
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "dependencies": {
17
+ "@angular/animations": "^17.3.0",
18
+ "@angular/common": "^17.3.0",
19
+ "@angular/compiler": "^17.3.0",
20
+ "@angular/core": "^17.3.0",
21
+ "@angular/forms": "^17.3.0",
22
+ "@angular/platform-browser": "^17.3.0",
23
+ "@angular/platform-browser-dynamic": "^17.3.0",
24
+ "@angular/router": "^17.3.0",
25
+ "rxjs": "~7.8.0",
26
+ "tslib": "^2.3.0",
27
+ "zone.js": "~0.14.3",
28
+ "@design-system-rte/core": "0.1.2-rc1"
29
+ },
30
+ "devDependencies": {
31
+ "@angular-devkit/build-angular": "^17.3.12",
32
+ "@angular/cli": "^17.3.12",
33
+ "@angular/compiler-cli": "^17.3.0",
34
+ "@chromatic-com/storybook": "^3.2.6",
35
+ "@compodoc/compodoc": "^1.1.26",
36
+ "@storybook/addon-a11y": "^8.6.6",
37
+ "@storybook/addon-docs": "^8.6.6",
38
+ "@storybook/addon-essentials": "^8.6.6",
39
+ "@storybook/addon-interactions": "^8.6.6",
40
+ "@storybook/addon-onboarding": "^8.6.6",
41
+ "@storybook/angular": "^8.6.6",
42
+ "@storybook/blocks": "^8.6.6",
43
+ "@storybook/test": "^8.6.6",
44
+ "@storybook/test-runner": "^0.22.0",
45
+ "@types/jasmine": "~5.1.0",
46
+ "jasmine-core": "~5.1.0",
47
+ "karma": "~6.4.0",
48
+ "karma-chrome-launcher": "~3.2.0",
49
+ "karma-coverage": "~2.2.0",
50
+ "karma-jasmine": "~5.1.0",
51
+ "karma-jasmine-html-reporter": "~2.1.0",
52
+ "storybook": "^8.6.6",
53
+ "typescript": "~5.4.2"
54
+ }
55
+ }
File without changes
@@ -0,0 +1,7 @@
1
+ <button
2
+ class="rte-button {{ variant() }} size-{{ size() }}"
3
+ [disabled]="disabled()"
4
+ (click)="onClick($event)"
5
+ >
6
+ <span class="rte-button-label">{{ label() }}</span>
7
+ </button>
@@ -0,0 +1,156 @@
1
+ @use '@design-system-rte/core/tokens/main.scss' as *;
2
+
3
+ .rte-button {
4
+ align-items: center;
5
+ cursor: pointer;
6
+ display: inline-flex;
7
+ flex-shrink: 0;
8
+ justify-content: center;
9
+
10
+ &:focus-visible {
11
+ outline: 1px solid var(--border-brand-focused);
12
+ outline-offset: 4px;
13
+ }
14
+
15
+ &.size-s {
16
+ @include typography-button-s;
17
+ height: 24px;
18
+ border-radius: $radius-s;
19
+ padding: $positive-spacing_050 $positive-spacing_100;
20
+
21
+ .rte-button-label {
22
+ margin: 0 $positive-spacing_050;
23
+ }
24
+ }
25
+
26
+ &.size-m {
27
+ @include typography-button-m;
28
+ height: 32px;
29
+ border-radius: $radius-s;
30
+ padding: $positive-spacing_050 $positive-spacing_150;
31
+
32
+ .rte-button-label {
33
+ margin: 0 $positive-spacing_075;
34
+ }
35
+ }
36
+
37
+ &.size-l {
38
+ @include typography-button-l;
39
+ height: 40px;
40
+ border-radius: $radius-m;
41
+ padding: $positive-spacing_050 $positive-spacing_200;
42
+
43
+ .rte-button-label {
44
+ margin: 0 $positive-spacing_100;
45
+ }
46
+ }
47
+
48
+ &.filled {
49
+ border: var(--border-brand-default);
50
+ color: var(--content-primary-inverse);
51
+ background: var(--background-brand-default);
52
+
53
+ &:hover {
54
+ background: var(--background-brand-hover);
55
+ border: var(--background-brand-hover);
56
+ }
57
+
58
+ &:active {
59
+ background: var(--background-brand-pressed);
60
+ }
61
+
62
+ &:disabled {
63
+ background: var(--background-disabled);
64
+ border: solid 1px var(--border-disabled);
65
+ color: var(--content-disabled);
66
+ box-shadow: none;
67
+ cursor: default;
68
+ }
69
+ };
70
+
71
+ &.outlined {
72
+ background: var(--background-default);
73
+ border: solid 1px var(--border-brand-default);
74
+ color: var(--content-brand-default);
75
+
76
+ &:hover {
77
+ background: var(--background-brand-inverse-hover);
78
+ border: solid 1px var(--border-brand-default);
79
+ }
80
+
81
+ &:active {
82
+ border: var(--background-brand-inverse);
83
+ background: var(--background-brand-inverse-pressed);
84
+ }
85
+
86
+ &:disabled {
87
+ background: var(--background-disabled);
88
+ border: solid 1px var(--border-disabled);
89
+ color: var(--content-disabled);
90
+ cursor: default;
91
+ }
92
+ };
93
+
94
+ &.text {
95
+ background: transparent;
96
+ border: none;
97
+ color: var(--content-brand-default);
98
+
99
+ &:hover {
100
+ background: var(--background-brand-inverse-hover);
101
+ }
102
+
103
+ &:active {
104
+ background: var(--background-brand-inverse-pressed);
105
+ }
106
+
107
+ &:disabled {
108
+ background: var(--background-disabled);
109
+ color: var(--content-disabled);
110
+ cursor: default;
111
+ }
112
+ };
113
+
114
+ &.transparent {
115
+ background: transparent;
116
+ border: none;
117
+ color: var(--content-brand-default);
118
+
119
+ &:hover {
120
+ color: var(--content-brand-hover);
121
+ }
122
+
123
+ &:active {
124
+ color: var(--content-brand-pressed);
125
+ }
126
+
127
+ &:disabled {
128
+ color: var(--content-disabled);
129
+ box-shadow: none;
130
+ cursor: default;
131
+ }
132
+ };
133
+
134
+ &.danger {
135
+ background: var(--background-danger-default);
136
+ border: none;
137
+ color: var(--content-primary-inverse);
138
+ border-radius: $radius-m;
139
+
140
+ &:hover {
141
+ background: var(--background-danger-hover);
142
+ }
143
+
144
+ &:active {
145
+ background: var(--background-danger-pressed);
146
+ }
147
+
148
+ &:disabled {
149
+ background: var(--background-disabled);
150
+ border: var(--border-disabled);
151
+ color: var(--content-disabled);
152
+ box-shadow: none;
153
+ cursor: default;
154
+ }
155
+ }
156
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { ButtonComponent } from './button.component';
4
+
5
+ describe('ButtonComponent', () => {
6
+ let component: ButtonComponent;
7
+ let fixture: ComponentFixture<ButtonComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [ButtonComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(ButtonComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,103 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular';
2
+ import { fn, userEvent, within, expect } from '@storybook/test';
3
+ // TODO: Resolve import from core
4
+ // import { ENTER_KEY, SPACE_KEY, TAB_KEY } from '@design-system-rte/core/constants/keyboard.constants';
5
+
6
+ import { ButtonComponent } from './button.component';
7
+
8
+
9
+ const meta: Meta<ButtonComponent>= {
10
+ title: 'Button',
11
+ component: ButtonComponent,
12
+ tags: ['autodocs'],
13
+ argTypes: {
14
+ variant: {
15
+ control: 'select',
16
+ options: ['filled', 'outlined', 'text', 'transparent', 'danger'],
17
+ },
18
+ size: {
19
+ control: 'select',
20
+ options: ['s', 'm', 'l'],
21
+ },
22
+ disabled: {
23
+ control: 'boolean',
24
+ },
25
+ },
26
+ args: { click: fn() },
27
+ };
28
+
29
+ export default meta;
30
+ type Story = StoryObj<ButtonComponent>;
31
+
32
+ const mockFn = fn();
33
+
34
+ export const Default: Story = {
35
+
36
+ args: {
37
+ variant: 'filled',
38
+ label: 'Button',
39
+ click: mockFn,
40
+ },
41
+ play: async ({ canvasElement }) => {
42
+ const canvas = within(canvasElement);
43
+ const button = canvas.getByRole('button');
44
+ await userEvent.click(button);
45
+ expect(mockFn).toHaveBeenCalled();
46
+ button.blur();
47
+ },
48
+ };
49
+
50
+ export const Sizing: Story = {
51
+
52
+ render: (args) => ({
53
+ props: args,
54
+ template: `
55
+ <div style="display: flex; gap: 8px;">
56
+ <rte-button
57
+ size="s"
58
+ label="Small"
59
+ variant="filled"
60
+ data-testid="small-button"
61
+ />
62
+ <rte-button
63
+ size="m"
64
+ label="Medium"
65
+ variant="filled"
66
+ data-testid="medium-button"
67
+ />
68
+ <rte-button
69
+ size="l"
70
+ label="Large"
71
+ variant="filled"
72
+ data-testid="large-button"
73
+ />
74
+ </div>
75
+ `,
76
+ }),
77
+ play: async ({ canvasElement }) => {
78
+ const canvas = within(canvasElement);
79
+ const smallButton = canvas.getByTestId('small-button').getElementsByTagName('button')[0];
80
+ const mediumButton = canvas.getByTestId('medium-button').getElementsByTagName('button')[0];
81
+ const largeButton = canvas.getByTestId('large-button').getElementsByTagName('button')[0];
82
+
83
+ expect(smallButton.clientHeight).toBe(24);
84
+ expect(mediumButton.clientHeight).toBe(32);
85
+ expect(largeButton.clientHeight).toBe(40);
86
+ },
87
+ };
88
+
89
+ export const KeyboardInteraction: Story = {
90
+ args: {
91
+ ...Default.args,
92
+ },
93
+ play: async ({ canvasElement }) => {
94
+ const canvas = within(canvasElement);
95
+ const button = canvas.getByRole('button');
96
+ await userEvent.keyboard(`{Tab}`);
97
+ expect(button).toHaveFocus();
98
+ await userEvent.keyboard(`{Enter}}`);
99
+ await userEvent.keyboard(`{ }`);
100
+ expect(mockFn).toHaveBeenCalledTimes(2);
101
+ button.blur();
102
+ },
103
+ };
@@ -0,0 +1,25 @@
1
+ import { Component, input, output } from '@angular/core';
2
+ import { ButtonSize, ButtonVariant } from '@design-system-rte/core/components/button/button.interface';
3
+
4
+ @Component({
5
+ selector: 'rte-button',
6
+ standalone: true,
7
+ imports: [],
8
+ templateUrl: './button.component.html',
9
+ styleUrl: './button.component.scss'
10
+ })
11
+ export class ButtonComponent {
12
+
13
+ label = input('');
14
+ variant = input<ButtonVariant>('filled');
15
+ size = input<ButtonSize>('m');
16
+ disabled = input(false);
17
+
18
+ click = output<void>();
19
+
20
+ onClick(event: MouseEvent | KeyboardEvent): void {
21
+ event.stopPropagation();
22
+ this.click.emit();
23
+ }
24
+
25
+ }