@muxima-ui/core 1.1.0 → 1.3.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 (43) hide show
  1. package/README.md +15 -0
  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-color-picker.mjs +755 -0
  5. package/fesm2022/muxima-ui-core-color-picker.mjs.map +1 -0
  6. package/fesm2022/muxima-ui-core-data-grid.mjs +1187 -0
  7. package/fesm2022/muxima-ui-core-data-grid.mjs.map +1 -0
  8. package/fesm2022/muxima-ui-core-editor.mjs +575 -0
  9. package/fesm2022/muxima-ui-core-editor.mjs.map +1 -0
  10. package/fesm2022/muxima-ui-core-image-cropper.mjs +568 -0
  11. package/fesm2022/muxima-ui-core-image-cropper.mjs.map +1 -0
  12. package/fesm2022/muxima-ui-core-kanban.mjs +369 -0
  13. package/fesm2022/muxima-ui-core-kanban.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-sidebar.mjs +333 -0
  17. package/fesm2022/muxima-ui-core-sidebar.mjs.map +1 -0
  18. package/fesm2022/muxima-ui-core-timeline.mjs +117 -0
  19. package/fesm2022/muxima-ui-core-timeline.mjs.map +1 -0
  20. package/fesm2022/muxima-ui-core.mjs +1 -1
  21. package/fesm2022/muxima-ui-core.mjs.map +1 -1
  22. package/package.json +57 -2
  23. package/styles/base.css +17 -0
  24. package/styles/components/carousel.css +113 -0
  25. package/styles/components/color-picker.css +207 -0
  26. package/styles/components/data-grid.css +235 -0
  27. package/styles/components/editor.css +187 -0
  28. package/styles/components/image-cropper.css +113 -0
  29. package/styles/components/kanban.css +115 -0
  30. package/styles/components/notification-center.css +220 -0
  31. package/styles/components/sidebar.css +211 -0
  32. package/styles/components/timeline.css +180 -0
  33. package/styles/muxima.css +9 -0
  34. package/types/muxima-ui-core-carousel.d.ts +72 -0
  35. package/types/muxima-ui-core-color-picker.d.ts +153 -0
  36. package/types/muxima-ui-core-data-grid.d.ts +175 -0
  37. package/types/muxima-ui-core-editor.d.ts +104 -0
  38. package/types/muxima-ui-core-image-cropper.d.ts +105 -0
  39. package/types/muxima-ui-core-kanban.d.ts +83 -0
  40. package/types/muxima-ui-core-notification-center.d.ts +91 -0
  41. package/types/muxima-ui-core-sidebar.d.ts +115 -0
  42. package/types/muxima-ui-core-timeline.d.ts +59 -0
  43. package/types/muxima-ui-core.d.ts +1 -1
