@muxima-ui/core 1.0.0 → 1.1.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 (35) hide show
  1. package/README.md +7 -4
  2. package/fesm2022/muxima-ui-core-chips.mjs +349 -0
  3. package/fesm2022/muxima-ui-core-chips.mjs.map +1 -0
  4. package/fesm2022/muxima-ui-core-clipboard.mjs +110 -0
  5. package/fesm2022/muxima-ui-core-clipboard.mjs.map +1 -0
  6. package/fesm2022/muxima-ui-core-date-picker.mjs +494 -12
  7. package/fesm2022/muxima-ui-core-date-picker.mjs.map +1 -1
  8. package/fesm2022/muxima-ui-core-file-upload.mjs +392 -0
  9. package/fesm2022/muxima-ui-core-file-upload.mjs.map +1 -0
  10. package/fesm2022/muxima-ui-core-rating.mjs +212 -0
  11. package/fesm2022/muxima-ui-core-rating.mjs.map +1 -0
  12. package/fesm2022/muxima-ui-core-slider.mjs +211 -3
  13. package/fesm2022/muxima-ui-core-slider.mjs.map +1 -1
  14. package/fesm2022/muxima-ui-core-time-picker.mjs +389 -0
  15. package/fesm2022/muxima-ui-core-time-picker.mjs.map +1 -0
  16. package/fesm2022/muxima-ui-core.mjs +1 -1
  17. package/fesm2022/muxima-ui-core.mjs.map +1 -1
  18. package/package.json +21 -1
  19. package/styles/base.css +9 -1
  20. package/styles/components/chips.css +170 -0
  21. package/styles/components/clipboard.css +52 -0
  22. package/styles/components/date-picker.css +135 -0
  23. package/styles/components/file-upload.css +164 -0
  24. package/styles/components/rating.css +89 -0
  25. package/styles/components/slider.css +111 -0
  26. package/styles/components/time-picker.css +39 -0
  27. package/styles/muxima.css +5 -0
  28. package/types/muxima-ui-core-chips.d.ts +120 -0
  29. package/types/muxima-ui-core-clipboard.d.ts +42 -0
  30. package/types/muxima-ui-core-date-picker.d.ts +130 -2
  31. package/types/muxima-ui-core-file-upload.d.ts +96 -0
  32. package/types/muxima-ui-core-rating.d.ts +64 -0
  33. package/types/muxima-ui-core-slider.d.ts +68 -6
  34. package/types/muxima-ui-core-time-picker.d.ts +83 -0
  35. package/types/muxima-ui-core.d.ts +1 -1
package/README.md CHANGED
@@ -30,9 +30,14 @@ Cada componente tem o seu ponto de entrada, para só importares o que usas:
30
30
  | `@muxima-ui/core/checkbox` | `MxCheckbox` |
31
31
  | `@muxima-ui/core/radio` | `MxRadio` |
32
32
  | `@muxima-ui/core/switch` | `MxSwitch` |
33
- | `@muxima-ui/core/slider` | `MxSlider` |
34
- | `@muxima-ui/core/date-picker` | `MxDatePicker`, `MxCalendar`, `mxParseDate`, `mxFormatDate` |
33
+ | `@muxima-ui/core/slider` | `MxSlider`, `MxRangeSlider` (dois cursores) |
34
+ | `@muxima-ui/core/date-picker` | `MxDatePicker`, `MxDateRangePicker`, `MxCalendar`, `mxDefaultRangePresets`, `mxDateRangeComplete`, `mxParseDate`, `mxFormatDate` |
35
+ | `@muxima-ui/core/time-picker` | `MxTimePicker`, `mxParseTime` |
35
36
  | `@muxima-ui/core/otp` | `MxOtp` |
37
+ | `@muxima-ui/core/chips` | `MxChip`, `MxChipToggle`, `MxTagInput` |
38
+ | `@muxima-ui/core/file-upload` | `MxFileUpload`, `mxFormatBytes` |
39
+ | `@muxima-ui/core/rating` | `MxRating` |
40
+ | `@muxima-ui/core/clipboard` | `MxCopy`, `MxCopyButton` |
36
41
  | `@muxima-ui/core/table` | `MX_TABLE`, `mxSortData` |
37
42
  | `@muxima-ui/core/card` | `MX_CARD` |
38
43
  | `@muxima-ui/core/badge` | `MxBadge` |
@@ -54,6 +59,4 @@ Cada componente tem o seu ponto de entrada, para só importares o que usas:
54
59
  | `@muxima-ui/core/skeleton` | `MxSkeleton` |
55
60
  | `@muxima-ui/core/toast` | `MxToast` |
56
61
 
57
- Time picker usa `input[type=time][mxInput]`, sem componente próprio.
58
-
59
62
  Licença MIT.
