@kraft.stitch/angular 0.0.4-beta.1 → 0.0.4-beta.2

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 (56) hide show
  1. package/fesm2022/kraft.stitch-angular.mjs +3043 -0
  2. package/fesm2022/kraft.stitch-angular.mjs.map +1 -0
  3. package/package.json +17 -16
  4. package/types/kraft.stitch-angular.d.ts +2395 -0
  5. package/.github/workflows/npm-publish.yml +0 -41
  6. package/ng-package.json +0 -10
  7. package/src/lib/Buttons/button/button.ts +0 -152
  8. package/src/lib/Buttons/button-group/button-group.ts +0 -129
  9. package/src/lib/Buttons/chips/chips.ts +0 -131
  10. package/src/lib/Buttons/fab/fab.ts +0 -96
  11. package/src/lib/Buttons/split-button/split-button.ts +0 -111
  12. package/src/lib/Calendars/datepicker/datepicker.ts +0 -105
  13. package/src/lib/Calendars/daterange/daterange.ts +0 -112
  14. package/src/lib/Calendars/timepicker/timepicker.ts +0 -117
  15. package/src/lib/Dropdowns/dropdown/dropdown.ts +0 -121
  16. package/src/lib/Dropdowns/listbox/listbox.ts +0 -116
  17. package/src/lib/Inputs/checkbox/checkbox.ts +0 -126
  18. package/src/lib/Inputs/colour-picker/colour-picker.ts +0 -101
  19. package/src/lib/Inputs/input/input.ts +0 -139
  20. package/src/lib/Inputs/otp-input/otp-input.ts +0 -113
  21. package/src/lib/Inputs/radio/radio.ts +0 -115
  22. package/src/lib/Inputs/rating/rating.ts +0 -104
  23. package/src/lib/Inputs/rolling-number/rolling-number.ts +0 -136
  24. package/src/lib/Inputs/slider/slider.ts +0 -121
  25. package/src/lib/Inputs/switch/switch.ts +0 -100
  26. package/src/lib/Inputs/textarea/textarea.ts +0 -129
  27. package/src/lib/Inputs/theme-switch/theme-switch.ts +0 -61
  28. package/src/lib/Inputs/uploader/uploader.ts +0 -97
  29. package/src/lib/Layout/avatar/avatar.ts +0 -66
  30. package/src/lib/Layout/card/card.ts +0 -88
  31. package/src/lib/Layout/code-view/code-view.ts +0 -77
  32. package/src/lib/Layout/dialog/dialog.ts +0 -80
  33. package/src/lib/Layout/not-found/not-found.ts +0 -73
  34. package/src/lib/Layout/sidebar/sidebar.ts +0 -97
  35. package/src/lib/Layout/table/table.ts +0 -81
  36. package/src/lib/Layout/tooltip/tooltip.ts +0 -48
  37. package/src/lib/Navigation/accordion/accordion.ts +0 -80
  38. package/src/lib/Navigation/breadcrumb/breadcrumb.ts +0 -58
  39. package/src/lib/Navigation/carousel/carousel.ts +0 -70
  40. package/src/lib/Navigation/context-menu/context-menu.ts +0 -79
  41. package/src/lib/Navigation/nav-bar/nav-bar.ts +0 -72
  42. package/src/lib/Navigation/pagination/pagination.ts +0 -82
  43. package/src/lib/Navigation/stepper/stepper.ts +0 -77
  44. package/src/lib/Navigation/tab/tab.ts +0 -71
  45. package/src/lib/Navigation/toolbar/toolbar.ts +0 -60
  46. package/src/lib/Navigation/top-nav-bar/top-nav-bar.ts +0 -71
  47. package/src/lib/Navigation/tree-view/tree-view.ts +0 -75
  48. package/src/lib/Notification/badge/badge.ts +0 -55
  49. package/src/lib/Notification/loader/loader.ts +0 -41
  50. package/src/lib/Notification/message/message.ts +0 -60
  51. package/src/lib/Notification/progress/progress.ts +0 -65
  52. package/src/lib/Notification/spinner/spinner.ts +0 -50
  53. package/src/lib/Notification/toast/toast.ts +0 -56
  54. package/src/public-api.ts +0 -68
  55. package/src/utils/theme-service.ts +0 -11
  56. package/tsconfig.json +0 -23
