@muxima-ui/core 1.0.0 → 1.2.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 (55) hide show
  1. package/README.md +12 -4
  2. package/fesm2022/muxima-ui-core-carousel.mjs +377 -0
  3. package/fesm2022/muxima-ui-core-carousel.mjs.map +1 -0
  4. package/fesm2022/muxima-ui-core-chips.mjs +349 -0
  5. package/fesm2022/muxima-ui-core-chips.mjs.map +1 -0
  6. package/fesm2022/muxima-ui-core-clipboard.mjs +110 -0
  7. package/fesm2022/muxima-ui-core-clipboard.mjs.map +1 -0
  8. package/fesm2022/muxima-ui-core-color-picker.mjs +755 -0
  9. package/fesm2022/muxima-ui-core-color-picker.mjs.map +1 -0
  10. package/fesm2022/muxima-ui-core-date-picker.mjs +494 -12
  11. package/fesm2022/muxima-ui-core-date-picker.mjs.map +1 -1
  12. package/fesm2022/muxima-ui-core-file-upload.mjs +392 -0
  13. package/fesm2022/muxima-ui-core-file-upload.mjs.map +1 -0
  14. package/fesm2022/muxima-ui-core-notification-center.mjs +487 -0
  15. package/fesm2022/muxima-ui-core-notification-center.mjs.map +1 -0
  16. package/fesm2022/muxima-ui-core-rating.mjs +212 -0
  17. package/fesm2022/muxima-ui-core-rating.mjs.map +1 -0
  18. package/fesm2022/muxima-ui-core-sidebar.mjs +333 -0
  19. package/fesm2022/muxima-ui-core-sidebar.mjs.map +1 -0
  20. package/fesm2022/muxima-ui-core-slider.mjs +211 -3
  21. package/fesm2022/muxima-ui-core-slider.mjs.map +1 -1
  22. package/fesm2022/muxima-ui-core-time-picker.mjs +389 -0
  23. package/fesm2022/muxima-ui-core-time-picker.mjs.map +1 -0
  24. package/fesm2022/muxima-ui-core-timeline.mjs +117 -0
  25. package/fesm2022/muxima-ui-core-timeline.mjs.map +1 -0
  26. package/fesm2022/muxima-ui-core.mjs +1 -1
  27. package/fesm2022/muxima-ui-core.mjs.map +1 -1
  28. package/package.json +41 -1
  29. package/styles/base.css +21 -1
  30. package/styles/components/carousel.css +113 -0
  31. package/styles/components/chips.css +170 -0
  32. package/styles/components/clipboard.css +52 -0
  33. package/styles/components/color-picker.css +207 -0
  34. package/styles/components/date-picker.css +135 -0
  35. package/styles/components/file-upload.css +164 -0
  36. package/styles/components/notification-center.css +220 -0
  37. package/styles/components/rating.css +89 -0
  38. package/styles/components/sidebar.css +211 -0
  39. package/styles/components/slider.css +111 -0
  40. package/styles/components/time-picker.css +39 -0
  41. package/styles/components/timeline.css +180 -0
  42. package/styles/muxima.css +10 -0
  43. package/types/muxima-ui-core-carousel.d.ts +72 -0
  44. package/types/muxima-ui-core-chips.d.ts +120 -0
  45. package/types/muxima-ui-core-clipboard.d.ts +42 -0
  46. package/types/muxima-ui-core-color-picker.d.ts +153 -0
  47. package/types/muxima-ui-core-date-picker.d.ts +130 -2
  48. package/types/muxima-ui-core-file-upload.d.ts +96 -0
  49. package/types/muxima-ui-core-notification-center.d.ts +91 -0
  50. package/types/muxima-ui-core-rating.d.ts +64 -0
  51. package/types/muxima-ui-core-sidebar.d.ts +115 -0
  52. package/types/muxima-ui-core-slider.d.ts +68 -6
  53. package/types/muxima-ui-core-time-picker.d.ts +83 -0
  54. package/types/muxima-ui-core-timeline.d.ts +59 -0
  55. package/types/muxima-ui-core.d.ts +1 -1
