@colletdev/angular 0.1.3
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/README.md +60 -0
- package/package.json +43 -0
- package/src/accordion.component.ts +97 -0
- package/src/activity-group.component.ts +61 -0
- package/src/alert.component.ts +75 -0
- package/src/autocomplete.component.ts +196 -0
- package/src/avatar.component.ts +59 -0
- package/src/backdrop.component.ts +51 -0
- package/src/badge.component.ts +67 -0
- package/src/breadcrumb.component.ts +77 -0
- package/src/button.component.ts +74 -0
- package/src/card.component.ts +72 -0
- package/src/carousel.component.ts +96 -0
- package/src/chat-input.component.ts +116 -0
- package/src/checkbox.component.ts +121 -0
- package/src/code-block.component.ts +67 -0
- package/src/collapsible.component.ts +72 -0
- package/src/date-picker.component.ts +159 -0
- package/src/dialog.component.ts +67 -0
- package/src/drawer.component.ts +67 -0
- package/src/fab.component.ts +70 -0
- package/src/file-upload.component.ts +77 -0
- package/src/index.ts +99 -0
- package/src/listbox.component.ts +121 -0
- package/src/menu.component.ts +99 -0
- package/src/message-bubble.component.ts +67 -0
- package/src/message-group.component.ts +77 -0
- package/src/message-part.component.ts +47 -0
- package/src/pagination.component.ts +67 -0
- package/src/popover.component.ts +77 -0
- package/src/profile-menu.component.ts +87 -0
- package/src/progress.component.ts +60 -0
- package/src/radio-group.component.ts +138 -0
- package/src/scrollbar.component.ts +59 -0
- package/src/search-bar.component.ts +127 -0
- package/src/select.component.ts +181 -0
- package/src/sidebar.component.ts +91 -0
- package/src/skeleton.component.ts +57 -0
- package/src/slider.component.ts +134 -0
- package/src/speed-dial.component.ts +100 -0
- package/src/spinner.component.ts +53 -0
- package/src/split-button.component.ts +97 -0
- package/src/stepper.component.ts +83 -0
- package/src/switch.component.ts +123 -0
- package/src/table.component.ts +219 -0
- package/src/tabs.component.ts +82 -0
- package/src/text-input.component.ts +158 -0
- package/src/text.component.ts +73 -0
- package/src/thinking.component.ts +57 -0
- package/src/toast.component.ts +72 -0
- package/src/toggle-group.component.ts +123 -0
- package/src/tooltip.component.ts +61 -0
- package/src/types.ts +334 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @collet/angular
|
|
2
|
+
|
|
3
|
+
Angular 16+ standalone components for the Collet component library. Typed `@Input`/`@Output` bindings, `ControlValueAccessor` for forms, and OnPush change detection over 48 Rust/WASM Custom Elements.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @collet/angular @collet/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`@angular/forms` is an optional peer dependency, required only if you use form-associated components (`CxTextInput`, `CxSelect`, `CxCheckbox`, etc.) with `ngModel` or reactive forms.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { Component } from '@angular/core';
|
|
17
|
+
import { CxButton, CxTextInput, init } from '@collet/angular';
|
|
18
|
+
|
|
19
|
+
await init(); // once, at app bootstrap
|
|
20
|
+
|
|
21
|
+
@Component({
|
|
22
|
+
standalone: true,
|
|
23
|
+
imports: [CxButton, CxTextInput],
|
|
24
|
+
template: `
|
|
25
|
+
<cx-button collet variant="filled" label="Save" intent="primary"
|
|
26
|
+
(cxClick)="save()"></cx-button>
|
|
27
|
+
<cx-text-input collet label="Email" kind="email"
|
|
28
|
+
(cxInput)="onInput($event)"></cx-text-input>
|
|
29
|
+
`
|
|
30
|
+
})
|
|
31
|
+
export class AppComponent { }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Standalone components** -- no `NgModule` required, import directly
|
|
37
|
+
- **Typed inputs** -- union-literal types for variant, intent, size, and all enums
|
|
38
|
+
- **Typed outputs** -- `(cxClick)`, `(cxChange)`, `(cxInput)` with typed `$event.detail`
|
|
39
|
+
- **ControlValueAccessor** -- form-associated components work with `ngModel` and `FormControl`
|
|
40
|
+
- **OnPush** -- all wrappers use `ChangeDetectionStrategy.OnPush` with detached `ChangeDetectorRef`
|
|
41
|
+
- **Ships source** -- `.ts` files included; compile with your project's TypeScript/ng-packagr
|
|
42
|
+
|
|
43
|
+
## Naming Convention
|
|
44
|
+
|
|
45
|
+
Angular wrappers use the `Cx` prefix: `CxButton`, `CxTextInput`, `CxSelect`, `CxDialog`, etc. Template tags remain `<cx-button>`, `<cx-text-input>`, etc. with the `collet` directive attribute.
|
|
46
|
+
|
|
47
|
+
## Event Pattern
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<cx-select collet label="Country" [options]="countries"
|
|
51
|
+
(cxChange)="setCountry($event)"></cx-select>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API Reference
|
|
55
|
+
|
|
56
|
+
See [@collet/docs](https://www.npmjs.com/package/@collet/docs) for the full props/events reference and framework guides.
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
MIT -- [github.com/Danrozen87/collet](https://github.com/Danrozen87/collet)
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@colletdev/angular",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Angular wrappers for Collet Rust/WASM UI components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"default": "./src/index.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src/"
|
|
16
|
+
],
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@angular/core": ">=16.0.0",
|
|
19
|
+
"@angular/forms": ">=16.0.0",
|
|
20
|
+
"@colletdev/core": ">=0.1.0"
|
|
21
|
+
},
|
|
22
|
+
"peerDependenciesMeta": {
|
|
23
|
+
"@angular/forms": {
|
|
24
|
+
"optional": true
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"angular",
|
|
29
|
+
"web-components",
|
|
30
|
+
"rust",
|
|
31
|
+
"wasm",
|
|
32
|
+
"ui",
|
|
33
|
+
"collet"
|
|
34
|
+
],
|
|
35
|
+
"author": "Dan",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"sideEffects": false,
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/Danrozen87/collet",
|
|
41
|
+
"directory": "packages/angular"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-angular.mjs — DO NOT EDIT
|
|
2
|
+
// Angular wrapper for <cx-accordion>
|
|
3
|
+
import {
|
|
4
|
+
Component,
|
|
5
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
6
|
+
ChangeDetectionStrategy,
|
|
7
|
+
ChangeDetectorRef,
|
|
8
|
+
ElementRef,
|
|
9
|
+
ViewChild,
|
|
10
|
+
Input,
|
|
11
|
+
Output,
|
|
12
|
+
EventEmitter,
|
|
13
|
+
OnChanges,
|
|
14
|
+
SimpleChanges,
|
|
15
|
+
AfterViewInit,
|
|
16
|
+
} from '@angular/core';
|
|
17
|
+
import type { AccordionDetail, AccordionItem } from './types.js';
|
|
18
|
+
|
|
19
|
+
@Component({
|
|
20
|
+
selector: 'cx-accordion[collet]',
|
|
21
|
+
standalone: true,
|
|
22
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
23
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
24
|
+
template: `
|
|
25
|
+
<cx-accordion
|
|
26
|
+
[attr.id]="id"
|
|
27
|
+
[attr.label]="label"
|
|
28
|
+
[items]="_serialize_items()"
|
|
29
|
+
[attr.mode]="mode"
|
|
30
|
+
[attr.collapsible]="collapsible || null"
|
|
31
|
+
[attr.heading-level]="headingLevel"
|
|
32
|
+
[default-expanded]="_serialize_defaultExpanded()"
|
|
33
|
+
[attr.size]="size"
|
|
34
|
+
[attr.disabled]="disabled || null"
|
|
35
|
+
#el
|
|
36
|
+
><ng-content /></cx-accordion>
|
|
37
|
+
`,
|
|
38
|
+
})
|
|
39
|
+
export class CxAccordion implements AfterViewInit, OnChanges {
|
|
40
|
+
@ViewChild('el', { static: true }) el!: ElementRef<HTMLElement>;
|
|
41
|
+
|
|
42
|
+
@Input() id?: string = undefined;
|
|
43
|
+
@Input() label?: string = undefined;
|
|
44
|
+
@Input() items?: AccordionItem[] | string = undefined;
|
|
45
|
+
@Input() mode?: 'single' | 'multiple' = undefined;
|
|
46
|
+
@Input() collapsible?: boolean = undefined;
|
|
47
|
+
@Input() headingLevel?: 'h2' | 'h3' | 'h4' | 'h5' | 'h6' = undefined;
|
|
48
|
+
@Input() defaultExpanded?: string[] | string = undefined;
|
|
49
|
+
@Input() size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = undefined;
|
|
50
|
+
@Input() disabled?: boolean = undefined;
|
|
51
|
+
|
|
52
|
+
@Output() cxChange = new EventEmitter<CustomEvent<AccordionDetail>>();
|
|
53
|
+
|
|
54
|
+
constructor(private c: ChangeDetectorRef) {
|
|
55
|
+
c.detach();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ngAfterViewInit(): void {
|
|
59
|
+
this.el.nativeElement.addEventListener('cx-change', (e: Event) => {
|
|
60
|
+
this.cxChange.emit(e as CustomEvent);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
65
|
+
if (changes['items'] && this.el) {
|
|
66
|
+
const val = this.items;
|
|
67
|
+
if (val != null) {
|
|
68
|
+
this.el.nativeElement.setAttribute('items', typeof val === 'object' ? JSON.stringify(val) : String(val));
|
|
69
|
+
} else {
|
|
70
|
+
this.el.nativeElement.removeAttribute('items');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (changes['defaultExpanded'] && this.el) {
|
|
74
|
+
const val = this.defaultExpanded;
|
|
75
|
+
if (val != null) {
|
|
76
|
+
this.el.nativeElement.setAttribute('default-expanded', typeof val === 'object' ? JSON.stringify(val) : String(val));
|
|
77
|
+
} else {
|
|
78
|
+
this.el.nativeElement.removeAttribute('default-expanded');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_serialize_items(): string | null {
|
|
84
|
+
const val = this.items;
|
|
85
|
+
if (val == null) return null;
|
|
86
|
+
return typeof val === 'object' ? JSON.stringify(val) : String(val);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_serialize_defaultExpanded(): string | null {
|
|
90
|
+
const val = this.defaultExpanded;
|
|
91
|
+
if (val == null) return null;
|
|
92
|
+
return typeof val === 'object' ? JSON.stringify(val) : String(val);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-angular.mjs — DO NOT EDIT
|
|
2
|
+
// Angular wrapper for <cx-activity-group>
|
|
3
|
+
import {
|
|
4
|
+
Component,
|
|
5
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
6
|
+
ChangeDetectionStrategy,
|
|
7
|
+
ChangeDetectorRef,
|
|
8
|
+
ElementRef,
|
|
9
|
+
ViewChild,
|
|
10
|
+
Input,
|
|
11
|
+
Output,
|
|
12
|
+
EventEmitter,
|
|
13
|
+
AfterViewInit,
|
|
14
|
+
} from '@angular/core';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: 'cx-activity-group[collet]',
|
|
18
|
+
standalone: true,
|
|
19
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
20
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
21
|
+
template: `
|
|
22
|
+
<cx-activity-group
|
|
23
|
+
[attr.id]="id"
|
|
24
|
+
[attr.status]="status"
|
|
25
|
+
[attr.size]="size"
|
|
26
|
+
[attr.border]="border"
|
|
27
|
+
[attr.summary]="summary"
|
|
28
|
+
[attr.action]="action"
|
|
29
|
+
[attr.expanded]="expanded || null"
|
|
30
|
+
[attr.parts]="parts"
|
|
31
|
+
#el
|
|
32
|
+
><ng-content /></cx-activity-group>
|
|
33
|
+
`,
|
|
34
|
+
})
|
|
35
|
+
export class CxActivityGroup implements AfterViewInit {
|
|
36
|
+
@ViewChild('el', { static: true }) el!: ElementRef<HTMLElement>;
|
|
37
|
+
|
|
38
|
+
@Input() id?: string = undefined;
|
|
39
|
+
@Input() status?: string = undefined;
|
|
40
|
+
@Input() size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = undefined;
|
|
41
|
+
@Input() border?: string = undefined;
|
|
42
|
+
@Input() summary?: string = undefined;
|
|
43
|
+
@Input() action?: string = undefined;
|
|
44
|
+
@Input() expanded?: boolean = undefined;
|
|
45
|
+
@Input() parts?: string = undefined;
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
constructor(private c: ChangeDetectorRef) {
|
|
50
|
+
c.detach();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
ngAfterViewInit(): void {
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-angular.mjs — DO NOT EDIT
|
|
2
|
+
// Angular wrapper for <cx-alert>
|
|
3
|
+
import {
|
|
4
|
+
Component,
|
|
5
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
6
|
+
ChangeDetectionStrategy,
|
|
7
|
+
ChangeDetectorRef,
|
|
8
|
+
ElementRef,
|
|
9
|
+
ViewChild,
|
|
10
|
+
Input,
|
|
11
|
+
Output,
|
|
12
|
+
EventEmitter,
|
|
13
|
+
AfterViewInit,
|
|
14
|
+
} from '@angular/core';
|
|
15
|
+
import type { DismissDetail } from './types.js';
|
|
16
|
+
|
|
17
|
+
@Component({
|
|
18
|
+
selector: 'cx-alert[collet]',
|
|
19
|
+
standalone: true,
|
|
20
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
21
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
22
|
+
template: `
|
|
23
|
+
<cx-alert
|
|
24
|
+
[attr.id]="id"
|
|
25
|
+
[attr.title]="title"
|
|
26
|
+
[attr.description]="description"
|
|
27
|
+
[attr.variant]="variant"
|
|
28
|
+
[attr.intent]="intent"
|
|
29
|
+
[attr.size]="size"
|
|
30
|
+
[attr.show-icon]="showIcon || null"
|
|
31
|
+
[attr.icon]="icon"
|
|
32
|
+
[attr.dismissible]="dismissible || null"
|
|
33
|
+
[attr.dismiss-label]="dismissLabel"
|
|
34
|
+
[attr.compact]="compact || null"
|
|
35
|
+
[attr.dynamic]="dynamic || null"
|
|
36
|
+
[attr.actions-html]="actionsHtml"
|
|
37
|
+
#el
|
|
38
|
+
><ng-content />
|
|
39
|
+
<ng-content select="[slot=actions]" /></cx-alert>
|
|
40
|
+
`,
|
|
41
|
+
})
|
|
42
|
+
export class CxAlert implements AfterViewInit {
|
|
43
|
+
@ViewChild('el', { static: true }) el!: ElementRef<HTMLElement>;
|
|
44
|
+
|
|
45
|
+
@Input() id?: string = undefined;
|
|
46
|
+
@Input() title?: string = undefined;
|
|
47
|
+
@Input() description?: string = undefined;
|
|
48
|
+
@Input() variant?: 'subtle' | 'filled' | 'outline' = undefined;
|
|
49
|
+
@Input() intent?: 'neutral' | 'primary' | 'info' | 'success' | 'warning' | 'danger' = undefined;
|
|
50
|
+
@Input() size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = undefined;
|
|
51
|
+
@Input() showIcon?: boolean = undefined;
|
|
52
|
+
@Input() icon?: string = undefined;
|
|
53
|
+
@Input() dismissible?: boolean = undefined;
|
|
54
|
+
@Input() dismissLabel?: string = undefined;
|
|
55
|
+
@Input() compact?: boolean = undefined;
|
|
56
|
+
@Input() dynamic?: boolean = undefined;
|
|
57
|
+
@Input() actionsHtml?: string = undefined;
|
|
58
|
+
|
|
59
|
+
@Output() cxDismiss = new EventEmitter<CustomEvent<DismissDetail>>();
|
|
60
|
+
|
|
61
|
+
constructor(private c: ChangeDetectorRef) {
|
|
62
|
+
c.detach();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
ngAfterViewInit(): void {
|
|
66
|
+
this.el.nativeElement.addEventListener('cx-dismiss', (e: Event) => {
|
|
67
|
+
this.cxDismiss.emit(e as CustomEvent);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-angular.mjs — DO NOT EDIT
|
|
2
|
+
// Angular wrapper for <cx-autocomplete>
|
|
3
|
+
import {
|
|
4
|
+
Component,
|
|
5
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
6
|
+
ChangeDetectionStrategy,
|
|
7
|
+
ChangeDetectorRef,
|
|
8
|
+
ElementRef,
|
|
9
|
+
ViewChild,
|
|
10
|
+
Input,
|
|
11
|
+
Output,
|
|
12
|
+
EventEmitter,
|
|
13
|
+
OnChanges,
|
|
14
|
+
SimpleChanges,
|
|
15
|
+
AfterViewInit,
|
|
16
|
+
forwardRef,
|
|
17
|
+
} from '@angular/core';
|
|
18
|
+
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
19
|
+
import type { FocusDetail, InputDetail, KeyboardDetail, OptionGroup, SelectDetail, SelectOption } from './types.js';
|
|
20
|
+
|
|
21
|
+
@Component({
|
|
22
|
+
selector: 'cx-autocomplete[collet]',
|
|
23
|
+
standalone: true,
|
|
24
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
25
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
26
|
+
providers: [{
|
|
27
|
+
provide: NG_VALUE_ACCESSOR,
|
|
28
|
+
useExisting: forwardRef(() => CxAutocomplete),
|
|
29
|
+
multi: true,
|
|
30
|
+
}],
|
|
31
|
+
template: `
|
|
32
|
+
<cx-autocomplete
|
|
33
|
+
[attr.id]="id"
|
|
34
|
+
[attr.label]="label"
|
|
35
|
+
[attr.variant]="variant"
|
|
36
|
+
[attr.shape]="shape"
|
|
37
|
+
[attr.size]="size"
|
|
38
|
+
[attr.mode]="mode"
|
|
39
|
+
[selected]="_serialize_selected()"
|
|
40
|
+
[attr.query]="query"
|
|
41
|
+
[attr.placeholder]="placeholder"
|
|
42
|
+
[attr.helper-text]="helperText"
|
|
43
|
+
[attr.error]="error"
|
|
44
|
+
[attr.disabled]="disabled || null"
|
|
45
|
+
[attr.required]="required || null"
|
|
46
|
+
[attr.readonly]="readonly || null"
|
|
47
|
+
[attr.name]="name"
|
|
48
|
+
[attr.allow-custom]="allowCustom || null"
|
|
49
|
+
[attr.clearable]="clearable || null"
|
|
50
|
+
[items]="_serialize_items()"
|
|
51
|
+
[groups]="_serialize_groups()"
|
|
52
|
+
#el
|
|
53
|
+
><ng-content /></cx-autocomplete>
|
|
54
|
+
`,
|
|
55
|
+
})
|
|
56
|
+
export class CxAutocomplete implements AfterViewInit, OnChanges, ControlValueAccessor {
|
|
57
|
+
@ViewChild('el', { static: true }) el!: ElementRef<HTMLElement>;
|
|
58
|
+
|
|
59
|
+
@Input() id?: string = undefined;
|
|
60
|
+
@Input() label?: string = undefined;
|
|
61
|
+
@Input() variant?: 'outline' | 'filled' | 'ghost' = undefined;
|
|
62
|
+
@Input() shape?: 'sharp' | 'rounded' | 'pill' = undefined;
|
|
63
|
+
@Input() size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = undefined;
|
|
64
|
+
/** 'single' for single select, 'multiple' for multi-select with chips. */
|
|
65
|
+
@Input() mode?: 'single' | 'multiple' = undefined;
|
|
66
|
+
@Input() selected?: string[] | string = undefined;
|
|
67
|
+
/** Current search query text. Controlled by onInput events. */
|
|
68
|
+
@Input() query?: string = undefined;
|
|
69
|
+
@Input() placeholder?: string = undefined;
|
|
70
|
+
@Input() helperText?: string = undefined;
|
|
71
|
+
@Input() error?: string = undefined;
|
|
72
|
+
@Input() disabled?: boolean = undefined;
|
|
73
|
+
@Input() required?: boolean = undefined;
|
|
74
|
+
@Input() readonly?: boolean = undefined;
|
|
75
|
+
@Input() name?: string = undefined;
|
|
76
|
+
/** When true, user can submit values not in the items list. */
|
|
77
|
+
@Input() allowCustom?: boolean = undefined;
|
|
78
|
+
@Input() clearable?: boolean = undefined;
|
|
79
|
+
/** Options to filter from. Filtering is client-side (fuzzy substring match). For server-side search, update this array in your onInput handler. */
|
|
80
|
+
@Input() items?: SelectOption[] | string = undefined;
|
|
81
|
+
@Input() groups?: OptionGroup[] | string = undefined;
|
|
82
|
+
|
|
83
|
+
@Output() cxInput = new EventEmitter<CustomEvent<InputDetail>>();
|
|
84
|
+
@Output() cxChange = new EventEmitter<CustomEvent<SelectDetail>>();
|
|
85
|
+
@Output() cxFocus = new EventEmitter<CustomEvent<FocusDetail>>();
|
|
86
|
+
@Output() cxBlur = new EventEmitter<CustomEvent<FocusDetail>>();
|
|
87
|
+
@Output() cxKeydown = new EventEmitter<CustomEvent<KeyboardDetail>>();
|
|
88
|
+
@Output() cxKeyup = new EventEmitter<CustomEvent<KeyboardDetail>>();
|
|
89
|
+
|
|
90
|
+
constructor(private c: ChangeDetectorRef) {
|
|
91
|
+
c.detach();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
ngAfterViewInit(): void {
|
|
95
|
+
this.el.nativeElement.addEventListener('cx-input', (e: Event) => {
|
|
96
|
+
this.cxInput.emit(e as CustomEvent);
|
|
97
|
+
});
|
|
98
|
+
this.el.nativeElement.addEventListener('cx-change', (e: Event) => {
|
|
99
|
+
this.cxChange.emit(e as CustomEvent);
|
|
100
|
+
});
|
|
101
|
+
this.el.nativeElement.addEventListener('cx-focus', (e: Event) => {
|
|
102
|
+
this.cxFocus.emit(e as CustomEvent);
|
|
103
|
+
});
|
|
104
|
+
this.el.nativeElement.addEventListener('cx-blur', (e: Event) => {
|
|
105
|
+
this.cxBlur.emit(e as CustomEvent);
|
|
106
|
+
});
|
|
107
|
+
this.el.nativeElement.addEventListener('cx-keydown', (e: Event) => {
|
|
108
|
+
this.cxKeydown.emit(e as CustomEvent);
|
|
109
|
+
});
|
|
110
|
+
this.el.nativeElement.addEventListener('cx-keyup', (e: Event) => {
|
|
111
|
+
this.cxKeyup.emit(e as CustomEvent);
|
|
112
|
+
});
|
|
113
|
+
// CVA: sync CE value changes back to Angular forms
|
|
114
|
+
this.el.nativeElement.addEventListener('cx-change', (e: Event) => {
|
|
115
|
+
this._onChange((e as CustomEvent).detail?.value);
|
|
116
|
+
});
|
|
117
|
+
this.el.nativeElement.addEventListener('focusout', () => {
|
|
118
|
+
this._onTouched();
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
123
|
+
if (changes['selected'] && this.el) {
|
|
124
|
+
const val = this.selected;
|
|
125
|
+
if (val != null) {
|
|
126
|
+
this.el.nativeElement.setAttribute('selected', typeof val === 'object' ? JSON.stringify(val) : String(val));
|
|
127
|
+
} else {
|
|
128
|
+
this.el.nativeElement.removeAttribute('selected');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (changes['items'] && this.el) {
|
|
132
|
+
const val = this.items;
|
|
133
|
+
if (val != null) {
|
|
134
|
+
this.el.nativeElement.setAttribute('items', typeof val === 'object' ? JSON.stringify(val) : String(val));
|
|
135
|
+
} else {
|
|
136
|
+
this.el.nativeElement.removeAttribute('items');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (changes['groups'] && this.el) {
|
|
140
|
+
const val = this.groups;
|
|
141
|
+
if (val != null) {
|
|
142
|
+
this.el.nativeElement.setAttribute('groups', typeof val === 'object' ? JSON.stringify(val) : String(val));
|
|
143
|
+
} else {
|
|
144
|
+
this.el.nativeElement.removeAttribute('groups');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
_serialize_selected(): string | null {
|
|
150
|
+
const val = this.selected;
|
|
151
|
+
if (val == null) return null;
|
|
152
|
+
return typeof val === 'object' ? JSON.stringify(val) : String(val);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
_serialize_items(): string | null {
|
|
156
|
+
const val = this.items;
|
|
157
|
+
if (val == null) return null;
|
|
158
|
+
return typeof val === 'object' ? JSON.stringify(val) : String(val);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
_serialize_groups(): string | null {
|
|
162
|
+
const val = this.groups;
|
|
163
|
+
if (val == null) return null;
|
|
164
|
+
return typeof val === 'object' ? JSON.stringify(val) : String(val);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Opens the suggestion dropdown. */
|
|
168
|
+
open(): void { (this.el.nativeElement as any).open(); }
|
|
169
|
+
|
|
170
|
+
/** Closes the suggestion dropdown. */
|
|
171
|
+
close(): void { (this.el.nativeElement as any).close(); }
|
|
172
|
+
|
|
173
|
+
/** Clears all selections (multi-mode) or the input (single-mode). */
|
|
174
|
+
clear(): void { (this.el.nativeElement as any).clear(); }
|
|
175
|
+
|
|
176
|
+
/** Focuses the search input. */
|
|
177
|
+
focus(): void { (this.el.nativeElement as any).focus(); }
|
|
178
|
+
|
|
179
|
+
// ── ControlValueAccessor ──
|
|
180
|
+
private _onChange: (value: any) => void = () => {};
|
|
181
|
+
private _onTouched: () => void = () => {};
|
|
182
|
+
|
|
183
|
+
writeValue(value: any): void {
|
|
184
|
+
if (this.el) (this.el.nativeElement as any).value = value ?? '';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
registerOnChange(fn: (value: any) => void): void { this._onChange = fn; }
|
|
188
|
+
registerOnTouched(fn: () => void): void { this._onTouched = fn; }
|
|
189
|
+
|
|
190
|
+
setDisabledState(isDisabled: boolean): void {
|
|
191
|
+
if (this.el) {
|
|
192
|
+
if (isDisabled) this.el.nativeElement.setAttribute('disabled', '');
|
|
193
|
+
else this.el.nativeElement.removeAttribute('disabled');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-angular.mjs — DO NOT EDIT
|
|
2
|
+
// Angular wrapper for <cx-avatar>
|
|
3
|
+
import {
|
|
4
|
+
Component,
|
|
5
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
6
|
+
ChangeDetectionStrategy,
|
|
7
|
+
ChangeDetectorRef,
|
|
8
|
+
ElementRef,
|
|
9
|
+
ViewChild,
|
|
10
|
+
Input,
|
|
11
|
+
Output,
|
|
12
|
+
EventEmitter,
|
|
13
|
+
AfterViewInit,
|
|
14
|
+
} from '@angular/core';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: 'cx-avatar[collet]',
|
|
18
|
+
standalone: true,
|
|
19
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
20
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
21
|
+
template: `
|
|
22
|
+
<cx-avatar
|
|
23
|
+
[attr.id]="id"
|
|
24
|
+
[attr.label]="label"
|
|
25
|
+
[attr.shape]="shape"
|
|
26
|
+
[attr.size]="size"
|
|
27
|
+
[attr.image]="image"
|
|
28
|
+
[attr.initials]="initials"
|
|
29
|
+
[attr.clickable]="clickable || null"
|
|
30
|
+
#el
|
|
31
|
+
><ng-content /></cx-avatar>
|
|
32
|
+
`,
|
|
33
|
+
})
|
|
34
|
+
export class CxAvatar implements AfterViewInit {
|
|
35
|
+
@ViewChild('el', { static: true }) el!: ElementRef<HTMLElement>;
|
|
36
|
+
|
|
37
|
+
@Input() id?: string = undefined;
|
|
38
|
+
@Input() label?: string = undefined;
|
|
39
|
+
@Input() shape?: 'circle' | 'rounded' = undefined;
|
|
40
|
+
@Input() size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = undefined;
|
|
41
|
+
@Input() image?: string = undefined;
|
|
42
|
+
@Input() initials?: string = undefined;
|
|
43
|
+
@Input() clickable?: boolean = undefined;
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
constructor(private c: ChangeDetectorRef) {
|
|
48
|
+
c.detach();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
ngAfterViewInit(): void {
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-angular.mjs — DO NOT EDIT
|
|
2
|
+
// Angular wrapper for <cx-backdrop>
|
|
3
|
+
import {
|
|
4
|
+
Component,
|
|
5
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
6
|
+
ChangeDetectionStrategy,
|
|
7
|
+
ChangeDetectorRef,
|
|
8
|
+
ElementRef,
|
|
9
|
+
ViewChild,
|
|
10
|
+
Input,
|
|
11
|
+
Output,
|
|
12
|
+
EventEmitter,
|
|
13
|
+
AfterViewInit,
|
|
14
|
+
} from '@angular/core';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: 'cx-backdrop[collet]',
|
|
18
|
+
standalone: true,
|
|
19
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
20
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
21
|
+
template: `
|
|
22
|
+
<cx-backdrop
|
|
23
|
+
[attr.tint]="tint"
|
|
24
|
+
[attr.blur]="blur"
|
|
25
|
+
[attr.dismissible]="dismissible || null"
|
|
26
|
+
#el
|
|
27
|
+
><ng-content /></cx-backdrop>
|
|
28
|
+
`,
|
|
29
|
+
})
|
|
30
|
+
export class CxBackdrop implements AfterViewInit {
|
|
31
|
+
@ViewChild('el', { static: true }) el!: ElementRef<HTMLElement>;
|
|
32
|
+
|
|
33
|
+
@Input() tint?: string = undefined;
|
|
34
|
+
@Input() blur?: string = undefined;
|
|
35
|
+
@Input() dismissible?: boolean = undefined;
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
constructor(private c: ChangeDetectorRef) {
|
|
40
|
+
c.detach();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
ngAfterViewInit(): void {
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
}
|