@@ -1,104 +0,0 @@
1
- // Side-effect import: registers the `ks-rating` tag — see
2
- // `Buttons/button/button.ts` for the full explanation of this pattern.
3
- import '@kraft.stitch/core/dist/components/ks-rating.js';
4
-
5
- import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, effect, inject, input, output } from '@angular/core';
6
- import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
7
- import type { KsBaseSize } from '@kraft.stitch/core';
8
-
9
- /** DOM shape of the real `<ks-rating>` custom element, typed for the wrapper. */
10
- type KsRatingElement = HTMLElement & {
11
- max: number;
12
- size: KsBaseSize;
13
- readOnly: boolean;
14
- showLabel: boolean;
15
- label: string;
16
- disabled: boolean;
17
- value: number;
18
- writeValue(val: number): Promise<void>;
19
- };
20
-
21
- /**
22
- * Angular wrapper around the `<ks-rating>` Stencil custom element.
23
- *
24
- * Two-way binding is via `ControlValueAccessor` — use `[(ngModel)]` or
25
- * `formControlName`. See `Buttons/chips/chips.ts` for the full rationale.
26
- *
27
- * For plain (non-forms) two-way use, bind explicitly instead:
28
- * `[value]="v" (ksValueChange)="v = $event"`.
29
- *
30
- * `template: ''` — no `<slot>` in the wrapped Stencil render.
31
- */
32
- @Component({
33
- selector: 'ks-rating',
34
- standalone: true,
35
- template: '',
36
- changeDetection: ChangeDetectionStrategy.OnPush,
37
- providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: KsRatingComponent, multi: true }],
38
- })
39
- export class KsRatingComponent implements ControlValueAccessor {
40
- private readonly el: KsRatingElement;
41
- private onChange: (value: number) => void = () => {};
42
- private onTouched: () => void = () => {};
43
-
44
- /** Total number of stars */
45
- readonly max = input(5);
46
-
47
- /** Size */
48
- readonly size = input<KsBaseSize>('md');
49
-
50
- /** Read-only / non-interactive */
51
- readonly readOnly = input(false);
52
-
53
- /** Show numeric label */
54
- readonly showLabel = input(false);
55
-
56
- /** Field label */
57
- readonly label = input('');
58
-
59
- /** Disabled */
60
- readonly disabled = input(false);
61
-
62
- /** Initial/controlled value. Prefer `[(ngModel)]` / `formControlName`. */
63
- readonly value = input(0);
64
-
65
- /** Emits the newly-picked rating. From the native `valueChange` event. */
66
- readonly ksValueChange = output<number>();
67
-
68
- constructor(ref: ElementRef<KsRatingElement>) {
69
- this.el = ref.nativeElement;
70
-
71
- effect(() => (this.el.max = this.max()));
72
- effect(() => (this.el.size = this.size()));
73
- effect(() => (this.el.readOnly = this.readOnly()));
74
- effect(() => (this.el.showLabel = this.showLabel()));
75
- effect(() => (this.el.label = this.label()));
76
- effect(() => (this.el.disabled = this.disabled()));
77
- effect(() => void this.el.writeValue(this.value()));
78
-
79
- const onNativeValueChange = (event: Event): void => {
80
- const detail = (event as CustomEvent<number>).detail;
81
- this.ksValueChange.emit(detail);
82
- this.onChange(detail);
83
- this.onTouched();
84
- };
85
- this.el.addEventListener('valueChange', onNativeValueChange);
86
- inject(DestroyRef).onDestroy(() => this.el.removeEventListener('valueChange', onNativeValueChange));
87
- }
88
-
89
- writeValue(value: number): void {
90
- void this.el.writeValue(value ?? 0);
91
- }
92
-
93
- registerOnChange(fn: (value: number) => void): void {
94
- this.onChange = fn;
95
- }
96
-
97
- registerOnTouched(fn: () => void): void {
98
- this.onTouched = fn;
99
- }
100
-
101
- setDisabledState(isDisabled: boolean): void {
102
- this.el.disabled = isDisabled;
103
- }
104
- }
@@ -1,136 +0,0 @@
1
- // Side-effect import: registers the `ks-rolling-number` tag (and its
2
- // `ks-rolling-digit` dependency) — see `Buttons/button/button.ts` for the full
3
- // explanation of this pattern.
4
- import '@kraft.stitch/core/dist/components/ks-rolling-number.js';
5
-
6
- import { ChangeDetectionStrategy, Component, ElementRef, effect, input } from '@angular/core';
7
- import type { KsRollingDesign, KsRollingDirection, KsRollingGrouping, KsSize, KsTextTone } from '@kraft.stitch/core';
8
-
9
- export type { KsRollingDesign, KsRollingDirection, KsRollingGrouping };
10
-
11
- /**
12
- * DOM shape of the real `<ks-rolling-number>` custom element, typed for the wrapper.
13
- * `prefixText` / `suffixText` / `animated` are used on the element because
14
- * `prefix` and `animate` collide with native `Element` members.
15
- */
16
- type KsRollingNumberElement = HTMLElement & {
17
- value: number | string | bigint;
18
- prefixText: string;
19
- suffixText: string;
20
- startValue: number | string | bigint;
21
- decimals: number | null;
22
- separator: string;
23
- decimalSeparator: string;
24
- grouping: KsRollingGrouping;
25
- duration: number;
26
- delay: number;
27
- easing: string;
28
- stagger: number | null;
29
- spins: number;
30
- direction: KsRollingDirection;
31
- design: KsRollingDesign;
32
- size: KsSize;
33
- tone: KsTextTone;
34
- animated: boolean;
35
- label: string;
36
- };
37
-
38
- /**
39
- * Angular wrapper around the `<ks-rolling-number>` Stencil custom element.
40
- * Purely presentational — no events, no `<slot>`, plain inputs only.
41
- *
42
- * @example
43
- * ```html
44
- * <ks-rolling-number [value]="total()" prefix="$" [decimals]="2" design="finance" />
45
- * ```
46
- */
47
- @Component({
48
- selector: 'ks-rolling-number',
49
- standalone: true,
50
- template: '',
51
- changeDetection: ChangeDetectionStrategy.OnPush,
52
- })
53
- export class KsRollingNumberComponent {
54
- private readonly el: KsRollingNumberElement;
55
-
56
- /** Target value. Use a string or bigint for numbers beyond 2^53 */
57
- readonly value = input<number | string | bigint>(0);
58
-
59
- /** Shown before the number ($, €, ₹ …) */
60
- readonly prefix = input('');
61
-
62
- /** Shown after the number (K, M, %, " users" …). Leading spaces are preserved */
63
- readonly suffix = input('');
64
-
65
- /** Value the reels roll from on first render */
66
- readonly startValue = input<number | string | bigint>(0);
67
-
68
- /** Fixed decimal places. Leave unset to infer from the value */
69
- readonly decimals = input<number | null>(null);
70
-
71
- /** Thousands separator. Empty string disables grouping */
72
- readonly separator = input(',');
73
-
74
- /** Decimal separator */
75
- readonly decimalSeparator = input('.');
76
-
77
- /** Digit grouping style (`indian` gives 12,34,567) */
78
- readonly grouping = input<KsRollingGrouping>('standard');
79
-
80
- /** Total roll time in ms, including the cascade between digits */
81
- readonly duration = input(2000);
82
-
83
- /** Delay before rolling starts, in ms */
84
- readonly delay = input(0);
85
-
86
- /** Any CSS easing. The default decelerates gently into place */
87
- readonly easing = input('cubic-bezier(0.22, 1, 0.36, 1)');
88
-
89
- /** Gap in ms between neighbouring digits stopping. Unset = automatic */
90
- readonly stagger = input<number | null>(null);
91
-
92
- /** Extra full revolutions each reel makes on the first roll */
93
- readonly spins = input(1);
94
-
95
- /** `auto` rolls up when the value grows and down when it shrinks */
96
- readonly direction = input<KsRollingDirection>('auto');
97
-
98
- /** Visual style */
99
- readonly design = input<KsRollingDesign>('default');
100
-
101
- /** Size */
102
- readonly size = input<KsSize>('md');
103
-
104
- /** Text colour */
105
- readonly tone = input<KsTextTone>('primary');
106
-
107
- /** Set false to skip animation entirely */
108
- readonly animate = input(true);
109
-
110
- /** Accessible name. Defaults to the formatted value */
111
- readonly label = input('');
112
-
113
- constructor(ref: ElementRef<KsRollingNumberElement>) {
114
- this.el = ref.nativeElement;
115
-
116
- effect(() => (this.el.value = this.value()));
117
- effect(() => (this.el.prefixText = this.prefix()));
118
- effect(() => (this.el.suffixText = this.suffix()));
119
- effect(() => (this.el.startValue = this.startValue()));
120
- effect(() => (this.el.decimals = this.decimals()));
121
- effect(() => (this.el.separator = this.separator()));
122
- effect(() => (this.el.decimalSeparator = this.decimalSeparator()));
123
- effect(() => (this.el.grouping = this.grouping()));
124
- effect(() => (this.el.duration = this.duration()));
125
- effect(() => (this.el.delay = this.delay()));
126
- effect(() => (this.el.easing = this.easing()));
127
- effect(() => (this.el.stagger = this.stagger()));
128
- effect(() => (this.el.spins = this.spins()));
129
- effect(() => (this.el.direction = this.direction()));
130
- effect(() => (this.el.design = this.design()));
131
- effect(() => (this.el.size = this.size()));
132
- effect(() => (this.el.tone = this.tone()));
133
- effect(() => (this.el.animated = this.animate()));
134
- effect(() => (this.el.label = this.label()));
135
- }
136
- }
@@ -1,121 +0,0 @@
1
- // Side-effect import: registers the `ks-slider` tag — see
2
- // `Buttons/button/button.ts` for the full explanation of this pattern.
3
- import '@kraft.stitch/core/dist/components/ks-slider.js';
4
-
5
- import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, effect, inject, input, output } from '@angular/core';
6
- import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
7
-
8
- /** DOM shape of the real `<ks-slider>` custom element, typed for the wrapper. */
9
- type KsSliderElement = HTMLElement & {
10
- min: number;
11
- max: number;
12
- step: number;
13
- showTooltip: boolean;
14
- showLabels: boolean;
15
- label: string;
16
- disabled: boolean;
17
- value: number;
18
- writeValue(val: number): Promise<void>;
19
- };
20
-
21
- /**
22
- * Angular wrapper around the `<ks-slider>` Stencil custom element.
23
- *
24
- * Two-way binding is via `ControlValueAccessor` — use `[(ngModel)]` or
25
- * `formControlName`. See `Buttons/chips/chips.ts` for the full rationale.
26
- * The native `ksBlur` event (already `ks`-prefixed by the Stencil author)
27
- * is re-exposed as `ksBlurred` — see `Inputs/input/input.ts` for why the
28
- * literal name can't be reused.
29
- *
30
- * For plain (non-forms) two-way use, bind explicitly instead:
31
- * `[value]="v" (ksValueChange)="v = $event"`.
32
- *
33
- * `template: ''` — no `<slot>` in the wrapped Stencil render.
34
- */
35
- @Component({
36
- selector: 'ks-slider',
37
- standalone: true,
38
- template: '',
39
- changeDetection: ChangeDetectionStrategy.OnPush,
40
- providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: KsSliderComponent, multi: true }],
41
- })
42
- export class KsSliderComponent implements ControlValueAccessor {
43
- private readonly el: KsSliderElement;
44
- private onChange: (value: number) => void = () => {};
45
- private onTouched: () => void = () => {};
46
-
47
- /** Minimum value */
48
- readonly min = input(0);
49
-
50
- /** Maximum value */
51
- readonly max = input(100);
52
-
53
- /** Step increment */
54
- readonly step = input(1);
55
-
56
- /** Show value tooltip */
57
- readonly showTooltip = input(true);
58
-
59
- /** Show min/max labels */
60
- readonly showLabels = input(false);
61
-
62
- /** Field label */
63
- readonly label = input('');
64
-
65
- /** Disabled state */
66
- readonly disabled = input(false);
67
-
68
- /** Initial/controlled value. Prefer `[(ngModel)]` / `formControlName`. */
69
- readonly value = input(0);
70
-
71
- /** Emits the newly-picked value. From the native `valueChange` event. */
72
- readonly ksValueChange = output<number>();
73
-
74
- /** Emitted on native blur. From the native `ksBlur` event. */
75
- readonly ksBlurred = output<void>();
76
-
77
- constructor(ref: ElementRef<KsSliderElement>) {
78
- this.el = ref.nativeElement;
79
-
80
- effect(() => (this.el.min = this.min()));
81
- effect(() => (this.el.max = this.max()));
82
- effect(() => (this.el.step = this.step()));
83
- effect(() => (this.el.showTooltip = this.showTooltip()));
84
- effect(() => (this.el.showLabels = this.showLabels()));
85
- effect(() => (this.el.label = this.label()));
86
- effect(() => (this.el.disabled = this.disabled()));
87
- effect(() => void this.el.writeValue(this.value()));
88
-
89
- const onNativeValueChange = (event: Event): void => {
90
- const detail = (event as CustomEvent<number>).detail;
91
- this.ksValueChange.emit(detail);
92
- this.onChange(detail);
93
- };
94
- const onNativeBlur = (): void => {
95
- this.ksBlurred.emit();
96
- this.onTouched();
97
- };
98
- this.el.addEventListener('valueChange', onNativeValueChange);
99
- this.el.addEventListener('ksBlur', onNativeBlur);
100
- inject(DestroyRef).onDestroy(() => {
101
- this.el.removeEventListener('valueChange', onNativeValueChange);
102
- this.el.removeEventListener('ksBlur', onNativeBlur);
103
- });
104
- }
105
-
106
- writeValue(value: number): void {
107
- void this.el.writeValue(value ?? 0);
108
- }
109
-
110
- registerOnChange(fn: (value: number) => void): void {
111
- this.onChange = fn;
112
- }
113
-
114
- registerOnTouched(fn: () => void): void {
115
- this.onTouched = fn;
116
- }
117
-
118
- setDisabledState(isDisabled: boolean): void {
119
- this.el.disabled = isDisabled;
120
- }
121
- }
@@ -1,100 +0,0 @@
1
- // Side-effect import: registers the `ks-switch` tag — see
2
- // `Buttons/button/button.ts` for the full explanation of this pattern.
3
- import '@kraft.stitch/core/dist/components/ks-switch.js';
4
-
5
- import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, effect, inject, input, output } from '@angular/core';
6
- import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
7
- import type { KsBaseVariant } from '@kraft.stitch/core';
8
-
9
- /** DOM shape of the real `<ks-switch>` custom element, typed for the wrapper. */
10
- type KsSwitchElement = HTMLElement & {
11
- label: string;
12
- variant: KsBaseVariant;
13
- disabled: boolean;
14
- checked: boolean;
15
- labelPosition: 'left' | 'right';
16
- formDisabled: boolean;
17
- setDisabledState(isDisabled: boolean): Promise<void>;
18
- };
19
-
20
- /**
21
- * Angular wrapper around the `<ks-switch>` Stencil custom element.
22
- *
23
- * Two-way binding is via `ControlValueAccessor` — use `[(ngModel)]` or
24
- * `formControlName`. Unlike most other form-control wrappers here,
25
- * `<ks-switch>` has no `@Method() writeValue()`, so `writeValue` below
26
- * sets `el.checked` directly; it DOES expose a real
27
- * `@Method() setDisabledState()` (mirroring CVA exactly), which
28
- * `setDisabledState` below delegates to instead of setting a plain prop.
29
- *
30
- * For plain (non-forms) two-way use, bind explicitly instead:
31
- * `[checked]="c" (ksCheckedChange)="c = $event"`.
32
- *
33
- * `template: ''` — no `<slot>` in the wrapped Stencil render.
34
- */
35
- @Component({
36
- selector: 'ks-switch',
37
- standalone: true,
38
- template: '',
39
- changeDetection: ChangeDetectionStrategy.OnPush,
40
- providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: KsSwitchComponent, multi: true }],
41
- })
42
- export class KsSwitchComponent implements ControlValueAccessor {
43
- private readonly el: KsSwitchElement;
44
- private onChange: (value: boolean) => void = () => {};
45
- private onTouched: () => void = () => {};
46
-
47
- /** Label text */
48
- readonly label = input('');
49
-
50
- /** Colour variant */
51
- readonly variant = input<KsBaseVariant>('brand');
52
-
53
- /** Disabled */
54
- readonly disabled = input(false);
55
-
56
- /** Initial/controlled checked value. Prefer `[(ngModel)]` / `formControlName`. */
57
- readonly checked = input(false);
58
-
59
- /** Label position relative to the switch track */
60
- readonly labelPosition = input<'left' | 'right'>('left');
61
-
62
- /** Emits whenever `checked` changes. From the native `checkedChange` event. */
63
- readonly ksCheckedChange = output<boolean>();
64
-
65
- constructor(ref: ElementRef<KsSwitchElement>) {
66
- this.el = ref.nativeElement;
67
-
68
- effect(() => (this.el.label = this.label()));
69
- effect(() => (this.el.variant = this.variant()));
70
- effect(() => (this.el.disabled = this.disabled()));
71
- effect(() => (this.el.checked = this.checked()));
72
- effect(() => (this.el.labelPosition = this.labelPosition()));
73
-
74
- const onNativeCheckedChange = (event: Event): void => {
75
- const detail = (event as CustomEvent<boolean>).detail;
76
- this.ksCheckedChange.emit(detail);
77
- this.onChange(detail);
78
- this.onTouched();
79
- };
80
- this.el.addEventListener('checkedChange', onNativeCheckedChange);
81
- inject(DestroyRef).onDestroy(() => this.el.removeEventListener('checkedChange', onNativeCheckedChange));
82
- }
83
-
84
- writeValue(value: boolean): void {
85
- this.el.checked = value ?? false;
86
- }
87
-
88
- registerOnChange(fn: (value: boolean) => void): void {
89
- this.onChange = fn;
90
- }
91
-
92
- registerOnTouched(fn: () => void): void {
93
- this.onTouched = fn;
94
- }
95
-
96
- /** Delegates to `<ks-switch>`'s own `@Method() setDisabledState()`. */
97
- setDisabledState(isDisabled: boolean): void {
98
- void this.el.setDisabledState(isDisabled);
99
- }
100
- }
@@ -1,129 +0,0 @@
1
- // Side-effect import: registers the `ks-textarea` tag — see
2
- // `Buttons/button/button.ts` for the full explanation of this pattern.
3
- import '@kraft.stitch/core/dist/components/ks-textarea.js';
4
-
5
- import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, effect, inject, input, output } from '@angular/core';
6
- import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
7
-
8
- /** DOM shape of the real `<ks-textarea>` custom element, typed for the wrapper. */
9
- type KsTextareaElement = HTMLElement & {
10
- label: string;
11
- placeholder: string;
12
- rows: number;
13
- maxLength: number;
14
- showCounter: boolean;
15
- autoResize: boolean;
16
- disabled: boolean;
17
- error: string;
18
- hint: string;
19
- value: string;
20
- };
21
-
22
- /**
23
- * Angular wrapper around the `<ks-textarea>` Stencil custom element.
24
- *
25
- * Two-way binding is via `ControlValueAccessor` (see `Inputs/input/input.ts`
26
- * for the equivalent no-`writeValue()`-method pattern this follows —
27
- * `writeValue` here sets `el.value` directly). The native `ksBlur` event
28
- * is re-exposed as `ksBlurred` for the same reason.
29
- *
30
- * For plain (non-forms) two-way use, bind explicitly instead:
31
- * `[value]="v" (ksValueChange)="v = $event"`.
32
- *
33
- * `template: ''` — no `<slot>` in the wrapped Stencil render.
34
- */
35
- @Component({
36
- selector: 'ks-textarea',
37
- standalone: true,
38
- template: '',
39
- changeDetection: ChangeDetectionStrategy.OnPush,
40
- providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: KsTextareaComponent, multi: true }],
41
- })
42
- export class KsTextareaComponent implements ControlValueAccessor {
43
- private readonly el: KsTextareaElement;
44
- private onChange: (value: string) => void = () => {};
45
- private onTouched: () => void = () => {};
46
-
47
- /** Textarea label */
48
- readonly label = input('');
49
-
50
- /** Placeholder text */
51
- readonly placeholder = input('');
52
-
53
- /** Number of visible rows */
54
- readonly rows = input(3);
55
-
56
- /** Maximum character count */
57
- readonly maxLength = input(500);
58
-
59
- /** Show character counter */
60
- readonly showCounter = input(false);
61
-
62
- /** Auto-resize based on content */
63
- readonly autoResize = input(false);
64
-
65
- /** Disabled state */
66
- readonly disabled = input(false);
67
-
68
- /** Error state */
69
- readonly error = input('');
70
-
71
- /** Helper/error text */
72
- readonly hint = input('');
73
-
74
- /** Initial/controlled value. Prefer `[(ngModel)]` / `formControlName`. */
75
- readonly value = input('');
76
-
77
- /** Emits the newly-typed value. From the native `valueChange` event. */
78
- readonly ksValueChange = output<string>();
79
-
80
- /** Emitted on native blur. From the native `ksBlur` event. */
81
- readonly ksBlurred = output<void>();
82
-
83
- constructor(ref: ElementRef<KsTextareaElement>) {
84
- this.el = ref.nativeElement;
85
-
86
- effect(() => (this.el.label = this.label()));
87
- effect(() => (this.el.placeholder = this.placeholder()));
88
- effect(() => (this.el.rows = this.rows()));
89
- effect(() => (this.el.maxLength = this.maxLength()));
90
- effect(() => (this.el.showCounter = this.showCounter()));
91
- effect(() => (this.el.autoResize = this.autoResize()));
92
- effect(() => (this.el.disabled = this.disabled()));
93
- effect(() => (this.el.error = this.error()));
94
- effect(() => (this.el.hint = this.hint()));
95
- effect(() => (this.el.value = this.value()));
96
-
97
- const onNativeValueChange = (event: Event): void => {
98
- const detail = (event as CustomEvent<string>).detail;
99
- this.ksValueChange.emit(detail);
100
- this.onChange(detail);
101
- };
102
- const onNativeBlur = (): void => {
103
- this.ksBlurred.emit();
104
- this.onTouched();
105
- };
106
- this.el.addEventListener('valueChange', onNativeValueChange);
107
- this.el.addEventListener('ksBlur', onNativeBlur);
108
- inject(DestroyRef).onDestroy(() => {
109
- this.el.removeEventListener('valueChange', onNativeValueChange);
110
- this.el.removeEventListener('ksBlur', onNativeBlur);
111
- });
112
- }
113
-
114
- writeValue(value: string): void {
115
- this.el.value = value ?? '';
116
- }
117
-
118
- registerOnChange(fn: (value: string) => void): void {
119
- this.onChange = fn;
120
- }
121
-
122
- registerOnTouched(fn: () => void): void {
123
- this.onTouched = fn;
124
- }
125
-
126
- setDisabledState(isDisabled: boolean): void {
127
- this.el.disabled = isDisabled;
128
- }
129
- }
@@ -1,61 +0,0 @@
1
- // Side-effect import: registers the `ks-theme-switch` tag — see
2
- // `Buttons/button/button.ts` for the full explanation of this pattern.
3
- import '@kraft.stitch/core/dist/components/ks-theme-switch.js';
4
-
5
- import { ChangeDetectionStrategy, Component, ElementRef, effect, input } from '@angular/core';
6
- import { ThemeMode } from '@kraft.stitch/core';
7
- import type { Palette } from '@kraft.stitch/core';
8
-
9
- /** DOM shape of the real `<ks-theme-switch>` custom element, typed for the wrapper. */
10
- type KsThemeSwitchElement = HTMLElement & {
11
- includeSystem: boolean;
12
- includePalette: boolean;
13
- onlyIcon: boolean;
14
- palette: Palette;
15
- mode: ThemeMode;
16
- };
17
-
18
- /**
19
- * Angular wrapper around the `<ks-theme-switch>` Stencil custom element.
20
- *
21
- * Purely presentational — it drives the shared `themeService` singleton
22
- * (see `core/src/utils/ks-theme.util.ts`) directly and dispatches no
23
- * events of its own, so this wrapper has plain inputs only, no outputs
24
- * and no `ControlValueAccessor`.
25
- *
26
- * `template: ''` — no `<slot>` in the wrapped Stencil render.
27
- */
28
- @Component({
29
- selector: 'ks-theme-switch',
30
- standalone: true,
31
- template: '',
32
- changeDetection: ChangeDetectionStrategy.OnPush,
33
- })
34
- export class KsThemeSwitchComponent {
35
- private readonly el: KsThemeSwitchElement;
36
-
37
- /** When true the mode-toggle shows three options: System | Light | Dark. */
38
- readonly includeSystem = input(true);
39
-
40
- /** When true the colour-palette switcher is shown. */
41
- readonly includePalette = input(false);
42
-
43
- /** When true only icons are shown in the mode-toggle switch. */
44
- readonly onlyIcon = input(false);
45
-
46
- /** The palette that should be active on init. */
47
- readonly palette = input<Palette>('ForestGreen');
48
-
49
- /** The mode that should be active on init. */
50
- readonly mode = input<ThemeMode>(ThemeMode.Light);
51
-
52
- constructor(ref: ElementRef<KsThemeSwitchElement>) {
53
- this.el = ref.nativeElement;
54
-
55
- effect(() => (this.el.includeSystem = this.includeSystem()));
56
- effect(() => (this.el.includePalette = this.includePalette()));
57
- effect(() => (this.el.onlyIcon = this.onlyIcon()));
58
- effect(() => (this.el.palette = this.palette()));
59
- effect(() => (this.el.mode = this.mode()));
60
- }
61
- }