@@ -0,0 +1,389 @@
1
+ import * as i0 from '@angular/core';
2
+ import { model, input, numberAttribute, booleanAttribute, inject, ElementRef, computed, signal, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { CdkOverlayOrigin, CdkConnectedOverlay } from '@angular/cdk/overlay';
4
+ import { NgControl, Validators } from '@angular/forms';
5
+ import { MxFormField, mxUniqueId, MX_FORM_FIELD_CONTROL } from '@muxima-ui/core/form-field';
6
+
7
+ const POSITIONS = [
8
+ { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },
9
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },
10
+ ];
11
+ /**
12
+ * Converte o que se escreve numa hora "HH:mm". Aceita "9", "930", "9:30", "9h30", "9.30" e "21h".
13
+ * Devolve null se não for uma hora válida.
14
+ */
15
+ function mxParseTime(text) {
16
+ const t = text.trim().toLowerCase().replace(/\s+/g, '');
17
+ if (!t)
18
+ return null;
19
+ let h;
20
+ let m = 0;
21
+ const sep = t.match(/^(\d{1,2})[:h.](\d{0,2})$/);
22
+ if (sep) {
23
+ h = Number(sep[1]);
24
+ m = sep[2] ? Number(sep[2].padEnd(2, '0')) : 0;
25
+ }
26
+ else if (/^\d{1,4}$/.test(t)) {
27
+ if (t.length <= 2)
28
+ h = Number(t);
29
+ else {
30
+ h = Number(t.slice(0, t.length - 2));
31
+ m = Number(t.slice(-2));
32
+ }
33
+ }
34
+ else
35
+ return null;
36
+ if (h > 23 || m > 59)
37
+ return null;
38
+ return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
39
+ }
40
+ /** Minutos desde a meia-noite de uma hora "HH:mm". */
41
+ function mxTimeToMinutes(time) {
42
+ const [h, m] = time.split(':').map(Number);
43
+ return h * 60 + m;
44
+ }
45
+ function minutesToTime(min) {
46
+ return `${String(Math.floor(min / 60)).padStart(2, '0')}:${String(min % 60).padStart(2, '0')}`;
47
+ }
48
+ /**
49
+ * Campo de hora: escreve-se (9, 930, 9h30, 09:30) ou escolhe-se numa lista com o intervalo
50
+ * definido em `step`. Padrão WAI-ARIA "combobox com lista".
51
+ *
52
+ * ```html
53
+ * <mx-form-field>
54
+ * <label mxLabel>Hora da reunião</label>
55
+ * <mx-time-picker formControlName="hora" [step]="15" min="08:00" max="18:00" />
56
+ * </mx-form-field>
57
+ * ```
58
+ *
59
+ * O valor é uma string "HH:mm" (24 horas) ou null. Uma hora fora de min/max deixa o campo com erro.
60
+ * Para uma hora isolada sem lista, o input type=time nativo com mxInput também serve.
61
+ */
62
+ class MxTimePicker {
63
+ value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
64
+ /** Minutos entre as horas da lista. */
65
+ step = input(30, { ...(ngDevMode ? { debugName: "step" } : /* istanbul ignore next */ {}), transform: numberAttribute });
66
+ /** Primeira e última hora permitidas, "HH:mm". */
67
+ min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
68
+ max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
69
+ placeholder = input('hh:mm', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
70
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
71
+ required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
72
+ invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
73
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
74
+ id = input(undefined, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
75
+ ariaLabel = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
76
+ field = inject(MxFormField, { optional: true });
77
+ ngControl = inject(NgControl, { self: true, optional: true });
78
+ host = inject(ElementRef).nativeElement;
79
+ positions = POSITIONS;
80
+ listId = mxUniqueId('mx-time-list');
81
+ generatedId = mxUniqueId('mx-time');
82
+ controlId = computed(() => this.id() ?? this.generatedId, ...(ngDevMode ? [{ debugName: "controlId" }] : /* istanbul ignore next */ []));
83
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
84
+ panelWidth = signal(0, ...(ngDevMode ? [{ debugName: "panelWidth" }] : /* istanbul ignore next */ []));
85
+ active = signal(-1, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
86
+ draft = signal(null, ...(ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []));
87
+ formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []));
88
+ isDisabled = computed(() => this.disabled() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
89
+ text = computed(() => this.draft() ?? this.value() ?? '', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
90
+ slots = computed(() => {
91
+ const step = Math.max(1, this.step());
92
+ const from = this.min() ? mxTimeToMinutes(this.min()) : 0;
93
+ const to = this.max() ? mxTimeToMinutes(this.max()) : 24 * 60 - 1;
94
+ const out = [];
95
+ for (let m = from; m <= to; m += step)
96
+ out.push(minutesToTime(m));
97
+ return out;
98
+ }, ...(ngDevMode ? [{ debugName: "slots" }] : /* istanbul ignore next */ []));
99
+ /** Texto que não é hora, ou hora fora de min/max. */
100
+ badValue = computed(() => {
101
+ const d = this.draft();
102
+ if (d && !mxParseTime(d))
103
+ return true;
104
+ const v = this.value();
105
+ if (!v)
106
+ return false;
107
+ const m = mxTimeToMinutes(v);
108
+ return (!!this.min() && m < mxTimeToMinutes(this.min())) || (!!this.max() && m > mxTimeToMinutes(this.max()));
109
+ }, ...(ngDevMode ? [{ debugName: "badValue" }] : /* istanbul ignore next */ []));
110
+ onChange = () => { };
111
+ onTouched = () => { };
112
+ constructor() {
113
+ if (this.ngControl)
114
+ this.ngControl.valueAccessor = this;
115
+ }
116
+ optionId(i) {
117
+ return `${this.listId}-${i}`;
118
+ }
119
+ /** Índice da hora da lista mais próxima de um valor (ou da hora actual). */
120
+ nearest(time) {
121
+ const slots = this.slots();
122
+ if (!slots.length)
123
+ return -1;
124
+ const now = new Date();
125
+ const target = time ? mxTimeToMinutes(time) : now.getHours() * 60 + now.getMinutes();
126
+ let best = 0;
127
+ slots.forEach((s, i) => {
128
+ if (Math.abs(mxTimeToMinutes(s) - target) < Math.abs(mxTimeToMinutes(slots[best]) - target))
129
+ best = i;
130
+ });
131
+ return best;
132
+ }
133
+ open() {
134
+ if (this.isDisabled() || this.isOpen())
135
+ return;
136
+ this.panelWidth.set(this.host.getBoundingClientRect().width);
137
+ this.active.set(this.nearest(this.value()));
138
+ this.isOpen.set(true);
139
+ }
140
+ close() {
141
+ if (!this.isOpen())
142
+ return;
143
+ this.isOpen.set(false);
144
+ this.active.set(-1);
145
+ }
146
+ scrollToActive() {
147
+ queueMicrotask(() => document.getElementById(this.optionId(this.active()))?.scrollIntoView?.({ block: 'nearest' }));
148
+ }
149
+ choose(time) {
150
+ this.draft.set(null);
151
+ this.setValue(time);
152
+ this.close();
153
+ }
154
+ onInput(event) {
155
+ const text = event.target.value;
156
+ const parsed = mxParseTime(text);
157
+ this.draft.set(text || null);
158
+ this.setValue(parsed);
159
+ if (this.isOpen() && parsed) {
160
+ this.active.set(this.nearest(parsed));
161
+ this.scrollToActive();
162
+ }
163
+ }
164
+ onKeydown(event) {
165
+ const n = this.slots().length;
166
+ switch (event.key) {
167
+ case 'ArrowDown':
168
+ event.preventDefault();
169
+ if (!this.isOpen() || event.altKey) {
170
+ this.open();
171
+ break;
172
+ }
173
+ this.active.set(Math.min(this.active() + 1, n - 1));
174
+ break;
175
+ case 'ArrowUp':
176
+ event.preventDefault();
177
+ if (event.altKey)
178
+ this.close();
179
+ else if (this.isOpen())
180
+ this.active.set(Math.max(this.active() - 1, 0));
181
+ break;
182
+ case 'PageDown':
183
+ case 'PageUp':
184
+ if (!this.isOpen())
185
+ return;
186
+ event.preventDefault();
187
+ this.active.set(Math.min(Math.max(this.active() + (event.key === 'PageDown' ? 8 : -8), 0), n - 1));
188
+ break;
189
+ case 'Enter':
190
+ if (this.isOpen() && this.active() >= 0) {
191
+ event.preventDefault();
192
+ this.choose(this.slots()[this.active()]);
193
+ }
194
+ return;
195
+ case 'Escape':
196
+ if (this.isOpen()) {
197
+ event.preventDefault();
198
+ this.close();
199
+ }
200
+ return;
201
+ case 'Tab':
202
+ this.close();
203
+ return;
204
+ default:
205
+ return;
206
+ }
207
+ this.scrollToActive();
208
+ }
209
+ onOutside(event) {
210
+ if (!this.host.contains(event.target))
211
+ this.close();
212
+ }
213
+ onBlur() {
214
+ // "930" passa a "09:30" quando é válido
215
+ if (!this.isOpen() && this.draft() && mxParseTime(this.draft()))
216
+ this.draft.set(null);
217
+ this.onTouched();
218
+ }
219
+ setValue(v) {
220
+ if (v === this.value())
221
+ return;
222
+ this.value.set(v);
223
+ this.onChange(v);
224
+ }
225
+ // ---- MxFormFieldControl ----
226
+ errorState() {
227
+ if (this.invalid() || this.badValue())
228
+ return true;
229
+ const c = this.ngControl;
230
+ return !!c && !!c.invalid && !!(c.touched || c.dirty);
231
+ }
232
+ isRequired() {
233
+ return this.required() || !!this.ngControl?.control?.hasValidator?.(Validators.required);
234
+ }
235
+ // ---- ControlValueAccessor ----
236
+ writeValue(value) {
237
+ this.value.set(value ? mxParseTime(value) : null);
238
+ this.draft.set(null);
239
+ }
240
+ registerOnChange(fn) {
241
+ this.onChange = fn;
242
+ }
243
+ registerOnTouched(fn) {
244
+ this.onTouched = fn;
245
+ }
246
+ setDisabledState(isDisabled) {
247
+ this.formDisabled.set(isDisabled);
248
+ }
249
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
250
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: MxTimePicker, isStandalone: true, selector: "mx-time-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", 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 }, size: { classPropertyName: "size", publicName: "size", 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" }, host: { properties: { "attr.aria-label": "null" }, classAttribute: "mx-time-picker" }, providers: [{ provide: MX_FORM_FIELD_CONTROL, useExisting: MxTimePicker }], exportAs: ["mxTimePicker"], ngImport: i0, template: `
251
+ <div class="mx-time-picker-field" cdkOverlayOrigin #origin="cdkOverlayOrigin">
252
+ <input
253
+ class="mx-input mx-time-picker-input"
254
+ type="text"
255
+ role="combobox"
256
+ inputmode="numeric"
257
+ autocomplete="off"
258
+ aria-autocomplete="none"
259
+ [id]="controlId()"
260
+ [placeholder]="placeholder()"
261
+ [value]="text()"
262
+ [disabled]="isDisabled()"
263
+ [attr.data-size]="size() === 'md' ? null : size()"
264
+ [attr.aria-expanded]="isOpen()"
265
+ [attr.aria-controls]="isOpen() ? listId : null"
266
+ [attr.aria-activedescendant]="isOpen() && active() >= 0 ? optionId(active()) : null"
267
+ [attr.aria-invalid]="errorState() ? 'true' : null"
268
+ [attr.aria-required]="isRequired() ? 'true' : null"
269
+ [attr.aria-describedby]="field?.describedBy() ?? null"
270
+ [attr.aria-label]="ariaLabel() ?? null"
271
+ (input)="onInput($event)"
272
+ (keydown)="onKeydown($event)"
273
+ (click)="open()"
274
+ (blur)="onBlur()"
275
+ />
276
+ <svg class="mx-time-picker-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
277
+ <circle cx="8" cy="8" r="5.75" stroke="currentColor" stroke-width="1.3" />
278
+ <path d="M8 5v3.2l2 1.3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" />
279
+ </svg>
280
+ </div>
281
+
282
+ <ng-template
283
+ cdkConnectedOverlay
284
+ [cdkConnectedOverlayOrigin]="origin"
285
+ [cdkConnectedOverlayOpen]="isOpen()"
286
+ [cdkConnectedOverlayPositions]="positions"
287
+ [cdkConnectedOverlayWidth]="panelWidth()"
288
+ (overlayOutsideClick)="onOutside($event)"
289
+ (attach)="scrollToActive()"
290
+ (detach)="close()"
291
+ >
292
+ <ul class="mx-select-panel mx-time-picker-panel" role="listbox" [id]="listId" [attr.aria-labelledby]="field?.labelId() ?? null" [attr.aria-label]="field?.labelId() ? null : (ariaLabel() ?? 'Horas')">
293
+ @for (s of slots(); track s; let i = $index) {
294
+ <li
295
+ class="mx-option"
296
+ role="option"
297
+ [id]="optionId(i)"
298
+ [attr.aria-selected]="s === value()"
299
+ [attr.data-active]="i === active() ? '' : null"
300
+ (mousedown)="$event.preventDefault()"
301
+ (mousemove)="active.set(i)"
302
+ (click)="choose(s)"
303
+ >
304
+ {{ s }}
305
+ </li>
306
+ }
307
+ </ul>
308
+ </ng-template>
309
+ `, isInline: true, dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
310
+ }
311
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimePicker, decorators: [{
312
+ type: Component,
313
+ args: [{
314
+ selector: 'mx-time-picker',
315
+ exportAs: 'mxTimePicker',
316
+ imports: [CdkOverlayOrigin, CdkConnectedOverlay],
317
+ providers: [{ provide: MX_FORM_FIELD_CONTROL, useExisting: MxTimePicker }],
318
+ changeDetection: ChangeDetectionStrategy.OnPush,
319
+ encapsulation: ViewEncapsulation.None,
320
+ host: { class: 'mx-time-picker', '[attr.aria-label]': 'null' },
321
+ template: `
322
+ <div class="mx-time-picker-field" cdkOverlayOrigin #origin="cdkOverlayOrigin">
323
+ <input
324
+ class="mx-input mx-time-picker-input"
325
+ type="text"
326
+ role="combobox"
327
+ inputmode="numeric"
328
+ autocomplete="off"
329
+ aria-autocomplete="none"
330
+ [id]="controlId()"
331
+ [placeholder]="placeholder()"
332
+ [value]="text()"
333
+ [disabled]="isDisabled()"
334
+ [attr.data-size]="size() === 'md' ? null : size()"
335
+ [attr.aria-expanded]="isOpen()"
336
+ [attr.aria-controls]="isOpen() ? listId : null"
337
+ [attr.aria-activedescendant]="isOpen() && active() >= 0 ? optionId(active()) : null"
338
+ [attr.aria-invalid]="errorState() ? 'true' : null"
339
+ [attr.aria-required]="isRequired() ? 'true' : null"
340
+ [attr.aria-describedby]="field?.describedBy() ?? null"
341
+ [attr.aria-label]="ariaLabel() ?? null"
342
+ (input)="onInput($event)"
343
+ (keydown)="onKeydown($event)"
344
+ (click)="open()"
345
+ (blur)="onBlur()"
346
+ />
347
+ <svg class="mx-time-picker-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
348
+ <circle cx="8" cy="8" r="5.75" stroke="currentColor" stroke-width="1.3" />
349
+ <path d="M8 5v3.2l2 1.3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" />
350
+ </svg>
351
+ </div>
352
+
353
+ <ng-template
354
+ cdkConnectedOverlay
355
+ [cdkConnectedOverlayOrigin]="origin"
356
+ [cdkConnectedOverlayOpen]="isOpen()"
357
+ [cdkConnectedOverlayPositions]="positions"
358
+ [cdkConnectedOverlayWidth]="panelWidth()"
359
+ (overlayOutsideClick)="onOutside($event)"
360
+ (attach)="scrollToActive()"
361
+ (detach)="close()"
362
+ >
363
+ <ul class="mx-select-panel mx-time-picker-panel" role="listbox" [id]="listId" [attr.aria-labelledby]="field?.labelId() ?? null" [attr.aria-label]="field?.labelId() ? null : (ariaLabel() ?? 'Horas')">
364
+ @for (s of slots(); track s; let i = $index) {
365
+ <li
366
+ class="mx-option"
367
+ role="option"
368
+ [id]="optionId(i)"
369
+ [attr.aria-selected]="s === value()"
370
+ [attr.data-active]="i === active() ? '' : null"
371
+ (mousedown)="$event.preventDefault()"
372
+ (mousemove)="active.set(i)"
373
+ (click)="choose(s)"
374
+ >
375
+ {{ s }}
376
+ </li>
377
+ }
378
+ </ul>
379
+ </ng-template>
380
+ `,
381
+ }]
382
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", 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 }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", 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 }] }] } });
383
+
384
+ /**
385
+ * Generated bundle index. Do not edit.
386
+ */
387
+
388
+ export { MxTimePicker, mxParseTime, mxTimeToMinutes };
389
+ //# sourceMappingURL=muxima-ui-core-time-picker.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxima-ui-core-time-picker.mjs","sources":["../../../projects/core/time-picker/time-picker.ts","../../../projects/core/time-picker/muxima-ui-core-time-picker.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n booleanAttribute,\n computed,\n inject,\n input,\n model,\n numberAttribute,\n signal,\n} from '@angular/core';\nimport { CdkConnectedOverlay, CdkOverlayOrigin, ConnectedPosition } from '@angular/cdk/overlay';\nimport { ControlValueAccessor, NgControl, Validators } from '@angular/forms';\nimport { MX_FORM_FIELD_CONTROL, MxFormField, MxFormFieldControl, mxUniqueId } from '@muxima-ui/core/form-field';\n\nconst POSITIONS: ConnectedPosition[] = [\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },\n];\n\n/**\n * Converte o que se escreve numa hora \"HH:mm\". Aceita \"9\", \"930\", \"9:30\", \"9h30\", \"9.30\" e \"21h\".\n * Devolve null se não for uma hora válida.\n */\nexport function mxParseTime(text: string): string | null {\n const t = text.trim().toLowerCase().replace(/\\s+/g, '');\n if (!t) return null;\n let h: number;\n let m = 0;\n const sep = t.match(/^(\\d{1,2})[:h.](\\d{0,2})$/);\n if (sep) {\n h = Number(sep[1]);\n m = sep[2] ? Number(sep[2].padEnd(2, '0')) : 0;\n } else if (/^\\d{1,4}$/.test(t)) {\n if (t.length <= 2) h = Number(t);\n else {\n h = Number(t.slice(0, t.length - 2));\n m = Number(t.slice(-2));\n }\n } else return null;\n if (h > 23 || m > 59) return null;\n return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;\n}\n\n/** Minutos desde a meia-noite de uma hora \"HH:mm\". */\nexport function mxTimeToMinutes(time: string): number {\n const [h, m] = time.split(':').map(Number);\n return h * 60 + m;\n}\n\nfunction minutesToTime(min: number): string {\n return `${String(Math.floor(min / 60)).padStart(2, '0')}:${String(min % 60).padStart(2, '0')}`;\n}\n\n/**\n * Campo de hora: escreve-se (9, 930, 9h30, 09:30) ou escolhe-se numa lista com o intervalo\n * definido em `step`. Padrão WAI-ARIA \"combobox com lista\".\n *\n * ```html\n * <mx-form-field>\n * <label mxLabel>Hora da reunião</label>\n * <mx-time-picker formControlName=\"hora\" [step]=\"15\" min=\"08:00\" max=\"18:00\" />\n * </mx-form-field>\n * ```\n *\n * O valor é uma string \"HH:mm\" (24 horas) ou null. Uma hora fora de min/max deixa o campo com erro.\n * Para uma hora isolada sem lista, o input type=time nativo com mxInput também serve.\n */\n@Component({\n selector: 'mx-time-picker',\n exportAs: 'mxTimePicker',\n imports: [CdkOverlayOrigin, CdkConnectedOverlay],\n providers: [{ provide: MX_FORM_FIELD_CONTROL, useExisting: MxTimePicker }],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'mx-time-picker', '[attr.aria-label]': 'null' },\n template: `\n <div class=\"mx-time-picker-field\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n <input\n class=\"mx-input mx-time-picker-input\"\n type=\"text\"\n role=\"combobox\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n aria-autocomplete=\"none\"\n [id]=\"controlId()\"\n [placeholder]=\"placeholder()\"\n [value]=\"text()\"\n [disabled]=\"isDisabled()\"\n [attr.data-size]=\"size() === 'md' ? null : size()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? listId : null\"\n [attr.aria-activedescendant]=\"isOpen() && active() >= 0 ? optionId(active()) : null\"\n [attr.aria-invalid]=\"errorState() ? 'true' : null\"\n [attr.aria-required]=\"isRequired() ? 'true' : null\"\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (click)=\"open()\"\n (blur)=\"onBlur()\"\n />\n <svg class=\"mx-time-picker-icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"5.75\" stroke=\"currentColor\" stroke-width=\"1.3\" />\n <path d=\"M8 5v3.2l2 1.3\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayWidth]=\"panelWidth()\"\n (overlayOutsideClick)=\"onOutside($event)\"\n (attach)=\"scrollToActive()\"\n (detach)=\"close()\"\n >\n <ul class=\"mx-select-panel mx-time-picker-panel\" role=\"listbox\" [id]=\"listId\" [attr.aria-labelledby]=\"field?.labelId() ?? null\" [attr.aria-label]=\"field?.labelId() ? null : (ariaLabel() ?? 'Horas')\">\n @for (s of slots(); track s; let i = $index) {\n <li\n class=\"mx-option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"s === value()\"\n [attr.data-active]=\"i === active() ? '' : null\"\n (mousedown)=\"$event.preventDefault()\"\n (mousemove)=\"active.set(i)\"\n (click)=\"choose(s)\"\n >\n {{ s }}\n </li>\n }\n </ul>\n </ng-template>\n `,\n})\nexport class MxTimePicker implements ControlValueAccessor, MxFormFieldControl {\n readonly value = model<string | null>(null);\n /** Minutos entre as horas da lista. */\n readonly step = input(30, { transform: numberAttribute });\n /** Primeira e última hora permitidas, \"HH:mm\". */\n readonly min = input<string | null>(null);\n readonly max = input<string | null>(null);\n readonly placeholder = input('hh:mm');\n readonly disabled = input(false, { transform: booleanAttribute });\n readonly required = input(false, { transform: booleanAttribute });\n readonly invalid = input(false, { transform: booleanAttribute });\n readonly size = input<'sm' | 'md' | 'lg'>('md');\n readonly id = input<string | undefined>(undefined);\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\n\n protected readonly field = inject(MxFormField, { optional: true });\n private readonly ngControl = inject(NgControl, { self: true, optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n protected readonly positions = POSITIONS;\n protected readonly listId = mxUniqueId('mx-time-list');\n private readonly generatedId = mxUniqueId('mx-time');\n readonly controlId = computed(() => this.id() ?? this.generatedId);\n protected readonly isOpen = signal(false);\n protected readonly panelWidth = signal(0);\n protected readonly active = signal(-1);\n private readonly draft = signal<string | null>(null);\n private readonly formDisabled = signal(false);\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n protected readonly text = computed(() => this.draft() ?? this.value() ?? '');\n\n protected readonly slots = computed(() => {\n const step = Math.max(1, this.step());\n const from = this.min() ? mxTimeToMinutes(this.min()!) : 0;\n const to = this.max() ? mxTimeToMinutes(this.max()!) : 24 * 60 - 1;\n const out: string[] = [];\n for (let m = from; m <= to; m += step) out.push(minutesToTime(m));\n return out;\n });\n\n /** Texto que não é hora, ou hora fora de min/max. */\n readonly badValue = computed(() => {\n const d = this.draft();\n if (d && !mxParseTime(d)) return true;\n const v = this.value();\n if (!v) return false;\n const m = mxTimeToMinutes(v);\n return (!!this.min() && m < mxTimeToMinutes(this.min()!)) || (!!this.max() && m > mxTimeToMinutes(this.max()!));\n });\n\n private onChange: (value: string | null) => void = () => {};\n private onTouched: () => void = () => {};\n\n constructor() {\n if (this.ngControl) this.ngControl.valueAccessor = this;\n }\n\n protected optionId(i: number): string {\n return `${this.listId}-${i}`;\n }\n\n /** Índice da hora da lista mais próxima de um valor (ou da hora actual). */\n private nearest(time: string | null): number {\n const slots = this.slots();\n if (!slots.length) return -1;\n const now = new Date();\n const target = time ? mxTimeToMinutes(time) : now.getHours() * 60 + now.getMinutes();\n let best = 0;\n slots.forEach((s, i) => {\n if (Math.abs(mxTimeToMinutes(s) - target) < Math.abs(mxTimeToMinutes(slots[best]) - target)) best = i;\n });\n return best;\n }\n\n open(): void {\n if (this.isDisabled() || this.isOpen()) return;\n this.panelWidth.set(this.host.getBoundingClientRect().width);\n this.active.set(this.nearest(this.value()));\n this.isOpen.set(true);\n }\n close(): void {\n if (!this.isOpen()) return;\n this.isOpen.set(false);\n this.active.set(-1);\n }\n\n protected scrollToActive(): void {\n queueMicrotask(() => document.getElementById(this.optionId(this.active()))?.scrollIntoView?.({ block: 'nearest' }));\n }\n\n protected choose(time: string): void {\n this.draft.set(null);\n this.setValue(time);\n this.close();\n }\n\n protected onInput(event: Event): void {\n const text = (event.target as HTMLInputElement).value;\n const parsed = mxParseTime(text);\n this.draft.set(text || null);\n this.setValue(parsed);\n if (this.isOpen() && parsed) {\n this.active.set(this.nearest(parsed));\n this.scrollToActive();\n }\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const n = this.slots().length;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n if (!this.isOpen() || event.altKey) {\n this.open();\n break;\n }\n this.active.set(Math.min(this.active() + 1, n - 1));\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (event.altKey) this.close();\n else if (this.isOpen()) this.active.set(Math.max(this.active() - 1, 0));\n break;\n case 'PageDown':\n case 'PageUp':\n if (!this.isOpen()) return;\n event.preventDefault();\n this.active.set(Math.min(Math.max(this.active() + (event.key === 'PageDown' ? 8 : -8), 0), n - 1));\n break;\n case 'Enter':\n if (this.isOpen() && this.active() >= 0) {\n event.preventDefault();\n this.choose(this.slots()[this.active()]);\n }\n return;\n case 'Escape':\n if (this.isOpen()) {\n event.preventDefault();\n this.close();\n }\n return;\n case 'Tab':\n this.close();\n return;\n default:\n return;\n }\n this.scrollToActive();\n }\n\n protected onOutside(event: MouseEvent): void {\n if (!this.host.contains(event.target as Node)) this.close();\n }\n\n protected onBlur(): void {\n // \"930\" passa a \"09:30\" quando é válido\n if (!this.isOpen() && this.draft() && mxParseTime(this.draft()!)) this.draft.set(null);\n this.onTouched();\n }\n\n private setValue(v: string | null): void {\n if (v === this.value()) return;\n this.value.set(v);\n this.onChange(v);\n }\n\n // ---- MxFormFieldControl ----\n errorState(): boolean {\n if (this.invalid() || this.badValue()) 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 ? mxParseTime(value) : null);\n this.draft.set(null);\n }\n registerOnChange(fn: (value: string | null) => 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,117 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, Directive, booleanAttribute } from '@angular/core';
3
+
4
+ /**
5
+ * Acontecimentos por ordem, sobre uma lista ordenada nativa: o leitor de ecrã anuncia
6
+ * "lista, 4 itens" e a posição de cada um.
7
+ *
8
+ * ```html
9
+ * <ol mxTimeline>
10
+ * <li mxTimelineItem variant="success">
11
+ * <time mxTimelineTime datetime="2026-10-27T09:40">27 out, 09:40</time>
12
+ * <p mxTimelineTitle>Factura paga</p>
13
+ * <p mxTimelineDescription>Banco Mutamba pagou FT 2026/0196.</p>
14
+ * </li>
15
+ * </ol>
16
+ * ```
17
+ */
18
+ class MxTimeline {
19
+ orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
20
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
21
+ /** `alternate` põe os itens alternadamente dos dois lados da linha (só vertical, ecrãs largos). */
22
+ align = input('start', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
23
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimeline, deps: [], target: i0.ɵɵFactoryTarget.Directive });
24
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: MxTimeline, isStandalone: true, selector: "ol[mxTimeline], ul[mxTimeline]", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-orientation": "orientation() === \"vertical\" ? null : orientation()", "attr.data-size": "size() === \"md\" ? null : size()", "attr.data-align": "align() === \"start\" ? null : align()", "attr.tabindex": "orientation() === \"horizontal\" ? 0 : null" }, classAttribute: "mx-timeline" }, exportAs: ["mxTimeline"], ngImport: i0 });
25
+ }
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimeline, decorators: [{
27
+ type: Directive,
28
+ args: [{
29
+ selector: 'ol[mxTimeline], ul[mxTimeline]',
30
+ exportAs: 'mxTimeline',
31
+ host: {
32
+ class: 'mx-timeline',
33
+ '[attr.data-orientation]': 'orientation() === "vertical" ? null : orientation()',
34
+ '[attr.data-size]': 'size() === "md" ? null : size()',
35
+ '[attr.data-align]': 'align() === "start" ? null : align()',
36
+ // na horizontal pode haver scroll: o teclado tem de lá chegar
37
+ '[attr.tabindex]': 'orientation() === "horizontal" ? 0 : null',
38
+ },
39
+ }]
40
+ }], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }] } });
41
+ /**
42
+ * Um acontecimento. O marcador fica na linha; com `pending` aparece tracejado
43
+ * (passo ainda por acontecer). Diz isso também no texto, para o leitor de ecrã.
44
+ */
45
+ class MxTimelineItem {
46
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
47
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
48
+ /** Marcador maior, com espaço para um ícone (mxTimelineIcon). */
49
+ icon = input(false, { ...(ngDevMode ? { debugName: "icon" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
50
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
51
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: MxTimelineItem, isStandalone: true, selector: "li[mxTimelineItem]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, pending: { classPropertyName: "pending", publicName: "pending", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variant": "variant() === \"default\" ? null : variant()", "attr.data-pending": "pending() ? \"\" : null", "attr.data-has-icon": "icon() ? \"\" : null" }, classAttribute: "mx-timeline-item" }, exportAs: ["mxTimelineItem"], ngImport: i0 });
52
+ }
53
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineItem, decorators: [{
54
+ type: Directive,
55
+ args: [{
56
+ selector: 'li[mxTimelineItem]',
57
+ exportAs: 'mxTimelineItem',
58
+ host: {
59
+ class: 'mx-timeline-item',
60
+ '[attr.data-variant]': 'variant() === "default" ? null : variant()',
61
+ '[attr.data-pending]': 'pending() ? "" : null',
62
+ '[attr.data-has-icon]': 'icon() ? "" : null',
63
+ },
64
+ }]
65
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }] } });
66
+ /** Ícone dentro do marcador (svg decorativo). Usa com `icon` no item. */
67
+ class MxTimelineIcon {
68
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive });
69
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineIcon, isStandalone: true, selector: "[mxTimelineIcon]", host: { attributes: { "aria-hidden": "true" }, classAttribute: "mx-timeline-icon" }, ngImport: i0 });
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineIcon, decorators: [{
72
+ type: Directive,
73
+ args: [{
74
+ selector: '[mxTimelineIcon]',
75
+ host: { class: 'mx-timeline-icon', 'aria-hidden': 'true' },
76
+ }]
77
+ }] });
78
+ /** Data ou hora do acontecimento. Usa um `<time datetime>`. */
79
+ class MxTimelineTime {
80
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTime, deps: [], target: i0.ɵɵFactoryTarget.Directive });
81
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineTime, isStandalone: true, selector: "[mxTimelineTime]", host: { classAttribute: "mx-timeline-time" }, ngImport: i0 });
82
+ }
83
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTime, decorators: [{
84
+ type: Directive,
85
+ args: [{ selector: '[mxTimelineTime]', host: { class: 'mx-timeline-time' } }]
86
+ }] });
87
+ class MxTimelineTitle {
88
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTitle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
89
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineTitle, isStandalone: true, selector: "[mxTimelineTitle]", host: { classAttribute: "mx-timeline-title" }, ngImport: i0 });
90
+ }
91
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineTitle, decorators: [{
92
+ type: Directive,
93
+ args: [{ selector: '[mxTimelineTitle]', host: { class: 'mx-timeline-title' } }]
94
+ }] });
95
+ class MxTimelineDescription {
96
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive });
97
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: MxTimelineDescription, isStandalone: true, selector: "[mxTimelineDescription]", host: { classAttribute: "mx-timeline-description" }, ngImport: i0 });
98
+ }
99
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: MxTimelineDescription, decorators: [{
100
+ type: Directive,
101
+ args: [{ selector: '[mxTimelineDescription]', host: { class: 'mx-timeline-description' } }]
102
+ }] });
103
+ const MX_TIMELINE = [
104
+ MxTimeline,
105
+ MxTimelineItem,
106
+ MxTimelineIcon,
107
+ MxTimelineTime,
108
+ MxTimelineTitle,
109
+ MxTimelineDescription,
110
+ ];
111
+
112
+ /**
113
+ * Generated bundle index. Do not edit.
114
+ */
115
+
116
+ export { MX_TIMELINE, MxTimeline, MxTimelineDescription, MxTimelineIcon, MxTimelineItem, MxTimelineTime, MxTimelineTitle };
117
+ //# sourceMappingURL=muxima-ui-core-timeline.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxima-ui-core-timeline.mjs","sources":["../../../projects/core/timeline/timeline.ts","../../../projects/core/timeline/muxima-ui-core-timeline.ts"],"sourcesContent":["import { Directive, booleanAttribute, input } from '@angular/core';\n\nexport type MxTimelineVariant = 'default' | 'accent' | 'success' | 'warning' | 'danger';\n\n/**\n * Acontecimentos por ordem, sobre uma lista ordenada nativa: o leitor de ecrã anuncia\n * \"lista, 4 itens\" e a posição de cada um.\n *\n * ```html\n * <ol mxTimeline>\n * <li mxTimelineItem variant=\"success\">\n * <time mxTimelineTime datetime=\"2026-10-27T09:40\">27 out, 09:40</time>\n * <p mxTimelineTitle>Factura paga</p>\n * <p mxTimelineDescription>Banco Mutamba pagou FT 2026/0196.</p>\n * </li>\n * </ol>\n * ```\n */\n@Directive({\n selector: 'ol[mxTimeline], ul[mxTimeline]',\n exportAs: 'mxTimeline',\n host: {\n class: 'mx-timeline',\n '[attr.data-orientation]': 'orientation() === \"vertical\" ? null : orientation()',\n '[attr.data-size]': 'size() === \"md\" ? null : size()',\n '[attr.data-align]': 'align() === \"start\" ? null : align()',\n // na horizontal pode haver scroll: o teclado tem de lá chegar\n '[attr.tabindex]': 'orientation() === \"horizontal\" ? 0 : null',\n },\n})\nexport class MxTimeline {\n readonly orientation = input<'vertical' | 'horizontal'>('vertical');\n readonly size = input<'sm' | 'md'>('md');\n /** `alternate` põe os itens alternadamente dos dois lados da linha (só vertical, ecrãs largos). */\n readonly align = input<'start' | 'alternate'>('start');\n}\n\n/**\n * Um acontecimento. O marcador fica na linha; com `pending` aparece tracejado\n * (passo ainda por acontecer). Diz isso também no texto, para o leitor de ecrã.\n */\n@Directive({\n selector: 'li[mxTimelineItem]',\n exportAs: 'mxTimelineItem',\n host: {\n class: 'mx-timeline-item',\n '[attr.data-variant]': 'variant() === \"default\" ? null : variant()',\n '[attr.data-pending]': 'pending() ? \"\" : null',\n '[attr.data-has-icon]': 'icon() ? \"\" : null',\n },\n})\nexport class MxTimelineItem {\n readonly variant = input<MxTimelineVariant>('default');\n readonly pending = input(false, { transform: booleanAttribute });\n /** Marcador maior, com espaço para um ícone (mxTimelineIcon). */\n readonly icon = input(false, { transform: booleanAttribute });\n}\n\n/** Ícone dentro do marcador (svg decorativo). Usa com `icon` no item. */\n@Directive({\n selector: '[mxTimelineIcon]',\n host: { class: 'mx-timeline-icon', 'aria-hidden': 'true' },\n})\nexport class MxTimelineIcon {}\n\n/** Data ou hora do acontecimento. Usa um `<time datetime>`. */\n@Directive({ selector: '[mxTimelineTime]', host: { class: 'mx-timeline-time' } })\nexport class MxTimelineTime {}\n\n@Directive({ selector: '[mxTimelineTitle]', host: { class: 'mx-timeline-title' } })\nexport class MxTimelineTitle {}\n\n@Directive({ selector: '[mxTimelineDescription]', host: { class: 'mx-timeline-description' } })\nexport class MxTimelineDescription {}\n\nexport const MX_TIMELINE = [\n MxTimeline,\n MxTimelineItem,\n MxTimelineIcon,\n MxTimelineTime,\n MxTimelineTitle,\n MxTimelineDescription,\n] as const;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  * Os componentes vivem em entradas secundárias, para só incluíres o que usas:
4
4
  * import { MxButton } from '@muxima-ui/core/button';
