ngx-opalbytes-components 1.21.0 → 1.23.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.
Files changed (28) hide show
  1. package/README.md +173 -0
  2. package/fesm2022/ngx-opalbytes-components.mjs +464 -20
  3. package/fesm2022/ngx-opalbytes-components.mjs.map +1 -1
  4. package/package.json +1 -1
  5. package/src/lib/shared/components/error/error.css +10 -0
  6. package/src/lib/shared/components/error/error.html +5 -0
  7. package/src/lib/shared/components/error/error.spec.ts +76 -0
  8. package/src/lib/shared/components/error/error.stories.ts +61 -0
  9. package/src/lib/shared/components/error/error.ts +33 -0
  10. package/src/lib/shared/components/form-field/error-state-matcher.ts +41 -0
  11. package/src/lib/shared/components/form-field/form-field-control.ts +10 -0
  12. package/src/lib/shared/components/form-field/form-field.css +154 -0
  13. package/src/lib/shared/components/form-field/form-field.html +51 -0
  14. package/src/lib/shared/components/form-field/form-field.spec.ts +114 -0
  15. package/src/lib/shared/components/form-field/form-field.stories.ts +177 -0
  16. package/src/lib/shared/components/form-field/form-field.ts +118 -0
  17. package/src/lib/shared/components/hint/hint.css +10 -0
  18. package/src/lib/shared/components/hint/hint.html +1 -0
  19. package/src/lib/shared/components/hint/hint.spec.ts +22 -0
  20. package/src/lib/shared/components/hint/hint.stories.ts +53 -0
  21. package/src/lib/shared/components/hint/hint.ts +9 -0
  22. package/src/lib/shared/components/index.ts +12 -1
  23. package/src/lib/shared/components/skeleton/skeleton.css +92 -0
  24. package/src/lib/shared/components/skeleton/skeleton.html +3 -0
  25. package/src/lib/shared/components/skeleton/skeleton.spec.ts +22 -0
  26. package/src/lib/shared/components/skeleton/skeleton.stories.ts +131 -0
  27. package/src/lib/shared/components/skeleton/skeleton.ts +46 -0
  28. package/types/ngx-opalbytes-components.d.ts +178 -2