@@ -0,0 +1,175 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+
4
+ /** Coluna da grelha. */
5
+ interface MxGridColumn<T = any> {
6
+ key: string;
7
+ header: string;
8
+ /** Valor para ordenar e filtrar; por omissão row[key]. */
9
+ value?: (row: T) => unknown;
10
+ /** Texto mostrado; por omissão String(valor). */
11
+ format?: (value: any, row: T) => string;
12
+ /** Largura inicial em px. */
13
+ width?: number;
14
+ minWidth?: number;
15
+ sortable?: boolean;
16
+ /** Filtro no cabeçalho. `number` aceita 100, >100, <100 e 10-20. */
17
+ filter?: 'text' | 'number' | 'select' | false;
18
+ /** Opções do filtro `select`; por omissão, os valores que existem nos dados. */
19
+ filterOptions?: string[];
20
+ align?: 'start' | 'center' | 'end';
21
+ /** Fixa a coluna à esquerda (`start`) ou à direita (`end`) durante o scroll horizontal. */
22
+ pinned?: 'start' | 'end';
23
+ resizable?: boolean;
24
+ hidden?: boolean;
25
+ /** false: não aparece no menu de colunas. */
26
+ hideable?: boolean;
27
+ }
28
+ interface MxGridSort {
29
+ key: string | null;
30
+ direction: 'asc' | 'desc';
31
+ }
32
+ /**
33
+ * Modelo de uma célula: `<ng-template mxGridCell="estado" let-row let-value="value">`.
34
+ */
35
+ declare class MxGridCell {
36
+ readonly key: _angular_core.InputSignal<string>;
37
+ readonly template: TemplateRef<any>;
38
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxGridCell, never>;
39
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<MxGridCell, "ng-template[mxGridCell]", never, { "key": { "alias": "mxGridCell"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
40
+ }
41
+ /** Conteúdo da barra por cima da grelha (pesquisa, botões). */
42
+ declare class MxGridToolbar {
43
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxGridToolbar, never>;
44
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<MxGridToolbar, "[mxGridToolbar]", never, {}, {}, never, never, true, never>;
45
+ }
46
+ /**
47
+ * Grelha de dados (padrão WAI-ARIA Grid): ordenação, filtros por coluna, pesquisa,
48
+ * selecção, colunas redimensionáveis, fixas e escondíveis, e scroll virtual para
49
+ * milhares de linhas. Navega-se célula a célula com as setas.
50
+ *
51
+ * ```html
52
+ * <mx-data-grid [data]="facturas" [columns]="colunas" rowKey="numero"
53
+ * selection="multiple" [(selected)]="escolhidas" height="480px" aria-label="Facturas">
54
+ * <ng-template mxGridCell="estado" let-row>
55
+ * <span mxBadge [variant]="cor(row.estado)">{{ row.estado }}</span>
56
+ * </ng-template>
57
+ * </mx-data-grid>
58
+ * ```
59
+ *
60
+ * Com `manual`, a grelha não ordena nem filtra: emite [(sort)] e [(filters)] para o
61
+ * servidor e mostra `data` tal como chega (indica o total em `totalRows`).
62
+ */
63
+ declare class MxDataGrid<T = any> {
64
+ readonly data: _angular_core.InputSignal<readonly T[]>;
65
+ readonly columns: _angular_core.InputSignal<readonly MxGridColumn<T>[]>;
66
+ /** Chave única de cada linha: nome do campo ou função. */
67
+ readonly rowKey: _angular_core.InputSignal<string | ((row: T) => unknown)>;
68
+ readonly selection: _angular_core.InputSignal<"none" | "single" | "multiple">;
69
+ /** Chaves das linhas seleccionadas. */
70
+ readonly selected: _angular_core.ModelSignal<readonly unknown[]>;
71
+ readonly sort: _angular_core.ModelSignal<MxGridSort>;
72
+ /** Texto de cada filtro, por chave de coluna. */
73
+ readonly filters: _angular_core.ModelSignal<Record<string, string>>;
74
+ /** Pesquisa em todas as colunas visíveis. */
75
+ readonly query: _angular_core.InputSignal<string>;
76
+ /** Não ordena nem filtra: só emite sort e filters (dados do servidor). */
77
+ readonly manual: _angular_core.InputSignalWithTransform<boolean, unknown>;
78
+ /** Total de linhas no servidor (modo manual), para aria-rowcount e o estado. */
79
+ readonly totalRows: _angular_core.InputSignal<number | null>;
80
+ readonly height: _angular_core.InputSignal<string | null>;
81
+ readonly maxHeight: _angular_core.InputSignal<string | null>;
82
+ readonly rowHeight: _angular_core.InputSignalWithTransform<number, unknown>;
83
+ /** Scroll virtual: `auto` liga a partir de 100 linhas (precisa de height). */
84
+ readonly virtual: _angular_core.InputSignal<boolean | "auto">;
85
+ readonly density: _angular_core.InputSignal<"comfortable" | "compact">;
86
+ readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
87
+ readonly columnMenu: _angular_core.InputSignalWithTransform<boolean, unknown>;
88
+ readonly ariaLabel: _angular_core.InputSignal<string>;
89
+ /** Coluna cujo texto identifica a linha nos nomes ("Seleccionar FT 2026/0201"). */
90
+ readonly labelKey: _angular_core.InputSignal<string | null>;
91
+ readonly emptyText: _angular_core.InputSignal<string>;
92
+ readonly loadingText: _angular_core.InputSignal<string>;
93
+ readonly columnsText: _angular_core.InputSignal<string>;
94
+ readonly filterText: _angular_core.InputSignal<string>;
95
+ readonly allText: _angular_core.InputSignal<string>;
96
+ readonly selectAllText: _angular_core.InputSignal<string>;
97
+ readonly selectRowText: _angular_core.InputSignal<string>;
98
+ readonly selectText: _angular_core.InputSignal<string>;
99
+ readonly resizeHint: _angular_core.InputSignal<string>;
100
+ /** Enter ou duplo clique numa linha. */
101
+ readonly rowActivate: _angular_core.OutputEmitterRef<T>;
102
+ private readonly cells;
103
+ private readonly toolbarSlot;
104
+ private readonly scroller;
105
+ private readonly host;
106
+ private readonly injector;
107
+ private readonly announcer;
108
+ protected readonly checkWidth = 44;
109
+ protected readonly resizeHintId: string;
110
+ protected readonly radioName: string;
111
+ private readonly widths;
112
+ private readonly hiddenKeys;
113
+ private readonly scrollTop;
114
+ private readonly viewport;
115
+ /** Célula activa: linha e coluna na grelha (0 = cabeçalho). */
116
+ private readonly active;
117
+ protected readonly showToolbar: _angular_core.Signal<boolean>;
118
+ protected readonly offset: _angular_core.Signal<1 | 0>;
119
+ protected readonly hasFilters: _angular_core.Signal<boolean>;
120
+ protected readonly headerRows: _angular_core.Signal<number>;
121
+ protected readonly hideableColumns: _angular_core.Signal<MxGridColumn<T>[]>;
122
+ protected readonly visibleColumns: _angular_core.Signal<MxGridColumn<T>[]>;
123
+ protected readonly colCount: _angular_core.Signal<number>;
124
+ protected readonly tableWidth: _angular_core.Signal<number>;
125
+ /** Linhas depois de filtros, pesquisa e ordenação. */
126
+ readonly rows: _angular_core.Signal<readonly T[]>;
127
+ protected readonly isVirtual: _angular_core.Signal<boolean>;
128
+ protected readonly range: _angular_core.Signal<{
129
+ start: number;
130
+ end: number;
131
+ }>;
132
+ protected readonly rendered: _angular_core.Signal<T[]>;
133
+ protected readonly rowCount: _angular_core.Signal<number>;
134
+ private readonly selectedSet;
135
+ protected readonly allSelected: _angular_core.Signal<boolean>;
136
+ protected readonly someSelected: _angular_core.Signal<boolean>;
137
+ protected readonly statusText: _angular_core.Signal<string>;
138
+ constructor();
139
+ keyOf(row: T): unknown;
140
+ valueOf(c: MxGridColumn<T>, row: T): unknown;
141
+ protected text(c: MxGridColumn<T>, row: T): string;
142
+ protected rowLabel(row: T): string;
143
+ protected cellTemplate(key: string): TemplateRef<unknown> | null;
144
+ protected widthOf(c: MxGridColumn<T>): number;
145
+ protected pinOffset(c: MxGridColumn<T>): number;
146
+ protected pinOffsetEnd(c: MxGridColumn<T>): number;
147
+ protected optionsOf(c: MxGridColumn<T>): string[];
148
+ protected isHidden(c: MxGridColumn<T>): boolean;
149
+ protected ariaSort(c: MxGridColumn<T>): string | null;
150
+ isSelected(row: T): boolean;
151
+ toggleSort(c: MxGridColumn<T>): void;
152
+ setFilter(key: string, value: string): void;
153
+ toggleColumn(key: string): void;
154
+ toggleRow(row: T): void;
155
+ toggleAll(): void;
156
+ setWidth(key: string, width: number): void;
157
+ protected resetWidth(c: MxGridColumn<T>): void;
158
+ protected startResize(event: PointerEvent, c: MxGridColumn<T>): void;
159
+ private measure;
160
+ protected onScroll(): void;
161
+ private scrollTo;
162
+ private widgetIn;
163
+ private parseCell;
164
+ protected onFocusIn(event: FocusEvent): void;
165
+ private lastRow;
166
+ /** Move a célula activa e põe-lhe o foco (fazendo scroll se for preciso). */
167
+ focusCell(row: number, col: number): void;
168
+ protected onKeydown(event: KeyboardEvent): void;
169
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxDataGrid<any>, never>;
170
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MxDataGrid<any>, "mx-data-grid", ["mxDataGrid"], { "data": { "alias": "data"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "rowKey": { "alias": "rowKey"; "required": false; "isSignal": true; }; "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "selected": { "alias": "selected"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "query": { "alias": "query"; "required": false; "isSignal": true; }; "manual": { "alias": "manual"; "required": false; "isSignal": true; }; "totalRows": { "alias": "totalRows"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "rowHeight": { "alias": "rowHeight"; "required": false; "isSignal": true; }; "virtual": { "alias": "virtual"; "required": false; "isSignal": true; }; "density": { "alias": "density"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "columnMenu": { "alias": "columnMenu"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "labelKey": { "alias": "labelKey"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "loadingText": { "alias": "loadingText"; "required": false; "isSignal": true; }; "columnsText": { "alias": "columnsText"; "required": false; "isSignal": true; }; "filterText": { "alias": "filterText"; "required": false; "isSignal": true; }; "allText": { "alias": "allText"; "required": false; "isSignal": true; }; "selectAllText": { "alias": "selectAllText"; "required": false; "isSignal": true; }; "selectRowText": { "alias": "selectRowText"; "required": false; "isSignal": true; }; "selectText": { "alias": "selectText"; "required": false; "isSignal": true; }; "resizeHint": { "alias": "resizeHint"; "required": false; "isSignal": true; }; }, { "selected": "selectedChange"; "sort": "sortChange"; "filters": "filtersChange"; "rowActivate": "rowActivate"; }, ["cells", "toolbarSlot"], ["[mxGridToolbar]", "[mxGridFooter]"], true, never>;
171
+ }
172
+ declare const MX_DATA_GRID: readonly [typeof MxDataGrid, typeof MxGridCell, typeof MxGridToolbar];
173
+
174
+ export { MX_DATA_GRID, MxDataGrid, MxGridCell, MxGridToolbar };
175
+ export type { MxGridColumn, MxGridSort };
@@ -0,0 +1,104 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { ControlValueAccessor } from '@angular/forms';
3
+ import { SafeHtml } from '@angular/platform-browser';
4
+ import { Editor } from '@tiptap/core';
5
+ import { MxFormFieldControl, MxFormField } from '@muxima-ui/core/form-field';
6
+
7
+ /** Botões possíveis da barra de formatação. `|` desenha um separador. */
8
+ type MxEditorTool = 'bold' | 'italic' | 'underline' | 'strike' | 'code' | 'heading2' | 'heading3' | 'paragraph' | 'bulletList' | 'orderedList' | 'blockquote' | 'link' | 'undo' | 'redo' | '|';
9
+ declare const MX_EDITOR_DEFAULT_TOOLS: MxEditorTool[];
10
+ interface ToolDef {
11
+ label: string;
12
+ shortcut?: string;
13
+ icon: string;
14
+ run: (e: Editor) => void;
15
+ active?: (e: Editor) => boolean;
16
+ enabled?: (e: Editor) => boolean;
17
+ toggle?: boolean;
18
+ }
19
+ /**
20
+ * Editor de texto com formatação, sobre o Tiptap (ProseMirror). O Tiptap é uma dependência
21
+ * opcional: instala-o só se usares este ponto de entrada.
22
+ *
23
+ * ```bash
24
+ * npm install @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extensions
25
+ * ```
26
+ * ```html
27
+ * <mx-form-field>
28
+ * <label mxLabel>Notas da factura</label>
29
+ * <mx-editor formControlName="notas" placeholder="Escreve aqui..." [maxLength]="2000" />
30
+ * </mx-form-field>
31
+ * ```
32
+ *
33
+ * O valor é HTML (string; vazio quando não há texto). A barra é um role=toolbar:
34
+ * setas entre botões, Alt + F10 vai do texto para a barra e Esc volta ao texto.
35
+ */
36
+ declare class MxEditor implements ControlValueAccessor, MxFormFieldControl {
37
+ readonly value: _angular_core.ModelSignal<string>;
38
+ readonly placeholder: _angular_core.InputSignal<string>;
39
+ readonly tools: Record<"bold" | "italic" | "underline" | "strike" | "code" | "heading2" | "heading3" | "paragraph" | "bulletList" | "orderedList" | "blockquote" | "link" | "undo" | "redo", ToolDef>;
40
+ readonly toolbar: _angular_core.InputSignal<MxEditorTool[]>;
41
+ /** Máximo de caracteres; mostra a contagem. */
42
+ readonly maxLength: _angular_core.InputSignalWithTransform<number | null, unknown>;
43
+ readonly minHeight: _angular_core.InputSignal<string>;
44
+ readonly maxHeight: _angular_core.InputSignal<string | null>;
45
+ readonly readonly: _angular_core.InputSignalWithTransform<boolean, unknown>;
46
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
47
+ readonly required: _angular_core.InputSignalWithTransform<boolean, unknown>;
48
+ readonly invalid: _angular_core.InputSignalWithTransform<boolean, unknown>;
49
+ readonly id: _angular_core.InputSignal<string | undefined>;
50
+ readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
51
+ readonly toolbarLabel: _angular_core.InputSignal<string>;
52
+ readonly linkLabel: _angular_core.InputSignal<string>;
53
+ protected readonly field: MxFormField | null;
54
+ private readonly ngControl;
55
+ private readonly content;
56
+ private readonly toolbarEl;
57
+ private readonly linkInput;
58
+ private readonly injector;
59
+ private readonly generatedId;
60
+ readonly controlId: _angular_core.Signal<string>;
61
+ private readonly formDisabled;
62
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
63
+ protected readonly toolList: _angular_core.Signal<MxEditorTool[]>;
64
+ protected readonly focusIndex: _angular_core.WritableSignal<number>;
65
+ /** Muda a cada transacção, para os botões reflectirem o estado. */
66
+ private readonly tick;
67
+ protected readonly count: _angular_core.WritableSignal<number>;
68
+ protected readonly linkOpen: _angular_core.WritableSignal<boolean>;
69
+ protected readonly linkUrl: _angular_core.WritableSignal<string>;
70
+ protected readonly linkActive: _angular_core.WritableSignal<boolean>;
71
+ /** O editor do Tiptap, para comandos próprios (editor()?.chain()...). */
72
+ readonly editor: _angular_core.WritableSignal<Editor | null>;
73
+ private writing;
74
+ private onChange;
75
+ private onTouched;
76
+ constructor();
77
+ private create;
78
+ private readonly sanitizer;
79
+ private readonly icons;
80
+ protected icon(t: Exclude<MxEditorTool, '|'>): SafeHtml;
81
+ protected isActive(t: Exclude<MxEditorTool, '|'>): boolean;
82
+ protected isEnabled(t: Exclude<MxEditorTool, '|'>): boolean;
83
+ protected runTool(t: Exclude<MxEditorTool, '|'>, index: number): void;
84
+ openLink(): void;
85
+ protected applyLink(): void;
86
+ protected removeLink(): void;
87
+ protected closeLink(): void;
88
+ private buttons;
89
+ focusToolbar(): void;
90
+ protected onToolbarKey(event: KeyboardEvent): void;
91
+ /** Põe o foco no texto. */
92
+ focus(): void;
93
+ errorState(): boolean;
94
+ isRequired(): boolean;
95
+ writeValue(value: string | null): void;
96
+ registerOnChange(fn: (v: string) => void): void;
97
+ registerOnTouched(fn: () => void): void;
98
+ setDisabledState(isDisabled: boolean): void;
99
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxEditor, never>;
100
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MxEditor, "mx-editor", ["mxEditor"], { "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "toolbarLabel": { "alias": "toolbarLabel"; "required": false; "isSignal": true; }; "linkLabel": { "alias": "linkLabel"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
101
+ }
102
+
103
+ export { MX_EDITOR_DEFAULT_TOOLS, MxEditor };
104
+ export type { MxEditorTool };
@@ -0,0 +1,105 @@
1
+ import * as _angular_core from '@angular/core';
2
+
3
+ /** Rectângulo em píxeis. */
4
+ interface MxRect {
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ }
10
+ /** Puxadores de redimensionar: cantos e lados. */
11
+ type MxCropHandle = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';
12
+ /** Mantém o rectângulo dentro dos limites, sem mudar o tamanho (a não ser que não caiba). */
13
+ declare function mxClampRect(r: MxRect, bounds: MxRect): MxRect;
14
+ /** Maior rectângulo com a proporção dada, centrado nos limites (ocupa `fill` do espaço). */
15
+ declare function mxCenteredRect(bounds: MxRect, ratio: number | null, fill?: number): MxRect;
16
+ /**
17
+ * Redimensiona a partir de um puxador por (dx, dy), respeitando a proporção, o tamanho
18
+ * mínimo e os limites. O lado oposto ao puxador fica parado.
19
+ */
20
+ declare function mxResizeRect(r: MxRect, handle: MxCropHandle, dx: number, dy: number, bounds: MxRect, ratio: number | null, min?: number): MxRect;
21
+
22
+ /** Área recortada em píxeis da imagem original, com a rotação aplicada antes. */
23
+ interface MxCropArea extends MxRect {
24
+ rotation: number;
25
+ }
26
+ /**
27
+ * Recortar uma imagem antes de a enviar: arrastar a área, redimensionar pelos cantos,
28
+ * zoom e rodar. Com teclado: setas movem a área, Alt + setas mudam o tamanho (Shift para
29
+ * passos maiores); cada mudança é anunciada.
30
+ *
31
+ * ```html
32
+ * <mx-image-cropper #c [src]="ficheiro" [aspectRatio]="1" round />
33
+ * <button mxButton (click)="c.toBlob().then(enviar)">Guardar</button>
34
+ * ```
35
+ *
36
+ * `src` aceita um URL ou um File. `toBlob()` devolve a imagem recortada na resolução original.
37
+ */
38
+ declare class MxImageCropper {
39
+ readonly src: _angular_core.InputSignal<string | File | Blob | null>;
40
+ readonly alt: _angular_core.InputSignal<string>;
41
+ /** Largura / altura da área (1 = quadrado, 16/9...). null = livre. */
42
+ readonly aspectRatio: _angular_core.InputSignal<number | null>;
43
+ /** Máscara redonda (fotografias de perfil). toBlob devolve PNG com cantos transparentes. */
44
+ readonly round: _angular_core.InputSignalWithTransform<boolean, unknown>;
45
+ readonly controls: _angular_core.InputSignalWithTransform<boolean, unknown>;
46
+ readonly height: _angular_core.InputSignal<string>;
47
+ /** Tamanho mínimo da área no ecrã, em px. */
48
+ readonly minSize: _angular_core.InputSignalWithTransform<number, unknown>;
49
+ readonly zoom: _angular_core.ModelSignal<number>;
50
+ readonly rotation: _angular_core.ModelSignal<number>;
51
+ readonly helpText: _angular_core.InputSignal<string>;
52
+ readonly zoomText: _angular_core.InputSignal<string>;
53
+ readonly rotateLeftText: _angular_core.InputSignal<string>;
54
+ readonly rotateRightText: _angular_core.InputSignal<string>;
55
+ readonly resetText: _angular_core.InputSignal<string>;
56
+ /** Área recortada em píxeis da imagem original. */
57
+ readonly areaChange: _angular_core.OutputEmitterRef<MxCropArea>;
58
+ private readonly stage;
59
+ private readonly img;
60
+ private readonly announcer;
61
+ protected readonly helpId: string;
62
+ protected readonly handles: MxCropHandle[];
63
+ protected readonly url: _angular_core.WritableSignal<string | null>;
64
+ protected readonly natural: _angular_core.WritableSignal<{
65
+ w: number;
66
+ h: number;
67
+ }>;
68
+ private readonly stageSize;
69
+ protected readonly ready: _angular_core.WritableSignal<boolean>;
70
+ readonly box: _angular_core.WritableSignal<MxRect>;
71
+ protected readonly live: _angular_core.WritableSignal<string>;
72
+ private objectUrl;
73
+ private liveTimer?;
74
+ /** Escala que faz a imagem caber no palco, vezes o zoom. */
75
+ private readonly fit;
76
+ protected readonly scale: _angular_core.Signal<number>;
77
+ protected readonly zoomPct: _angular_core.Signal<number>;
78
+ /** Rectângulo da imagem no palco (onde a área pode estar). */
79
+ private readonly bounds;
80
+ /** Área em píxeis da imagem (rodada). */
81
+ readonly area: _angular_core.Signal<MxCropArea>;
82
+ protected readonly boxLabel: _angular_core.Signal<string>;
83
+ constructor();
84
+ private measure;
85
+ protected onLoad(): void;
86
+ /** Volta ao zoom 1, sem rotação, área centrada. */
87
+ reset(): void;
88
+ setZoom(z: number): void;
89
+ rotate(deg: number): void;
90
+ private say;
91
+ protected onKeydown(e: KeyboardEvent): void;
92
+ private drag;
93
+ protected startMove(e: PointerEvent): void;
94
+ protected startResize(e: PointerEvent, h: MxCropHandle): void;
95
+ /** Desenha o recorte num canvas na resolução original. */
96
+ toCanvas(): HTMLCanvasElement;
97
+ /** Recorte como Blob (PNG por omissão; com `round` é sempre PNG). */
98
+ toBlob(type?: string, quality?: number): Promise<Blob | null>;
99
+ toDataURL(type?: string, quality?: number): string;
100
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxImageCropper, never>;
101
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MxImageCropper, "mx-image-cropper", ["mxImageCropper"], { "src": { "alias": "src"; "required": false; "isSignal": true; }; "alt": { "alias": "alt"; "required": false; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "round": { "alias": "round"; "required": false; "isSignal": true; }; "controls": { "alias": "controls"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "minSize": { "alias": "minSize"; "required": false; "isSignal": true; }; "zoom": { "alias": "zoom"; "required": false; "isSignal": true; }; "rotation": { "alias": "rotation"; "required": false; "isSignal": true; }; "helpText": { "alias": "helpText"; "required": false; "isSignal": true; }; "zoomText": { "alias": "zoomText"; "required": false; "isSignal": true; }; "rotateLeftText": { "alias": "rotateLeftText"; "required": false; "isSignal": true; }; "rotateRightText": { "alias": "rotateRightText"; "required": false; "isSignal": true; }; "resetText": { "alias": "resetText"; "required": false; "isSignal": true; }; }, { "zoom": "zoomChange"; "rotation": "rotationChange"; "areaChange": "areaChange"; }, never, never, true, never>;
102
+ }
103
+
104
+ export { MxImageCropper, mxCenteredRect, mxClampRect, mxResizeRect };
105
+ export type { MxCropArea, MxCropHandle, MxRect };
@@ -0,0 +1,83 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+ import { CdkDrag, CdkDropList, CdkDragDrop } from '@angular/cdk/drag-drop';
4
+
5
+ interface MxKanbanColumn<T = any> {
6
+ id: string;
7
+ title: string;
8
+ items: T[];
9
+ /** Máximo de cartões na coluna (WIP). Acima disso não se larga lá. */
10
+ limit?: number;
11
+ }
12
+ interface MxKanbanMove<T = any> {
13
+ item: T;
14
+ from: string;
15
+ to: string;
16
+ fromIndex: number;
17
+ toIndex: number;
18
+ }
19
+ /** Conteúdo do cartão: `<ng-template mxKanbanCard let-item let-column="column">`. */
20
+ declare class MxKanbanCard {
21
+ readonly template: TemplateRef<any>;
22
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxKanbanCard, never>;
23
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<MxKanbanCard, "ng-template[mxKanbanCard]", never, {}, {}, never, never, true, never>;
24
+ }
25
+ /** Rodapé de cada coluna (ex.: botão "Adicionar"): `<ng-template mxKanbanColumnFooter let-column>`. */
26
+ declare class MxKanbanColumnFooter {
27
+ readonly template: TemplateRef<any>;
28
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxKanbanColumnFooter, never>;
29
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<MxKanbanColumnFooter, "ng-template[mxKanbanColumnFooter]", never, {}, {}, never, never, true, never>;
30
+ }
31
+ /**
32
+ * Quadro Kanban: cartões em colunas, com arrastar e largar (rato e toque) e mover com
33
+ * o teclado. Num cartão: Espaço agarra, setas movem (cima e baixo na coluna, esquerda e
34
+ * direita entre colunas), Espaço larga e Esc cancela. Cada passo é anunciado.
35
+ *
36
+ * ```html
37
+ * <mx-kanban [(columns)]="quadro" [itemLabel]="titulo" (moved)="guardar($event)">
38
+ * <ng-template mxKanbanCard let-tarefa>{{ tarefa.titulo }}</ng-template>
39
+ * </mx-kanban>
40
+ * ```
41
+ */
42
+ declare class MxKanban<T = any> {
43
+ readonly columns: _angular_core.ModelSignal<MxKanbanColumn<T>[]>;
44
+ /** Chave única de cada cartão: nome do campo ou função. */
45
+ readonly itemKey: _angular_core.InputSignal<string | ((item: T) => unknown)>;
46
+ /** Nome do cartão nos anúncios. Por omissão o campo `title` ou `titulo`. */
47
+ readonly itemLabel: _angular_core.InputSignal<(item: T) => string>;
48
+ readonly ariaLabel: _angular_core.InputSignal<string>;
49
+ readonly headingLevel: _angular_core.InputSignal<number>;
50
+ readonly emptyText: _angular_core.InputSignal<string>;
51
+ readonly helpText: _angular_core.InputSignal<string>;
52
+ readonly moved: _angular_core.OutputEmitterRef<MxKanbanMove<T>>;
53
+ protected readonly cardTpl: _angular_core.Signal<MxKanbanCard | undefined>;
54
+ protected readonly footerTpl: _angular_core.Signal<MxKanbanColumnFooter | undefined>;
55
+ private readonly announcer;
56
+ private readonly host;
57
+ private readonly injector;
58
+ private readonly uid;
59
+ protected readonly helpId: string;
60
+ /** Cartão agarrado com o teclado: posição actual e de onde saiu. */
61
+ private readonly grabbed;
62
+ protected titleId(i: number): string;
63
+ protected listId(i: number): string;
64
+ keyOf(item: T): unknown;
65
+ protected labelOf(item: T): string;
66
+ protected isGrabbed(c: number, i: number): boolean;
67
+ protected isFull(col: MxKanbanColumn<T>): boolean;
68
+ protected canEnter(ci: number): (drag: CdkDrag, drop: CdkDropList) => boolean;
69
+ /** Move um cartão e devolve as colunas novas (sem mudar as antigas). */
70
+ private move;
71
+ protected onDrop(e: CdkDragDrop<number>): void;
72
+ private emitMove;
73
+ private focusCard;
74
+ private where;
75
+ protected onKeydown(event: KeyboardEvent, ci: number, ii: number): void;
76
+ protected onBlur(ci: number, ii: number): void;
77
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxKanban<any>, never>;
78
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MxKanban<any>, "mx-kanban", ["mxKanban"], { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "itemKey": { "alias": "itemKey"; "required": false; "isSignal": true; }; "itemLabel": { "alias": "itemLabel"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "headingLevel": { "alias": "headingLevel"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "helpText": { "alias": "helpText"; "required": false; "isSignal": true; }; }, { "columns": "columnsChange"; "moved": "moved"; }, ["cardTpl", "footerTpl"], never, true, never>;
79
+ }
80
+ declare const MX_KANBAN: readonly [typeof MxKanban, typeof MxKanbanCard, typeof MxKanbanColumnFooter];
81
+
82
+ export { MX_KANBAN, MxKanban, MxKanbanCard, MxKanbanColumnFooter };
83
+ export type { MxKanbanColumn, MxKanbanMove };
@@ -0,0 +1,91 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+
4
+ interface MxNotification<D = unknown> {
5
+ id: string | number;
6
+ title: string;
7
+ description?: string;
8
+ time: Date;
9
+ read?: boolean;
10
+ /** Cor do marcador: info em Kwanza, success, warning, danger. */
11
+ variant?: 'default' | 'info' | 'success' | 'warning' | 'danger';
12
+ /** Agrupa por categoria nos filtros (ex.: "Facturas"). */
13
+ category?: string;
14
+ data?: D;
15
+ }
16
+ /** "agora", "há 5 min", "ontem", "há 3 dias" e, depois de uma semana, a data. */
17
+ declare function mxRelativeTime(date: Date, now?: Date, locale?: string): string;
18
+ /** Modelo para o conteúdo de cada notificação: `<ng-template mxNotificationContent let-n>`. */
19
+ declare class MxNotificationContent {
20
+ readonly template: TemplateRef<any>;
21
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxNotificationContent, never>;
22
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<MxNotificationContent, "ng-template[mxNotificationContent]", never, {}, {}, never, never, true, never>;
23
+ }
24
+ /**
25
+ * Lista de notificações com por ler e lidas, filtro "Por ler", "Marcar todas como lidas"
26
+ * e acções por notificação. Usa-se dentro de um popover, de um drawer ou numa página.
27
+ *
28
+ * ```html
29
+ * <mx-notification-center [items]="notificacoes()" (opened)="abrir($event)"
30
+ * (markRead)="marcar($event)" (markAllRead)="marcarTodas()" (dismiss)="remover($event)" />
31
+ * ```
32
+ *
33
+ * O componente não guarda estado: recebe a lista e emite o que a pessoa fez.
34
+ * Quando chegam notificações novas por ler, anuncia-as ao leitor de ecrã.
35
+ */
36
+ declare class MxNotificationCenter<D = unknown> {
37
+ readonly items: _angular_core.InputSignal<readonly MxNotification<D>[]>;
38
+ readonly title: _angular_core.InputSignal<string>;
39
+ /** Nível do título para o leitor de ecrã (h2 por omissão). */
40
+ readonly headingLevel: _angular_core.InputSignal<number>;
41
+ readonly markAllText: _angular_core.InputSignal<string>;
42
+ readonly emptyText: _angular_core.InputSignal<string>;
43
+ readonly emptyUnreadText: _angular_core.InputSignal<string>;
44
+ readonly filterLabel: _angular_core.InputSignal<string>;
45
+ /** Mostra os filtros Todas, Por ler e as categorias. */
46
+ readonly showFilter: _angular_core.InputSignalWithTransform<boolean, unknown>;
47
+ /** Mostra o botão de remover em cada notificação. */
48
+ readonly dismissible: _angular_core.InputSignalWithTransform<boolean, unknown>;
49
+ /** Marca como lida ao abrir (emite markRead além de opened). */
50
+ readonly markReadOnOpen: _angular_core.InputSignalWithTransform<boolean, unknown>;
51
+ /** Anuncia ao leitor de ecrã quando chegam notificações por ler. */
52
+ readonly announce: _angular_core.InputSignalWithTransform<boolean, unknown>;
53
+ readonly locale: _angular_core.InputSignal<string>;
54
+ readonly opened: _angular_core.OutputEmitterRef<MxNotification<D>>;
55
+ readonly markRead: _angular_core.OutputEmitterRef<MxNotification<D>>;
56
+ readonly markAllRead: _angular_core.OutputEmitterRef<void>;
57
+ readonly dismiss: _angular_core.OutputEmitterRef<MxNotification<D>>;
58
+ protected readonly contentTpl: _angular_core.Signal<MxNotificationContent | undefined>;
59
+ private readonly announcer;
60
+ protected readonly titleId: string;
61
+ readonly filter: _angular_core.WritableSignal<string>;
62
+ /** Muda a cada minuto, para "há 5 min" se actualizar. */
63
+ private readonly now;
64
+ readonly unread: _angular_core.Signal<number>;
65
+ protected readonly categories: _angular_core.Signal<string[]>;
66
+ protected readonly visible: _angular_core.Signal<MxNotification<D>[]>;
67
+ constructor();
68
+ protected relative(d: Date): string;
69
+ protected open(n: MxNotification<D>): void;
70
+ protected dismissItem(n: MxNotification<D>): void;
71
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxNotificationCenter<any>, never>;
72
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MxNotificationCenter<any>, "mx-notification-center", ["mxNotificationCenter"], { "items": { "alias": "items"; "required": true; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "headingLevel": { "alias": "headingLevel"; "required": false; "isSignal": true; }; "markAllText": { "alias": "markAllText"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "emptyUnreadText": { "alias": "emptyUnreadText"; "required": false; "isSignal": true; }; "filterLabel": { "alias": "filterLabel"; "required": false; "isSignal": true; }; "showFilter": { "alias": "showFilter"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; "markReadOnOpen": { "alias": "markReadOnOpen"; "required": false; "isSignal": true; }; "announce": { "alias": "announce"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; }, { "opened": "opened"; "markRead": "markRead"; "markAllRead": "markAllRead"; "dismiss": "dismiss"; }, ["contentTpl"], ["[mxNotificationFooter]"], true, never>;
73
+ }
74
+ /**
75
+ * Botão do sino com a contagem por ler. O nome inclui a contagem:
76
+ * "Notificações, 3 por ler".
77
+ *
78
+ * ```html
79
+ * <button mxNotificationBell [count]="porLer()" [mxPopoverTrigger]="painel"></button>
80
+ * ```
81
+ */
82
+ declare class MxNotificationBell {
83
+ readonly count: _angular_core.InputSignal<number>;
84
+ readonly max: _angular_core.InputSignal<number>;
85
+ readonly label: _angular_core.InputSignal<string>;
86
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MxNotificationBell, never>;
87
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MxNotificationBell, "button[mxNotificationBell]", ["mxNotificationBell"], { "count": { "alias": "count"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
88
+ }
89
+
90
+ export { MxNotificationBell, MxNotificationCenter, MxNotificationContent, mxRelativeTime };
91
+ export type { MxNotification };