5
5
  */
6
- const MUXIMA_VERSION = '1.0.0';
6
+ const MUXIMA_VERSION = '1.2.0';
7
7
 
8
8
  /**
9
9
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"muxima-ui-core.mjs","sources":["../../../projects/core/src/public-api.ts","../../../projects/core/src/muxima-ui-core.ts"],"sourcesContent":["/*\n * Muxima UI — ponto de entrada principal.\n * Os componentes vivem em entradas secundárias, para só incluíres o que usas:\n * import { MxButton } from '@muxima-ui/core/button';\n */\nexport const MUXIMA_VERSION = '1.0.0';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;AAIG;AACI,MAAM,cAAc,GAAG;;ACL9B;;AAEG;;"}
1
+ {"version":3,"file":"muxima-ui-core.mjs","sources":["../../../projects/core/src/public-api.ts","../../../projects/core/src/muxima-ui-core.ts"],"sourcesContent":["/*\n * Muxima UI — ponto de entrada principal.\n * Os componentes vivem em entradas secundárias, para só incluíres o que usas:\n * import { MxButton } from '@muxima-ui/core/button';\n */\nexport const MUXIMA_VERSION = '1.2.0';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;AAIG;AACI,MAAM,cAAc,GAAG;;ACL9B;;AAEG;;"}