@@ -0,0 +1,349 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, booleanAttribute, output, viewChild, signal, afterRenderEffect, ViewEncapsulation, ChangeDetectionStrategy, Component, model, Directive, numberAttribute, inject, ElementRef, Injector, computed, afterNextRender } from '@angular/core';
3
+ import { LiveAnnouncer } from '@angular/cdk/a11y';
4
+ import { NgControl, Validators } from '@angular/forms';
5
+ import { MxFormField, mxUniqueId, MX_FORM_FIELD_CONTROL } from '@muxima-ui/core/form-field';
6
+
7
+ /**
8
+ * Etiqueta curta, opcionalmente com botão para remover.
9
+ *
10
+ * ```html
11
+ * <mx-chip>Luanda</mx-chip>
12
+ * <mx-chip removable (removed)="tirar('Luanda')">Luanda</mx-chip>
13
+ * ```
14
+ *
15
+ * O botão de remover chama-se "Remover Luanda" (o texto do chip). Em listas, põe os chips num
16
+ * `<ul>` com `<li>`, para o leitor de ecrã dizer quantos são.
17
+ */
18
+ class MxChip {
19
+ removable = input(false, { ...(ngDevMode ? { debugName: "removable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
20
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
21
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
22
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
23
+ /** Verbo do botão de remover, seguido do texto do chip. */
24
+ removeLabel = input('Remover', ...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
25
+ removed = output();
26
+ label = viewChild.required('label');
27
+ text = signal('', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
28
+ constructor() {
29
+ afterRenderEffect({ read: () => this.text.set(this.label().nativeElement.textContent?.trim() ?? '') });
30
+ }
31
+ /** Põe o foco no botão de remover (usado pelo MxTagInput). */
32
+ focusRemove() {
33
+ this.label().nativeElement.parentElement?.querySelector('.mx-chip-remove')?.focus();
34
+ }
35
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxChip, deps: [], target: i0.ɵɵFactoryTarget.Component });
36
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: MxChip, isStandalone: true, selector: "mx-chip", inputs: { removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { removed: "removed" }, host: { properties: { "attr.data-variant": "variant() === \"default\" ? null : variant()", "attr.data-size": "size() === \"md\" ? null : size()", "attr.data-disabled": "disabled() ? \"\" : null" }, classAttribute: "mx-chip" }, viewQueries: [{ propertyName: "label", first: true, predicate: ["label"], descendants: true, isSignal: true }], exportAs: ["mxChip"], ngImport: i0, template: `
37
+ <span class="mx-chip-label" #label><ng-content /></span>
38
+ @if (removable()) {
39
+ <button type="button" class="mx-chip-remove" [disabled]="disabled()" [attr.aria-label]="removeLabel() + ' ' + text()" (click)="removed.emit()">
40
+ <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /></svg>
41
+ </button>
42
+ }
43
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
44
+ }
45
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxChip, decorators: [{
46
+ type: Component,
47
+ args: [{
48
+ selector: 'mx-chip',
49
+ exportAs: 'mxChip',
50
+ changeDetection: ChangeDetectionStrategy.OnPush,
51
+ encapsulation: ViewEncapsulation.None,
52
+ host: {
53
+ class: 'mx-chip',
54
+ '[attr.data-variant]': 'variant() === "default" ? null : variant()',
55
+ '[attr.data-size]': 'size() === "md" ? null : size()',
56
+ '[attr.data-disabled]': 'disabled() ? "" : null',
57
+ },
58
+ template: `
59
+ <span class="mx-chip-label" #label><ng-content /></span>
60
+ @if (removable()) {
61
+ <button type="button" class="mx-chip-remove" [disabled]="disabled()" [attr.aria-label]="removeLabel() + ' ' + text()" (click)="removed.emit()">
62
+ <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /></svg>
63
+ </button>
64
+ }
65
+ `,
66
+ }]
67
+ }], ctorParameters: () => [], propDecorators: { removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], removed: [{ type: i0.Output, args: ["removed"] }], label: [{ type: i0.ViewChild, args: ['label', { isSignal: true }] }] } });
68
+ /**
69
+ * Chip que liga e desliga, para filtros. É um `<button>` com aria-pressed.
70
+ *
71
+ * ```html
72
+ * <div role="group" aria-label="Estado">
73
+ * <button mxChipToggle [(selected)]="soPagas">Pagas</button>
74
+ * </div>
75
+ * ```
76
+ */
77
+ class MxChipToggle {
78
+ selected = model(false, ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
79
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
80
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxChipToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
81
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: MxChipToggle, isStandalone: true, selector: "button[mxChipToggle]", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange" }, host: { attributes: { "type": "button" }, listeners: { "click": "selected.set(!selected())" }, properties: { "attr.aria-pressed": "selected()", "attr.data-size": "size() === \"md\" ? null : size()" }, classAttribute: "mx-chip mx-chip-toggle" }, exportAs: ["mxChipToggle"], ngImport: i0 });
82
+ }
83
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxChipToggle, decorators: [{
84
+ type: Directive,
85
+ args: [{
86
+ selector: 'button[mxChipToggle]',
87
+ exportAs: 'mxChipToggle',
88
+ host: {
89
+ class: 'mx-chip mx-chip-toggle',
90
+ type: 'button',
91
+ '[attr.aria-pressed]': 'selected()',
92
+ '[attr.data-size]': 'size() === "md" ? null : size()',
93
+ '(click)': 'selected.set(!selected())',
94
+ },
95
+ }]
96
+ }], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
97
+ /**
98
+ * Campo de etiquetas: escreve-se e Enter (ou vírgula) acrescenta; Backspace no campo vazio
99
+ * vai para a última etiqueta. O valor é `string[]`.
100
+ *
101
+ * ```html
102
+ * <mx-form-field>
103
+ * <label mxLabel>Destinatários</label>
104
+ * <mx-tag-input formControlName="emails" placeholder="Escreve e carrega Enter" />
105
+ * </mx-form-field>
106
+ * ```
107
+ *
108
+ * Cada etiqueta acrescentada ou removida é anunciada pelo leitor de ecrã.
109
+ */
110
+ class MxTagInput {
111
+ value = model([], ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
112
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
113
+ /** Teclas que acrescentam a etiqueta, além de Enter. */
114
+ separators = input([',', ';'], ...(ngDevMode ? [{ debugName: "separators" }] : /* istanbul ignore next */ []));
115
+ maxTags = input(Infinity, { ...(ngDevMode ? { debugName: "maxTags" } : /* istanbul ignore next */ {}), transform: numberAttribute });
116
+ allowDuplicates = input(false, { ...(ngDevMode ? { debugName: "allowDuplicates" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
117
+ /** Valida cada etiqueta antes de a acrescentar (ex.: email). Devolve a mensagem de erro ou null. */
118
+ validate = input(() => null, ...(ngDevMode ? [{ debugName: "validate" }] : /* istanbul ignore next */ []));
119
+ /** Nome da lista para o leitor de ecrã. */
120
+ listLabel = input('Etiquetas', ...(ngDevMode ? [{ debugName: "listLabel" }] : /* istanbul ignore next */ []));
121
+ helpText = input('Enter para acrescentar. Backspace no campo vazio vai para a última etiqueta.', ...(ngDevMode ? [{ debugName: "helpText" }] : /* istanbul ignore next */ []));
122
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
123
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
124
+ required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
125
+ invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
126
+ id = input(undefined, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
127
+ ariaLabel = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
128
+ /** Emite a etiqueta rejeitada por `validate`, duplicada ou acima do máximo. */
129
+ rejected = output();
130
+ field = inject(MxFormField, { optional: true });
131
+ ngControl = inject(NgControl, { self: true, optional: true });
132
+ announcer = inject(LiveAnnouncer);
133
+ host = inject(ElementRef).nativeElement;
134
+ input = viewChild.required('input');
135
+ injector = inject(Injector);
136
+ generatedId = mxUniqueId('mx-tag-input');
137
+ controlId = computed(() => this.id() ?? this.generatedId, ...(ngDevMode ? [{ debugName: "controlId" }] : /* istanbul ignore next */ []));
138
+ helpId = mxUniqueId('mx-tag-help');
139
+ draft = signal('', ...(ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []));
140
+ tags = computed(() => this.value() ?? [], ...(ngDevMode ? [{ debugName: "tags" }] : /* istanbul ignore next */ []));
141
+ formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []));
142
+ isDisabled = computed(() => this.disabled() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
143
+ describedBy = computed(() => [this.field?.describedBy(), this.helpId].filter(Boolean).join(' '), ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
144
+ onChange = () => { };
145
+ onTouched = () => { };
146
+ constructor() {
147
+ if (this.ngControl)
148
+ this.ngControl.valueAccessor = this;
149
+ }
150
+ /** Acrescenta uma etiqueta. Devolve false se foi rejeitada. */
151
+ add(raw) {
152
+ const tag = raw.trim();
153
+ if (!tag)
154
+ return false;
155
+ const reject = (reason) => {
156
+ this.rejected.emit({ tag, reason });
157
+ this.announcer.announce(reason, 'assertive');
158
+ return false;
159
+ };
160
+ if (this.tags().length >= this.maxTags())
161
+ return reject(`Máximo de ${this.maxTags()} etiquetas.`);
162
+ if (!this.allowDuplicates() && this.tags().some((t) => t.toLocaleLowerCase() === tag.toLocaleLowerCase()))
163
+ return reject(`${tag} já está na lista.`);
164
+ const error = this.validate()(tag);
165
+ if (error)
166
+ return reject(error);
167
+ this.update([...this.tags(), tag]);
168
+ this.announcer.announce(`${tag} acrescentado.`);
169
+ return true;
170
+ }
171
+ remove(index) {
172
+ const tag = this.tags()[index];
173
+ this.update(this.tags().filter((_, i) => i !== index));
174
+ this.announcer.announce(`${tag} removido.`);
175
+ // o foco passa para a etiqueta seguinte, ou para o campo
176
+ afterNextRender(() => {
177
+ const chips = this.host.querySelectorAll('.mx-chip-remove');
178
+ (chips[Math.min(index, chips.length - 1)] ?? this.input().nativeElement).focus();
179
+ }, { injector: this.injector });
180
+ }
181
+ update(tags) {
182
+ this.value.set(tags);
183
+ this.onChange(tags);
184
+ }
185
+ onKeydown(event) {
186
+ const el = event.target;
187
+ if (event.key === 'Enter' || this.separators().includes(event.key)) {
188
+ if (!this.draft().trim()) {
189
+ if (event.key !== 'Enter')
190
+ event.preventDefault();
191
+ return;
192
+ }
193
+ event.preventDefault();
194
+ if (this.add(this.draft()))
195
+ this.clearDraft();
196
+ }
197
+ else if (event.key === 'Backspace' && !el.value && this.tags().length) {
198
+ event.preventDefault();
199
+ this.host.querySelectorAll('.mx-chip-remove')[this.tags().length - 1]?.focus();
200
+ }
201
+ }
202
+ clearDraft() {
203
+ this.draft.set('');
204
+ // o binding [value] pode não ter visto o texto escrito: limpa o elemento
205
+ this.input().nativeElement.value = '';
206
+ }
207
+ onChipKey(event, index) {
208
+ const removes = this.host.querySelectorAll('.mx-chip-remove');
209
+ if (event.key === 'Backspace' || event.key === 'Delete') {
210
+ event.preventDefault();
211
+ this.remove(index);
212
+ }
213
+ else if (event.key === 'ArrowLeft') {
214
+ event.preventDefault();
215
+ removes[Math.max(index - 1, 0)]?.focus();
216
+ }
217
+ else if (event.key === 'ArrowRight') {
218
+ event.preventDefault();
219
+ (removes[index + 1] ?? this.input().nativeElement).focus();
220
+ }
221
+ }
222
+ onPaste(event) {
223
+ const text = event.clipboardData?.getData('text') ?? '';
224
+ const parts = text.split(new RegExp(`[\\n${this.separators().map((s) => '\\' + s).join('')}]`)).filter((p) => p.trim());
225
+ if (parts.length > 1) {
226
+ event.preventDefault();
227
+ parts.forEach((p) => this.add(p));
228
+ }
229
+ }
230
+ onBlur() {
231
+ if (this.draft().trim() && this.add(this.draft()))
232
+ this.clearDraft();
233
+ this.onTouched();
234
+ }
235
+ focusInput(event) {
236
+ if (!event.target.closest('button, input'))
237
+ this.input().nativeElement.focus();
238
+ }
239
+ // ---- MxFormFieldControl ----
240
+ errorState() {
241
+ if (this.invalid())
242
+ return true;
243
+ const c = this.ngControl;
244
+ return !!c && !!c.invalid && !!(c.touched || c.dirty);
245
+ }
246
+ isRequired() {
247
+ return this.required() || !!this.ngControl?.control?.hasValidator?.(Validators.required);
248
+ }
249
+ // ---- ControlValueAccessor ----
250
+ writeValue(value) {
251
+ this.value.set(value ?? []);
252
+ }
253
+ registerOnChange(fn) {
254
+ this.onChange = fn;
255
+ }
256
+ registerOnTouched(fn) {
257
+ this.onTouched = fn;
258
+ }
259
+ setDisabledState(isDisabled) {
260
+ this.formDisabled.set(isDisabled);
261
+ }
262
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTagInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
263
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: MxTagInput, isStandalone: true, selector: "mx-tag-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, separators: { classPropertyName: "separators", publicName: "separators", isSignal: true, isRequired: false, transformFunction: null }, maxTags: { classPropertyName: "maxTags", publicName: "maxTags", isSignal: true, isRequired: false, transformFunction: null }, allowDuplicates: { classPropertyName: "allowDuplicates", publicName: "allowDuplicates", isSignal: true, isRequired: false, transformFunction: null }, validate: { classPropertyName: "validate", publicName: "validate", isSignal: true, isRequired: false, transformFunction: null }, listLabel: { classPropertyName: "listLabel", publicName: "listLabel", isSignal: true, isRequired: false, transformFunction: null }, helpText: { classPropertyName: "helpText", publicName: "helpText", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", rejected: "rejected" }, host: { listeners: { "click": "focusInput($event)" }, properties: { "attr.data-size": "size() === \"md\" ? null : size()", "attr.data-invalid": "errorState() ? \"\" : null", "attr.data-disabled": "isDisabled() ? \"\" : null", "attr.aria-label": "null" }, classAttribute: "mx-tag-input" }, providers: [{ provide: MX_FORM_FIELD_CONTROL, useExisting: MxTagInput }], viewQueries: [{ propertyName: "input", first: true, predicate: ["input"], descendants: true, isSignal: true }], exportAs: ["mxTagInput"], ngImport: i0, template: `
264
+ @if (tags().length) {
265
+ <ul class="mx-tag-input-list" [attr.aria-label]="listLabel()">
266
+ @for (t of tags(); track t; let i = $index) {
267
+ <li>
268
+ <mx-chip size="sm" [removable]="!isDisabled()" (removed)="remove(i)" (keydown)="onChipKey($event, i)">{{ t }}</mx-chip>
269
+ </li>
270
+ }
271
+ </ul>
272
+ }
273
+ <input
274
+ #input
275
+ class="mx-tag-input-field"
276
+ type="text"
277
+ autocomplete="off"
278
+ [id]="controlId()"
279
+ [placeholder]="tags().length ? '' : placeholder()"
280
+ [disabled]="isDisabled()"
281
+ [value]="draft()"
282
+ [attr.aria-invalid]="errorState() ? 'true' : null"
283
+ [attr.aria-required]="isRequired() ? 'true' : null"
284
+ [attr.aria-describedby]="describedBy()"
285
+ [attr.aria-label]="ariaLabel() ?? null"
286
+ (input)="draft.set($any($event.target).value)"
287
+ (keydown)="onKeydown($event)"
288
+ (blur)="onBlur()"
289
+ (paste)="onPaste($event)"
290
+ />
291
+ <span class="mx-visually-hidden" [id]="helpId">{{ helpText() }}</span>
292
+ `, isInline: true, dependencies: [{ kind: "component", type: MxChip, selector: "mx-chip", inputs: ["removable", "disabled", "variant", "size", "removeLabel"], outputs: ["removed"], exportAs: ["mxChip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
293
+ }
294
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTagInput, decorators: [{
295
+ type: Component,
296
+ args: [{
297
+ selector: 'mx-tag-input',
298
+ exportAs: 'mxTagInput',
299
+ imports: [MxChip],
300
+ providers: [{ provide: MX_FORM_FIELD_CONTROL, useExisting: MxTagInput }],
301
+ changeDetection: ChangeDetectionStrategy.OnPush,
302
+ encapsulation: ViewEncapsulation.None,
303
+ host: {
304
+ class: 'mx-tag-input',
305
+ '[attr.data-size]': 'size() === "md" ? null : size()',
306
+ '[attr.data-invalid]': 'errorState() ? "" : null',
307
+ '[attr.data-disabled]': 'isDisabled() ? "" : null',
308
+ '[attr.aria-label]': 'null',
309
+ '(click)': 'focusInput($event)',
310
+ },
311
+ template: `
312
+ @if (tags().length) {
313
+ <ul class="mx-tag-input-list" [attr.aria-label]="listLabel()">
314
+ @for (t of tags(); track t; let i = $index) {
315
+ <li>
316
+ <mx-chip size="sm" [removable]="!isDisabled()" (removed)="remove(i)" (keydown)="onChipKey($event, i)">{{ t }}</mx-chip>
317
+ </li>
318
+ }
319
+ </ul>
320
+ }
321
+ <input
322
+ #input
323
+ class="mx-tag-input-field"
324
+ type="text"
325
+ autocomplete="off"
326
+ [id]="controlId()"
327
+ [placeholder]="tags().length ? '' : placeholder()"
328
+ [disabled]="isDisabled()"
329
+ [value]="draft()"
330
+ [attr.aria-invalid]="errorState() ? 'true' : null"
331
+ [attr.aria-required]="isRequired() ? 'true' : null"
332
+ [attr.aria-describedby]="describedBy()"
333
+ [attr.aria-label]="ariaLabel() ?? null"
334
+ (input)="draft.set($any($event.target).value)"
335
+ (keydown)="onKeydown($event)"
336
+ (blur)="onBlur()"
337
+ (paste)="onPaste($event)"
338
+ />
339
+ <span class="mx-visually-hidden" [id]="helpId">{{ helpText() }}</span>
340
+ `,
341
+ }]
342
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], separators: [{ type: i0.Input, args: [{ isSignal: true, alias: "separators", required: false }] }], maxTags: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTags", required: false }] }], allowDuplicates: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDuplicates", required: false }] }], validate: [{ type: i0.Input, args: [{ isSignal: true, alias: "validate", required: false }] }], listLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "listLabel", required: false }] }], helpText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helpText", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], rejected: [{ type: i0.Output, args: ["rejected"] }], input: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
343
+
344
+ /**
345
+ * Generated bundle index. Do not edit.
346
+ */
347
+
348
+ export { MxChip, MxChipToggle, MxTagInput };
349
+ //# sourceMappingURL=muxima-ui-core-chips.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxima-ui-core-chips.mjs","sources":["../../../projects/core/chips/chips.ts","../../../projects/core/chips/muxima-ui-core-chips.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Injector,\n afterNextRender,\n Component,\n Directive,\n ElementRef,\n ViewEncapsulation,\n afterRenderEffect,\n booleanAttribute,\n computed,\n inject,\n input,\n model,\n numberAttribute,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { LiveAnnouncer } from '@angular/cdk/a11y';\nimport { ControlValueAccessor, NgControl, Validators } from '@angular/forms';\nimport { MX_FORM_FIELD_CONTROL, MxFormField, MxFormFieldControl, mxUniqueId } from '@muxima-ui/core/form-field';\n\n/**\n * Etiqueta curta, opcionalmente com botão para remover.\n *\n * ```html\n * <mx-chip>Luanda</mx-chip>\n * <mx-chip removable (removed)=\"tirar('Luanda')\">Luanda</mx-chip>\n * ```\n *\n * O botão de remover chama-se \"Remover Luanda\" (o texto do chip). Em listas, põe os chips num\n * `<ul>` com `<li>`, para o leitor de ecrã dizer quantos são.\n */\n@Component({\n selector: 'mx-chip',\n exportAs: 'mxChip',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'mx-chip',\n '[attr.data-variant]': 'variant() === \"default\" ? null : variant()',\n '[attr.data-size]': 'size() === \"md\" ? null : size()',\n '[attr.data-disabled]': 'disabled() ? \"\" : null',\n },\n template: `\n <span class=\"mx-chip-label\" #label><ng-content /></span>\n @if (removable()) {\n <button type=\"button\" class=\"mx-chip-remove\" [disabled]=\"disabled()\" [attr.aria-label]=\"removeLabel() + ' ' + text()\" (click)=\"removed.emit()\">\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M4.5 4.5l7 7M11.5 4.5l-7 7\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" /></svg>\n </button>\n }\n `,\n})\nexport class MxChip {\n readonly removable = input(false, { transform: booleanAttribute });\n readonly disabled = input(false, { transform: booleanAttribute });\n readonly variant = input<'default' | 'outline' | 'accent'>('default');\n readonly size = input<'sm' | 'md'>('md');\n /** Verbo do botão de remover, seguido do texto do chip. */\n readonly removeLabel = input('Remover');\n readonly removed = output<void>();\n\n private readonly label = viewChild.required<ElementRef<HTMLElement>>('label');\n protected readonly text = signal('');\n\n constructor() {\n afterRenderEffect({ read: () => this.text.set(this.label().nativeElement.textContent?.trim() ?? '') });\n }\n\n /** Põe o foco no botão de remover (usado pelo MxTagInput). */\n focusRemove(): void {\n this.label().nativeElement.parentElement?.querySelector<HTMLButtonElement>('.mx-chip-remove')?.focus();\n }\n}\n\n/**\n * Chip que liga e desliga, para filtros. É um `<button>` com aria-pressed.\n *\n * ```html\n * <div role=\"group\" aria-label=\"Estado\">\n * <button mxChipToggle [(selected)]=\"soPagas\">Pagas</button>\n * </div>\n * ```\n */\n@Directive({\n selector: 'button[mxChipToggle]',\n exportAs: 'mxChipToggle',\n host: {\n class: 'mx-chip mx-chip-toggle',\n type: 'button',\n '[attr.aria-pressed]': 'selected()',\n '[attr.data-size]': 'size() === \"md\" ? null : size()',\n '(click)': 'selected.set(!selected())',\n },\n})\nexport class MxChipToggle {\n readonly selected = model(false);\n readonly size = input<'sm' | 'md'>('md');\n}\n\n/**\n * Campo de etiquetas: escreve-se e Enter (ou vírgula) acrescenta; Backspace no campo vazio\n * vai para a última etiqueta. O valor é `string[]`.\n *\n * ```html\n * <mx-form-field>\n * <label mxLabel>Destinatários</label>\n * <mx-tag-input formControlName=\"emails\" placeholder=\"Escreve e carrega Enter\" />\n * </mx-form-field>\n * ```\n *\n * Cada etiqueta acrescentada ou removida é anunciada pelo leitor de ecrã.\n */\n@Component({\n selector: 'mx-tag-input',\n exportAs: 'mxTagInput',\n imports: [MxChip],\n providers: [{ provide: MX_FORM_FIELD_CONTROL, useExisting: MxTagInput }],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'mx-tag-input',\n '[attr.data-size]': 'size() === \"md\" ? null : size()',\n '[attr.data-invalid]': 'errorState() ? \"\" : null',\n '[attr.data-disabled]': 'isDisabled() ? \"\" : null',\n '[attr.aria-label]': 'null',\n '(click)': 'focusInput($event)',\n },\n template: `\n @if (tags().length) {\n <ul class=\"mx-tag-input-list\" [attr.aria-label]=\"listLabel()\">\n @for (t of tags(); track t; let i = $index) {\n <li>\n <mx-chip size=\"sm\" [removable]=\"!isDisabled()\" (removed)=\"remove(i)\" (keydown)=\"onChipKey($event, i)\">{{ t }}</mx-chip>\n </li>\n }\n </ul>\n }\n <input\n #input\n class=\"mx-tag-input-field\"\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"controlId()\"\n [placeholder]=\"tags().length ? '' : placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"draft()\"\n [attr.aria-invalid]=\"errorState() ? 'true' : null\"\n [attr.aria-required]=\"isRequired() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n (input)=\"draft.set($any($event.target).value)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onBlur()\"\n (paste)=\"onPaste($event)\"\n />\n <span class=\"mx-visually-hidden\" [id]=\"helpId\">{{ helpText() }}</span>\n `,\n})\nexport class MxTagInput implements ControlValueAccessor, MxFormFieldControl {\n readonly value = model<string[]>([]);\n readonly placeholder = input('');\n /** Teclas que acrescentam a etiqueta, além de Enter. */\n readonly separators = input<string[]>([',', ';']);\n readonly maxTags = input(Infinity, { transform: numberAttribute });\n readonly allowDuplicates = input(false, { transform: booleanAttribute });\n /** Valida cada etiqueta antes de a acrescentar (ex.: email). Devolve a mensagem de erro ou null. */\n readonly validate = input<(tag: string) => string | null>(() => null);\n /** Nome da lista para o leitor de ecrã. */\n readonly listLabel = input('Etiquetas');\n readonly helpText = input('Enter para acrescentar. Backspace no campo vazio vai para a última etiqueta.');\n readonly size = input<'sm' | 'md' | 'lg'>('md');\n readonly disabled = input(false, { transform: booleanAttribute });\n readonly required = input(false, { transform: booleanAttribute });\n readonly invalid = input(false, { transform: booleanAttribute });\n readonly id = input<string | undefined>(undefined);\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\n /** Emite a etiqueta rejeitada por `validate`, duplicada ou acima do máximo. */\n readonly rejected = output<{ tag: string; reason: string }>();\n\n protected readonly field = inject(MxFormField, { optional: true });\n private readonly ngControl = inject(NgControl, { self: true, optional: true });\n private readonly announcer = inject(LiveAnnouncer);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly input = viewChild.required<ElementRef<HTMLInputElement>>('input');\n private readonly injector = inject(Injector);\n\n private readonly generatedId = mxUniqueId('mx-tag-input');\n readonly controlId = computed(() => this.id() ?? this.generatedId);\n protected readonly helpId = mxUniqueId('mx-tag-help');\n protected readonly draft = signal('');\n protected readonly tags = computed(() => this.value() ?? []);\n private readonly formDisabled = signal(false);\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n protected readonly describedBy = computed(() => [this.field?.describedBy(), this.helpId].filter(Boolean).join(' '));\n\n private onChange: (value: string[]) => void = () => {};\n private onTouched: () => void = () => {};\n\n constructor() {\n if (this.ngControl) this.ngControl.valueAccessor = this;\n }\n\n /** Acrescenta uma etiqueta. Devolve false se foi rejeitada. */\n add(raw: string): boolean {\n const tag = raw.trim();\n if (!tag) return false;\n const reject = (reason: string) => {\n this.rejected.emit({ tag, reason });\n this.announcer.announce(reason, 'assertive');\n return false;\n };\n if (this.tags().length >= this.maxTags()) return reject(`Máximo de ${this.maxTags()} etiquetas.`);\n if (!this.allowDuplicates() && this.tags().some((t) => t.toLocaleLowerCase() === tag.toLocaleLowerCase())) return reject(`${tag} já está na lista.`);\n const error = this.validate()(tag);\n if (error) return reject(error);\n this.update([...this.tags(), tag]);\n this.announcer.announce(`${tag} acrescentado.`);\n return true;\n }\n\n remove(index: number): void {\n const tag = this.tags()[index];\n this.update(this.tags().filter((_, i) => i !== index));\n this.announcer.announce(`${tag} removido.`);\n // o foco passa para a etiqueta seguinte, ou para o campo\n afterNextRender(() => {\n const chips = this.host.querySelectorAll<HTMLElement>('.mx-chip-remove');\n (chips[Math.min(index, chips.length - 1)] ?? this.input().nativeElement).focus();\n }, { injector: this.injector });\n }\n\n private update(tags: string[]): void {\n this.value.set(tags);\n this.onChange(tags);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const el = event.target as HTMLInputElement;\n if (event.key === 'Enter' || this.separators().includes(event.key)) {\n if (!this.draft().trim()) {\n if (event.key !== 'Enter') event.preventDefault();\n return;\n }\n event.preventDefault();\n if (this.add(this.draft())) this.clearDraft();\n } else if (event.key === 'Backspace' && !el.value && this.tags().length) {\n event.preventDefault();\n this.host.querySelectorAll<HTMLElement>('.mx-chip-remove')[this.tags().length - 1]?.focus();\n }\n }\n\n private clearDraft(): void {\n this.draft.set('');\n // o binding [value] pode não ter visto o texto escrito: limpa o elemento\n this.input().nativeElement.value = '';\n }\n\n protected onChipKey(event: KeyboardEvent, index: number): void {\n const removes = this.host.querySelectorAll<HTMLElement>('.mx-chip-remove');\n if (event.key === 'Backspace' || event.key === 'Delete') {\n event.preventDefault();\n this.remove(index);\n } else if (event.key === 'ArrowLeft') {\n event.preventDefault();\n removes[Math.max(index - 1, 0)]?.focus();\n } else if (event.key === 'ArrowRight') {\n event.preventDefault();\n (removes[index + 1] ?? this.input().nativeElement).focus();\n }\n }\n\n protected onPaste(event: ClipboardEvent): void {\n const text = event.clipboardData?.getData('text') ?? '';\n const parts = text.split(new RegExp(`[\\\\n${this.separators().map((s) => '\\\\' + s).join('')}]`)).filter((p) => p.trim());\n if (parts.length > 1) {\n event.preventDefault();\n parts.forEach((p) => this.add(p));\n }\n }\n\n protected onBlur(): void {\n if (this.draft().trim() && this.add(this.draft())) this.clearDraft();\n this.onTouched();\n }\n\n protected focusInput(event: MouseEvent): void {\n if (!(event.target as HTMLElement).closest('button, input')) this.input().nativeElement.focus();\n }\n\n // ---- MxFormFieldControl ----\n errorState(): boolean {\n if (this.invalid()) return true;\n const c = this.ngControl;\n return !!c && !!c.invalid && !!(c.touched || c.dirty);\n }\n isRequired(): boolean {\n return this.required() || !!this.ngControl?.control?.hasValidator?.(Validators.required);\n }\n\n // ---- ControlValueAccessor ----\n writeValue(value: string[] | null): void {\n this.value.set(value ?? []);\n }\n registerOnChange(fn: (value: string[]) => void): void {\n this.onChange = fn;\n }\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, inject, signal, DestroyRef, Directive, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { LiveAnnouncer } from '@angular/cdk/a11y';
4
+ import { Clipboard } from '@angular/cdk/clipboard';
5
+
6
+ /**
7
+ * Copia texto para a área de transferência quando o elemento é clicado.
8
+ * Durante 2 s o elemento fica com data-copied, e "Copiado" é anunciado ao leitor de ecrã.
9
+ *
10
+ * ```html
11
+ * <button mxButton variant="outline" [mxCopy]="iban">Copiar IBAN</button>
12
+ * ```
13
+ */
14
+ class MxCopy {
15
+ text = input.required({ ...(ngDevMode ? { debugName: "text" } : /* istanbul ignore next */ {}), alias: 'mxCopy' });
16
+ /** Mensagem anunciada ao copiar. */
17
+ copiedMessage = input('Copiado', { ...(ngDevMode ? { debugName: "copiedMessage" } : /* istanbul ignore next */ {}), alias: 'mxCopyMessage' });
18
+ copiedChange = output({ alias: 'mxCopied' });
19
+ clipboard = inject(Clipboard);
20
+ announcer = inject(LiveAnnouncer);
21
+ copied = signal(false, ...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
22
+ timer;
23
+ constructor() {
24
+ inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));
25
+ }
26
+ /** Copia; devolve false se o navegador recusar. */
27
+ copy() {
28
+ const ok = this.clipboard.copy(this.text());
29
+ this.copiedChange.emit(ok);
30
+ this.announcer.announce(ok ? this.copiedMessage() : 'Não foi possível copiar', ok ? 'polite' : 'assertive');
31
+ if (ok) {
32
+ this.copied.set(true);
33
+ clearTimeout(this.timer);
34
+ this.timer = setTimeout(() => this.copied.set(false), 2000);
35
+ }
36
+ return ok;
37
+ }
38
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxCopy, deps: [], target: i0.ɵɵFactoryTarget.Directive });
39
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: MxCopy, isStandalone: true, selector: "[mxCopy]", inputs: { text: { classPropertyName: "text", publicName: "mxCopy", isSignal: true, isRequired: true, transformFunction: null }, copiedMessage: { classPropertyName: "copiedMessage", publicName: "mxCopyMessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { copiedChange: "mxCopied" }, host: { listeners: { "click": "copy()" }, properties: { "attr.data-copied": "copied() ? \"\" : null" } }, exportAs: ["mxCopy"], ngImport: i0 });
40
+ }
41
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxCopy, decorators: [{
42
+ type: Directive,
43
+ args: [{
44
+ selector: '[mxCopy]',
45
+ exportAs: 'mxCopy',
46
+ host: {
47
+ '(click)': 'copy()',
48
+ '[attr.data-copied]': 'copied() ? "" : null',
49
+ },
50
+ }]
51
+ }], ctorParameters: () => [], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "mxCopy", required: true }] }], copiedMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "mxCopyMessage", required: false }] }], copiedChange: [{ type: i0.Output, args: ["mxCopied"] }] } });
52
+ /**
53
+ * Botão de ícone que copia um valor. O nome acessível muda para "Copiado" durante 2 s.
54
+ *
55
+ * ```html
56
+ * <button mxCopyButton [value]="chave" label="Copiar chave da API"></button>
57
+ * ```
58
+ */
59
+ class MxCopyButton {
60
+ copy = inject(MxCopy, { self: true });
61
+ label = input('Copiar', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
62
+ copiedLabel = input('Copiado', ...(ngDevMode ? [{ debugName: "copiedLabel" }] : /* istanbul ignore next */ []));
63
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
64
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxCopyButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
65
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: MxCopyButton, isStandalone: true, selector: "button[mxCopyButton]", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, copiedLabel: { classPropertyName: "copiedLabel", publicName: "copiedLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, properties: { "attr.aria-label": "copy.copied() ? copiedLabel() : label()", "attr.data-size": "size() === \"md\" ? null : size()" }, classAttribute: "mx-copy-button" }, exportAs: ["mxCopyButton"], hostDirectives: [{ directive: MxCopy, inputs: ["mxCopy", "value"], outputs: ["mxCopied", "mxCopied"] }], ngImport: i0, template: `
66
+ @if (copy.copied()) {
67
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" /></svg>
68
+ } @else {
69
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
70
+ <rect x="5.5" y="5.5" width="8" height="8" rx="1.5" stroke="currentColor" stroke-width="1.3" />
71
+ <path d="M10.5 3.5v-.5A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v5A1.5 1.5 0 0 0 4 9.5h.5" stroke="currentColor" stroke-width="1.3" />
72
+ </svg>
73
+ }
74
+ <ng-content />
75
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
76
+ }
77
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxCopyButton, decorators: [{
78
+ type: Component,
79
+ args: [{
80
+ selector: 'button[mxCopyButton]',
81
+ exportAs: 'mxCopyButton',
82
+ hostDirectives: [{ directive: MxCopy, inputs: ['mxCopy: value'], outputs: ['mxCopied'] }],
83
+ changeDetection: ChangeDetectionStrategy.OnPush,
84
+ encapsulation: ViewEncapsulation.None,
85
+ host: {
86
+ class: 'mx-copy-button',
87
+ type: 'button',
88
+ '[attr.aria-label]': 'copy.copied() ? copiedLabel() : label()',
89
+ '[attr.data-size]': 'size() === "md" ? null : size()',
90
+ },
91
+ template: `
92
+ @if (copy.copied()) {
93
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" /></svg>
94
+ } @else {
95
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
96
+ <rect x="5.5" y="5.5" width="8" height="8" rx="1.5" stroke="currentColor" stroke-width="1.3" />
97
+ <path d="M10.5 3.5v-.5A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v5A1.5 1.5 0 0 0 4 9.5h.5" stroke="currentColor" stroke-width="1.3" />
98
+ </svg>
99
+ }
100
+ <ng-content />
101
+ `,
102
+ }]
103
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], copiedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "copiedLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
104
+
105
+ /**
106
+ * Generated bundle index. Do not edit.
107
+ */
108
+
109
+ export { MxCopy, MxCopyButton };
110
+ //# sourceMappingURL=muxima-ui-core-clipboard.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxima-ui-core-clipboard.mjs","sources":["../../../projects/core/clipboard/clipboard.ts","../../../projects/core/clipboard/muxima-ui-core-clipboard.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ViewEncapsulation, inject, input, output, signal } from '@angular/core';\nimport { LiveAnnouncer } from '@angular/cdk/a11y';\nimport { Clipboard } from '@angular/cdk/clipboard';\n\n/**\n * Copia texto para a área de transferência quando o elemento é clicado.\n * Durante 2 s o elemento fica com data-copied, e \"Copiado\" é anunciado ao leitor de ecrã.\n *\n * ```html\n * <button mxButton variant=\"outline\" [mxCopy]=\"iban\">Copiar IBAN</button>\n * ```\n */\n@Directive({\n selector: '[mxCopy]',\n exportAs: 'mxCopy',\n host: {\n '(click)': 'copy()',\n '[attr.data-copied]': 'copied() ? \"\" : null',\n },\n})\nexport class MxCopy {\n readonly text = input.required<string>({ alias: 'mxCopy' });\n /** Mensagem anunciada ao copiar. */\n readonly copiedMessage = input('Copiado', { alias: 'mxCopyMessage' });\n readonly copiedChange = output<boolean>({ alias: 'mxCopied' });\n\n private readonly clipboard = inject(Clipboard);\n private readonly announcer = inject(LiveAnnouncer);\n readonly copied = signal(false);\n private timer?: ReturnType<typeof setTimeout>;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n\n /** Copia; devolve false se o navegador recusar. */\n copy(): boolean {\n const ok = this.clipboard.copy(this.text());\n this.copiedChange.emit(ok);\n this.announcer.announce(ok ? this.copiedMessage() : 'Não foi possível copiar', ok ? 'polite' : 'assertive');\n if (ok) {\n this.copied.set(true);\n clearTimeout(this.timer);\n this.timer = setTimeout(() => this.copied.set(false), 2000);\n }\n return ok;\n }\n}\n\n/**\n * Botão de ícone que copia um valor. O nome acessível muda para \"Copiado\" durante 2 s.\n *\n * ```html\n * <button mxCopyButton [value]=\"chave\" label=\"Copiar chave da API\"></button>\n * ```\n */\n@Component({\n selector: 'button[mxCopyButton]',\n exportAs: 'mxCopyButton',\n hostDirectives: [{ directive: MxCopy, inputs: ['mxCopy: value'], outputs: ['mxCopied'] }],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'mx-copy-button',\n type: 'button',\n '[attr.aria-label]': 'copy.copied() ? copiedLabel() : label()',\n '[attr.data-size]': 'size() === \"md\" ? null : size()',\n },\n template: `\n @if (copy.copied()) {\n <svg viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\"><path d=\"M3.5 8.5l3 3 6-7\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" /></svg>\n } @else {\n <svg viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.3\" />\n <path d=\"M10.5 3.5v-.5A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v5A1.5 1.5 0 0 0 4 9.5h.5\" stroke=\"currentColor\" stroke-width=\"1.3\" />\n </svg>\n }\n <ng-content />\n `,\n})\nexport class MxCopyButton {\n protected readonly copy = inject(MxCopy, { self: true });\n readonly label = input('Copiar');\n readonly copiedLabel = input('Copiado');\n readonly size = input<'sm' | 'md'>('md');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}