@@ -0,0 +1,177 @@
1
+ import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
2
+
3
+ import type { Meta, StoryObj } from '@storybook/angular-vite';
4
+
5
+ import { CaoFormField } from './form-field';
6
+ import { CaoBaseInput } from '../base-input/base-input';
7
+ import { CaoError } from '../error/error';
8
+ import { CaoHint } from '../hint/hint';
9
+
10
+ const storyImports = [ReactiveFormsModule, CaoFormField, CaoBaseInput, CaoHint, CaoError];
11
+
12
+ const renderFormField = (inner: string, props: Record<string, unknown> = {}) => ({
13
+ template: `<div style="max-width: 420px;">${inner}</div>`,
14
+ moduleMetadata: { imports: storyImports },
15
+ props,
16
+ });
17
+
18
+ const control = () => new FormControl('', [Validators.required]);
19
+
20
+ const meta: Meta<CaoFormField> = {
21
+ title: 'Componentes/Form Field',
22
+ component: CaoFormField,
23
+ subcomponents: {
24
+ caoBaseInput: CaoBaseInput,
25
+ caoHint: CaoHint,
26
+ caoError: CaoError,
27
+ },
28
+ tags: ['autodocs'],
29
+ argTypes: {
30
+ label: { control: 'text' },
31
+ labelInside: { control: 'boolean' },
32
+ hintLabel: { control: 'text' },
33
+ leadingIcon: { control: 'text' },
34
+ trailingIcon: { control: 'text' },
35
+ inputBackground: { control: 'color' },
36
+ borderColor: { control: 'color' },
37
+ borderWidth: { control: 'text' },
38
+ borderRadius: { control: 'text' },
39
+ errorColor: { control: 'color' },
40
+ labelColor: { control: 'color' },
41
+ hintColor: { control: 'color' },
42
+ textColor: { control: 'color' },
43
+ focusBorderColor: { control: 'color' },
44
+ successBorderColor: { control: 'color' },
45
+ },
46
+ };
47
+
48
+ export default meta;
49
+ type Story = StoryObj<CaoFormField>;
50
+
51
+ export const Padrao: Story = {
52
+ render: () =>
53
+ renderFormField(
54
+ `
55
+ <cao-form-field forId="padrao" [label]="'Nome'" [control]="control">
56
+ <cao-input [control]="control" [placeholder]="'Digite seu nome'"></cao-input>
57
+ </cao-form-field>
58
+ `,
59
+ { control: control() }
60
+ ),
61
+ };
62
+
63
+ export const LabelDentro: Story = {
64
+ render: () =>
65
+ renderFormField(
66
+ `
67
+ <cao-form-field forId="label-dentro" [label]="'Nome'" [labelInside]="true" [control]="control">
68
+ <cao-input [control]="control" [placeholder]="' '"></cao-input>
69
+ </cao-form-field>
70
+ `,
71
+ { control: control() }
72
+ ),
73
+ };
74
+
75
+ export const ComHint: Story = {
76
+ render: () =>
77
+ renderFormField(
78
+ `
79
+ <cao-form-field forId="cep" [label]="'CEP'" [control]="control">
80
+ <cao-input [control]="control" [placeholder]="'00000-000'"></cao-input>
81
+ <cao-hint>Formato: 00000-000</cao-hint>
82
+ </cao-form-field>
83
+ `,
84
+ { control: control() }
85
+ ),
86
+ };
87
+
88
+ export const ComErro: Story = {
89
+ render: () => {
90
+ const erroControl = control();
91
+ erroControl.markAsTouched();
92
+ return renderFormField(
93
+ `
94
+ <cao-form-field forId="email" [label]="'E-mail'" [control]="control">
95
+ <cao-input [control]="control" [placeholder]="'Digite seu e-mail'"></cao-input>
96
+ <cao-error>Campo obrigatório</cao-error>
97
+ </cao-form-field>
98
+ `,
99
+ { control: erroControl }
100
+ );
101
+ },
102
+ };
103
+
104
+ export const ComIcones: Story = {
105
+ render: () =>
106
+ renderFormField(
107
+ `
108
+ <cao-form-field
109
+ forId="buscar"
110
+ [label]="'Buscar'"
111
+ leadingIcon="Search"
112
+ trailingIcon="SlidersHorizontal"
113
+ iconColor="#4f46e5"
114
+ [control]="control">
115
+ <cao-input [control]="control" [placeholder]="'Pesquisar...'"></cao-input>
116
+ </cao-form-field>
117
+ `,
118
+ { control: control() }
119
+ ),
120
+ };
121
+
122
+ export const ComMascaraCPF: Story = {
123
+ render: () =>
124
+ renderFormField(
125
+ `
126
+ <cao-form-field forId="cpf" [label]="'CPF'" [control]="control">
127
+ <cao-input
128
+ [control]="control"
129
+ [placeholder]="'000.000.000-00'"
130
+ [mask]="'000.000.000-00'"></cao-input>
131
+ </cao-form-field>
132
+ `,
133
+ { control: control() }
134
+ ),
135
+ };
136
+
137
+ export const Desabilitado: Story = {
138
+ render: () =>
139
+ renderFormField(
140
+ `
141
+ <cao-form-field forId="bloqueado" [label]="'Campo bloqueado'" [control]="control">
142
+ <cao-input [control]="control" [isDisabled]="true" [placeholder]="'Valor indisponível'"></cao-input>
143
+ </cao-form-field>
144
+ `,
145
+ { control: new FormControl({ value: '', disabled: true }) }
146
+ ),
147
+ };
148
+
149
+ export const CoresCustomizadas: Story = {
150
+ render: () => {
151
+ const coresControl = control();
152
+ coresControl.markAsTouched();
153
+ return renderFormField(
154
+ `
155
+ <cao-form-field
156
+ forId="cores"
157
+ [label]="'Personalizado'"
158
+ inputBackground="#f8fafc"
159
+ borderColor="#94a3b8"
160
+ borderWidth="2px"
161
+ borderRadius="16px"
162
+ errorColor="#e11d48"
163
+ labelColor="#0f766e"
164
+ hintColor="#64748b"
165
+ textColor="#0f172a"
166
+ focusBorderColor="#0d9488"
167
+ successBorderColor="#16a34a"
168
+ [control]="control">
169
+ <cao-input [control]="control" [placeholder]="'Cores via input'"></cao-input>
170
+ <cao-hint>Hint customizado</cao-hint>
171
+ <cao-error>Erro customizado</cao-error>
172
+ </cao-form-field>
173
+ `,
174
+ { control: coresControl }
175
+ );
176
+ },
177
+ };
@@ -0,0 +1,118 @@
1
+ import { Component, computed, input, Input } from '@angular/core';
2
+ import { AbstractControl, Validators } from '@angular/forms';
3
+
4
+ import { IErrorStateMatcher } from './error-state-matcher';
5
+ import { IFormFieldControl } from './form-field-control';
6
+ import { CaoBaseIcon } from '../base-icon/base-icon';
7
+
8
+ @Component({
9
+ selector: 'cao-form-field',
10
+ imports: [CaoBaseIcon],
11
+ templateUrl: './form-field.html',
12
+ styleUrl: './form-field.css',
13
+ })
14
+ export class CaoFormField extends CaoBaseIcon implements IFormFieldControl {
15
+ inputBackground = input<string>();
16
+ borderColor = input<string>();
17
+ borderWidth = input<string>();
18
+ borderRadius = input<string>();
19
+ errorColor = input<string>();
20
+ labelColor = input<string>();
21
+ hintColor = input<string>();
22
+ textColor = input<string>();
23
+ focusBorderColor = input<string>();
24
+ successBorderColor = input<string>();
25
+
26
+ formFieldStyles = computed(() => {
27
+ const styles: Record<string, string> = {};
28
+
29
+ if (this.inputBackground()) {
30
+ styles['--cao-form-field-bg-background'] = this.inputBackground()!;
31
+ }
32
+ if (this.borderColor()) {
33
+ styles['--cao-form-field-border-color'] = this.borderColor()!;
34
+ }
35
+ if (this.borderWidth()) {
36
+ styles['--cao-form-field-border-width'] = this.borderWidth()!;
37
+ }
38
+ if (this.borderRadius()) {
39
+ styles['--cao-form-field-border-radius'] = this.borderRadius()!;
40
+ }
41
+ if (this.errorColor()) {
42
+ styles['--cao-form-field-color-error'] = this.errorColor()!;
43
+ }
44
+ if (this.labelColor()) {
45
+ styles['--cao-form-field-color-label'] = this.labelColor()!;
46
+ }
47
+ if (this.hintColor()) {
48
+ styles['--cao-form-field-color-hint'] = this.hintColor()!;
49
+ }
50
+ if (this.textColor()) {
51
+ styles['--cao-form-field-color-text'] = this.textColor()!;
52
+ }
53
+ if (this.focusBorderColor()) {
54
+ styles['--cao-form-field-focus-border'] = this.focusBorderColor()!;
55
+ }
56
+ if (this.successBorderColor()) {
57
+ styles['--cao-form-field-success-border'] = this.successBorderColor()!;
58
+ }
59
+
60
+ return styles;
61
+ });
62
+ @Input() label = '';
63
+ @Input() labelInside = false;
64
+ @Input() hintLabel = '';
65
+ @Input() control: AbstractControl | null = null;
66
+ @Input() forId = '';
67
+ @Input() errorStateMatcher?: IErrorStateMatcher;
68
+ @Input() leadingIcon?: string;
69
+ @Input() trailingIcon?: string;
70
+
71
+ _isSubmitted = false;
72
+ _focused = false;
73
+
74
+ get id(): string {
75
+ return this.forId;
76
+ }
77
+
78
+ get disabled(): boolean {
79
+ return !!this.control?.disabled;
80
+ }
81
+
82
+ get required(): boolean {
83
+ if (!this.control) {
84
+ return false;
85
+ }
86
+ const hasValidator =
87
+ typeof this.control.hasValidator === 'function'
88
+ ? this.control.hasValidator(Validators.required)
89
+ : false;
90
+ return hasValidator;
91
+ }
92
+
93
+ get floating(): boolean {
94
+ return this._focused || !!this.control?.value;
95
+ }
96
+
97
+ get errorStateActive(): boolean {
98
+ const control = this.control;
99
+ if (!control) {
100
+ return false;
101
+ }
102
+ const matcher = this.errorStateMatcher;
103
+ return matcher
104
+ ? matcher.isErrorState(control, this)
105
+ : !!(control.invalid && (control.touched || control.dirty || this._isSubmitted));
106
+ }
107
+
108
+ onFocusIn(): void {
109
+ this._focused = true;
110
+ if (this.control && !this._isSubmitted) {
111
+ this.control.markAsTouched();
112
+ }
113
+ }
114
+
115
+ onFocusOut(): void {
116
+ this._focused = false;
117
+ }
118
+ }
@@ -0,0 +1,10 @@
1
+ :host {
2
+ display: block;
3
+ font-size: 0.75rem;
4
+ line-height: 1.25rem;
5
+ color: var(--cao-form-field-color-hint, var(--input-text, #9ca3af));
6
+ }
7
+
8
+ .cao-hint {
9
+ display: block;
10
+ }
@@ -0,0 +1 @@
1
+ <span class="cao-hint"><ng-content /></span>
@@ -0,0 +1,22 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { CaoHint } from './hint';
4
+
5
+ describe('CaoHint', () => {
6
+ let component: CaoHint;
7
+ let fixture: ComponentFixture<CaoHint>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [CaoHint],
12
+ }).compileComponents();
13
+
14
+ fixture = TestBed.createComponent(CaoHint);
15
+ component = fixture.componentInstance;
16
+ await fixture.whenStable();
17
+ });
18
+
19
+ it('should create', () => {
20
+ expect(component).toBeTruthy();
21
+ });
22
+ });
@@ -0,0 +1,53 @@
1
+ import { Component } from '@angular/core';
2
+ import { FormControl, ReactiveFormsModule } from '@angular/forms';
3
+
4
+ import type { Meta, StoryObj } from '@storybook/angular-vite';
5
+
6
+ import { CaoHint } from './hint';
7
+ import { CaoBaseInput } from '../base-input/base-input';
8
+ import { CaoFormField } from '../form-field/form-field';
9
+
10
+ @Component({
11
+ selector: 'cao-hint-story',
12
+ imports: [ReactiveFormsModule, CaoFormField, CaoBaseInput, CaoHint],
13
+ template: `
14
+ <div style="max-width: 420px;">
15
+ <cao-form-field [control]="control" label="Usuário">
16
+ <cao-input [control]="control" placeholder="nome.sobrenome"></cao-input>
17
+ <cao-hint>{{ text }}</cao-hint>
18
+ </cao-form-field>
19
+ </div>
20
+ `,
21
+ })
22
+ class CaoHintStoryComponent {
23
+ control = new FormControl('');
24
+ text = 'Use seu nome de usuário ou e-mail';
25
+ }
26
+
27
+ const render = (args: Partial<CaoHintStoryComponent>) => ({
28
+ component: CaoHintStoryComponent,
29
+ props: args,
30
+ });
31
+
32
+ const meta: Meta<CaoHint> = {
33
+ title: 'Componentes/Hint',
34
+ component: CaoHint,
35
+ tags: ['autodocs'],
36
+ argTypes: {
37
+ text: { control: 'text' },
38
+ },
39
+ args: {
40
+ text: 'Use seu nome de usuário ou e-mail',
41
+ },
42
+ };
43
+
44
+ export default meta;
45
+ type Story = StoryObj<CaoHint>;
46
+
47
+ export const Padrao: Story = {
48
+ render: () => render({ text: 'Uma dica para auxiliar o preenchimento' }),
49
+ };
50
+
51
+ export const ComTextoExemplo: Story = {
52
+ render: () => render({ text: 'Formato esperado: 000.000.000-00' }),
53
+ };
@@ -0,0 +1,9 @@
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'cao-hint',
5
+ imports: [],
6
+ templateUrl: './hint.html',
7
+ styleUrl: './hint.css',
8
+ })
9
+ export class CaoHint {}
@@ -16,4 +16,15 @@ export * from "./tab-group/tab-group"
16
16
  export * from "./tab-panel/tab-panel"
17
17
 
18
18
  export * from "./base-icon/base-icon"
19
- export * from "./kpi/kpi"
19
+ export * from "./kpi/kpi"
20
+ export * from "./skeleton/skeleton"
21
+
22
+ export * from "./form-field/form-field"
23
+ export * from "./form-field/form-field-control"
24
+ export * from "./form-field/error-state-matcher"
25
+ export * from "./hint/hint"
26
+ export * from "./error/error"
27
+
28
+ export * from "./card/card.component"
29
+ export * from "./base-toggle/base-toggle.component"
30
+ export * from "./footer/footer"
@@ -0,0 +1,92 @@
1
+ /*
2
+ * CSS Custom Properties — all prefixed with --skeleton-*
3
+ * These cascade naturally, so a parent component can override any token:
4
+ *
5
+ * .my-card {
6
+ * --skeleton-bg: #d1d5db;
7
+ * --skeleton-shine: #f3f4f6;
8
+ * --skeleton-radius: 8px;
9
+ * --skeleton-speed: 2s;
10
+ * }
11
+ */
12
+
13
+ :host {
14
+ /* ─── Layout defaults (overridable via [width]/[height] inputs) ─── */
15
+ --skeleton-width: 100%;
16
+ --skeleton-height: 100%;
17
+
18
+ /* ─── Visual tokens — inherit from parent if set there ─── */
19
+ --skeleton-bg: #e2e8f0;
20
+ --skeleton-shine: #f8fafc;
21
+ --skeleton-radius: 14px;
22
+ --skeleton-speed: 2s;
23
+ --skeleton-animation-deg: 90deg;
24
+
25
+ display: contents; /* host element is transparent to layout */
26
+ }
27
+
28
+ /* ─────────────────────────── Base block ─────────────────────────── */
29
+
30
+ .cao-skeleton {
31
+ position: relative;
32
+ display: block;
33
+ overflow: hidden;
34
+ width: var(--skeleton-width);
35
+ height: var(--skeleton-height);
36
+ background-color: var(--skeleton-bg);
37
+ border-radius: var(--skeleton-radius);
38
+
39
+ /* Prevent content from leaking during SSR */
40
+ color: transparent;
41
+ user-select: none;
42
+ pointer-events: none;
43
+
44
+ /* Respect reduced-motion preference */
45
+ @media (prefers-reduced-motion: no-preference) {
46
+ will-change: transform; /* promote shimmer layer */
47
+ }
48
+ }
49
+
50
+ /* ─────────────────────────── Variants ───────────────────────────── */
51
+
52
+ .cao-skeleton--circle {
53
+ --skeleton-radius: 50%;
54
+ /* For circles the consumer usually sets equal width/height;
55
+ but we guard with aspect-ratio so it stays circular even
56
+ when only width is specified. */
57
+ aspect-ratio: 1 / 1;
58
+ }
59
+
60
+ .cao-skeleton--text {
61
+ --skeleton-radius: 4px;
62
+ height: 1em; /* matches current font-size of parent context */
63
+ width: var(--skeleton-width);
64
+ }
65
+
66
+ /* ─────────────────────────── Shimmer ────────────────────────────── */
67
+
68
+ .cao-skeleton__shimmer {
69
+ position: absolute;
70
+ inset: 0;
71
+
72
+ background: linear-gradient(
73
+ var(--skeleton-animation-deg),
74
+ transparent 30%,
75
+ var(--skeleton-shine) 50%,
76
+ transparent 70%
77
+ );
78
+ background-size: 200% 100%;
79
+
80
+ @media (prefers-reduced-motion: no-preference) {
81
+ animation: skeleton-shimmer var(--skeleton-speed) ease-in-out infinite;
82
+ }
83
+ }
84
+
85
+ @keyframes skeleton-shimmer {
86
+ 0% {
87
+ background-position: 200% center;
88
+ }
89
+ 100% {
90
+ background-position: -200% center;
91
+ }
92
+ }
@@ -0,0 +1,3 @@
1
+ <span class="cao-skeleton" [ngClass]="'cao-skeleton--' + variant()" [style]="skeletonStyles()">
2
+ <span class="cao-skeleton__shimmer"></span>
3
+ </span>
@@ -0,0 +1,22 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { CaoSkeletonComponent } from './skeleton';
4
+
5
+ describe('CaoSkeletonComponent', () => {
6
+ let component: CaoSkeletonComponent;
7
+ let fixture: ComponentFixture<CaoSkeletonComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [CaoSkeletonComponent],
12
+ }).compileComponents();
13
+
14
+ fixture = TestBed.createComponent(CaoSkeletonComponent);
15
+ component = fixture.componentInstance;
16
+ await fixture.whenStable();
17
+ });
18
+
19
+ it('should create', () => {
20
+ expect(component).toBeTruthy();
21
+ });
22
+ });
@@ -0,0 +1,131 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular-vite';
2
+
3
+ import { CaoSkeletonComponent } from './skeleton';
4
+
5
+ const meta: Meta<CaoSkeletonComponent> = {
6
+ title: 'Componentes/Skeleton',
7
+ component: CaoSkeletonComponent,
8
+ tags: ['autodocs'],
9
+ argTypes: {
10
+ variant: {
11
+ control: 'select',
12
+ options: ['rect', 'circle', 'text'],
13
+ },
14
+ width: { control: 'text' },
15
+ height: { control: 'text' },
16
+ size: { control: 'text' },
17
+ bgColor: { control: 'color' },
18
+ shine: { control: 'color' },
19
+ borderRadius: { control: 'text' },
20
+ speed: { control: 'text' },
21
+ animationDeg: { control: 'text' },
22
+ },
23
+ args: {
24
+ variant: 'rect',
25
+ width: '200px',
26
+ height: '40px',
27
+ bgColor: '#e2e8f0',
28
+ shine: '#f8fafc',
29
+ speed: '2s',
30
+ },
31
+ };
32
+
33
+ export default meta;
34
+ type Story = StoryObj<CaoSkeletonComponent>;
35
+
36
+ export const Retangulo: Story = {
37
+ args: {
38
+ variant: 'rect',
39
+ width: '200px',
40
+ height: '40px',
41
+ },
42
+ };
43
+
44
+ export const RetanguloComBordaArredondada: Story = {
45
+ args: {
46
+ variant: 'rect',
47
+ width: '200px',
48
+ height: '60px',
49
+ borderRadius: '8px',
50
+ },
51
+ };
52
+
53
+ export const Circulos: Story = {
54
+ args: {
55
+ bgColor: '#8100ff',
56
+ },
57
+
58
+ render: (args) => ({
59
+ props: args,
60
+ template: `
61
+ <div style="display: flex; align-items: center; gap: 16px;">
62
+ <cao-skeleton [size]="'24px'" [variant]="'circle'"></cao-skeleton>
63
+ <cao-skeleton [size]="'48px'" [variant]="'circle'"></cao-skeleton>
64
+ <cao-skeleton [size]="'80px'" [variant]="'circle'"></cao-skeleton>
65
+ </div>
66
+ `,
67
+ }),
68
+ };
69
+
70
+ export const RetangulosComTamanhosVariados: Story = {
71
+ render: () => ({
72
+ template: `
73
+ <div style="display: flex; flex-direction: column; gap: 12px; width: 320px;">
74
+ <cao-skeleton [width]="'100%'" [height]="'12px'"></cao-skeleton>
75
+ <cao-skeleton [width]="'80%'" [height]="'12px'"></cao-skeleton>
76
+ <cao-skeleton [width]="'60%'" [height]="'12px'"></cao-skeleton>
77
+ </div>
78
+ `,
79
+ }),
80
+ };
81
+
82
+ export const LinhaDeTexto: Story = {
83
+ render: (args) => ({
84
+ props: args,
85
+ template: `
86
+ <div style="display: flex; flex-direction: column; gap: 12px; width: 260px;">
87
+ <cao-skeleton [variant]="'text'" [width]="'100%'"></cao-skeleton>
88
+ <cao-skeleton [variant]="'text'" [width]="'90%'"></cao-skeleton>
89
+ <cao-skeleton [variant]="'text'" [width]="'70%'"></cao-skeleton>
90
+ </div>
91
+ `,
92
+ }),
93
+ };
94
+
95
+ export const CorCustomizada: Story = {
96
+ args: {
97
+ variant: 'rect',
98
+ width: '220px',
99
+ height: '48px',
100
+ bgColor: '#e0e7ff',
101
+ shine: '#ffffff',
102
+ borderRadius: '12px',
103
+ },
104
+ };
105
+
106
+ export const AnimacaoRapida: Story = {
107
+ args: {
108
+ variant: 'rect',
109
+ width: '200px',
110
+ height: '40px',
111
+ speed: '0.8s',
112
+ },
113
+ };
114
+
115
+ export const AnimacaoLenta: Story = {
116
+ args: {
117
+ variant: 'rect',
118
+ width: '200px',
119
+ height: '40px',
120
+ speed: '4s',
121
+ },
122
+ };
123
+
124
+ export const GradienteVertical: Story = {
125
+ args: {
126
+ variant: 'rect',
127
+ width: '200px',
128
+ height: '40px',
129
+ animationDeg: '0deg',
130
+ },
131
+ };