@mosaicoo/kanban 0.1.0 → 0.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.
@@ -0,0 +1,3551 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, ChangeDetectionStrategy, Component, output, signal, viewChild, computed, Injectable, inject, effect, untracked } from '@angular/core';
3
+ import * as i1 from '@angular/material/menu';
4
+ import { MatMenuModule } from '@angular/material/menu';
5
+ import * as i1$2 from '@angular/material/tabs';
6
+ import { MatTabsModule } from '@angular/material/tabs';
7
+ import { MosKanbanBoard } from '@mosaicoo/kanban/ui';
8
+ import { CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
9
+ import { NgTemplateOutlet } from '@angular/common';
10
+ import * as i1$1 from '@angular/forms';
11
+ import { FormsModule } from '@angular/forms';
12
+ import { validateConfig, createBoard } from '@mosaicoo/kanban/core';
13
+
14
+ class MkbIcon {
15
+ name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
16
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
17
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: MkbIcon, isStandalone: true, selector: "mkb-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
18
+ <svg
19
+ viewBox="0 0 24 24"
20
+ fill="none"
21
+ stroke="currentColor"
22
+ stroke-width="1.8"
23
+ stroke-linecap="round"
24
+ stroke-linejoin="round"
25
+ aria-hidden="true"
26
+ focusable="false"
27
+ >
28
+ @switch (name()) {
29
+ @case ('drag') {
30
+ <circle cx="9" cy="5" r="1.6" fill="currentColor" stroke="none" />
31
+ <circle cx="15" cy="5" r="1.6" fill="currentColor" stroke="none" />
32
+ <circle cx="9" cy="12" r="1.6" fill="currentColor" stroke="none" />
33
+ <circle cx="15" cy="12" r="1.6" fill="currentColor" stroke="none" />
34
+ <circle cx="9" cy="19" r="1.6" fill="currentColor" stroke="none" />
35
+ <circle cx="15" cy="19" r="1.6" fill="currentColor" stroke="none" />
36
+ }
37
+ @case ('up') {
38
+ <path d="M6 14.5 12 8.5l6 6" />
39
+ }
40
+ @case ('down') {
41
+ <path d="M6 9.5 12 15.5l6-6" />
42
+ }
43
+ @case ('close') {
44
+ <path d="M6.5 6.5 17.5 17.5M17.5 6.5 6.5 17.5" />
45
+ }
46
+ @case ('add') {
47
+ <path d="M12 5v14M5 12h14" />
48
+ }
49
+ @case ('upload') {
50
+ <path d="M12 15.5V4M8 7.5 12 3.5l4 4" />
51
+ <path d="M4 16v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" />
52
+ }
53
+ @case ('download') {
54
+ <path d="M12 3.5V15M8 11l4 4 4-4" />
55
+ <path d="M4 16v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" />
56
+ }
57
+ @case ('expand') {
58
+ <path d="M7 10l5 5 5-5" />
59
+ }
60
+ @case ('trash') {
61
+ <path d="M4 7h16M10 7V4.5h4V7M6.5 7l1 13h9l1-13" />
62
+ }
63
+ @case ('check-circle') {
64
+ <circle cx="12" cy="12" r="8.5" />
65
+ <path d="M8.5 12.2l2.6 2.6 4.6-5.2" />
66
+ }
67
+ @case ('alert-circle') {
68
+ <circle cx="12" cy="12" r="8.5" />
69
+ <path d="M12 7.6v5" />
70
+ <circle cx="12" cy="16" r="1" fill="currentColor" stroke="none" />
71
+ }
72
+ @case ('eye') {
73
+ <path d="M2.5 12S6 6.2 12 6.2 21.5 12 21.5 12 18 17.8 12 17.8 2.5 12 2.5 12Z" />
74
+ <circle cx="12" cy="12" r="3" />
75
+ }
76
+ @case ('rows') {
77
+ <rect x="3.2" y="4.5" width="17.6" height="15" rx="2.4" />
78
+ <path d="M3.2 9.5h17.6M3.2 14.5h17.6" />
79
+ }
80
+ @case ('reset') {
81
+ <path d="M4 11a8 8 0 1 0 2.6-5.3" />
82
+ <path d="M3.6 4.2v4.6h4.6" />
83
+ }
84
+ }
85
+ </svg>
86
+ `, isInline: true, styles: [":host{display:inline-flex;width:1.25em;height:1.25em;flex:none}svg{width:100%;height:100%;display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
87
+ }
88
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbIcon, decorators: [{
89
+ type: Component,
90
+ args: [{ selector: 'mkb-icon', changeDetection: ChangeDetectionStrategy.OnPush, template: `
91
+ <svg
92
+ viewBox="0 0 24 24"
93
+ fill="none"
94
+ stroke="currentColor"
95
+ stroke-width="1.8"
96
+ stroke-linecap="round"
97
+ stroke-linejoin="round"
98
+ aria-hidden="true"
99
+ focusable="false"
100
+ >
101
+ @switch (name()) {
102
+ @case ('drag') {
103
+ <circle cx="9" cy="5" r="1.6" fill="currentColor" stroke="none" />
104
+ <circle cx="15" cy="5" r="1.6" fill="currentColor" stroke="none" />
105
+ <circle cx="9" cy="12" r="1.6" fill="currentColor" stroke="none" />
106
+ <circle cx="15" cy="12" r="1.6" fill="currentColor" stroke="none" />
107
+ <circle cx="9" cy="19" r="1.6" fill="currentColor" stroke="none" />
108
+ <circle cx="15" cy="19" r="1.6" fill="currentColor" stroke="none" />
109
+ }
110
+ @case ('up') {
111
+ <path d="M6 14.5 12 8.5l6 6" />
112
+ }
113
+ @case ('down') {
114
+ <path d="M6 9.5 12 15.5l6-6" />
115
+ }
116
+ @case ('close') {
117
+ <path d="M6.5 6.5 17.5 17.5M17.5 6.5 6.5 17.5" />
118
+ }
119
+ @case ('add') {
120
+ <path d="M12 5v14M5 12h14" />
121
+ }
122
+ @case ('upload') {
123
+ <path d="M12 15.5V4M8 7.5 12 3.5l4 4" />
124
+ <path d="M4 16v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" />
125
+ }
126
+ @case ('download') {
127
+ <path d="M12 3.5V15M8 11l4 4 4-4" />
128
+ <path d="M4 16v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" />
129
+ }
130
+ @case ('expand') {
131
+ <path d="M7 10l5 5 5-5" />
132
+ }
133
+ @case ('trash') {
134
+ <path d="M4 7h16M10 7V4.5h4V7M6.5 7l1 13h9l1-13" />
135
+ }
136
+ @case ('check-circle') {
137
+ <circle cx="12" cy="12" r="8.5" />
138
+ <path d="M8.5 12.2l2.6 2.6 4.6-5.2" />
139
+ }
140
+ @case ('alert-circle') {
141
+ <circle cx="12" cy="12" r="8.5" />
142
+ <path d="M12 7.6v5" />
143
+ <circle cx="12" cy="16" r="1" fill="currentColor" stroke="none" />
144
+ }
145
+ @case ('eye') {
146
+ <path d="M2.5 12S6 6.2 12 6.2 21.5 12 21.5 12 18 17.8 12 17.8 2.5 12 2.5 12Z" />
147
+ <circle cx="12" cy="12" r="3" />
148
+ }
149
+ @case ('rows') {
150
+ <rect x="3.2" y="4.5" width="17.6" height="15" rx="2.4" />
151
+ <path d="M3.2 9.5h17.6M3.2 14.5h17.6" />
152
+ }
153
+ @case ('reset') {
154
+ <path d="M4 11a8 8 0 1 0 2.6-5.3" />
155
+ <path d="M3.6 4.2v4.6h4.6" />
156
+ }
157
+ }
158
+ </svg>
159
+ `, styles: [":host{display:inline-flex;width:1.25em;height:1.25em;flex:none}svg{width:100%;height:100%;display:block}\n"] }]
160
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }] } });
161
+
162
+ /** Comparação tolerante: sem caixa e sem acento (ex.: "icone" acha "Ícone"). */
163
+ function normalize(text) {
164
+ return text
165
+ .toLocaleLowerCase('pt-BR')
166
+ .normalize('NFD')
167
+ .replace(/[\u0300-\u036f]/g, '')
168
+ .trim();
169
+ }
170
+ /**
171
+ * Combobox do Designer — gatilho no padrão de campo do DS + painel de menu
172
+ * (§11 dos Componentes: superfície card, itens navitem, selecionado em
173
+ * primary-container).
174
+ *
175
+ * Existe porque `<select>` nativo abre uma lista renderizada pelo SISTEMA,
176
+ * que não aceita estilo: dentro do DS ela destoa por completo. Serve tanto
177
+ * seleção única quanto múltipla; no múltiplo o painel não fecha a cada
178
+ * escolha e o estado é booleano por item (nada de array em [ngModel], que
179
+ * realimentava a detecção de mudanças).
180
+ */
181
+ class MkbCombo {
182
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
183
+ options = input.required(...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
184
+ /** Valor único (string) ou lista de valores quando `multiple`. */
185
+ value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
186
+ multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
187
+ /** Texto exibido quando nada está selecionado. */
188
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
189
+ valueChange = output();
190
+ valuesChange = output();
191
+ /** Acima deste número a varredura visual perde para a digitação: o painel
192
+ * ganha campo de filtro (convenção de ~10 itens). */
193
+ static SEARCH_THRESHOLD = 10;
194
+ open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
195
+ filter = signal('', ...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
196
+ search = viewChild('search', ...(ngDevMode ? [{ debugName: "search" }] : /* istanbul ignore next */ []));
197
+ searchable = computed(() => this.options().length > MkbCombo.SEARCH_THRESHOLD, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
198
+ /** Opções após o filtro — sem acento e sem caixa, como se espera em pt-BR. */
199
+ visible = computed(() => {
200
+ const query = normalize(this.filter());
201
+ if (!query)
202
+ return this.options();
203
+ return this.options().filter((o) => normalize(o.label).includes(query));
204
+ }, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
205
+ onOpen() {
206
+ this.open.set(true);
207
+ // o menu foca o primeiro item; com filtro, o cursor deve ir para a busca
208
+ if (this.searchable()) {
209
+ setTimeout(() => this.search()?.nativeElement.focus());
210
+ }
211
+ }
212
+ onClose() {
213
+ this.open.set(false);
214
+ this.filter.set('');
215
+ }
216
+ /** Deixa passar o que o MENU precisa tratar (fechar, navegar, escolher) e
217
+ * segura o resto, senão o typeahead do Material rouba a digitação. */
218
+ onSearchKeydown(event) {
219
+ const passthrough = event.key === 'Escape' ||
220
+ event.key === 'Enter' ||
221
+ event.key === 'Tab' ||
222
+ event.key.startsWith('Arrow');
223
+ if (!passthrough)
224
+ event.stopPropagation();
225
+ }
226
+ selected = computed(() => {
227
+ const v = this.value();
228
+ if (v == null || v === '')
229
+ return [];
230
+ return typeof v === 'string' ? [v] : [...v];
231
+ }, ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
232
+ isSelected(value) {
233
+ return this.selected().includes(value);
234
+ }
235
+ /** Resumo no gatilho: rótulo da opção, lista curta ou contagem. */
236
+ summary() {
237
+ const selected = this.selected();
238
+ if (!selected.length)
239
+ return '';
240
+ const labels = selected.map((v) => this.options().find((o) => o.value === v)?.label ?? v);
241
+ if (!this.multiple())
242
+ return labels[0] ?? '';
243
+ return labels.length <= 2 ? labels.join(', ') : `${labels.length} selecionados`;
244
+ }
245
+ pick(value, event) {
246
+ if (!this.multiple()) {
247
+ this.valueChange.emit(value);
248
+ return;
249
+ }
250
+ // múltiplo: mantém o painel aberto para várias escolhas seguidas
251
+ event.stopPropagation();
252
+ const current = this.selected();
253
+ this.valuesChange.emit(current.includes(value) ? current.filter((v) => v !== value) : [...current, value]);
254
+ }
255
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbCombo, deps: [], target: i0.ɵɵFactoryTarget.Component });
256
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: MkbCombo, isStandalone: true, selector: "mkb-combo", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", valuesChange: "valuesChange" }, viewQueries: [{ propertyName: "search", first: true, predicate: ["search"], descendants: true, isSignal: true }], ngImport: i0, template: `
257
+ <div class="mkbd-field mkbd-field-combo" [class.mkbd-combo-open]="open()">
258
+ <span class="mkbd-label">{{ label() }}</span>
259
+ <button
260
+ type="button"
261
+ class="mkbd-combo-btn"
262
+ [matMenuTriggerFor]="menu"
263
+ (menuOpened)="onOpen()"
264
+ (menuClosed)="onClose()"
265
+ [attr.aria-label]="label()"
266
+ >
267
+ <span class="mkbd-combo-value" [class.mkbd-combo-empty]="!summary()">
268
+ {{ summary() || placeholder() }}
269
+ </span>
270
+ <mkb-icon name="expand" class="mkbd-combo-caret" />
271
+ </button>
272
+ </div>
273
+
274
+ <mat-menu #menu="matMenu" class="mkbd-menu">
275
+ @if (searchable()) {
276
+ <div class="mkbd-menu-search" (click)="$event.stopPropagation()">
277
+ <input
278
+ #search
279
+ type="text"
280
+ [value]="filter()"
281
+ (input)="filter.set($any($event.target).value)"
282
+ (keydown)="onSearchKeydown($event)"
283
+ [attr.aria-label]="'Filtrar ' + label()"
284
+ [placeholder]="'Filtrar ' + options().length + ' opções…'"
285
+ />
286
+ @if (filter()) {
287
+ <span class="mkbd-menu-count">{{ visible().length }}/{{ options().length }}</span>
288
+ }
289
+ </div>
290
+ }
291
+
292
+ @for (opt of visible(); track opt.value) {
293
+ <button
294
+ mat-menu-item
295
+ type="button"
296
+ [role]="multiple() ? 'menuitemcheckbox' : 'menuitemradio'"
297
+ [attr.aria-checked]="isSelected(opt.value)"
298
+ [class.mkbd-menu-item-active]="isSelected(opt.value)"
299
+ (click)="pick(opt.value, $event)"
300
+ >
301
+ @if (multiple()) {
302
+ <span
303
+ class="mkbd-menu-check"
304
+ [class.mkbd-menu-check-on]="isSelected(opt.value)"
305
+ aria-hidden="true"
306
+ ></span>
307
+ }
308
+ {{ opt.label }}
309
+ </button>
310
+ } @empty {
311
+ <p class="mkbd-menu-empty">Nenhuma opção corresponde a “{{ filter() }}”.</p>
312
+ }
313
+ </mat-menu>
314
+ `, isInline: true, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block;min-width:0}:host .mkbd-field{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MkbIcon, selector: "mkb-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
315
+ }
316
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbCombo, decorators: [{
317
+ type: Component,
318
+ args: [{ selector: 'mkb-combo', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatMenuModule, MkbIcon], template: `
319
+ <div class="mkbd-field mkbd-field-combo" [class.mkbd-combo-open]="open()">
320
+ <span class="mkbd-label">{{ label() }}</span>
321
+ <button
322
+ type="button"
323
+ class="mkbd-combo-btn"
324
+ [matMenuTriggerFor]="menu"
325
+ (menuOpened)="onOpen()"
326
+ (menuClosed)="onClose()"
327
+ [attr.aria-label]="label()"
328
+ >
329
+ <span class="mkbd-combo-value" [class.mkbd-combo-empty]="!summary()">
330
+ {{ summary() || placeholder() }}
331
+ </span>
332
+ <mkb-icon name="expand" class="mkbd-combo-caret" />
333
+ </button>
334
+ </div>
335
+
336
+ <mat-menu #menu="matMenu" class="mkbd-menu">
337
+ @if (searchable()) {
338
+ <div class="mkbd-menu-search" (click)="$event.stopPropagation()">
339
+ <input
340
+ #search
341
+ type="text"
342
+ [value]="filter()"
343
+ (input)="filter.set($any($event.target).value)"
344
+ (keydown)="onSearchKeydown($event)"
345
+ [attr.aria-label]="'Filtrar ' + label()"
346
+ [placeholder]="'Filtrar ' + options().length + ' opções…'"
347
+ />
348
+ @if (filter()) {
349
+ <span class="mkbd-menu-count">{{ visible().length }}/{{ options().length }}</span>
350
+ }
351
+ </div>
352
+ }
353
+
354
+ @for (opt of visible(); track opt.value) {
355
+ <button
356
+ mat-menu-item
357
+ type="button"
358
+ [role]="multiple() ? 'menuitemcheckbox' : 'menuitemradio'"
359
+ [attr.aria-checked]="isSelected(opt.value)"
360
+ [class.mkbd-menu-item-active]="isSelected(opt.value)"
361
+ (click)="pick(opt.value, $event)"
362
+ >
363
+ @if (multiple()) {
364
+ <span
365
+ class="mkbd-menu-check"
366
+ [class.mkbd-menu-check-on]="isSelected(opt.value)"
367
+ aria-hidden="true"
368
+ ></span>
369
+ }
370
+ {{ opt.label }}
371
+ </button>
372
+ } @empty {
373
+ <p class="mkbd-menu-empty">Nenhuma opção corresponde a “{{ filter() }}”.</p>
374
+ }
375
+ </mat-menu>
376
+ `, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block;min-width:0}:host .mkbd-field{width:100%}\n"] }]
377
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], valuesChange: [{ type: i0.Output, args: ["valuesChange"] }], search: [{ type: i0.ViewChild, args: ['search', { isSignal: true }] }] } });
378
+
379
+ /** Espelho de styles/kanban-tokens.css (defaults de fábrica). */
380
+ const TOKEN_GROUPS = [
381
+ {
382
+ label: 'Espaçamento',
383
+ tokens: [
384
+ { token: '--mkb-column-gap', label: 'Entre colunas', kind: 'text', default: '12px' },
385
+ { token: '--mkb-lane-gap', label: 'Entre lanes', kind: 'text', default: '12px' },
386
+ { token: '--mkb-card-gap', label: 'Entre cartões', kind: 'text', default: '8px' },
387
+ { token: '--mkb-entry-gap', label: 'Entre itens do cartão', kind: 'text', default: '4px' },
388
+ { token: '--mkb-block-gap', label: 'Entre blocos do cartão', kind: 'text', default: '8px' },
389
+ { token: '--mkb-fact-gap', label: 'Entre fatos (facts)', kind: 'text', default: '10px' },
390
+ { token: '--mkb-card-padding', label: 'Interno do cartão', kind: 'text', default: '10px 12px' },
391
+ { token: '--mkb-cell-padding', label: 'Interno da célula', kind: 'text', default: '4px 8px 10px' },
392
+ { token: '--mkb-header-padding', label: 'Interno dos cabeçalhos', kind: 'text', default: '10px 12px' },
393
+ { token: '--mkb-column-width', label: 'Largura da coluna', kind: 'text', default: 'clamp(220px, 26vw, 320px)' },
394
+ { token: '--mkb-grid-column-width', label: 'Largura da coluna (grade de lanes)', kind: 'text', default: 'var(--mkb-column-width)' },
395
+ { token: '--mkb-lane-label-width', label: 'Largura do rótulo da lane', kind: 'text', default: '140px' },
396
+ ],
397
+ },
398
+ {
399
+ label: 'Cores',
400
+ tokens: [
401
+ { token: '--mkb-surface', label: 'Fundo do board', kind: 'color', default: '#f6f5f8' },
402
+ { token: '--mkb-column-bg', label: 'Fundo da coluna', kind: 'color', default: '#efedf3' },
403
+ { token: '--mkb-card-bg', label: 'Fundo do cartão', kind: 'color', default: '#ffffff' },
404
+ { token: '--mkb-border', label: 'Borda', kind: 'color', default: '#e3e0ea' },
405
+ { token: '--mkb-border-strong', label: 'Borda forte', kind: 'color', default: '#c9c4d4' },
406
+ { token: '--mkb-foreground', label: 'Texto', kind: 'color', default: '#241f33' },
407
+ { token: '--mkb-muted', label: 'Texto secundário', kind: 'color', default: '#6f6a7c' },
408
+ { token: '--mkb-accent', label: 'Realce (accent)', kind: 'color', default: '#5e35b1' },
409
+ { token: '--mkb-accent-contrast', label: 'Contraste do realce', kind: 'color', default: '#ffffff' },
410
+ { token: '--mkb-danger', label: 'Perigo', kind: 'color', default: '#b3261e' },
411
+ { token: '--mkb-warning', label: 'Alerta', kind: 'color', default: '#9a6b00' },
412
+ { token: '--mkb-success', label: 'Sucesso', kind: 'color', default: '#1b6e3c' },
413
+ { token: '--mkb-info', label: 'Informação', kind: 'color', default: '#2264c4' },
414
+ ],
415
+ },
416
+ {
417
+ label: 'Forma e movimento',
418
+ tokens: [
419
+ { token: '--mkb-radius', label: 'Raio (containers)', kind: 'text', default: '10px' },
420
+ { token: '--mkb-radius-sm', label: 'Raio (cartões/controles)', kind: 'text', default: '6px' },
421
+ { token: '--mkb-dur', label: 'Duração (hover/foco)', kind: 'text', default: '150ms' },
422
+ { token: '--mkb-dur-move', label: 'Duração (movimento/settle)', kind: 'text', default: '180ms' },
423
+ ],
424
+ },
425
+ ];
426
+ const COMMON = [
427
+ { key: 'label', label: 'Rótulo (label)', kind: 'text' },
428
+ { key: 'class', label: 'Classes CSS (separadas por espaço)', kind: 'csv' },
429
+ ];
430
+ const FIELD = {
431
+ key: 'field',
432
+ label: 'Campo do item',
433
+ kind: 'text',
434
+ hint: 'Nome do campo lido no card (ex.: titulo)',
435
+ };
436
+ const TONES = ['neutral', 'info', 'success', 'warning', 'danger'];
437
+ /** Descritores dos campos editáveis de cada tipo de bloco. */
438
+ const BLOCK_FIELDS = {
439
+ text: [
440
+ FIELD,
441
+ { key: 'variant', label: 'Variante', kind: 'select', options: ['', 'title', 'subtitle', 'body', 'caption', 'highlight'] },
442
+ { key: 'prefix', label: 'Prefixo', kind: 'text' },
443
+ { key: 'suffix', label: 'Sufixo', kind: 'text' },
444
+ { key: 'format', label: 'Formatador (format:*)', kind: 'text', hint: 'Nome no registry do host' },
445
+ { key: 'clamp', label: 'Máx. de linhas', kind: 'number' },
446
+ ...COMMON,
447
+ ],
448
+ number: [
449
+ FIELD,
450
+ { key: 'variant', label: 'Variante', kind: 'select', options: ['', 'body', 'highlight'] },
451
+ { key: 'style', label: 'Estilo', kind: 'select', options: ['', 'decimal', 'currency', 'percent'] },
452
+ { key: 'currency', label: 'Moeda (ISO)', kind: 'text', hint: 'ex.: BRL' },
453
+ { key: 'decimals', label: 'Casas decimais', kind: 'number' },
454
+ { key: 'prefix', label: 'Prefixo', kind: 'text' },
455
+ { key: 'suffix', label: 'Sufixo', kind: 'text' },
456
+ ...COMMON,
457
+ ],
458
+ date: [
459
+ FIELD,
460
+ { key: 'dateStyle', label: 'Formato', kind: 'select', options: ['', 'short', 'medium', 'long', 'full'] },
461
+ { key: 'relative', label: 'Relativo (há 2 dias)', kind: 'toggle' },
462
+ ...COMMON,
463
+ ],
464
+ time: [
465
+ FIELD,
466
+ { key: 'timeStyle', label: 'Formato', kind: 'select', options: ['', 'short', 'medium'] },
467
+ ...COMMON,
468
+ ],
469
+ datetime: [
470
+ FIELD,
471
+ { key: 'dateStyle', label: 'Formato (data)', kind: 'select', options: ['', 'short', 'medium', 'long', 'full'] },
472
+ { key: 'timeStyle', label: 'Formato (hora)', kind: 'select', options: ['', 'short', 'medium'] },
473
+ { key: 'relative', label: 'Relativo', kind: 'toggle' },
474
+ ...COMMON,
475
+ ],
476
+ image: [
477
+ FIELD,
478
+ { key: 'alt', label: 'Texto alternativo', kind: 'text' },
479
+ { key: 'rounded', label: 'Arredondada', kind: 'toggle' },
480
+ ...COMMON,
481
+ ],
482
+ tag: [
483
+ FIELD,
484
+ { key: 'tone', label: 'Tom', kind: 'select', options: ['', ...TONES] },
485
+ { key: 'map', label: 'Mapa valor → estilo (JSON)', kind: 'json', hint: '{"ok": {"label": "OK", "tone": "success", "icon": "check"}}' },
486
+ ...COMMON,
487
+ ],
488
+ badge: [
489
+ FIELD,
490
+ { key: 'icon', label: 'Ícone (icon:*)', kind: 'text' },
491
+ { key: 'tone', label: 'Tom', kind: 'select', options: ['', ...TONES] },
492
+ { key: 'showText', label: 'Mostrar texto', kind: 'toggle' },
493
+ { key: 'map', label: 'Mapa valor → estilo (JSON)', kind: 'json' },
494
+ ...COMMON,
495
+ ],
496
+ icon: [
497
+ { key: 'icon', label: 'Ícone (icon:*)', kind: 'text' },
498
+ { key: 'tone', label: 'Tom', kind: 'select', options: ['', ...TONES] },
499
+ ...COMMON,
500
+ ],
501
+ avatar: [
502
+ { key: 'nameField', label: 'Campo do nome', kind: 'text' },
503
+ { key: 'photoField', label: 'Campo da foto (URL)', kind: 'text' },
504
+ ...COMMON,
505
+ ],
506
+ facts: [{ key: 'items', label: 'Fatos', kind: 'facts' }, ...COMMON],
507
+ items: [
508
+ FIELD,
509
+ { key: 'labelField', label: 'Campo do rótulo', kind: 'text', hint: 'default: label' },
510
+ { key: 'checkField', label: 'Campo de conclusão', kind: 'text', hint: 'ex.: done' },
511
+ { key: 'capabilities', label: 'Capacidades', kind: 'capabilities' },
512
+ { key: 'actions', label: 'Ações por item', kind: 'card-actions' },
513
+ { key: 'showProgress', label: 'Mostrar progresso (N/M)', kind: 'toggle' },
514
+ { key: 'maxVisible', label: 'Máx. visíveis', kind: 'number' },
515
+ ...COMMON,
516
+ ],
517
+ alert: [
518
+ FIELD,
519
+ { key: 'tone', label: 'Tom', kind: 'select', options: ['', ...TONES] },
520
+ { key: 'icon', label: 'Ícone (icon:*)', kind: 'text' },
521
+ ...COMMON,
522
+ ],
523
+ progress: [
524
+ FIELD,
525
+ { key: 'max', label: 'Máximo', kind: 'number' },
526
+ { key: 'tone', label: 'Tom', kind: 'select', options: ['', ...TONES] },
527
+ ...COMMON,
528
+ ],
529
+ divider: [...COMMON],
530
+ actions: [{ key: 'items', label: 'Ações', kind: 'card-actions' }, ...COMMON],
531
+ row: [
532
+ { key: 'align', label: 'Alinhamento', kind: 'select', options: ['', 'start', 'center', 'end', 'between'] },
533
+ { key: 'wrap', label: 'Quebrar linha', kind: 'toggle' },
534
+ ...COMMON,
535
+ ],
536
+ custom: [
537
+ { key: 'renderer', label: 'Renderer (renderer:*)', kind: 'text', hint: 'Nome no registry do host' },
538
+ ...COMMON,
539
+ ],
540
+ };
541
+ /** Tipos de bloco oferecidos no "adicionar bloco" (ordem de exibição). */
542
+ const BLOCK_TYPE_LABELS = [
543
+ { type: 'text', label: 'Texto' },
544
+ { type: 'number', label: 'Número' },
545
+ { type: 'date', label: 'Data' },
546
+ { type: 'time', label: 'Hora' },
547
+ { type: 'datetime', label: 'Data e hora' },
548
+ { type: 'image', label: 'Imagem' },
549
+ { type: 'tag', label: 'Tag' },
550
+ { type: 'badge', label: 'Selo (badge)' },
551
+ { type: 'icon', label: 'Ícone' },
552
+ { type: 'avatar', label: 'Avatar' },
553
+ { type: 'facts', label: 'Fatos (ícone + valor)' },
554
+ { type: 'items', label: 'Itens internos (checklist/ações)' },
555
+ { type: 'alert', label: 'Alerta' },
556
+ { type: 'progress', label: 'Progresso' },
557
+ { type: 'divider', label: 'Divisor' },
558
+ { type: 'actions', label: 'Ações do cartão' },
559
+ { type: 'row', label: 'Linha (composição horizontal)' },
560
+ { type: 'custom', label: 'Custom (renderer do host)' },
561
+ ];
562
+
563
+ const DEFAULT_CONFIG = {
564
+ columns: {
565
+ groups: [
566
+ { id: 'todo', title: 'A Fazer' },
567
+ { id: 'doing', title: 'Fazendo' },
568
+ { id: 'done', title: 'Feito' },
569
+ ],
570
+ },
571
+ card: { blocks: [{ type: 'text', field: 'title', variant: 'title' }] },
572
+ items: [
573
+ { id: 'item-1', column: 'todo', title: 'Primeiro cartão' },
574
+ { id: 'item-2', column: 'doing', title: 'Segundo cartão' },
575
+ ],
576
+ };
577
+ /**
578
+ * Estado do Designer — instância POR componente (provider do
579
+ * MosKanbanDesigner; nunca singleton de módulo). Fonte da verdade é um
580
+ * BoardConfig serializável em forma canônica de edição (eixos como objeto);
581
+ * toda mutação passa por `update()` (clone → muta → valida → re-preview).
582
+ */
583
+ class DesignerStore {
584
+ config = signal(structuredClone(DEFAULT_CONFIG), ...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
585
+ theme = signal({}, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
586
+ registry;
587
+ /** Validação contínua da config em edição. */
588
+ validation = computed(() => validateConfig(this.config()), ...(ngDevMode ? [{ debugName: "validation" }] : /* istanbul ignore next */ []));
589
+ errors = computed(() => this.validation().errors, ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
590
+ /** Board do preview — recriado a cada config VÁLIDA (a inválida mantém o
591
+ * último preview bom, com os erros listados ao lado). */
592
+ lastGood = null;
593
+ previewBoard = computed(() => {
594
+ const cfg = this.config();
595
+ if (!validateConfig(cfg).valid)
596
+ return this.lastGood;
597
+ try {
598
+ this.lastGood?.destroy();
599
+ this.lastGood = createBoard(structuredClone(cfg), { registry: this.registry });
600
+ }
601
+ catch {
602
+ /* estrutural já validado; regra de runtime inesperada mantém o último */
603
+ }
604
+ return this.lastGood;
605
+ }, ...(ngDevMode ? [{ debugName: "previewBoard" }] : /* istanbul ignore next */ []));
606
+ /** String de estilo com os tokens alterados (aplicada no preview). */
607
+ themeStyle = computed(() => Object.entries(this.theme())
608
+ .map(([token, value]) => `${token}: ${value}`)
609
+ .join('; '), ...(ngDevMode ? [{ debugName: "themeStyle" }] : /* istanbul ignore next */ []));
610
+ // ---- mutações ---------------------------------------------------------------
611
+ /** Toda mutação: clona, aplica, publica (imutável p/ OnPush). */
612
+ update(mutator) {
613
+ const draft = structuredClone(this.config());
614
+ mutator(draft);
615
+ this.config.set(draft);
616
+ }
617
+ load(config, theme) {
618
+ this.config.set(this.canonicalize(structuredClone(config)));
619
+ if (theme)
620
+ this.theme.set({ ...theme });
621
+ }
622
+ setToken(token, value) {
623
+ const def = TOKEN_GROUPS.flatMap((g) => g.tokens).find((t) => t.token === token);
624
+ const next = { ...this.theme() };
625
+ if (!value || value === def?.default)
626
+ delete next[token];
627
+ else
628
+ next[token] = value;
629
+ this.theme.set(next);
630
+ }
631
+ resetTheme() {
632
+ this.theme.set({});
633
+ }
634
+ // ---- eixos em forma canônica --------------------------------------------------
635
+ /** Eixo de colunas SEMPRE como objeto (açúcar de array normalizado). */
636
+ columnsAxis() {
637
+ return this.axisOf(this.config().columns);
638
+ }
639
+ lanesAxis() {
640
+ const lanes = this.config().lanes;
641
+ return lanes ? this.axisOf(lanes) : null;
642
+ }
643
+ axisOf(axis) {
644
+ if (Array.isArray(axis)) {
645
+ return {
646
+ groups: axis.map((g) => (typeof g === 'string' ? { id: g } : { ...g })),
647
+ };
648
+ }
649
+ return {
650
+ ...axis,
651
+ groups: axis.groups?.map((g) => (typeof g === 'string' ? { id: g } : { ...g })),
652
+ };
653
+ }
654
+ /** Importa qualquer config para a forma canônica de edição. */
655
+ canonicalize(config) {
656
+ config.columns = this.axisOf(config.columns);
657
+ if (config.lanes)
658
+ config.lanes = this.axisOf(config.lanes);
659
+ return config;
660
+ }
661
+ // ---- import / export ----------------------------------------------------------
662
+ /** Aceita BoardConfig puro OU KanbanDesignFile; retorna erros sem aplicar
663
+ * quando a config é inválida. */
664
+ import(json) {
665
+ let parsed;
666
+ try {
667
+ parsed = JSON.parse(json);
668
+ }
669
+ catch (e) {
670
+ return { ok: false, errors: [{ path: '', message: `JSON inválido: ${e.message}` }] };
671
+ }
672
+ const asFile = parsed;
673
+ const isDesignFile = !!asFile.config;
674
+ const config = (asFile.config ?? parsed);
675
+ const result = validateConfig(config);
676
+ if (!result.valid)
677
+ return { ok: false, errors: result.errors };
678
+ // Design file descreve o design INTEIRO: sem `theme` = tema no padrão, o
679
+ // que ZERA os tokens em edição. BoardConfig puro só traz estrutura, então
680
+ // preserva o tema atual.
681
+ this.load(config, isDesignFile ? (asFile.theme ?? {}) : undefined);
682
+ return { ok: true, errors: [] };
683
+ }
684
+ exportConfigJson() {
685
+ return JSON.stringify(this.config(), null, 2);
686
+ }
687
+ exportDesignJson() {
688
+ const file = { version: 1, config: this.config() };
689
+ if (Object.keys(this.theme()).length)
690
+ file.theme = this.theme();
691
+ return JSON.stringify(file, null, 2);
692
+ }
693
+ /** Snippet CSS só com os tokens alterados (nada = string vazia). */
694
+ exportThemeCss() {
695
+ const entries = Object.entries(this.theme());
696
+ if (!entries.length)
697
+ return '';
698
+ const lines = entries.map(([token, value]) => ` ${token}: ${value};`);
699
+ return `/* Tema @mosaicoo/kanban — gerado pelo Designer */\n:root {\n${lines.join('\n')}\n}\n`;
700
+ }
701
+ // ---- rascunho local -------------------------------------------------------------
702
+ saveDraft(storageKey) {
703
+ try {
704
+ localStorage.setItem(storageKey, this.exportDesignJson());
705
+ }
706
+ catch {
707
+ /* storage cheio/indisponível: rascunho é conveniência, não requisito */
708
+ }
709
+ }
710
+ loadDraft(storageKey) {
711
+ try {
712
+ const raw = localStorage.getItem(storageKey);
713
+ return raw ? this.import(raw).ok : false;
714
+ }
715
+ catch {
716
+ return false;
717
+ }
718
+ }
719
+ clearDraft(storageKey) {
720
+ try {
721
+ localStorage.removeItem(storageKey);
722
+ }
723
+ catch {
724
+ /* idem */
725
+ }
726
+ }
727
+ destroy() {
728
+ this.lastGood?.destroy();
729
+ this.lastGood = null;
730
+ }
731
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: DesignerStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
732
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: DesignerStore });
733
+ }
734
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: DesignerStore, decorators: [{
735
+ type: Injectable
736
+ }] });
737
+
738
+ const TYPE_LABEL = new Map(BLOCK_TYPE_LABELS.map((t) => [t.type, t.label]));
739
+ /** Bloco novo mínimo VÁLIDO por tipo (campos obrigatórios preenchidos). */
740
+ function blankBlock(type) {
741
+ switch (type) {
742
+ case 'icon':
743
+ return { type, icon: 'star' };
744
+ case 'avatar':
745
+ return { type, nameField: 'owner' };
746
+ case 'facts':
747
+ return { type, items: [{ field: 'campo' }] };
748
+ case 'actions':
749
+ return { type, items: [{ id: 'acao-1', label: 'Ação' }] };
750
+ case 'divider':
751
+ return { type };
752
+ case 'row':
753
+ return { type, blocks: [] };
754
+ case 'custom':
755
+ return { type, renderer: 'renderer:custom' };
756
+ default:
757
+ return { type, field: 'campo' };
758
+ }
759
+ }
760
+ /**
761
+ * Editor do CARTÃO: árvore de blocos (com `row` de um nível) + painel de
762
+ * propriedades GERADO a partir de BLOCK_FIELDS — novos campos entram na
763
+ * tabela, não em template escrito à mão.
764
+ */
765
+ class MkbCardEditor {
766
+ store = inject(DesignerStore);
767
+ config = this.store.config;
768
+ blockTypeOptions = BLOCK_TYPE_LABELS.map((t) => ({
769
+ value: t.type,
770
+ label: t.label,
771
+ }));
772
+ toneOptions = ['', 'neutral', 'info', 'success', 'warning', 'danger'].map((tone) => ({ value: tone, label: tone || '—' }));
773
+ allCapabilities = ['check', 'reorder', 'move-across', 'action'];
774
+ /** Opções por descritor de campo — memoizadas: os defs são constantes do
775
+ * módulo, então a referência da lista precisa ser estável entre ciclos. */
776
+ selectOptionsCache = new WeakMap();
777
+ selectOptions(def) {
778
+ let options = this.selectOptionsCache.get(def);
779
+ if (!options) {
780
+ options = (def.options ?? []).map((opt) => ({ value: opt, label: opt || '—' }));
781
+ this.selectOptionsCache.set(def, options);
782
+ }
783
+ return options;
784
+ }
785
+ newType = signal('text', ...(ngDevMode ? [{ debugName: "newType" }] : /* istanbul ignore next */ []));
786
+ selectedPath = signal(null, ...(ngDevMode ? [{ debugName: "selectedPath" }] : /* istanbul ignore next */ []));
787
+ jsonError = signal(null, ...(ngDevMode ? [{ debugName: "jsonError" }] : /* istanbul ignore next */ []));
788
+ selectedBlock = computed(() => {
789
+ const path = this.selectedPath();
790
+ return path ? this.blockAt(this.config().card?.blocks ?? [], path) : null;
791
+ }, ...(ngDevMode ? [{ debugName: "selectedBlock" }] : /* istanbul ignore next */ []));
792
+ blocks() {
793
+ return this.config().card?.blocks ?? [];
794
+ }
795
+ rowChildren(block) {
796
+ return block.type === 'row' ? block.blocks : [];
797
+ }
798
+ typeLabel(type) {
799
+ return TYPE_LABEL.get(type) ?? type;
800
+ }
801
+ summary(block) {
802
+ const b = block;
803
+ return String(b['field'] ?? b['icon'] ?? b['renderer'] ?? b['nameField'] ?? '');
804
+ }
805
+ fieldsFor(type) {
806
+ return BLOCK_FIELDS[type];
807
+ }
808
+ // ---- seleção / árvore --------------------------------------------------------
809
+ select(path) {
810
+ this.selectedPath.set(path);
811
+ this.jsonError.set(null);
812
+ }
813
+ isSelected(path) {
814
+ const sel = this.selectedPath();
815
+ return !!sel && sel.length === path.length && sel.every((v, i) => v === path[i]);
816
+ }
817
+ selectedIsRow() {
818
+ return this.selectedBlock()?.type === 'row';
819
+ }
820
+ blockAt(blocks, path) {
821
+ const top = blocks[path[0]];
822
+ if (!top)
823
+ return null;
824
+ if (path.length === 1)
825
+ return top;
826
+ return top.type === 'row' ? (top.blocks[path[1]] ?? null) : null;
827
+ }
828
+ /** Lista IRMÃ do caminho (raiz ou blocos de uma row) dentro do draft. */
829
+ siblingsAt(draft, path) {
830
+ const blocks = draft.card?.blocks;
831
+ if (!blocks)
832
+ return null;
833
+ if (path.length === 1)
834
+ return blocks;
835
+ const parent = blocks[path[0]];
836
+ return parent?.type === 'row' ? parent.blocks : null;
837
+ }
838
+ add(intoSelectedRow) {
839
+ const block = blankBlock(this.newType());
840
+ const rowPath = intoSelectedRow ? this.selectedPath() : null;
841
+ this.store.update((d) => {
842
+ d.card ??= { blocks: [] };
843
+ if (rowPath) {
844
+ const row = this.blockAt(d.card.blocks, rowPath);
845
+ if (row?.type === 'row') {
846
+ row.blocks.push(block);
847
+ return;
848
+ }
849
+ }
850
+ d.card.blocks.push(block);
851
+ });
852
+ if (rowPath) {
853
+ const row = this.blockAt(this.blocks(), rowPath);
854
+ this.select([...rowPath, (row?.type === 'row' ? row.blocks.length : 1) - 1]);
855
+ }
856
+ else {
857
+ this.select([this.blocks().length - 1]);
858
+ }
859
+ }
860
+ remove(path) {
861
+ this.store.update((d) => {
862
+ this.siblingsAt(d, path)?.splice(path[path.length - 1], 1);
863
+ });
864
+ this.selectedPath.set(null);
865
+ }
866
+ /** Arraste (CDK): `parentPath` vazio = lista raiz; [i] = filhos da row i. */
867
+ dropBlock(parentPath, event) {
868
+ const { previousIndex, currentIndex } = event;
869
+ if (previousIndex === currentIndex)
870
+ return;
871
+ this.move([...parentPath, previousIndex], currentIndex - previousIndex);
872
+ }
873
+ move(path, delta) {
874
+ const index = path[path.length - 1];
875
+ const target = index + delta;
876
+ let moved = false;
877
+ this.store.update((d) => {
878
+ const siblings = this.siblingsAt(d, path);
879
+ if (!siblings || target < 0 || target >= siblings.length)
880
+ return;
881
+ const [b] = siblings.splice(index, 1);
882
+ siblings.splice(target, 0, b);
883
+ moved = true;
884
+ });
885
+ if (moved && this.isSelected(path)) {
886
+ this.select([...path.slice(0, -1), target]);
887
+ }
888
+ }
889
+ // ---- leitura de propriedades ----------------------------------------------------
890
+ str(block, key) {
891
+ const v = block[key];
892
+ return typeof v === 'string' ? v : '';
893
+ }
894
+ num(block, key) {
895
+ const v = block[key];
896
+ return typeof v === 'number' ? v : null;
897
+ }
898
+ bool(block, key) {
899
+ return block[key] === true;
900
+ }
901
+ csv(block, key) {
902
+ const v = block[key];
903
+ return Array.isArray(v) ? v.join(' ') : typeof v === 'string' ? v : '';
904
+ }
905
+ json(block, key) {
906
+ const v = block[key];
907
+ return v === undefined ? '' : JSON.stringify(v, null, 2);
908
+ }
909
+ facts(block) {
910
+ return block.type === 'facts' ? block.items : [];
911
+ }
912
+ actions(block, key) {
913
+ const v = block[key];
914
+ return Array.isArray(v) ? v : [];
915
+ }
916
+ hasCapability(block, cap) {
917
+ return block.type === 'items' && !!block.capabilities?.includes(cap);
918
+ }
919
+ whenColumns(action) {
920
+ const col = action.when?.column;
921
+ return Array.isArray(col) ? col.join(', ') : (col ?? '');
922
+ }
923
+ // ---- escrita de propriedades ------------------------------------------------------
924
+ /** Escreve no bloco selecionado; undefined REMOVE a chave. */
925
+ setProp(key, value) {
926
+ const path = this.selectedPath();
927
+ if (!path)
928
+ return;
929
+ this.store.update((d) => {
930
+ const block = this.blockAt(d.card?.blocks ?? [], path);
931
+ if (!block)
932
+ return;
933
+ if (value === undefined)
934
+ delete block[key];
935
+ else
936
+ block[key] = value;
937
+ });
938
+ }
939
+ setCsv(key, raw) {
940
+ const list = raw.split(/[\s,]+/).filter(Boolean);
941
+ this.setProp(key, list.length ? list : undefined);
942
+ }
943
+ setJson(key, event) {
944
+ const raw = event.target.value.trim();
945
+ if (!raw) {
946
+ this.jsonError.set(null);
947
+ this.setProp(key, undefined);
948
+ return;
949
+ }
950
+ try {
951
+ this.setProp(key, JSON.parse(raw));
952
+ this.jsonError.set(null);
953
+ }
954
+ catch (e) {
955
+ this.jsonError.set(`JSON inválido: ${e.message}`);
956
+ }
957
+ }
958
+ toggleCapability(cap, enabled) {
959
+ const block = this.selectedBlock();
960
+ if (block?.type !== 'items')
961
+ return;
962
+ const caps = new Set(block.capabilities ?? []);
963
+ if (enabled)
964
+ caps.add(cap);
965
+ else
966
+ caps.delete(cap);
967
+ this.setProp('capabilities', caps.size ? [...caps] : undefined);
968
+ }
969
+ // ---- listas internas (facts / actions) --------------------------------------------
970
+ addFact(key) {
971
+ this.mutateList(key, (list) => list.push({ field: 'campo' }));
972
+ }
973
+ setFact(index, prop, value) {
974
+ this.mutateList('items', (list) => {
975
+ const fact = list[index];
976
+ if (!fact)
977
+ return;
978
+ if (value === undefined)
979
+ delete fact[prop];
980
+ else
981
+ fact[prop] = value;
982
+ });
983
+ }
984
+ addAction(key) {
985
+ this.mutateList(key, (list) => list.push({ id: `acao-${list.length + 1}`, label: 'Ação' }));
986
+ }
987
+ setAction(key, index, prop, value) {
988
+ this.mutateList(key, (list) => {
989
+ const action = list[index];
990
+ if (!action)
991
+ return;
992
+ if (value === undefined)
993
+ delete action[prop];
994
+ else
995
+ action[prop] = value;
996
+ });
997
+ }
998
+ setActionWhen(key, index, raw) {
999
+ const columns = raw.split(/[\s,]+/).filter(Boolean);
1000
+ this.mutateList(key, (list) => {
1001
+ const action = list[index];
1002
+ if (!action)
1003
+ return;
1004
+ if (!columns.length) {
1005
+ if (action.when)
1006
+ delete action.when.column;
1007
+ if (action.when && !action.when.lane)
1008
+ delete action.when;
1009
+ }
1010
+ else {
1011
+ action.when = { ...(action.when ?? {}), column: columns.length === 1 ? columns[0] : columns };
1012
+ }
1013
+ });
1014
+ }
1015
+ removeListItem(key, index) {
1016
+ this.mutateList(key, (list) => list.splice(index, 1));
1017
+ }
1018
+ mutateList(key, mutator) {
1019
+ const path = this.selectedPath();
1020
+ if (!path)
1021
+ return;
1022
+ this.store.update((d) => {
1023
+ const block = this.blockAt(d.card?.blocks ?? [], path);
1024
+ if (!block)
1025
+ return;
1026
+ block[key] ??= [];
1027
+ mutator(block[key]);
1028
+ });
1029
+ }
1030
+ // ---- geral -------------------------------------------------------------------------
1031
+ setDragHandle(value) {
1032
+ this.store.update((d) => {
1033
+ d.card ??= { blocks: [] };
1034
+ if (value)
1035
+ d.card.dragHandle = true;
1036
+ else
1037
+ delete d.card.dragHandle;
1038
+ });
1039
+ }
1040
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbCardEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
1041
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: MkbCardEditor, isStandalone: true, selector: "mkb-card-editor", ngImport: i0, template: `
1042
+ <div class="mkbd-options">
1043
+ <label class="mkbd-switch mkbd-switch-boxed">
1044
+ <input
1045
+ type="checkbox"
1046
+ [ngModel]="config().card?.dragHandle ?? false"
1047
+ (ngModelChange)="setDragHandle($event)"
1048
+ />
1049
+ Arrastar só pela alça
1050
+ </label>
1051
+ </div>
1052
+
1053
+ <div class="mkbd-section">
1054
+ <span class="mkbd-overline">Blocos do cartão</span>
1055
+ <span class="mkbd-count">{{ blocks().length }}</span>
1056
+ </div>
1057
+
1058
+ <!-- Listas AUTÔNOMAS (sem cdkDropListGroup): a raiz e os filhos de cada
1059
+ linha reordenam dentro de si. Conectar ancestral com descendente foi
1060
+ o que quebrou o DnD do board no spike D0. -->
1061
+ <div
1062
+ class="mkbd-rows"
1063
+ role="tree"
1064
+ aria-label="Blocos do cartão"
1065
+ cdkDropList
1066
+ (cdkDropListDropped)="dropBlock([], $event)"
1067
+ >
1068
+ @for (block of blocks(); track $index; let i = $index) {
1069
+ <!-- cdkDrag e a alça ficam AQUI, no mesmo template do cdkDropList:
1070
+ as queries do CDK seguem a posição de DECLARAÇÃO, então um
1071
+ ng-template com outlet não é registrado pela lista. Só o CORPO
1072
+ da linha continua fatorado no template. -->
1073
+ <div
1074
+ class="mkbd-row mkbd-block"
1075
+ role="treeitem"
1076
+ tabindex="0"
1077
+ cdkDrag
1078
+ cdkDragLockAxis="y"
1079
+ [class.mkbd-row-selected]="isSelected([i])"
1080
+ [attr.aria-selected]="isSelected([i])"
1081
+ (click)="select([i])"
1082
+ (keydown.enter)="select([i])"
1083
+ >
1084
+ <span class="mkbd-handle" cdkDragHandle [attr.aria-label]="'Arrastar bloco ' + typeLabel(block.type)">
1085
+ <mkb-icon name="drag" />
1086
+ </span>
1087
+ <ng-container
1088
+ *ngTemplateOutlet="blockBody; context: { block, path: [i], siblings: blocks().length }"
1089
+ />
1090
+ </div>
1091
+
1092
+ @if (block.type === 'row') {
1093
+ <div
1094
+ class="mkbd-rows mkbd-nested"
1095
+ cdkDropList
1096
+ (cdkDropListDropped)="dropBlock([i], $event)"
1097
+ >
1098
+ @for (child of rowChildren(block); track $index; let j = $index) {
1099
+ <div
1100
+ class="mkbd-row mkbd-block mkbd-block-child"
1101
+ role="treeitem"
1102
+ tabindex="0"
1103
+ cdkDrag
1104
+ cdkDragLockAxis="y"
1105
+ [class.mkbd-row-selected]="isSelected([i, j])"
1106
+ [attr.aria-selected]="isSelected([i, j])"
1107
+ (click)="select([i, j])"
1108
+ (keydown.enter)="select([i, j])"
1109
+ >
1110
+ <span class="mkbd-handle" cdkDragHandle [attr.aria-label]="'Arrastar bloco ' + typeLabel(child.type)">
1111
+ <mkb-icon name="drag" />
1112
+ </span>
1113
+ <ng-container
1114
+ *ngTemplateOutlet="
1115
+ blockBody;
1116
+ context: { block: child, path: [i, j], siblings: rowChildren(block).length }
1117
+ "
1118
+ />
1119
+ </div>
1120
+ }
1121
+ </div>
1122
+ }
1123
+ } @empty {
1124
+ <p class="mkbd-hint">Nenhum bloco — o cartão renderiza vazio. Adicione abaixo.</p>
1125
+ }
1126
+ </div>
1127
+
1128
+ <!-- Corpo da linha (sem a alça): compartilhado pela raiz e pelos filhos. -->
1129
+ <ng-template #blockBody let-block="block" let-path="path" let-siblings="siblings">
1130
+ <span class="mkbd-block-type">{{ typeLabel(block.type) }}</span>
1131
+ <span class="mkbd-block-summary">{{ summary(block) }}</span>
1132
+ <div class="mkbd-row-ctrls">
1133
+ <button
1134
+ class="mkbd-icon-btn"
1135
+ type="button"
1136
+ (click)="move(path, -1); $event.stopPropagation()"
1137
+ [disabled]="path[path.length - 1] === 0"
1138
+ aria-label="Mover para cima"
1139
+ >
1140
+ <mkb-icon name="up" />
1141
+ </button>
1142
+ <button
1143
+ class="mkbd-icon-btn"
1144
+ type="button"
1145
+ (click)="move(path, 1); $event.stopPropagation()"
1146
+ [disabled]="path[path.length - 1] === siblings - 1"
1147
+ aria-label="Mover para baixo"
1148
+ >
1149
+ <mkb-icon name="down" />
1150
+ </button>
1151
+ <button
1152
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1153
+ type="button"
1154
+ (click)="remove(path); $event.stopPropagation()"
1155
+ aria-label="Remover bloco"
1156
+ >
1157
+ <mkb-icon name="close" />
1158
+ </button>
1159
+ </div>
1160
+ </ng-template>
1161
+
1162
+ <div class="mkbd-new-block">
1163
+ <mkb-combo
1164
+ label="Tipo do novo bloco"
1165
+ [options]="blockTypeOptions"
1166
+ [value]="newType()"
1167
+ (valueChange)="newType.set($any($event))"
1168
+ />
1169
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="add(false)">
1170
+ <mkb-icon name="add" />
1171
+ Adicionar
1172
+ </button>
1173
+ @if (selectedIsRow()) {
1174
+ <button class="mkbd-btn mkbd-btn-tonal" type="button" (click)="add(true)">
1175
+ <mkb-icon name="add" />
1176
+ Dentro da linha
1177
+ </button>
1178
+ }
1179
+ </div>
1180
+
1181
+ @if (selectedBlock(); as block) {
1182
+ <div class="mkbd-section">
1183
+ <span class="mkbd-overline">Propriedades · {{ typeLabel(block.type) }}</span>
1184
+ </div>
1185
+ <div class="mkbd-stack">
1186
+ @for (def of fieldsFor(block.type); track def.key) {
1187
+ @switch (def.kind) {
1188
+ @case ('text') {
1189
+ <label class="mkbd-field">
1190
+ <span class="mkbd-label">{{ def.label }}</span>
1191
+ <input
1192
+ [ngModel]="str(block, def.key)"
1193
+ (ngModelChange)="setProp(def.key, $event || undefined)"
1194
+ [placeholder]="def.hint ?? ''"
1195
+ />
1196
+ </label>
1197
+ }
1198
+ @case ('number') {
1199
+ <label class="mkbd-field mkbd-field-sm">
1200
+ <span class="mkbd-label">{{ def.label }}</span>
1201
+ <input
1202
+ type="number"
1203
+ [ngModel]="num(block, def.key)"
1204
+ (ngModelChange)="setProp(def.key, $event === null || $event === '' ? undefined : +$event)"
1205
+ />
1206
+ </label>
1207
+ }
1208
+ @case ('toggle') {
1209
+ <label class="mkbd-switch mkbd-switch-boxed">
1210
+ <input
1211
+ type="checkbox"
1212
+ [ngModel]="bool(block, def.key)"
1213
+ (ngModelChange)="setProp(def.key, $event || undefined)"
1214
+ />
1215
+ {{ def.label }}
1216
+ </label>
1217
+ }
1218
+ @case ('select') {
1219
+ <mkb-combo
1220
+ [label]="def.label"
1221
+ [options]="selectOptions(def)"
1222
+ [value]="str(block, def.key)"
1223
+ (valueChange)="setProp(def.key, $event || undefined)"
1224
+ />
1225
+ }
1226
+ @case ('csv') {
1227
+ <label class="mkbd-field mkbd-field-grow">
1228
+ <span class="mkbd-label">{{ def.label }}</span>
1229
+ <input [ngModel]="csv(block, def.key)" (ngModelChange)="setCsv(def.key, $event)" />
1230
+ </label>
1231
+ }
1232
+ @case ('json') {
1233
+ <label class="mkbd-field mkbd-field-area mkbd-field-full">
1234
+ <span class="mkbd-label">{{ def.label }}</span>
1235
+ <textarea rows="4" [value]="json(block, def.key)" (change)="setJson(def.key, $event)"></textarea>
1236
+ </label>
1237
+ <p class="mkbd-hint mkbd-full" [class.mkbd-error-text]="jsonError()">
1238
+ {{ jsonError() || def.hint || 'Objeto JSON; vazio remove.' }}
1239
+ </p>
1240
+ }
1241
+ @case ('capabilities') {
1242
+ <div class="mkbd-caps">
1243
+ <span class="mkbd-caps-label">{{ def.label }}</span>
1244
+ @for (cap of allCapabilities; track cap) {
1245
+ <label class="mkbd-check">
1246
+ <input
1247
+ type="checkbox"
1248
+ [ngModel]="hasCapability(block, cap)"
1249
+ (ngModelChange)="toggleCapability(cap, $event)"
1250
+ />
1251
+ {{ cap }}
1252
+ </label>
1253
+ }
1254
+ </div>
1255
+ }
1256
+ @case ('facts') {
1257
+ <div class="mkbd-sub">
1258
+ <span class="mkbd-caps-label">{{ def.label }}</span>
1259
+ @for (fact of facts(block); track $index; let fi = $index) {
1260
+ <div class="mkbd-stack mkbd-subrow">
1261
+ <label class="mkbd-field mkbd-field-sm">
1262
+ <span class="mkbd-label">Campo</span>
1263
+ <input [ngModel]="fact.field" (ngModelChange)="setFact(fi, 'field', $event)" />
1264
+ </label>
1265
+ <label class="mkbd-field mkbd-field-sm">
1266
+ <span class="mkbd-label">Ícone</span>
1267
+ <input [ngModel]="fact.icon ?? ''" (ngModelChange)="setFact(fi, 'icon', $event || undefined)" />
1268
+ </label>
1269
+ <label class="mkbd-field mkbd-field-sm">
1270
+ <span class="mkbd-label">Rótulo</span>
1271
+ <input [ngModel]="fact.label ?? ''" (ngModelChange)="setFact(fi, 'label', $event || undefined)" />
1272
+ </label>
1273
+ <label class="mkbd-field mkbd-field-sm">
1274
+ <span class="mkbd-label">Prefixo</span>
1275
+ <input [ngModel]="fact.prefix ?? ''" (ngModelChange)="setFact(fi, 'prefix', $event || undefined)" />
1276
+ </label>
1277
+ <label class="mkbd-field mkbd-field-sm">
1278
+ <span class="mkbd-label">Sufixo</span>
1279
+ <input [ngModel]="fact.suffix ?? ''" (ngModelChange)="setFact(fi, 'suffix', $event || undefined)" />
1280
+ </label>
1281
+ <button
1282
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1283
+ type="button"
1284
+ (click)="removeListItem(def.key, fi)"
1285
+ aria-label="Remover fato"
1286
+ >
1287
+ <mkb-icon name="close" />
1288
+ </button>
1289
+ </div>
1290
+ }
1291
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addFact(def.key)">
1292
+ <mkb-icon name="add" />
1293
+ Fato
1294
+ </button>
1295
+ </div>
1296
+ }
1297
+ @case ('card-actions') {
1298
+ <div class="mkbd-sub">
1299
+ <span class="mkbd-caps-label">{{ def.label }}</span>
1300
+ @for (action of actions(block, def.key); track $index; let ai = $index) {
1301
+ <div class="mkbd-stack mkbd-subrow">
1302
+ <label class="mkbd-field mkbd-field-sm mkbd-field-mono">
1303
+ <span class="mkbd-label">Id</span>
1304
+ <input [ngModel]="action.id" (ngModelChange)="setAction(def.key, ai, 'id', $event)" />
1305
+ </label>
1306
+ <label class="mkbd-field mkbd-field-sm">
1307
+ <span class="mkbd-label">Rótulo</span>
1308
+ <input [ngModel]="action.label" (ngModelChange)="setAction(def.key, ai, 'label', $event)" />
1309
+ </label>
1310
+ <label class="mkbd-field mkbd-field-sm">
1311
+ <span class="mkbd-label">Ícone</span>
1312
+ <input [ngModel]="action.icon ?? ''" (ngModelChange)="setAction(def.key, ai, 'icon', $event || undefined)" />
1313
+ </label>
1314
+ <mkb-combo
1315
+ class="mkbd-field-sm"
1316
+ label="Tom"
1317
+ [options]="toneOptions"
1318
+ [value]="action.tone ?? ''"
1319
+ (valueChange)="setAction(def.key, ai, 'tone', $event || undefined)"
1320
+ />
1321
+ <label class="mkbd-field mkbd-field-sm">
1322
+ <span class="mkbd-label">Só nas colunas</span>
1323
+ <input
1324
+ placeholder="col-a, col-b"
1325
+ [ngModel]="whenColumns(action)"
1326
+ (ngModelChange)="setActionWhen(def.key, ai, $event)"
1327
+ />
1328
+ </label>
1329
+ <button
1330
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1331
+ type="button"
1332
+ (click)="removeListItem(def.key, ai)"
1333
+ aria-label="Remover ação"
1334
+ >
1335
+ <mkb-icon name="close" />
1336
+ </button>
1337
+ </div>
1338
+ }
1339
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addAction(def.key)">
1340
+ <mkb-icon name="add" />
1341
+ Ação
1342
+ </button>
1343
+ </div>
1344
+ }
1345
+ }
1346
+ }
1347
+ </div>
1348
+ } @else {
1349
+ <p class="mkbd-hint">Selecione um bloco para editar as propriedades.</p>
1350
+ }
1351
+ `, isInline: true, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-block{grid-template-columns:22px auto minmax(0,1fr) auto;cursor:pointer;border-left-color:var(--mkbd-border-strong)}.mkbd-block:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-block-child{border-left-color:var(--mkbd-primary-outline)}.mkbd-nested{margin-left:26px;margin-top:3px;gap:3px}.mkbd-handle[cdkDragHandle]{cursor:grab;touch-action:none}.mkbd-block.cdk-drag-preview{box-shadow:var(--elevation-3, 0 8px 30px rgba(20, 22, 30, .14));opacity:.96}.mkbd-block.cdk-drag-placeholder{opacity:.35}.cdk-drop-list-dragging .mkbd-block:not(.cdk-drag-placeholder){transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-block-type{font-size:12.5px;font-weight:500}.mkbd-block-summary{font:500 11.5px var(--mkbd-font-mono);color:var(--mkbd-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-new-block{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px}.mkbd-new-block .mkbd-field{width:230px}.mkbd-new-block .mkbd-field>.mkbd-label{background:var(--mkbd-canvas)}.mkbd-caps,.mkbd-sub{display:flex;flex-wrap:wrap;gap:10px;align-items:center;width:100%}.mkbd-sub{flex-direction:column;align-items:stretch;gap:8px}.mkbd-subrow{flex-wrap:wrap}.mkbd-caps-label{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-full{flex:1 0 100%;margin:0}.mkbd-error-text{color:var(--mkbd-error)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: MkbCombo, selector: "mkb-combo", inputs: ["label", "options", "value", "multiple", "placeholder"], outputs: ["valueChange", "valuesChange"] }, { kind: "component", type: MkbIcon, selector: "mkb-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1352
+ }
1353
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbCardEditor, decorators: [{
1354
+ type: Component,
1355
+ args: [{ selector: 'mkb-card-editor', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, FormsModule, CdkDropList, CdkDrag, CdkDragHandle, MkbCombo, MkbIcon], template: `
1356
+ <div class="mkbd-options">
1357
+ <label class="mkbd-switch mkbd-switch-boxed">
1358
+ <input
1359
+ type="checkbox"
1360
+ [ngModel]="config().card?.dragHandle ?? false"
1361
+ (ngModelChange)="setDragHandle($event)"
1362
+ />
1363
+ Arrastar só pela alça
1364
+ </label>
1365
+ </div>
1366
+
1367
+ <div class="mkbd-section">
1368
+ <span class="mkbd-overline">Blocos do cartão</span>
1369
+ <span class="mkbd-count">{{ blocks().length }}</span>
1370
+ </div>
1371
+
1372
+ <!-- Listas AUTÔNOMAS (sem cdkDropListGroup): a raiz e os filhos de cada
1373
+ linha reordenam dentro de si. Conectar ancestral com descendente foi
1374
+ o que quebrou o DnD do board no spike D0. -->
1375
+ <div
1376
+ class="mkbd-rows"
1377
+ role="tree"
1378
+ aria-label="Blocos do cartão"
1379
+ cdkDropList
1380
+ (cdkDropListDropped)="dropBlock([], $event)"
1381
+ >
1382
+ @for (block of blocks(); track $index; let i = $index) {
1383
+ <!-- cdkDrag e a alça ficam AQUI, no mesmo template do cdkDropList:
1384
+ as queries do CDK seguem a posição de DECLARAÇÃO, então um
1385
+ ng-template com outlet não é registrado pela lista. Só o CORPO
1386
+ da linha continua fatorado no template. -->
1387
+ <div
1388
+ class="mkbd-row mkbd-block"
1389
+ role="treeitem"
1390
+ tabindex="0"
1391
+ cdkDrag
1392
+ cdkDragLockAxis="y"
1393
+ [class.mkbd-row-selected]="isSelected([i])"
1394
+ [attr.aria-selected]="isSelected([i])"
1395
+ (click)="select([i])"
1396
+ (keydown.enter)="select([i])"
1397
+ >
1398
+ <span class="mkbd-handle" cdkDragHandle [attr.aria-label]="'Arrastar bloco ' + typeLabel(block.type)">
1399
+ <mkb-icon name="drag" />
1400
+ </span>
1401
+ <ng-container
1402
+ *ngTemplateOutlet="blockBody; context: { block, path: [i], siblings: blocks().length }"
1403
+ />
1404
+ </div>
1405
+
1406
+ @if (block.type === 'row') {
1407
+ <div
1408
+ class="mkbd-rows mkbd-nested"
1409
+ cdkDropList
1410
+ (cdkDropListDropped)="dropBlock([i], $event)"
1411
+ >
1412
+ @for (child of rowChildren(block); track $index; let j = $index) {
1413
+ <div
1414
+ class="mkbd-row mkbd-block mkbd-block-child"
1415
+ role="treeitem"
1416
+ tabindex="0"
1417
+ cdkDrag
1418
+ cdkDragLockAxis="y"
1419
+ [class.mkbd-row-selected]="isSelected([i, j])"
1420
+ [attr.aria-selected]="isSelected([i, j])"
1421
+ (click)="select([i, j])"
1422
+ (keydown.enter)="select([i, j])"
1423
+ >
1424
+ <span class="mkbd-handle" cdkDragHandle [attr.aria-label]="'Arrastar bloco ' + typeLabel(child.type)">
1425
+ <mkb-icon name="drag" />
1426
+ </span>
1427
+ <ng-container
1428
+ *ngTemplateOutlet="
1429
+ blockBody;
1430
+ context: { block: child, path: [i, j], siblings: rowChildren(block).length }
1431
+ "
1432
+ />
1433
+ </div>
1434
+ }
1435
+ </div>
1436
+ }
1437
+ } @empty {
1438
+ <p class="mkbd-hint">Nenhum bloco — o cartão renderiza vazio. Adicione abaixo.</p>
1439
+ }
1440
+ </div>
1441
+
1442
+ <!-- Corpo da linha (sem a alça): compartilhado pela raiz e pelos filhos. -->
1443
+ <ng-template #blockBody let-block="block" let-path="path" let-siblings="siblings">
1444
+ <span class="mkbd-block-type">{{ typeLabel(block.type) }}</span>
1445
+ <span class="mkbd-block-summary">{{ summary(block) }}</span>
1446
+ <div class="mkbd-row-ctrls">
1447
+ <button
1448
+ class="mkbd-icon-btn"
1449
+ type="button"
1450
+ (click)="move(path, -1); $event.stopPropagation()"
1451
+ [disabled]="path[path.length - 1] === 0"
1452
+ aria-label="Mover para cima"
1453
+ >
1454
+ <mkb-icon name="up" />
1455
+ </button>
1456
+ <button
1457
+ class="mkbd-icon-btn"
1458
+ type="button"
1459
+ (click)="move(path, 1); $event.stopPropagation()"
1460
+ [disabled]="path[path.length - 1] === siblings - 1"
1461
+ aria-label="Mover para baixo"
1462
+ >
1463
+ <mkb-icon name="down" />
1464
+ </button>
1465
+ <button
1466
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1467
+ type="button"
1468
+ (click)="remove(path); $event.stopPropagation()"
1469
+ aria-label="Remover bloco"
1470
+ >
1471
+ <mkb-icon name="close" />
1472
+ </button>
1473
+ </div>
1474
+ </ng-template>
1475
+
1476
+ <div class="mkbd-new-block">
1477
+ <mkb-combo
1478
+ label="Tipo do novo bloco"
1479
+ [options]="blockTypeOptions"
1480
+ [value]="newType()"
1481
+ (valueChange)="newType.set($any($event))"
1482
+ />
1483
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="add(false)">
1484
+ <mkb-icon name="add" />
1485
+ Adicionar
1486
+ </button>
1487
+ @if (selectedIsRow()) {
1488
+ <button class="mkbd-btn mkbd-btn-tonal" type="button" (click)="add(true)">
1489
+ <mkb-icon name="add" />
1490
+ Dentro da linha
1491
+ </button>
1492
+ }
1493
+ </div>
1494
+
1495
+ @if (selectedBlock(); as block) {
1496
+ <div class="mkbd-section">
1497
+ <span class="mkbd-overline">Propriedades · {{ typeLabel(block.type) }}</span>
1498
+ </div>
1499
+ <div class="mkbd-stack">
1500
+ @for (def of fieldsFor(block.type); track def.key) {
1501
+ @switch (def.kind) {
1502
+ @case ('text') {
1503
+ <label class="mkbd-field">
1504
+ <span class="mkbd-label">{{ def.label }}</span>
1505
+ <input
1506
+ [ngModel]="str(block, def.key)"
1507
+ (ngModelChange)="setProp(def.key, $event || undefined)"
1508
+ [placeholder]="def.hint ?? ''"
1509
+ />
1510
+ </label>
1511
+ }
1512
+ @case ('number') {
1513
+ <label class="mkbd-field mkbd-field-sm">
1514
+ <span class="mkbd-label">{{ def.label }}</span>
1515
+ <input
1516
+ type="number"
1517
+ [ngModel]="num(block, def.key)"
1518
+ (ngModelChange)="setProp(def.key, $event === null || $event === '' ? undefined : +$event)"
1519
+ />
1520
+ </label>
1521
+ }
1522
+ @case ('toggle') {
1523
+ <label class="mkbd-switch mkbd-switch-boxed">
1524
+ <input
1525
+ type="checkbox"
1526
+ [ngModel]="bool(block, def.key)"
1527
+ (ngModelChange)="setProp(def.key, $event || undefined)"
1528
+ />
1529
+ {{ def.label }}
1530
+ </label>
1531
+ }
1532
+ @case ('select') {
1533
+ <mkb-combo
1534
+ [label]="def.label"
1535
+ [options]="selectOptions(def)"
1536
+ [value]="str(block, def.key)"
1537
+ (valueChange)="setProp(def.key, $event || undefined)"
1538
+ />
1539
+ }
1540
+ @case ('csv') {
1541
+ <label class="mkbd-field mkbd-field-grow">
1542
+ <span class="mkbd-label">{{ def.label }}</span>
1543
+ <input [ngModel]="csv(block, def.key)" (ngModelChange)="setCsv(def.key, $event)" />
1544
+ </label>
1545
+ }
1546
+ @case ('json') {
1547
+ <label class="mkbd-field mkbd-field-area mkbd-field-full">
1548
+ <span class="mkbd-label">{{ def.label }}</span>
1549
+ <textarea rows="4" [value]="json(block, def.key)" (change)="setJson(def.key, $event)"></textarea>
1550
+ </label>
1551
+ <p class="mkbd-hint mkbd-full" [class.mkbd-error-text]="jsonError()">
1552
+ {{ jsonError() || def.hint || 'Objeto JSON; vazio remove.' }}
1553
+ </p>
1554
+ }
1555
+ @case ('capabilities') {
1556
+ <div class="mkbd-caps">
1557
+ <span class="mkbd-caps-label">{{ def.label }}</span>
1558
+ @for (cap of allCapabilities; track cap) {
1559
+ <label class="mkbd-check">
1560
+ <input
1561
+ type="checkbox"
1562
+ [ngModel]="hasCapability(block, cap)"
1563
+ (ngModelChange)="toggleCapability(cap, $event)"
1564
+ />
1565
+ {{ cap }}
1566
+ </label>
1567
+ }
1568
+ </div>
1569
+ }
1570
+ @case ('facts') {
1571
+ <div class="mkbd-sub">
1572
+ <span class="mkbd-caps-label">{{ def.label }}</span>
1573
+ @for (fact of facts(block); track $index; let fi = $index) {
1574
+ <div class="mkbd-stack mkbd-subrow">
1575
+ <label class="mkbd-field mkbd-field-sm">
1576
+ <span class="mkbd-label">Campo</span>
1577
+ <input [ngModel]="fact.field" (ngModelChange)="setFact(fi, 'field', $event)" />
1578
+ </label>
1579
+ <label class="mkbd-field mkbd-field-sm">
1580
+ <span class="mkbd-label">Ícone</span>
1581
+ <input [ngModel]="fact.icon ?? ''" (ngModelChange)="setFact(fi, 'icon', $event || undefined)" />
1582
+ </label>
1583
+ <label class="mkbd-field mkbd-field-sm">
1584
+ <span class="mkbd-label">Rótulo</span>
1585
+ <input [ngModel]="fact.label ?? ''" (ngModelChange)="setFact(fi, 'label', $event || undefined)" />
1586
+ </label>
1587
+ <label class="mkbd-field mkbd-field-sm">
1588
+ <span class="mkbd-label">Prefixo</span>
1589
+ <input [ngModel]="fact.prefix ?? ''" (ngModelChange)="setFact(fi, 'prefix', $event || undefined)" />
1590
+ </label>
1591
+ <label class="mkbd-field mkbd-field-sm">
1592
+ <span class="mkbd-label">Sufixo</span>
1593
+ <input [ngModel]="fact.suffix ?? ''" (ngModelChange)="setFact(fi, 'suffix', $event || undefined)" />
1594
+ </label>
1595
+ <button
1596
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1597
+ type="button"
1598
+ (click)="removeListItem(def.key, fi)"
1599
+ aria-label="Remover fato"
1600
+ >
1601
+ <mkb-icon name="close" />
1602
+ </button>
1603
+ </div>
1604
+ }
1605
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addFact(def.key)">
1606
+ <mkb-icon name="add" />
1607
+ Fato
1608
+ </button>
1609
+ </div>
1610
+ }
1611
+ @case ('card-actions') {
1612
+ <div class="mkbd-sub">
1613
+ <span class="mkbd-caps-label">{{ def.label }}</span>
1614
+ @for (action of actions(block, def.key); track $index; let ai = $index) {
1615
+ <div class="mkbd-stack mkbd-subrow">
1616
+ <label class="mkbd-field mkbd-field-sm mkbd-field-mono">
1617
+ <span class="mkbd-label">Id</span>
1618
+ <input [ngModel]="action.id" (ngModelChange)="setAction(def.key, ai, 'id', $event)" />
1619
+ </label>
1620
+ <label class="mkbd-field mkbd-field-sm">
1621
+ <span class="mkbd-label">Rótulo</span>
1622
+ <input [ngModel]="action.label" (ngModelChange)="setAction(def.key, ai, 'label', $event)" />
1623
+ </label>
1624
+ <label class="mkbd-field mkbd-field-sm">
1625
+ <span class="mkbd-label">Ícone</span>
1626
+ <input [ngModel]="action.icon ?? ''" (ngModelChange)="setAction(def.key, ai, 'icon', $event || undefined)" />
1627
+ </label>
1628
+ <mkb-combo
1629
+ class="mkbd-field-sm"
1630
+ label="Tom"
1631
+ [options]="toneOptions"
1632
+ [value]="action.tone ?? ''"
1633
+ (valueChange)="setAction(def.key, ai, 'tone', $event || undefined)"
1634
+ />
1635
+ <label class="mkbd-field mkbd-field-sm">
1636
+ <span class="mkbd-label">Só nas colunas</span>
1637
+ <input
1638
+ placeholder="col-a, col-b"
1639
+ [ngModel]="whenColumns(action)"
1640
+ (ngModelChange)="setActionWhen(def.key, ai, $event)"
1641
+ />
1642
+ </label>
1643
+ <button
1644
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1645
+ type="button"
1646
+ (click)="removeListItem(def.key, ai)"
1647
+ aria-label="Remover ação"
1648
+ >
1649
+ <mkb-icon name="close" />
1650
+ </button>
1651
+ </div>
1652
+ }
1653
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addAction(def.key)">
1654
+ <mkb-icon name="add" />
1655
+ Ação
1656
+ </button>
1657
+ </div>
1658
+ }
1659
+ }
1660
+ }
1661
+ </div>
1662
+ } @else {
1663
+ <p class="mkbd-hint">Selecione um bloco para editar as propriedades.</p>
1664
+ }
1665
+ `, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-block{grid-template-columns:22px auto minmax(0,1fr) auto;cursor:pointer;border-left-color:var(--mkbd-border-strong)}.mkbd-block:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-block-child{border-left-color:var(--mkbd-primary-outline)}.mkbd-nested{margin-left:26px;margin-top:3px;gap:3px}.mkbd-handle[cdkDragHandle]{cursor:grab;touch-action:none}.mkbd-block.cdk-drag-preview{box-shadow:var(--elevation-3, 0 8px 30px rgba(20, 22, 30, .14));opacity:.96}.mkbd-block.cdk-drag-placeholder{opacity:.35}.cdk-drop-list-dragging .mkbd-block:not(.cdk-drag-placeholder){transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-block-type{font-size:12.5px;font-weight:500}.mkbd-block-summary{font:500 11.5px var(--mkbd-font-mono);color:var(--mkbd-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-new-block{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px}.mkbd-new-block .mkbd-field{width:230px}.mkbd-new-block .mkbd-field>.mkbd-label{background:var(--mkbd-canvas)}.mkbd-caps,.mkbd-sub{display:flex;flex-wrap:wrap;gap:10px;align-items:center;width:100%}.mkbd-sub{flex-direction:column;align-items:stretch;gap:8px}.mkbd-subrow{flex-wrap:wrap}.mkbd-caps-label{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-full{flex:1 0 100%;margin:0}.mkbd-error-text{color:var(--mkbd-error)}\n"] }]
1666
+ }] });
1667
+
1668
+ /** Converte texto digitado no tipo mais provável (números e booleanos). */
1669
+ function coerce(raw) {
1670
+ if (raw === 'true')
1671
+ return true;
1672
+ if (raw === 'false')
1673
+ return false;
1674
+ if (/^-?\d+(\.\d+)?$/.test(raw))
1675
+ return Number(raw);
1676
+ return raw;
1677
+ }
1678
+ /**
1679
+ * Editor de DADOS: os itens de exemplo do board (`config.items`), suas
1680
+ * entries (blocos `items` do cartão) e os filtros iniciais. São os dados
1681
+ * que viajam junto na exportação — no runtime real o host normalmente
1682
+ * substitui por um adapter.
1683
+ */
1684
+ class MkbDataEditor {
1685
+ store = inject(DesignerStore);
1686
+ config = this.store.config;
1687
+ filtersError = signal(null, ...(ngDevMode ? [{ debugName: "filtersError" }] : /* istanbul ignore next */ []));
1688
+ /** Índice do item aberto (acordeão de um por vez). */
1689
+ expanded = signal(null, ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
1690
+ toggle(index) {
1691
+ this.expanded.update((current) => (current === index ? null : index));
1692
+ }
1693
+ items() {
1694
+ return this.config().items ?? [];
1695
+ }
1696
+ columnField() {
1697
+ return this.store.columnsAxis().field ?? 'column';
1698
+ }
1699
+ laneField() {
1700
+ return this.store.lanesAxis()?.field ?? 'lane';
1701
+ }
1702
+ hasLanes() {
1703
+ return !!this.store.lanesAxis();
1704
+ }
1705
+ /** Opções derivadas da config — computed, para a referência ser estável. */
1706
+ columnOptions = computed(() => (this.store.columnsAxis().groups ?? []).map((g) => ({
1707
+ value: g.id,
1708
+ label: g.title ? `${g.id} · ${g.title}` : g.id,
1709
+ })), ...(ngDevMode ? [{ debugName: "columnOptions" }] : /* istanbul ignore next */ []));
1710
+ laneOptions = computed(() => (this.store.lanesAxis()?.groups ?? []).map((g) => ({
1711
+ value: g.id,
1712
+ label: g.title ? `${g.id} · ${g.title}` : g.id,
1713
+ })), ...(ngDevMode ? [{ debugName: "laneOptions" }] : /* istanbul ignore next */ []));
1714
+ columnIds() {
1715
+ return (this.store.columnsAxis().groups ?? []).map((g) => g.id);
1716
+ }
1717
+ laneIds() {
1718
+ return (this.store.lanesAxis()?.groups ?? []).map((g) => g.id);
1719
+ }
1720
+ label(item) {
1721
+ const title = item['title'] ?? item['titulo'] ?? item['name'];
1722
+ return typeof title === 'string' && title ? title : item.id;
1723
+ }
1724
+ position(item) {
1725
+ const col = this.str(item, this.columnField());
1726
+ const lane = this.hasLanes() ? this.str(item, this.laneField()) : '';
1727
+ return lane ? `${col} · ${lane}` : col;
1728
+ }
1729
+ str(record, key) {
1730
+ const v = record[key];
1731
+ return typeof v === 'string' ? v : v == null ? '' : String(v);
1732
+ }
1733
+ display(item, key) {
1734
+ const v = item[key];
1735
+ return typeof v === 'object' ? JSON.stringify(v) : String(v ?? '');
1736
+ }
1737
+ coerceValue(raw) {
1738
+ return coerce(raw);
1739
+ }
1740
+ /** Campos livres do item: tudo menos id, eixos e campos de entries. */
1741
+ freeFields(item) {
1742
+ const reserved = new Set([
1743
+ 'id',
1744
+ this.columnField(),
1745
+ this.laneField(),
1746
+ ...this.entryDefs().map((d) => d.field),
1747
+ ]);
1748
+ return Object.keys(item).filter((k) => !reserved.has(k));
1749
+ }
1750
+ /** Blocos `items` declarados no cartão (recursivo em rows). */
1751
+ entryDefs() {
1752
+ const defs = [];
1753
+ const walk = (blocks) => {
1754
+ for (const block of blocks) {
1755
+ if (block.type === 'items') {
1756
+ defs.push({
1757
+ field: block.field,
1758
+ labelField: block.labelField ?? 'label',
1759
+ checkField: block.checkField,
1760
+ });
1761
+ }
1762
+ else if (block.type === 'row') {
1763
+ walk(block.blocks);
1764
+ }
1765
+ }
1766
+ };
1767
+ walk(this.config().card?.blocks ?? []);
1768
+ return defs;
1769
+ }
1770
+ entriesOf(item, field) {
1771
+ const v = item[field];
1772
+ return Array.isArray(v) ? v : [];
1773
+ }
1774
+ // ---- mutações de item ---------------------------------------------------------
1775
+ addItem() {
1776
+ const column = this.columnIds()[0] ?? 'todo';
1777
+ const lane = this.hasLanes() ? this.laneIds()[0] : undefined;
1778
+ this.store.update((d) => {
1779
+ d.items ??= [];
1780
+ const item = {
1781
+ id: `item-${d.items.length + 1}`,
1782
+ [this.columnField()]: column,
1783
+ title: 'Novo item',
1784
+ };
1785
+ if (lane)
1786
+ item[this.laneField()] = lane;
1787
+ d.items.push(item);
1788
+ });
1789
+ this.expanded.set(this.items().length - 1);
1790
+ }
1791
+ duplicateItem(index) {
1792
+ this.store.update((d) => {
1793
+ const source = d.items?.[index];
1794
+ if (!source || !d.items)
1795
+ return;
1796
+ const copy = structuredClone(source);
1797
+ copy['id'] = `${source.id}-copia`;
1798
+ d.items.splice(index + 1, 0, copy);
1799
+ });
1800
+ }
1801
+ removeItem(index) {
1802
+ this.store.update((d) => d.items?.splice(index, 1));
1803
+ this.expanded.set(null);
1804
+ }
1805
+ setItemProp(index, key, value) {
1806
+ this.store.update((d) => {
1807
+ const item = d.items?.[index];
1808
+ if (!item)
1809
+ return;
1810
+ if (value === undefined || value === '')
1811
+ delete item[key];
1812
+ else
1813
+ item[key] = value;
1814
+ });
1815
+ }
1816
+ addField(index) {
1817
+ this.store.update((d) => {
1818
+ const item = d.items?.[index];
1819
+ if (!item)
1820
+ return;
1821
+ let n = 1;
1822
+ while (`campo-${n}` in item)
1823
+ n++;
1824
+ item[`campo-${n}`] = '';
1825
+ });
1826
+ }
1827
+ renameField(index, oldKey, event) {
1828
+ const newKey = event.target.value.trim();
1829
+ if (!newKey || newKey === oldKey)
1830
+ return;
1831
+ this.store.update((d) => {
1832
+ const item = d.items?.[index];
1833
+ if (!item || newKey in item)
1834
+ return;
1835
+ item[newKey] = item[oldKey];
1836
+ delete item[oldKey];
1837
+ });
1838
+ }
1839
+ removeField(index, key) {
1840
+ this.setItemProp(index, key, undefined);
1841
+ }
1842
+ // ---- entries -------------------------------------------------------------------
1843
+ addEntry(index, def) {
1844
+ this.store.update((d) => {
1845
+ const item = d.items?.[index];
1846
+ if (!item)
1847
+ return;
1848
+ const list = (item[def.field] ??= []);
1849
+ const entry = {
1850
+ id: `entry-${list.length + 1}`,
1851
+ [def.labelField]: 'Novo item interno',
1852
+ };
1853
+ if (def.checkField)
1854
+ entry[def.checkField] = false;
1855
+ list.push(entry);
1856
+ });
1857
+ }
1858
+ setEntryProp(index, field, entryIndex, key, value) {
1859
+ this.store.update((d) => {
1860
+ const item = d.items?.[index];
1861
+ const list = item?.[field];
1862
+ const entry = list?.[entryIndex];
1863
+ if (!entry)
1864
+ return;
1865
+ entry[key] = value;
1866
+ });
1867
+ }
1868
+ removeEntry(index, field, entryIndex) {
1869
+ this.store.update((d) => {
1870
+ const item = d.items?.[index];
1871
+ const list = item?.[field];
1872
+ list?.splice(entryIndex, 1);
1873
+ });
1874
+ }
1875
+ // ---- filtros ---------------------------------------------------------------------
1876
+ filtersJson() {
1877
+ const filters = this.config().filters;
1878
+ return filters?.length ? JSON.stringify(filters, null, 2) : '';
1879
+ }
1880
+ setFilters(event) {
1881
+ const raw = event.target.value.trim();
1882
+ if (!raw) {
1883
+ this.filtersError.set(null);
1884
+ this.store.update((d) => delete d.filters);
1885
+ return;
1886
+ }
1887
+ try {
1888
+ const parsed = JSON.parse(raw);
1889
+ if (!Array.isArray(parsed))
1890
+ throw new Error('esperado um ARRAY de filtros');
1891
+ this.filtersError.set(null);
1892
+ this.store.update((d) => (d.filters = parsed));
1893
+ }
1894
+ catch (e) {
1895
+ this.filtersError.set(`JSON inválido: ${e.message}`);
1896
+ }
1897
+ }
1898
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbDataEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
1899
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: MkbDataEditor, isStandalone: true, selector: "mkb-data-editor", ngImport: i0, template: `
1900
+ <div class="mkbd-section">
1901
+ <span class="mkbd-overline">Itens</span>
1902
+ <span class="mkbd-count">{{ items().length }}</span>
1903
+ </div>
1904
+
1905
+ <div class="mkbd-rows">
1906
+ @for (item of items(); track $index; let i = $index) {
1907
+ <div class="mkbd-row mkbd-item" [class.mkbd-row-selected]="expanded() === i">
1908
+ <div class="mkbd-item-head">
1909
+ <button
1910
+ class="mkbd-item-toggle"
1911
+ type="button"
1912
+ [attr.aria-expanded]="expanded() === i"
1913
+ (click)="toggle(i)"
1914
+ >
1915
+ <mkb-icon [name]="expanded() === i ? 'down' : 'expand'" />
1916
+ <span class="mkbd-item-title">{{ label(item) }}</span>
1917
+ <span class="mkbd-item-where">{{ position(item) }}</span>
1918
+ </button>
1919
+ <button class="mkbd-icon-btn" type="button" (click)="duplicateItem(i)" aria-label="Duplicar item">
1920
+ <mkb-icon name="add" />
1921
+ </button>
1922
+ <button
1923
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1924
+ type="button"
1925
+ (click)="removeItem(i)"
1926
+ aria-label="Remover item"
1927
+ >
1928
+ <mkb-icon name="close" />
1929
+ </button>
1930
+ </div>
1931
+
1932
+ @if (expanded() === i) {
1933
+ <div class="mkbd-item-body">
1934
+ <div class="mkbd-stack">
1935
+ <label class="mkbd-field mkbd-field-mono">
1936
+ <span class="mkbd-label">Id</span>
1937
+ <input [ngModel]="item.id" (ngModelChange)="setItemProp(i, 'id', $event)" />
1938
+ </label>
1939
+
1940
+ @if (columnOptions().length) {
1941
+ <mkb-combo
1942
+ [label]="'Coluna (' + columnField() + ')'"
1943
+ [options]="columnOptions()"
1944
+ [value]="str(item, columnField())"
1945
+ (valueChange)="setItemProp(i, columnField(), $event)"
1946
+ />
1947
+ } @else {
1948
+ <label class="mkbd-field">
1949
+ <span class="mkbd-label">Coluna ({{ columnField() }})</span>
1950
+ <input
1951
+ [ngModel]="str(item, columnField())"
1952
+ (ngModelChange)="setItemProp(i, columnField(), $event)"
1953
+ />
1954
+ </label>
1955
+ }
1956
+
1957
+ @if (hasLanes()) {
1958
+ @if (laneOptions().length) {
1959
+ <mkb-combo
1960
+ [label]="'Lane (' + laneField() + ')'"
1961
+ [options]="laneOptions()"
1962
+ [value]="str(item, laneField())"
1963
+ (valueChange)="setItemProp(i, laneField(), $event)"
1964
+ />
1965
+ } @else {
1966
+ <label class="mkbd-field">
1967
+ <span class="mkbd-label">Lane ({{ laneField() }})</span>
1968
+ <input
1969
+ [ngModel]="str(item, laneField())"
1970
+ (ngModelChange)="setItemProp(i, laneField(), $event)"
1971
+ />
1972
+ </label>
1973
+ }
1974
+ }
1975
+ </div>
1976
+
1977
+ <div class="mkbd-subsection">
1978
+ <span class="mkbd-overline">Campos</span>
1979
+ </div>
1980
+ @for (key of freeFields(item); track key) {
1981
+ <div class="mkbd-stack mkbd-field-row">
1982
+ <label class="mkbd-field mkbd-field-mono mkbd-field-sm">
1983
+ <span class="mkbd-label">Campo</span>
1984
+ <input [ngModel]="key" (change)="renameField(i, key, $event)" />
1985
+ </label>
1986
+ <label class="mkbd-field mkbd-field-grow">
1987
+ <span class="mkbd-label">Valor</span>
1988
+ <input
1989
+ [ngModel]="display(item, key)"
1990
+ (ngModelChange)="setItemProp(i, key, coerceValue($event))"
1991
+ />
1992
+ </label>
1993
+ <button
1994
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
1995
+ type="button"
1996
+ (click)="removeField(i, key)"
1997
+ aria-label="Remover campo"
1998
+ >
1999
+ <mkb-icon name="close" />
2000
+ </button>
2001
+ </div>
2002
+ }
2003
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addField(i)">
2004
+ <mkb-icon name="add" />
2005
+ Campo
2006
+ </button>
2007
+
2008
+ @for (def of entryDefs(); track def.field) {
2009
+ <div class="mkbd-subsection">
2010
+ <span class="mkbd-overline">Itens internos · {{ def.field }}</span>
2011
+ </div>
2012
+ @for (entry of entriesOf(item, def.field); track $index; let ei = $index) {
2013
+ <div class="mkbd-stack mkbd-field-row">
2014
+ @if (def.checkField; as checkField) {
2015
+ <label class="mkbd-check">
2016
+ <input
2017
+ type="checkbox"
2018
+ [ngModel]="entry[checkField] === true"
2019
+ (ngModelChange)="setEntryProp(i, def.field, ei, checkField, $event)"
2020
+ />
2021
+ Feito
2022
+ </label>
2023
+ }
2024
+ <label class="mkbd-field mkbd-field-grow">
2025
+ <span class="mkbd-label">{{ def.labelField }}</span>
2026
+ <input
2027
+ [ngModel]="str(entry, def.labelField)"
2028
+ (ngModelChange)="setEntryProp(i, def.field, ei, def.labelField, $event)"
2029
+ />
2030
+ </label>
2031
+ <button
2032
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2033
+ type="button"
2034
+ (click)="removeEntry(i, def.field, ei)"
2035
+ aria-label="Remover item interno"
2036
+ >
2037
+ <mkb-icon name="close" />
2038
+ </button>
2039
+ </div>
2040
+ }
2041
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addEntry(i, def)">
2042
+ <mkb-icon name="add" />
2043
+ Item interno
2044
+ </button>
2045
+ }
2046
+ </div>
2047
+ }
2048
+ </div>
2049
+ }
2050
+ </div>
2051
+
2052
+ <button class="mkbd-add" type="button" (click)="addItem()">
2053
+ <mkb-icon name="add" />
2054
+ Adicionar item
2055
+ </button>
2056
+
2057
+ <div class="mkbd-section">
2058
+ <span class="mkbd-overline">Filtros iniciais</span>
2059
+ </div>
2060
+ <p class="mkbd-hint">Array de KanbanFilter aplicado na criação do board; vazio remove.</p>
2061
+ <label class="mkbd-field mkbd-field-area mkbd-field-full">
2062
+ <span class="mkbd-label">filters (JSON)</span>
2063
+ <textarea rows="4" [value]="filtersJson()" (change)="setFilters($event)"></textarea>
2064
+ </label>
2065
+ @if (filtersError(); as err) {
2066
+ <p class="mkbd-error-text">{{ err }}</p>
2067
+ }
2068
+ `, isInline: true, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-item{display:block;padding:0;border-left-color:var(--mkbd-border-strong)}.mkbd-item-head{display:flex;align-items:center;gap:4px;padding:6px 8px 6px 4px}.mkbd-item-toggle{flex:1;display:flex;align-items:center;gap:8px;min-width:0;padding:6px 8px;border:none;border-radius:var(--mkbd-radius-sm);background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.mkbd-item-toggle:hover{background:var(--mkbd-panel-3)}.mkbd-item-toggle:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-item-toggle>mkb-icon{font-size:18px;color:var(--mkbd-muted)}.mkbd-item-title{font-weight:500;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-item-where{margin-left:auto;font:500 10px var(--mkbd-font-mono);color:var(--mkbd-muted);background:var(--mkbd-panel-3);padding:2px 8px;border-radius:var(--mkbd-radius-pill);white-space:nowrap}.mkbd-item-body{padding:4px 12px 14px;border-top:1px solid var(--mkbd-border-soft)}.mkbd-item-body .mkbd-field>.mkbd-label{background:var(--mkbd-panel)}.mkbd-subsection{margin:16px 0 10px}.mkbd-field-row{margin-bottom:10px;flex-wrap:nowrap}.mkbd-add-sm{height:34px;margin-top:0;font-size:12px}.mkbd-error-text{margin:6px 0 0;font-size:11.5px;color:var(--mkbd-error)}.mkbd-field-full{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MkbCombo, selector: "mkb-combo", inputs: ["label", "options", "value", "multiple", "placeholder"], outputs: ["valueChange", "valuesChange"] }, { kind: "component", type: MkbIcon, selector: "mkb-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2069
+ }
2070
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbDataEditor, decorators: [{
2071
+ type: Component,
2072
+ args: [{ selector: 'mkb-data-editor', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, MkbCombo, MkbIcon], template: `
2073
+ <div class="mkbd-section">
2074
+ <span class="mkbd-overline">Itens</span>
2075
+ <span class="mkbd-count">{{ items().length }}</span>
2076
+ </div>
2077
+
2078
+ <div class="mkbd-rows">
2079
+ @for (item of items(); track $index; let i = $index) {
2080
+ <div class="mkbd-row mkbd-item" [class.mkbd-row-selected]="expanded() === i">
2081
+ <div class="mkbd-item-head">
2082
+ <button
2083
+ class="mkbd-item-toggle"
2084
+ type="button"
2085
+ [attr.aria-expanded]="expanded() === i"
2086
+ (click)="toggle(i)"
2087
+ >
2088
+ <mkb-icon [name]="expanded() === i ? 'down' : 'expand'" />
2089
+ <span class="mkbd-item-title">{{ label(item) }}</span>
2090
+ <span class="mkbd-item-where">{{ position(item) }}</span>
2091
+ </button>
2092
+ <button class="mkbd-icon-btn" type="button" (click)="duplicateItem(i)" aria-label="Duplicar item">
2093
+ <mkb-icon name="add" />
2094
+ </button>
2095
+ <button
2096
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2097
+ type="button"
2098
+ (click)="removeItem(i)"
2099
+ aria-label="Remover item"
2100
+ >
2101
+ <mkb-icon name="close" />
2102
+ </button>
2103
+ </div>
2104
+
2105
+ @if (expanded() === i) {
2106
+ <div class="mkbd-item-body">
2107
+ <div class="mkbd-stack">
2108
+ <label class="mkbd-field mkbd-field-mono">
2109
+ <span class="mkbd-label">Id</span>
2110
+ <input [ngModel]="item.id" (ngModelChange)="setItemProp(i, 'id', $event)" />
2111
+ </label>
2112
+
2113
+ @if (columnOptions().length) {
2114
+ <mkb-combo
2115
+ [label]="'Coluna (' + columnField() + ')'"
2116
+ [options]="columnOptions()"
2117
+ [value]="str(item, columnField())"
2118
+ (valueChange)="setItemProp(i, columnField(), $event)"
2119
+ />
2120
+ } @else {
2121
+ <label class="mkbd-field">
2122
+ <span class="mkbd-label">Coluna ({{ columnField() }})</span>
2123
+ <input
2124
+ [ngModel]="str(item, columnField())"
2125
+ (ngModelChange)="setItemProp(i, columnField(), $event)"
2126
+ />
2127
+ </label>
2128
+ }
2129
+
2130
+ @if (hasLanes()) {
2131
+ @if (laneOptions().length) {
2132
+ <mkb-combo
2133
+ [label]="'Lane (' + laneField() + ')'"
2134
+ [options]="laneOptions()"
2135
+ [value]="str(item, laneField())"
2136
+ (valueChange)="setItemProp(i, laneField(), $event)"
2137
+ />
2138
+ } @else {
2139
+ <label class="mkbd-field">
2140
+ <span class="mkbd-label">Lane ({{ laneField() }})</span>
2141
+ <input
2142
+ [ngModel]="str(item, laneField())"
2143
+ (ngModelChange)="setItemProp(i, laneField(), $event)"
2144
+ />
2145
+ </label>
2146
+ }
2147
+ }
2148
+ </div>
2149
+
2150
+ <div class="mkbd-subsection">
2151
+ <span class="mkbd-overline">Campos</span>
2152
+ </div>
2153
+ @for (key of freeFields(item); track key) {
2154
+ <div class="mkbd-stack mkbd-field-row">
2155
+ <label class="mkbd-field mkbd-field-mono mkbd-field-sm">
2156
+ <span class="mkbd-label">Campo</span>
2157
+ <input [ngModel]="key" (change)="renameField(i, key, $event)" />
2158
+ </label>
2159
+ <label class="mkbd-field mkbd-field-grow">
2160
+ <span class="mkbd-label">Valor</span>
2161
+ <input
2162
+ [ngModel]="display(item, key)"
2163
+ (ngModelChange)="setItemProp(i, key, coerceValue($event))"
2164
+ />
2165
+ </label>
2166
+ <button
2167
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2168
+ type="button"
2169
+ (click)="removeField(i, key)"
2170
+ aria-label="Remover campo"
2171
+ >
2172
+ <mkb-icon name="close" />
2173
+ </button>
2174
+ </div>
2175
+ }
2176
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addField(i)">
2177
+ <mkb-icon name="add" />
2178
+ Campo
2179
+ </button>
2180
+
2181
+ @for (def of entryDefs(); track def.field) {
2182
+ <div class="mkbd-subsection">
2183
+ <span class="mkbd-overline">Itens internos · {{ def.field }}</span>
2184
+ </div>
2185
+ @for (entry of entriesOf(item, def.field); track $index; let ei = $index) {
2186
+ <div class="mkbd-stack mkbd-field-row">
2187
+ @if (def.checkField; as checkField) {
2188
+ <label class="mkbd-check">
2189
+ <input
2190
+ type="checkbox"
2191
+ [ngModel]="entry[checkField] === true"
2192
+ (ngModelChange)="setEntryProp(i, def.field, ei, checkField, $event)"
2193
+ />
2194
+ Feito
2195
+ </label>
2196
+ }
2197
+ <label class="mkbd-field mkbd-field-grow">
2198
+ <span class="mkbd-label">{{ def.labelField }}</span>
2199
+ <input
2200
+ [ngModel]="str(entry, def.labelField)"
2201
+ (ngModelChange)="setEntryProp(i, def.field, ei, def.labelField, $event)"
2202
+ />
2203
+ </label>
2204
+ <button
2205
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2206
+ type="button"
2207
+ (click)="removeEntry(i, def.field, ei)"
2208
+ aria-label="Remover item interno"
2209
+ >
2210
+ <mkb-icon name="close" />
2211
+ </button>
2212
+ </div>
2213
+ }
2214
+ <button class="mkbd-add mkbd-add-sm" type="button" (click)="addEntry(i, def)">
2215
+ <mkb-icon name="add" />
2216
+ Item interno
2217
+ </button>
2218
+ }
2219
+ </div>
2220
+ }
2221
+ </div>
2222
+ }
2223
+ </div>
2224
+
2225
+ <button class="mkbd-add" type="button" (click)="addItem()">
2226
+ <mkb-icon name="add" />
2227
+ Adicionar item
2228
+ </button>
2229
+
2230
+ <div class="mkbd-section">
2231
+ <span class="mkbd-overline">Filtros iniciais</span>
2232
+ </div>
2233
+ <p class="mkbd-hint">Array de KanbanFilter aplicado na criação do board; vazio remove.</p>
2234
+ <label class="mkbd-field mkbd-field-area mkbd-field-full">
2235
+ <span class="mkbd-label">filters (JSON)</span>
2236
+ <textarea rows="4" [value]="filtersJson()" (change)="setFilters($event)"></textarea>
2237
+ </label>
2238
+ @if (filtersError(); as err) {
2239
+ <p class="mkbd-error-text">{{ err }}</p>
2240
+ }
2241
+ `, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-item{display:block;padding:0;border-left-color:var(--mkbd-border-strong)}.mkbd-item-head{display:flex;align-items:center;gap:4px;padding:6px 8px 6px 4px}.mkbd-item-toggle{flex:1;display:flex;align-items:center;gap:8px;min-width:0;padding:6px 8px;border:none;border-radius:var(--mkbd-radius-sm);background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.mkbd-item-toggle:hover{background:var(--mkbd-panel-3)}.mkbd-item-toggle:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-item-toggle>mkb-icon{font-size:18px;color:var(--mkbd-muted)}.mkbd-item-title{font-weight:500;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-item-where{margin-left:auto;font:500 10px var(--mkbd-font-mono);color:var(--mkbd-muted);background:var(--mkbd-panel-3);padding:2px 8px;border-radius:var(--mkbd-radius-pill);white-space:nowrap}.mkbd-item-body{padding:4px 12px 14px;border-top:1px solid var(--mkbd-border-soft)}.mkbd-item-body .mkbd-field>.mkbd-label{background:var(--mkbd-panel)}.mkbd-subsection{margin:16px 0 10px}.mkbd-field-row{margin-bottom:10px;flex-wrap:nowrap}.mkbd-add-sm{height:34px;margin-top:0;font-size:12px}.mkbd-error-text{margin:6px 0 0;font-size:11.5px;color:var(--mkbd-error)}.mkbd-field-full{width:100%}\n"] }]
2242
+ }] });
2243
+
2244
+ /**
2245
+ * Editor do PIPELINE: eixos (colunas/lanes — estáticos ou derivados),
2246
+ * regras de transição/nomeadas e ordenação.
2247
+ *
2248
+ * Visual: "linha de lista editável" do DS (§16 dos Componentes) — cada grupo
2249
+ * é um card em grid com acento de cor, alça, campos outline e controles de
2250
+ * ordem, como na tela 13a.
2251
+ */
2252
+ class MkbPipelineEditor {
2253
+ store = inject(DesignerStore);
2254
+ config = this.store.config;
2255
+ /** Cor default por posição — a paleta de dados do DS (--viz-*). */
2256
+ static PALETTE = ['#6f6a7c', '#2264c4', '#9a6b00', '#2e7d32', '#c62828', '#00897b'];
2257
+ // Opções fixas: constantes de instância (referência estável entre ciclos).
2258
+ modeOptions = [
2259
+ { value: 'static', label: 'Estático (grupos)' },
2260
+ { value: 'derived', label: 'Derivado (dinâmico)' },
2261
+ ];
2262
+ sortGroupOptions = [
2263
+ { value: '', label: 'Ordem declarada' },
2264
+ { value: 'asc', label: 'Crescente' },
2265
+ { value: 'desc', label: 'Decrescente' },
2266
+ ];
2267
+ directionOptions = [
2268
+ { value: 'asc', label: 'Crescente' },
2269
+ { value: 'desc', label: 'Decrescente' },
2270
+ ];
2271
+ /** Opções derivadas da config — computed, para não realocar a cada ciclo.
2272
+ * Nas regras o rótulo é o ID puro: é ele que a transição referencia. */
2273
+ columnOptions = computed(() => (this.store.columnsAxis().groups ?? []).map((g) => ({ value: g.id, label: g.id })), ...(ngDevMode ? [{ debugName: "columnOptions" }] : /* istanbul ignore next */ []));
2274
+ fromOptions = computed(() => [
2275
+ { value: '*', label: 'Qualquer' },
2276
+ ...this.columnOptions(),
2277
+ ], ...(ngDevMode ? [{ debugName: "fromOptions" }] : /* istanbul ignore next */ []));
2278
+ columnIds() {
2279
+ return (this.store.columnsAxis().groups ?? []).map((g) => g.id);
2280
+ }
2281
+ // ---- eixos -----------------------------------------------------------------
2282
+ toggleLanes(enabled) {
2283
+ this.store.update((d) => {
2284
+ if (enabled) {
2285
+ d.lanes = { groups: [{ id: 'lane-1', title: 'Lane 1' }] };
2286
+ }
2287
+ else {
2288
+ delete d.lanes;
2289
+ }
2290
+ });
2291
+ }
2292
+ setAxisMode(key, mode) {
2293
+ this.store.update((d) => {
2294
+ const axis = this.draftAxis(d, key);
2295
+ if (mode === 'derived') {
2296
+ delete axis.groups;
2297
+ delete axis.reorderable;
2298
+ axis.field ||= key === 'columns' ? 'column' : 'lane';
2299
+ }
2300
+ else {
2301
+ axis.groups ??= [{ id: 'grupo-1', title: 'Grupo 1' }];
2302
+ }
2303
+ });
2304
+ }
2305
+ setAxisProp(key, prop, value) {
2306
+ this.store.update((d) => {
2307
+ const axis = this.draftAxis(d, key);
2308
+ if (value === undefined)
2309
+ delete axis[prop];
2310
+ else
2311
+ axis[prop] = value;
2312
+ });
2313
+ }
2314
+ setGroup(key, index, prop, value) {
2315
+ this.store.update((d) => {
2316
+ const group = this.draftAxis(d, key).groups?.[index];
2317
+ if (!group)
2318
+ return;
2319
+ if (value === undefined)
2320
+ delete group[prop];
2321
+ else
2322
+ group[prop] = value;
2323
+ });
2324
+ }
2325
+ /** Cor do grupo: `meta.color` do host ou a cor default da POSIÇÃO na lista
2326
+ * (só exibição — nada é gravado na config até o usuário escolher uma cor). */
2327
+ groupColor(group, index = 0) {
2328
+ const color = group.meta?.['color'];
2329
+ if (typeof color === 'string')
2330
+ return color;
2331
+ const palette = MkbPipelineEditor.PALETTE;
2332
+ return palette[index % palette.length];
2333
+ }
2334
+ setGroupColor(key, index, color) {
2335
+ this.store.update((d) => {
2336
+ const group = this.draftAxis(d, key).groups?.[index];
2337
+ if (!group)
2338
+ return;
2339
+ group.meta = { ...(group.meta ?? {}), color };
2340
+ });
2341
+ }
2342
+ addGroup(key) {
2343
+ this.store.update((d) => {
2344
+ const groups = this.draftAxis(d, key).groups;
2345
+ groups?.push({ id: `grupo-${groups.length + 1}` });
2346
+ });
2347
+ }
2348
+ removeGroup(key, index) {
2349
+ this.store.update((d) => this.draftAxis(d, key).groups?.splice(index, 1));
2350
+ }
2351
+ /** Arraste (CDK) — mesma reordenação das setas ↑↓, por posição absoluta. */
2352
+ dropGroup(key, event) {
2353
+ const { previousIndex, currentIndex } = event;
2354
+ if (previousIndex === currentIndex)
2355
+ return;
2356
+ this.moveGroup(key, previousIndex, currentIndex - previousIndex);
2357
+ }
2358
+ moveGroup(key, index, delta) {
2359
+ this.store.update((d) => {
2360
+ const groups = this.draftAxis(d, key).groups;
2361
+ if (!groups)
2362
+ return;
2363
+ const target = index + delta;
2364
+ if (target < 0 || target >= groups.length)
2365
+ return;
2366
+ const [g] = groups.splice(index, 1);
2367
+ groups.splice(target, 0, g);
2368
+ });
2369
+ }
2370
+ draftAxis(d, key) {
2371
+ if (key === 'lanes') {
2372
+ d.lanes ??= {};
2373
+ if (Array.isArray(d.lanes))
2374
+ d.lanes = { groups: d.lanes };
2375
+ return d.lanes;
2376
+ }
2377
+ if (Array.isArray(d.columns))
2378
+ d.columns = { groups: d.columns };
2379
+ return d.columns;
2380
+ }
2381
+ // ---- regras ----------------------------------------------------------------
2382
+ transitions() {
2383
+ return this.config().rules?.transitions ?? [];
2384
+ }
2385
+ fromOf(t) {
2386
+ return typeof t.from === 'string' ? t.from : Array.isArray(t.from) ? (t.from[0] ?? '*') : '*';
2387
+ }
2388
+ addTransition() {
2389
+ this.store.update((d) => {
2390
+ d.rules ??= {};
2391
+ d.rules.transitions ??= [];
2392
+ d.rules.transitions.push({});
2393
+ });
2394
+ }
2395
+ removeTransition(index) {
2396
+ this.store.update((d) => {
2397
+ d.rules?.transitions?.splice(index, 1);
2398
+ if (d.rules?.transitions?.length === 0)
2399
+ delete d.rules.transitions;
2400
+ });
2401
+ }
2402
+ setTransition(index, side, value) {
2403
+ this.store.update((d) => {
2404
+ const t = d.rules?.transitions?.[index];
2405
+ if (!t)
2406
+ return;
2407
+ if (side === 'from') {
2408
+ if (value === '*')
2409
+ delete t['from'];
2410
+ else
2411
+ t['from'] = value;
2412
+ }
2413
+ else {
2414
+ const list = value;
2415
+ if (!list.length)
2416
+ delete t['to'];
2417
+ else
2418
+ t['to'] = list.length === 1 ? list[0] : list;
2419
+ }
2420
+ });
2421
+ }
2422
+ namesOf(key) {
2423
+ return (this.config().rules?.[key] ?? []).join(', ');
2424
+ }
2425
+ setNames(key, csv) {
2426
+ const names = csv.split(/[\s,]+/).filter(Boolean);
2427
+ this.store.update((d) => {
2428
+ d.rules ??= {};
2429
+ if (names.length)
2430
+ d.rules[key] = names;
2431
+ else
2432
+ delete d.rules[key];
2433
+ });
2434
+ }
2435
+ // ---- ordenação / geral -------------------------------------------------------
2436
+ toggleSort(enabled) {
2437
+ this.store.update((d) => {
2438
+ if (enabled)
2439
+ d.sort = { field: 'title', direction: 'asc' };
2440
+ else
2441
+ delete d.sort;
2442
+ });
2443
+ }
2444
+ setSort(prop, value) {
2445
+ this.store.update((d) => {
2446
+ if (!d.sort)
2447
+ return;
2448
+ if (prop === 'field')
2449
+ d.sort.field = value;
2450
+ else
2451
+ d.sort.direction = value;
2452
+ });
2453
+ }
2454
+ setReadOnly(value) {
2455
+ this.store.update((d) => {
2456
+ if (value)
2457
+ d.readOnly = true;
2458
+ else
2459
+ delete d.readOnly;
2460
+ });
2461
+ }
2462
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbPipelineEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
2463
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: MkbPipelineEditor, isStandalone: true, selector: "mkb-pipeline-editor", ngImport: i0, template: `
2464
+ <!-- ======================= COLUNAS ======================= -->
2465
+ <ng-container
2466
+ *ngTemplateOutlet="axisEditor; context: { axis: store.columnsAxis(), key: 'columns' }"
2467
+ />
2468
+
2469
+ <!-- ======================== LANES ======================== -->
2470
+ <div class="mkbd-feature">
2471
+ <mkb-icon name="rows" />
2472
+ <div>
2473
+ <div class="mkbd-feature-title">Lanes (swimlanes)</div>
2474
+ <div class="mkbd-feature-desc">Agrupa cartões em faixas horizontais por um eixo</div>
2475
+ </div>
2476
+ <label class="mkbd-switch">
2477
+ <input
2478
+ type="checkbox"
2479
+ [ngModel]="!!store.lanesAxis()"
2480
+ (ngModelChange)="toggleLanes($event)"
2481
+ aria-label="Usar lanes"
2482
+ />
2483
+ </label>
2484
+ </div>
2485
+ @if (store.lanesAxis(); as lanes) {
2486
+ <ng-container *ngTemplateOutlet="axisEditor; context: { axis: lanes, key: 'lanes' }" />
2487
+ }
2488
+
2489
+ <!-- ================= EDITOR DE EIXO (template) ============ -->
2490
+ <ng-template #axisEditor let-axis="axis" let-key="key">
2491
+ <div class="mkbd-options">
2492
+ <mkb-combo
2493
+ label="Modo"
2494
+ [options]="modeOptions"
2495
+ [value]="axis.groups ? 'static' : 'derived'"
2496
+ (valueChange)="setAxisMode(key, $any($event))"
2497
+ />
2498
+ <label class="mkbd-field">
2499
+ <span class="mkbd-label">Campo do item</span>
2500
+ <input
2501
+ [ngModel]="axis.field ?? ''"
2502
+ (ngModelChange)="setAxisProp(key, 'field', $event || undefined)"
2503
+ [placeholder]="key === 'columns' ? 'column' : 'lane'"
2504
+ />
2505
+ </label>
2506
+ <mkb-combo
2507
+ label="Ordenar grupos"
2508
+ [options]="sortGroupOptions"
2509
+ [value]="axis.sortGroups ?? ''"
2510
+ (valueChange)="setAxisProp(key, 'sortGroups', $event || undefined)"
2511
+ />
2512
+ @if (axis.groups) {
2513
+ <label class="mkbd-switch mkbd-switch-boxed">
2514
+ <input
2515
+ type="checkbox"
2516
+ [ngModel]="axis.reorderable ?? false"
2517
+ (ngModelChange)="setAxisProp(key, 'reorderable', $event || undefined)"
2518
+ />
2519
+ Reordenável
2520
+ </label>
2521
+ }
2522
+ </div>
2523
+
2524
+ @if (axis.groups; as groups) {
2525
+ <div class="mkbd-section">
2526
+ <span class="mkbd-overline">{{ key === 'columns' ? 'Colunas' : 'Lanes' }}</span>
2527
+ <span class="mkbd-count">{{ groups.length }}</span>
2528
+ </div>
2529
+
2530
+ <div class="mkbd-rows" cdkDropList (cdkDropListDropped)="dropGroup(key, $event)">
2531
+ @for (group of groups; track $index; let i = $index) {
2532
+ <div
2533
+ class="mkbd-row mkbd-row-group"
2534
+ cdkDrag
2535
+ cdkDragLockAxis="y"
2536
+ [cdkDragPreviewClass]="'mkbd-drag-preview'"
2537
+ [style.--mkbd-accent]="groupColor(group, i)"
2538
+ >
2539
+ <span
2540
+ class="mkbd-handle"
2541
+ cdkDragHandle
2542
+ [attr.aria-label]="'Arrastar ' + (group.title ?? group.id)"
2543
+ >
2544
+ <mkb-icon name="drag" />
2545
+ </span>
2546
+
2547
+ <label class="mkbd-field mkbd-field-mono">
2548
+ <span class="mkbd-label">Id</span>
2549
+ <input [ngModel]="group.id" (ngModelChange)="setGroup(key, i, 'id', $event)" />
2550
+ </label>
2551
+
2552
+ <label class="mkbd-field">
2553
+ <span class="mkbd-label">Título</span>
2554
+ <input
2555
+ [ngModel]="group.title ?? ''"
2556
+ (ngModelChange)="setGroup(key, i, 'title', $event || undefined)"
2557
+ />
2558
+ </label>
2559
+
2560
+ <label class="mkbd-swatch" [title]="'Cor de ' + (group.title ?? group.id)">
2561
+ <input
2562
+ type="color"
2563
+ [ngModel]="groupColor(group, i)"
2564
+ (ngModelChange)="setGroupColor(key, i, $event)"
2565
+ [attr.aria-label]="'Cor de ' + (group.title ?? group.id)"
2566
+ />
2567
+ <span [style.background]="groupColor(group, i)"></span>
2568
+ </label>
2569
+
2570
+ <label class="mkbd-field mkbd-field-optional">
2571
+ <span class="mkbd-label">WIP</span>
2572
+ <input
2573
+ type="number"
2574
+ min="0"
2575
+ placeholder="∞"
2576
+ [ngModel]="group.limit ?? null"
2577
+ (ngModelChange)="setGroup(key, i, 'limit', $event === null || $event === '' ? undefined : +$event)"
2578
+ />
2579
+ </label>
2580
+
2581
+ <div class="mkbd-row-ctrls">
2582
+ <label class="mkbd-check">
2583
+ <input
2584
+ type="checkbox"
2585
+ [ngModel]="group.locked ?? false"
2586
+ (ngModelChange)="setGroup(key, i, 'locked', $event || undefined)"
2587
+ />
2588
+ Travado
2589
+ </label>
2590
+ <button
2591
+ class="mkbd-icon-btn"
2592
+ type="button"
2593
+ (click)="moveGroup(key, i, -1)"
2594
+ [disabled]="i === 0"
2595
+ aria-label="Mover para cima"
2596
+ >
2597
+ <mkb-icon name="up" />
2598
+ </button>
2599
+ <button
2600
+ class="mkbd-icon-btn"
2601
+ type="button"
2602
+ (click)="moveGroup(key, i, 1)"
2603
+ [disabled]="i === groups.length - 1"
2604
+ aria-label="Mover para baixo"
2605
+ >
2606
+ <mkb-icon name="down" />
2607
+ </button>
2608
+ <button
2609
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2610
+ type="button"
2611
+ (click)="removeGroup(key, i)"
2612
+ aria-label="Remover grupo"
2613
+ >
2614
+ <mkb-icon name="close" />
2615
+ </button>
2616
+ </div>
2617
+ </div>
2618
+ }
2619
+ </div>
2620
+
2621
+ <button class="mkbd-add" type="button" (click)="addGroup(key)">
2622
+ <mkb-icon name="add" />
2623
+ Adicionar {{ key === 'columns' ? 'coluna' : 'lane' }}
2624
+ </button>
2625
+ }
2626
+ </ng-template>
2627
+
2628
+ <!-- ======================= REGRAS ========================= -->
2629
+ <div class="mkbd-section">
2630
+ <span class="mkbd-overline">Regras de transição</span>
2631
+ @if (transitions().length) {
2632
+ <span class="mkbd-count">{{ transitions().length }}</span>
2633
+ }
2634
+ </div>
2635
+ <p class="mkbd-hint">
2636
+ Sem regras = qualquer transição é permitida. Com regras, só as listadas passam.
2637
+ </p>
2638
+
2639
+ @if (transitions().length) {
2640
+ <div class="mkbd-rows">
2641
+ @for (t of transitions(); track $index; let i = $index) {
2642
+ <div class="mkbd-row mkbd-row-rule">
2643
+ <mkb-combo
2644
+ label="De"
2645
+ [options]="fromOptions()"
2646
+ [value]="fromOf(t)"
2647
+ (valueChange)="setTransition(i, 'from', $event)"
2648
+ />
2649
+ <!-- Destino é multi-seleção: o valor vem da própria config (sem
2650
+ alocar array a cada ciclo, que foi o que travou a tela). -->
2651
+ <mkb-combo
2652
+ label="Para"
2653
+ [multiple]="true"
2654
+ placeholder="Qualquer"
2655
+ [options]="columnOptions()"
2656
+ [value]="t.to ?? null"
2657
+ (valuesChange)="setTransition(i, 'to', $event)"
2658
+ />
2659
+ <button
2660
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2661
+ type="button"
2662
+ (click)="removeTransition(i)"
2663
+ aria-label="Remover transição"
2664
+ >
2665
+ <mkb-icon name="close" />
2666
+ </button>
2667
+ </div>
2668
+ }
2669
+ </div>
2670
+ }
2671
+ <button class="mkbd-btn mkbd-btn-outline mkbd-btn-block" type="button" (click)="addTransition()">
2672
+ <mkb-icon name="add" />
2673
+ Adicionar transição
2674
+ </button>
2675
+
2676
+ <div class="mkbd-section">
2677
+ <span class="mkbd-overline">Regras nomeadas</span>
2678
+ </div>
2679
+ <p class="mkbd-hint">Os nomes referenciam código registrado pelo host no KanbanRegistry.</p>
2680
+ <div class="mkbd-stack">
2681
+ <label class="mkbd-field mkbd-field-grow">
2682
+ <span class="mkbd-label">Regras de cartão (rule:*)</span>
2683
+ <input
2684
+ [ngModel]="namesOf('rules')"
2685
+ (ngModelChange)="setNames('rules', $event)"
2686
+ placeholder="rule:berco-livre, rule:sla"
2687
+ />
2688
+ </label>
2689
+ <label class="mkbd-field mkbd-field-grow">
2690
+ <span class="mkbd-label">Regras de itens (entryRules)</span>
2691
+ <input [ngModel]="namesOf('entryRules')" (ngModelChange)="setNames('entryRules', $event)" />
2692
+ </label>
2693
+ </div>
2694
+
2695
+ <!-- ================== ORDENAÇÃO / GERAL ==================== -->
2696
+ <div class="mkbd-section">
2697
+ <span class="mkbd-overline">Ordenação e geral</span>
2698
+ </div>
2699
+ <div class="mkbd-stack">
2700
+ <label class="mkbd-switch mkbd-switch-boxed">
2701
+ <input type="checkbox" [ngModel]="!!config().sort" (ngModelChange)="toggleSort($event)" />
2702
+ Ordenar itens por campo
2703
+ </label>
2704
+ @if (config().sort; as sort) {
2705
+ <label class="mkbd-field">
2706
+ <span class="mkbd-label">Campo</span>
2707
+ <input [ngModel]="sort.field" (ngModelChange)="setSort('field', $event)" />
2708
+ </label>
2709
+ <mkb-combo
2710
+ label="Direção"
2711
+ [options]="directionOptions"
2712
+ [value]="sort.direction ?? 'asc'"
2713
+ (valueChange)="setSort('direction', $event)"
2714
+ />
2715
+ }
2716
+ <label class="mkbd-switch mkbd-switch-boxed">
2717
+ <input
2718
+ type="checkbox"
2719
+ [ngModel]="config().readOnly ?? false"
2720
+ (ngModelChange)="setReadOnly($event)"
2721
+ />
2722
+ Somente leitura
2723
+ </label>
2724
+ </div>
2725
+ `, isInline: true, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-row-group{grid-template-columns:22px minmax(0,1.1fr) minmax(0,1.3fr) 42px 76px auto}.mkbd-row-rule{grid-template-columns:minmax(0,1fr) minmax(0,1.6fr) auto;border-left-color:var(--mkbd-border-strong)}.mkbd-btn-block{margin-top:4px}.mkbd-combo-btn{flex:1;min-width:0;height:100%;padding:0 16px 0 0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-field-combo:has(.mkbd-combo-btn:focus-visible){border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-combo-empty{color:var(--mkbd-muted)}.mkbd-handle[cdkDragHandle]{cursor:grab;touch-action:none}.mkbd-row.cdk-drag-preview{box-shadow:var(--elevation-3, 0 8px 30px rgba(20, 22, 30, .14));opacity:.96}.mkbd-row.cdk-drag-placeholder{opacity:.35}.mkbd-rows.cdk-drop-list-dragging .mkbd-row:not(.cdk-drag-placeholder){transition:transform var(--mkbd-dur) var(--mkbd-ease)}@media(max-width:720px){.mkbd-row-group{grid-template-columns:22px minmax(0,1fr) 42px 76px}.mkbd-row-group .mkbd-row-ctrls{grid-column:1 / -1;justify-content:flex-end}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: MkbCombo, selector: "mkb-combo", inputs: ["label", "options", "value", "multiple", "placeholder"], outputs: ["valueChange", "valuesChange"] }, { kind: "component", type: MkbIcon, selector: "mkb-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2726
+ }
2727
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbPipelineEditor, decorators: [{
2728
+ type: Component,
2729
+ args: [{ selector: 'mkb-pipeline-editor', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, FormsModule, CdkDropList, CdkDrag, CdkDragHandle, MkbCombo, MkbIcon], template: `
2730
+ <!-- ======================= COLUNAS ======================= -->
2731
+ <ng-container
2732
+ *ngTemplateOutlet="axisEditor; context: { axis: store.columnsAxis(), key: 'columns' }"
2733
+ />
2734
+
2735
+ <!-- ======================== LANES ======================== -->
2736
+ <div class="mkbd-feature">
2737
+ <mkb-icon name="rows" />
2738
+ <div>
2739
+ <div class="mkbd-feature-title">Lanes (swimlanes)</div>
2740
+ <div class="mkbd-feature-desc">Agrupa cartões em faixas horizontais por um eixo</div>
2741
+ </div>
2742
+ <label class="mkbd-switch">
2743
+ <input
2744
+ type="checkbox"
2745
+ [ngModel]="!!store.lanesAxis()"
2746
+ (ngModelChange)="toggleLanes($event)"
2747
+ aria-label="Usar lanes"
2748
+ />
2749
+ </label>
2750
+ </div>
2751
+ @if (store.lanesAxis(); as lanes) {
2752
+ <ng-container *ngTemplateOutlet="axisEditor; context: { axis: lanes, key: 'lanes' }" />
2753
+ }
2754
+
2755
+ <!-- ================= EDITOR DE EIXO (template) ============ -->
2756
+ <ng-template #axisEditor let-axis="axis" let-key="key">
2757
+ <div class="mkbd-options">
2758
+ <mkb-combo
2759
+ label="Modo"
2760
+ [options]="modeOptions"
2761
+ [value]="axis.groups ? 'static' : 'derived'"
2762
+ (valueChange)="setAxisMode(key, $any($event))"
2763
+ />
2764
+ <label class="mkbd-field">
2765
+ <span class="mkbd-label">Campo do item</span>
2766
+ <input
2767
+ [ngModel]="axis.field ?? ''"
2768
+ (ngModelChange)="setAxisProp(key, 'field', $event || undefined)"
2769
+ [placeholder]="key === 'columns' ? 'column' : 'lane'"
2770
+ />
2771
+ </label>
2772
+ <mkb-combo
2773
+ label="Ordenar grupos"
2774
+ [options]="sortGroupOptions"
2775
+ [value]="axis.sortGroups ?? ''"
2776
+ (valueChange)="setAxisProp(key, 'sortGroups', $event || undefined)"
2777
+ />
2778
+ @if (axis.groups) {
2779
+ <label class="mkbd-switch mkbd-switch-boxed">
2780
+ <input
2781
+ type="checkbox"
2782
+ [ngModel]="axis.reorderable ?? false"
2783
+ (ngModelChange)="setAxisProp(key, 'reorderable', $event || undefined)"
2784
+ />
2785
+ Reordenável
2786
+ </label>
2787
+ }
2788
+ </div>
2789
+
2790
+ @if (axis.groups; as groups) {
2791
+ <div class="mkbd-section">
2792
+ <span class="mkbd-overline">{{ key === 'columns' ? 'Colunas' : 'Lanes' }}</span>
2793
+ <span class="mkbd-count">{{ groups.length }}</span>
2794
+ </div>
2795
+
2796
+ <div class="mkbd-rows" cdkDropList (cdkDropListDropped)="dropGroup(key, $event)">
2797
+ @for (group of groups; track $index; let i = $index) {
2798
+ <div
2799
+ class="mkbd-row mkbd-row-group"
2800
+ cdkDrag
2801
+ cdkDragLockAxis="y"
2802
+ [cdkDragPreviewClass]="'mkbd-drag-preview'"
2803
+ [style.--mkbd-accent]="groupColor(group, i)"
2804
+ >
2805
+ <span
2806
+ class="mkbd-handle"
2807
+ cdkDragHandle
2808
+ [attr.aria-label]="'Arrastar ' + (group.title ?? group.id)"
2809
+ >
2810
+ <mkb-icon name="drag" />
2811
+ </span>
2812
+
2813
+ <label class="mkbd-field mkbd-field-mono">
2814
+ <span class="mkbd-label">Id</span>
2815
+ <input [ngModel]="group.id" (ngModelChange)="setGroup(key, i, 'id', $event)" />
2816
+ </label>
2817
+
2818
+ <label class="mkbd-field">
2819
+ <span class="mkbd-label">Título</span>
2820
+ <input
2821
+ [ngModel]="group.title ?? ''"
2822
+ (ngModelChange)="setGroup(key, i, 'title', $event || undefined)"
2823
+ />
2824
+ </label>
2825
+
2826
+ <label class="mkbd-swatch" [title]="'Cor de ' + (group.title ?? group.id)">
2827
+ <input
2828
+ type="color"
2829
+ [ngModel]="groupColor(group, i)"
2830
+ (ngModelChange)="setGroupColor(key, i, $event)"
2831
+ [attr.aria-label]="'Cor de ' + (group.title ?? group.id)"
2832
+ />
2833
+ <span [style.background]="groupColor(group, i)"></span>
2834
+ </label>
2835
+
2836
+ <label class="mkbd-field mkbd-field-optional">
2837
+ <span class="mkbd-label">WIP</span>
2838
+ <input
2839
+ type="number"
2840
+ min="0"
2841
+ placeholder="∞"
2842
+ [ngModel]="group.limit ?? null"
2843
+ (ngModelChange)="setGroup(key, i, 'limit', $event === null || $event === '' ? undefined : +$event)"
2844
+ />
2845
+ </label>
2846
+
2847
+ <div class="mkbd-row-ctrls">
2848
+ <label class="mkbd-check">
2849
+ <input
2850
+ type="checkbox"
2851
+ [ngModel]="group.locked ?? false"
2852
+ (ngModelChange)="setGroup(key, i, 'locked', $event || undefined)"
2853
+ />
2854
+ Travado
2855
+ </label>
2856
+ <button
2857
+ class="mkbd-icon-btn"
2858
+ type="button"
2859
+ (click)="moveGroup(key, i, -1)"
2860
+ [disabled]="i === 0"
2861
+ aria-label="Mover para cima"
2862
+ >
2863
+ <mkb-icon name="up" />
2864
+ </button>
2865
+ <button
2866
+ class="mkbd-icon-btn"
2867
+ type="button"
2868
+ (click)="moveGroup(key, i, 1)"
2869
+ [disabled]="i === groups.length - 1"
2870
+ aria-label="Mover para baixo"
2871
+ >
2872
+ <mkb-icon name="down" />
2873
+ </button>
2874
+ <button
2875
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2876
+ type="button"
2877
+ (click)="removeGroup(key, i)"
2878
+ aria-label="Remover grupo"
2879
+ >
2880
+ <mkb-icon name="close" />
2881
+ </button>
2882
+ </div>
2883
+ </div>
2884
+ }
2885
+ </div>
2886
+
2887
+ <button class="mkbd-add" type="button" (click)="addGroup(key)">
2888
+ <mkb-icon name="add" />
2889
+ Adicionar {{ key === 'columns' ? 'coluna' : 'lane' }}
2890
+ </button>
2891
+ }
2892
+ </ng-template>
2893
+
2894
+ <!-- ======================= REGRAS ========================= -->
2895
+ <div class="mkbd-section">
2896
+ <span class="mkbd-overline">Regras de transição</span>
2897
+ @if (transitions().length) {
2898
+ <span class="mkbd-count">{{ transitions().length }}</span>
2899
+ }
2900
+ </div>
2901
+ <p class="mkbd-hint">
2902
+ Sem regras = qualquer transição é permitida. Com regras, só as listadas passam.
2903
+ </p>
2904
+
2905
+ @if (transitions().length) {
2906
+ <div class="mkbd-rows">
2907
+ @for (t of transitions(); track $index; let i = $index) {
2908
+ <div class="mkbd-row mkbd-row-rule">
2909
+ <mkb-combo
2910
+ label="De"
2911
+ [options]="fromOptions()"
2912
+ [value]="fromOf(t)"
2913
+ (valueChange)="setTransition(i, 'from', $event)"
2914
+ />
2915
+ <!-- Destino é multi-seleção: o valor vem da própria config (sem
2916
+ alocar array a cada ciclo, que foi o que travou a tela). -->
2917
+ <mkb-combo
2918
+ label="Para"
2919
+ [multiple]="true"
2920
+ placeholder="Qualquer"
2921
+ [options]="columnOptions()"
2922
+ [value]="t.to ?? null"
2923
+ (valuesChange)="setTransition(i, 'to', $event)"
2924
+ />
2925
+ <button
2926
+ class="mkbd-icon-btn mkbd-icon-btn-danger"
2927
+ type="button"
2928
+ (click)="removeTransition(i)"
2929
+ aria-label="Remover transição"
2930
+ >
2931
+ <mkb-icon name="close" />
2932
+ </button>
2933
+ </div>
2934
+ }
2935
+ </div>
2936
+ }
2937
+ <button class="mkbd-btn mkbd-btn-outline mkbd-btn-block" type="button" (click)="addTransition()">
2938
+ <mkb-icon name="add" />
2939
+ Adicionar transição
2940
+ </button>
2941
+
2942
+ <div class="mkbd-section">
2943
+ <span class="mkbd-overline">Regras nomeadas</span>
2944
+ </div>
2945
+ <p class="mkbd-hint">Os nomes referenciam código registrado pelo host no KanbanRegistry.</p>
2946
+ <div class="mkbd-stack">
2947
+ <label class="mkbd-field mkbd-field-grow">
2948
+ <span class="mkbd-label">Regras de cartão (rule:*)</span>
2949
+ <input
2950
+ [ngModel]="namesOf('rules')"
2951
+ (ngModelChange)="setNames('rules', $event)"
2952
+ placeholder="rule:berco-livre, rule:sla"
2953
+ />
2954
+ </label>
2955
+ <label class="mkbd-field mkbd-field-grow">
2956
+ <span class="mkbd-label">Regras de itens (entryRules)</span>
2957
+ <input [ngModel]="namesOf('entryRules')" (ngModelChange)="setNames('entryRules', $event)" />
2958
+ </label>
2959
+ </div>
2960
+
2961
+ <!-- ================== ORDENAÇÃO / GERAL ==================== -->
2962
+ <div class="mkbd-section">
2963
+ <span class="mkbd-overline">Ordenação e geral</span>
2964
+ </div>
2965
+ <div class="mkbd-stack">
2966
+ <label class="mkbd-switch mkbd-switch-boxed">
2967
+ <input type="checkbox" [ngModel]="!!config().sort" (ngModelChange)="toggleSort($event)" />
2968
+ Ordenar itens por campo
2969
+ </label>
2970
+ @if (config().sort; as sort) {
2971
+ <label class="mkbd-field">
2972
+ <span class="mkbd-label">Campo</span>
2973
+ <input [ngModel]="sort.field" (ngModelChange)="setSort('field', $event)" />
2974
+ </label>
2975
+ <mkb-combo
2976
+ label="Direção"
2977
+ [options]="directionOptions"
2978
+ [value]="sort.direction ?? 'asc'"
2979
+ (valueChange)="setSort('direction', $event)"
2980
+ />
2981
+ }
2982
+ <label class="mkbd-switch mkbd-switch-boxed">
2983
+ <input
2984
+ type="checkbox"
2985
+ [ngModel]="config().readOnly ?? false"
2986
+ (ngModelChange)="setReadOnly($event)"
2987
+ />
2988
+ Somente leitura
2989
+ </label>
2990
+ </div>
2991
+ `, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-row-group{grid-template-columns:22px minmax(0,1.1fr) minmax(0,1.3fr) 42px 76px auto}.mkbd-row-rule{grid-template-columns:minmax(0,1fr) minmax(0,1.6fr) auto;border-left-color:var(--mkbd-border-strong)}.mkbd-btn-block{margin-top:4px}.mkbd-combo-btn{flex:1;min-width:0;height:100%;padding:0 16px 0 0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-field-combo:has(.mkbd-combo-btn:focus-visible){border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-combo-empty{color:var(--mkbd-muted)}.mkbd-handle[cdkDragHandle]{cursor:grab;touch-action:none}.mkbd-row.cdk-drag-preview{box-shadow:var(--elevation-3, 0 8px 30px rgba(20, 22, 30, .14));opacity:.96}.mkbd-row.cdk-drag-placeholder{opacity:.35}.mkbd-rows.cdk-drop-list-dragging .mkbd-row:not(.cdk-drag-placeholder){transition:transform var(--mkbd-dur) var(--mkbd-ease)}@media(max-width:720px){.mkbd-row-group{grid-template-columns:22px minmax(0,1fr) 42px 76px}.mkbd-row-group .mkbd-row-ctrls{grid-column:1 / -1;justify-content:flex-end}}\n"] }]
2992
+ }] });
2993
+
2994
+ /**
2995
+ * Editor de TEMA: personaliza os tokens --mkb-* (espaçamento, cores, forma).
2996
+ * Só os tokens ALTERADOS entram na exportação (design JSON / CSS) — o resto
2997
+ * continua herdando os defaults de kanban-tokens.css e do DS do host.
2998
+ */
2999
+ class MkbThemeEditor {
3000
+ store = inject(DesignerStore);
3001
+ groups = TOKEN_GROUPS;
3002
+ valueOf(def) {
3003
+ return this.store.theme()[def.token] ?? def.default;
3004
+ }
3005
+ isChanged(def) {
3006
+ return def.token in this.store.theme();
3007
+ }
3008
+ /** Quantos tokens do grupo estão alterados (0 = não mostra contador). */
3009
+ changedIn(label) {
3010
+ const group = this.groups.find((g) => g.label === label);
3011
+ return group?.tokens.filter((t) => this.isChanged(t)).length ?? 0;
3012
+ }
3013
+ changedCount() {
3014
+ return Object.keys(this.store.theme()).length;
3015
+ }
3016
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbThemeEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
3017
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: MkbThemeEditor, isStandalone: true, selector: "mkb-theme-editor", ngImport: i0, template: `
3018
+ <p class="mkbd-hint">
3019
+ Só o que você ALTERAR entra na exportação; o resto herda o default do
3020
+ pacote e os tokens do Design System do host.
3021
+ </p>
3022
+
3023
+ @for (group of groups; track group.label) {
3024
+ <div class="mkbd-section">
3025
+ <span class="mkbd-overline">{{ group.label }}</span>
3026
+ @if (changedIn(group.label); as n) {
3027
+ <span class="mkbd-count">{{ n }}</span>
3028
+ }
3029
+ </div>
3030
+
3031
+ <div class="mkbd-tokens">
3032
+ @for (def of group.tokens; track def.token) {
3033
+ <div class="mkbd-token" [class.mkbd-token-changed]="isChanged(def)">
3034
+ @if (def.kind === 'color') {
3035
+ <label class="mkbd-swatch">
3036
+ <input
3037
+ type="color"
3038
+ [ngModel]="valueOf(def)"
3039
+ (ngModelChange)="store.setToken(def.token, $event)"
3040
+ [attr.aria-label]="def.label"
3041
+ />
3042
+ <span [style.background]="valueOf(def)"></span>
3043
+ </label>
3044
+ <span class="mkbd-token-text">
3045
+ <span class="mkbd-token-label">{{ def.label }}</span>
3046
+ <code>{{ def.token }}</code>
3047
+ </span>
3048
+ } @else {
3049
+ <label class="mkbd-field mkbd-field-grow">
3050
+ <span class="mkbd-label">{{ def.label }}</span>
3051
+ <input
3052
+ [ngModel]="valueOf(def)"
3053
+ (ngModelChange)="store.setToken(def.token, $event)"
3054
+ [placeholder]="def.default"
3055
+ />
3056
+ </label>
3057
+ <code class="mkbd-token-code">{{ def.token }}</code>
3058
+ }
3059
+
3060
+ <button
3061
+ class="mkbd-icon-btn"
3062
+ type="button"
3063
+ (click)="store.setToken(def.token, '')"
3064
+ [disabled]="!isChanged(def)"
3065
+ [attr.aria-label]="'Restaurar ' + def.label"
3066
+ >
3067
+ <mkb-icon name="reset" />
3068
+ </button>
3069
+ </div>
3070
+ }
3071
+ </div>
3072
+ }
3073
+
3074
+ <div class="mkbd-theme-actions">
3075
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="store.resetTheme()" [disabled]="!changedCount()">
3076
+ <mkb-icon name="reset" />
3077
+ Restaurar todos os defaults
3078
+ </button>
3079
+ <span class="mkbd-hint mkbd-theme-count">{{ changedCount() }} token(s) alterado(s)</span>
3080
+ </div>
3081
+ `, isInline: true, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-tokens{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px 16px}.mkbd-token{display:flex;align-items:center;gap:10px;padding:6px 8px;border:1px solid transparent;border-radius:var(--mkbd-radius-md);min-width:0}.mkbd-token-changed{border-color:var(--mkbd-primary-outline);background:var(--mkbd-primary-soft)}.mkbd-token-text{display:flex;flex-direction:column;min-width:0;gap:2px}.mkbd-token-label{font-size:12.5px}.mkbd-token code,.mkbd-token-code{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-muted-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mkbd-token-code{width:92px;flex:none}.mkbd-token>.mkbd-icon-btn{margin-left:auto}.mkbd-theme-actions{display:flex;align-items:center;gap:12px;margin-top:20px}.mkbd-theme-count{margin:0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MkbIcon, selector: "mkb-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3082
+ }
3083
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MkbThemeEditor, decorators: [{
3084
+ type: Component,
3085
+ args: [{ selector: 'mkb-theme-editor', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, MkbIcon], template: `
3086
+ <p class="mkbd-hint">
3087
+ Só o que você ALTERAR entra na exportação; o resto herda o default do
3088
+ pacote e os tokens do Design System do host.
3089
+ </p>
3090
+
3091
+ @for (group of groups; track group.label) {
3092
+ <div class="mkbd-section">
3093
+ <span class="mkbd-overline">{{ group.label }}</span>
3094
+ @if (changedIn(group.label); as n) {
3095
+ <span class="mkbd-count">{{ n }}</span>
3096
+ }
3097
+ </div>
3098
+
3099
+ <div class="mkbd-tokens">
3100
+ @for (def of group.tokens; track def.token) {
3101
+ <div class="mkbd-token" [class.mkbd-token-changed]="isChanged(def)">
3102
+ @if (def.kind === 'color') {
3103
+ <label class="mkbd-swatch">
3104
+ <input
3105
+ type="color"
3106
+ [ngModel]="valueOf(def)"
3107
+ (ngModelChange)="store.setToken(def.token, $event)"
3108
+ [attr.aria-label]="def.label"
3109
+ />
3110
+ <span [style.background]="valueOf(def)"></span>
3111
+ </label>
3112
+ <span class="mkbd-token-text">
3113
+ <span class="mkbd-token-label">{{ def.label }}</span>
3114
+ <code>{{ def.token }}</code>
3115
+ </span>
3116
+ } @else {
3117
+ <label class="mkbd-field mkbd-field-grow">
3118
+ <span class="mkbd-label">{{ def.label }}</span>
3119
+ <input
3120
+ [ngModel]="valueOf(def)"
3121
+ (ngModelChange)="store.setToken(def.token, $event)"
3122
+ [placeholder]="def.default"
3123
+ />
3124
+ </label>
3125
+ <code class="mkbd-token-code">{{ def.token }}</code>
3126
+ }
3127
+
3128
+ <button
3129
+ class="mkbd-icon-btn"
3130
+ type="button"
3131
+ (click)="store.setToken(def.token, '')"
3132
+ [disabled]="!isChanged(def)"
3133
+ [attr.aria-label]="'Restaurar ' + def.label"
3134
+ >
3135
+ <mkb-icon name="reset" />
3136
+ </button>
3137
+ </div>
3138
+ }
3139
+ </div>
3140
+ }
3141
+
3142
+ <div class="mkbd-theme-actions">
3143
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="store.resetTheme()" [disabled]="!changedCount()">
3144
+ <mkb-icon name="reset" />
3145
+ Restaurar todos os defaults
3146
+ </button>
3147
+ <span class="mkbd-hint mkbd-theme-count">{{ changedCount() }} token(s) alterado(s)</span>
3148
+ </div>
3149
+ `, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:block}.mkbd-tokens{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px 16px}.mkbd-token{display:flex;align-items:center;gap:10px;padding:6px 8px;border:1px solid transparent;border-radius:var(--mkbd-radius-md);min-width:0}.mkbd-token-changed{border-color:var(--mkbd-primary-outline);background:var(--mkbd-primary-soft)}.mkbd-token-text{display:flex;flex-direction:column;min-width:0;gap:2px}.mkbd-token-label{font-size:12.5px}.mkbd-token code,.mkbd-token-code{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-muted-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mkbd-token-code{width:92px;flex:none}.mkbd-token>.mkbd-icon-btn{margin-left:auto}.mkbd-theme-actions{display:flex;align-items:center;gap:12px;margin-top:20px}.mkbd-theme-count{margin:0}\n"] }]
3150
+ }] });
3151
+
3152
+ /**
3153
+ * Designer do Board — tela OPT-IN (entry point isolado
3154
+ * `@mosaicoo/kanban/designer`): edita visualmente o BoardConfig (pipeline,
3155
+ * cartão, dados, tema) com preview ao vivo e importa/exporta no formato que
3156
+ * o kanban consome em runtime.
3157
+ *
3158
+ * Visual: linguagem do Mosaicoo Design System (tela 13a dos Layouts). Os
3159
+ * tokens caem no DS do host quando embarcado — ver designer.css.
3160
+ */
3161
+ class MosKanbanDesigner {
3162
+ store = inject(DesignerStore);
3163
+ /** Config inicial (senão: rascunho salvo → default). */
3164
+ config = input(null, ...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
3165
+ /** Tema inicial (tokens alterados). */
3166
+ theme = input(null, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
3167
+ /** Registry do host — deixa o preview resolver rule:, icon: e format:. */
3168
+ registry = input(undefined, ...(ngDevMode ? [{ debugName: "registry" }] : /* istanbul ignore next */ []));
3169
+ /** Chave do rascunho automático em localStorage; '' desliga. */
3170
+ storageKey = input('mkb-designer-draft', ...(ngDevMode ? [{ debugName: "storageKey" }] : /* istanbul ignore next */ []));
3171
+ /** Config a cada mudança VÁLIDA (para persistência pelo host). */
3172
+ configChange = output();
3173
+ themeChange = output();
3174
+ importErrors = signal([], ...(ngDevMode ? [{ debugName: "importErrors" }] : /* istanbul ignore next */ []));
3175
+ initialized = false;
3176
+ constructor() {
3177
+ // Inicialização: input config > rascunho salvo > default do store.
3178
+ effect(() => {
3179
+ const config = this.config();
3180
+ const key = untracked(this.storageKey);
3181
+ if (!this.initialized) {
3182
+ this.initialized = true;
3183
+ if (config) {
3184
+ this.store.load(config, untracked(this.theme) ?? undefined);
3185
+ }
3186
+ else if (key) {
3187
+ this.store.loadDraft(key);
3188
+ }
3189
+ return;
3190
+ }
3191
+ if (config)
3192
+ this.store.load(config, untracked(this.theme) ?? undefined);
3193
+ });
3194
+ // Registry é referência viva (funções) — passa direto ao preview.
3195
+ effect(() => {
3196
+ this.store.registry = this.registry();
3197
+ });
3198
+ // Cada mudança válida: emite pro host + salva rascunho.
3199
+ effect(() => {
3200
+ const config = this.store.config();
3201
+ const theme = this.store.theme();
3202
+ if (!untracked(this.store.validation).valid)
3203
+ return;
3204
+ this.configChange.emit(config);
3205
+ this.themeChange.emit(theme);
3206
+ const key = untracked(this.storageKey);
3207
+ if (key)
3208
+ this.store.saveDraft(key);
3209
+ });
3210
+ }
3211
+ hasTheme() {
3212
+ return Object.keys(this.store.theme()).length > 0;
3213
+ }
3214
+ // ---- import / export -----------------------------------------------------------
3215
+ onImportFile(event) {
3216
+ const inputEl = event.target;
3217
+ const file = inputEl.files?.[0];
3218
+ inputEl.value = '';
3219
+ if (!file)
3220
+ return;
3221
+ file.text().then((text) => {
3222
+ const result = this.store.import(text);
3223
+ this.importErrors.set(result.ok ? [] : result.errors);
3224
+ });
3225
+ }
3226
+ applyJson(area) {
3227
+ const result = this.store.import(area.value);
3228
+ this.importErrors.set(result.ok ? [] : result.errors);
3229
+ // O textarea é editado pelo usuário, e o [value] só reescreve quando a
3230
+ // string ligada muda — sem isto ele fica com o texto digitado (design file
3231
+ // ou açúcar de eixo) em vez da config canônica que passou a valer.
3232
+ if (result.ok)
3233
+ area.value = this.store.exportConfigJson();
3234
+ }
3235
+ exportConfig() {
3236
+ this.download('board-config.json', this.store.exportConfigJson(), 'application/json');
3237
+ }
3238
+ exportDesign() {
3239
+ this.download('board-design.json', this.store.exportDesignJson(), 'application/json');
3240
+ }
3241
+ exportCss() {
3242
+ const css = this.store.exportThemeCss();
3243
+ if (css)
3244
+ this.download('kanban-theme.css', css, 'text/css');
3245
+ }
3246
+ clearDraft() {
3247
+ const key = this.storageKey();
3248
+ if (key)
3249
+ this.store.clearDraft(key);
3250
+ }
3251
+ download(name, content, mime) {
3252
+ const url = URL.createObjectURL(new Blob([content], { type: mime }));
3253
+ const a = document.createElement('a');
3254
+ a.href = url;
3255
+ a.download = name;
3256
+ a.click();
3257
+ URL.revokeObjectURL(url);
3258
+ }
3259
+ ngOnDestroy() {
3260
+ this.store.destroy();
3261
+ }
3262
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MosKanbanDesigner, deps: [], target: i0.ɵɵFactoryTarget.Component });
3263
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: MosKanbanDesigner, isStandalone: true, selector: "mos-kanban-designer", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, registry: { classPropertyName: "registry", publicName: "registry", isSignal: true, isRequired: false, transformFunction: null }, storageKey: { classPropertyName: "storageKey", publicName: "storageKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { configChange: "configChange", themeChange: "themeChange" }, providers: [DesignerStore], ngImport: i0, template: `
3264
+ <div class="mkbd-toolbar">
3265
+ <h2 class="mkbd-title">Designer do Board</h2>
3266
+ @if (store.errors().length; as count) {
3267
+ <span class="mkbd-chip mkbd-chip-error" role="status">
3268
+ <mkb-icon name="alert-circle" />
3269
+ {{ count }} erro(s)
3270
+ </span>
3271
+ } @else {
3272
+ <span class="mkbd-chip mkbd-chip-ok" role="status">
3273
+ <mkb-icon name="check-circle" />
3274
+ Config válida
3275
+ </span>
3276
+ }
3277
+
3278
+ <div class="mkbd-toolbar-actions">
3279
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="fileInput.click()">
3280
+ <mkb-icon name="upload" />
3281
+ Importar
3282
+ </button>
3283
+ <input
3284
+ #fileInput
3285
+ type="file"
3286
+ accept=".json,application/json"
3287
+ hidden
3288
+ (change)="onImportFile($event)"
3289
+ />
3290
+
3291
+ <button class="mkbd-btn mkbd-btn-tonal" type="button" [matMenuTriggerFor]="exportMenu">
3292
+ <mkb-icon name="download" />
3293
+ Exportar
3294
+ <mkb-icon name="expand" />
3295
+ </button>
3296
+ <mat-menu #exportMenu="matMenu">
3297
+ <button mat-menu-item type="button" (click)="exportConfig()">
3298
+ <span class="mkbd-menu-item">
3299
+ <strong>Exportar config</strong>
3300
+ <small>BoardConfig — o que o runtime consome</small>
3301
+ </span>
3302
+ </button>
3303
+ <button mat-menu-item type="button" (click)="exportDesign()">
3304
+ <span class="mkbd-menu-item">
3305
+ <strong>Exportar design</strong>
3306
+ <small>Config + tema, para reabrir aqui</small>
3307
+ </span>
3308
+ </button>
3309
+ <button mat-menu-item type="button" [disabled]="!hasTheme()" (click)="exportCss()">
3310
+ <span class="mkbd-menu-item">
3311
+ <strong>Exportar CSS</strong>
3312
+ <small>Só os tokens alterados</small>
3313
+ </span>
3314
+ </button>
3315
+ </mat-menu>
3316
+
3317
+ @if (storageKey()) {
3318
+ <span class="mkbd-toolbar-sep"></span>
3319
+ <button class="mkbd-btn mkbd-btn-danger" type="button" (click)="clearDraft()">
3320
+ <mkb-icon name="trash" />
3321
+ Limpar rascunho
3322
+ </button>
3323
+ }
3324
+ </div>
3325
+ </div>
3326
+
3327
+ @if (importErrors().length) {
3328
+ <div class="mkbd-banner" role="alert">
3329
+ <mkb-icon name="alert-circle" />
3330
+ <div>
3331
+ <strong>Importação rejeitada</strong>
3332
+ <ul>
3333
+ @for (issue of importErrors(); track $index) {
3334
+ <li><code>{{ issue.path }}</code> {{ issue.message }}</li>
3335
+ }
3336
+ </ul>
3337
+ </div>
3338
+ <button class="mkbd-icon-btn" type="button" (click)="importErrors.set([])" aria-label="Fechar aviso">
3339
+ <mkb-icon name="close" />
3340
+ </button>
3341
+ </div>
3342
+ }
3343
+
3344
+ <div class="mkbd-body">
3345
+ <div class="mkbd-editors">
3346
+ <mat-tab-group class="mkbd-tabs" stretchTabs="false" animationDuration="0ms">
3347
+ <mat-tab label="Pipeline">
3348
+ <div class="mkbd-pane"><mkb-pipeline-editor /></div>
3349
+ </mat-tab>
3350
+ <mat-tab label="Cartão">
3351
+ <div class="mkbd-pane"><mkb-card-editor /></div>
3352
+ </mat-tab>
3353
+ <mat-tab label="Dados">
3354
+ <div class="mkbd-pane"><mkb-data-editor /></div>
3355
+ </mat-tab>
3356
+ <mat-tab label="Tema">
3357
+ <div class="mkbd-pane"><mkb-theme-editor /></div>
3358
+ </mat-tab>
3359
+ <mat-tab label="JSON">
3360
+ <div class="mkbd-pane">
3361
+ <p class="mkbd-hint">
3362
+ BoardConfig ao vivo. Edite e aplique — inválido não substitui o design atual.
3363
+ </p>
3364
+ <textarea class="mkbd-json" rows="22" spellcheck="false" [value]="store.exportConfigJson()" #jsonArea></textarea>
3365
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="applyJson(jsonArea)">
3366
+ Aplicar JSON
3367
+ </button>
3368
+ </div>
3369
+ </mat-tab>
3370
+ </mat-tab-group>
3371
+ </div>
3372
+
3373
+ <div class="mkbd-preview">
3374
+ <div class="mkbd-preview-head">
3375
+ <mkb-icon name="eye" class="mkbd-preview-eye" />
3376
+ <span class="mkbd-overline">Preview ao vivo</span>
3377
+ @if (store.errors().length) {
3378
+ <span class="mkbd-hint mkbd-preview-note">mostrando a última config válida</span>
3379
+ }
3380
+ </div>
3381
+ @if (store.errors().length) {
3382
+ <ul class="mkbd-issues">
3383
+ @for (issue of store.errors(); track $index) {
3384
+ <li><code>{{ issue.path }}</code> {{ issue.message }}</li>
3385
+ }
3386
+ </ul>
3387
+ }
3388
+ <div class="mkbd-preview-board" [style]="store.themeStyle()">
3389
+ <mos-kanban-board [board]="store.previewBoard()" />
3390
+ </div>
3391
+ </div>
3392
+ </div>
3393
+ `, isInline: true, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--mkbd-surface)}.mkbd-toolbar{flex:none;display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:14px 20px 12px;background:var(--mkbd-panel);border-bottom:1px solid var(--mkbd-border-soft)}.mkbd-title{margin:0;font:500 17px var(--mkbd-font);letter-spacing:-.2px}.mkbd-toolbar-actions{margin-left:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap}.mkbd-toolbar-sep{width:1px;height:26px;background:var(--mkbd-border)}.mkbd-menu-item{display:flex;flex-direction:column;line-height:1.35}.mkbd-menu-item strong{font:500 13px var(--mkbd-font)}.mkbd-menu-item small{font-size:11px;color:var(--mkbd-muted)}.mkbd-banner{flex:none;display:flex;align-items:flex-start;gap:10px;margin:12px 20px 0;padding:12px 14px;border:1px solid var(--mkbd-error);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-error-container);color:var(--mkbd-error);font-size:12px}.mkbd-banner>mkb-icon{font-size:20px;margin-top:1px}.mkbd-banner ul{margin:4px 0 0;padding-left:18px}.mkbd-banner strong{font:500 13px var(--mkbd-font)}.mkbd-banner>.mkbd-icon-btn{margin-left:auto;color:inherit}.mkbd-body{display:flex;flex:1;min-height:0}.mkbd-editors{flex:1;display:flex;flex-direction:column;min-width:0;background:var(--mkbd-canvas);border-right:1px solid var(--mkbd-border)}.mkbd-pane{padding:18px 20px 28px}.mkbd-tabs{flex:1;min-height:0}.mkbd-tabs ::ng-deep .mat-mdc-tab-header{background:var(--mkbd-panel);padding:0 12px;flex:none;border-bottom:1px solid var(--mkbd-border-soft)}.mkbd-tabs ::ng-deep .mat-mdc-tab{min-width:0;padding:0 14px}.mkbd-tabs ::ng-deep .mdc-tab__text-label{font:500 13.5px var(--mkbd-font);letter-spacing:0;color:var(--mkbd-muted);transition:color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-tabs ::ng-deep .mdc-tab--active .mdc-tab__text-label{color:var(--mkbd-primary)}.mkbd-tabs ::ng-deep .mdc-tab-indicator__content--underline{border-top-width:3px;border-radius:3px 3px 0 0;border-color:var(--mkbd-primary)}.mkbd-tabs ::ng-deep .mat-mdc-tab-body-wrapper{flex:1;min-height:0}.mkbd-tabs ::ng-deep .mat-mdc-tab-body-content{overflow:auto}.mkbd-preview{flex:none;width:clamp(360px,42%,560px);display:flex;flex-direction:column;min-width:0;background:var(--mkbd-surface)}.mkbd-preview-head{flex:none;display:flex;align-items:center;gap:8px;padding:14px 18px 10px}.mkbd-preview-eye{font-size:16px;color:var(--mkbd-success)}.mkbd-preview-note{margin:0;text-transform:none}.mkbd-preview-board{flex:1;min-height:0;overflow:auto;padding:0 18px 16px}.mkbd-preview-board>mos-kanban-board{display:block;height:100%}.mkbd-issues{margin:0 18px 8px;padding:8px 12px 8px 26px;font-size:11.5px;color:var(--mkbd-error);background:var(--mkbd-error-container);border-radius:var(--mkbd-radius-md)}.mkbd-issues code,.mkbd-banner code{font-family:var(--mkbd-font-mono)}.mkbd-json{display:block;width:100%;margin-bottom:12px;padding:12px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel);color:var(--mkbd-fg);font:400 12px/1.5 var(--mkbd-font-mono);box-sizing:border-box;resize:vertical}.mkbd-json:focus-visible{outline:none;border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}::ng-deep .mat-mdc-menu-panel.mkbd-menu{min-width:176px;padding:6px;border:1px solid var(--color-border, #e6e8ee);border-radius:var(--radius-xl, 14px);background:var(--color-panel, #ffffff);box-shadow:var(--elevation-2, 0 1px 2px rgba(20, 22, 30, .1), 0 2px 6px rgba(20, 22, 30, .08))}::ng-deep .mkbd-menu .mat-mdc-menu-content{padding:0;max-height:285px;overflow-y:auto;overscroll-behavior:contain}::ng-deep .mkbd-menu .mkbd-menu-search{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:8px;padding:2px 4px 8px;background:var(--color-panel, #ffffff)}::ng-deep .mkbd-menu .mkbd-menu-search input{flex:1;min-width:0;height:34px;padding:0 10px;border:1px solid var(--color-border-strong, #c9cdd6);border-radius:var(--radius-sm, 8px);background:var(--color-panel, #ffffff);color:var(--color-foreground, #1e1f24);font:400 12.5px var(--font-sans, \"Roboto\", system-ui, sans-serif);outline:none}::ng-deep .mkbd-menu .mkbd-menu-search input:focus{border-color:var(--color-primary, #5e35b1);box-shadow:var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4))}::ng-deep .mkbd-menu .mkbd-menu-count{font:500 10px var(--font-mono, ui-monospace, monospace);color:var(--color-muted, #8b909c);padding-right:4px}::ng-deep .mkbd-menu .mkbd-menu-empty{margin:0;padding:10px;font-size:12px;color:var(--color-muted, #8b909c)}::ng-deep .mkbd-menu .mat-mdc-menu-item{display:flex;align-items:center;gap:12px;min-height:38px;padding:0 10px;border-radius:var(--radius-md, 10px);color:var(--color-secondary, #4a4d57);font:400 12.5px var(--font-sans, \"Roboto\", system-ui, sans-serif);letter-spacing:0}::ng-deep .mkbd-menu .mat-mdc-menu-item .mat-mdc-menu-item-text{font:inherit;display:flex;align-items:center;gap:10px}::ng-deep .mkbd-menu .mat-mdc-menu-item:hover:not([disabled]){background:color-mix(in srgb,var(--color-foreground, #1e1f24) 8%,transparent)}::ng-deep .mkbd-menu .mkbd-menu-item-active{background:var(--color-primary-container, #ede7f6);color:var(--color-on-primary-container, #2a1258);font-weight:500}::ng-deep .mkbd-menu .mat-mdc-menu-item[disabled]{color:var(--color-disabled-fg, #b3b7c1)}::ng-deep .mkbd-menu .mkbd-menu-item{display:flex;flex-direction:column;line-height:1.35}::ng-deep .mkbd-menu .mkbd-menu-item strong{font:500 13px var(--font-sans, sans-serif)}::ng-deep .mkbd-menu .mkbd-menu-item small{font-size:11px;color:var(--color-muted, #8b909c)}::ng-deep .mkbd-menu .mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none;border:1.5px solid var(--color-border-strong, #c9cdd6);border-radius:4px}::ng-deep .mkbd-menu .mkbd-menu-check-on{background:var(--color-primary, #5e35b1);border-color:var(--color-primary, #5e35b1)}::ng-deep .mkbd-menu .mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--color-on-primary, #ffffff);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}@media(max-width:900px){.mkbd-body{flex-direction:column}.mkbd-editors{border-right:none;border-bottom:1px solid var(--mkbd-border)}.mkbd-preview{width:auto;flex:1}}\n"], dependencies: [{ kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i1$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i1$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MkbIcon, selector: "mkb-icon", inputs: ["name"] }, { kind: "component", type: MosKanbanBoard, selector: "mos-kanban-board", inputs: ["board", "loading", "error", "showSearch", "itemActions"], outputs: ["itemClick", "itemMove", "moveRejected", "itemAction", "entryAction", "dragStarted", "dragEnded", "dragCanceled"] }, { kind: "component", type: MkbPipelineEditor, selector: "mkb-pipeline-editor" }, { kind: "component", type: MkbCardEditor, selector: "mkb-card-editor" }, { kind: "component", type: MkbDataEditor, selector: "mkb-data-editor" }, { kind: "component", type: MkbThemeEditor, selector: "mkb-theme-editor" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3394
+ }
3395
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: MosKanbanDesigner, decorators: [{
3396
+ type: Component,
3397
+ args: [{ selector: 'mos-kanban-designer', changeDetection: ChangeDetectionStrategy.OnPush, providers: [DesignerStore], imports: [
3398
+ MatTabsModule,
3399
+ MatMenuModule,
3400
+ MkbIcon,
3401
+ MosKanbanBoard,
3402
+ MkbPipelineEditor,
3403
+ MkbCardEditor,
3404
+ MkbDataEditor,
3405
+ MkbThemeEditor,
3406
+ ], template: `
3407
+ <div class="mkbd-toolbar">
3408
+ <h2 class="mkbd-title">Designer do Board</h2>
3409
+ @if (store.errors().length; as count) {
3410
+ <span class="mkbd-chip mkbd-chip-error" role="status">
3411
+ <mkb-icon name="alert-circle" />
3412
+ {{ count }} erro(s)
3413
+ </span>
3414
+ } @else {
3415
+ <span class="mkbd-chip mkbd-chip-ok" role="status">
3416
+ <mkb-icon name="check-circle" />
3417
+ Config válida
3418
+ </span>
3419
+ }
3420
+
3421
+ <div class="mkbd-toolbar-actions">
3422
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="fileInput.click()">
3423
+ <mkb-icon name="upload" />
3424
+ Importar
3425
+ </button>
3426
+ <input
3427
+ #fileInput
3428
+ type="file"
3429
+ accept=".json,application/json"
3430
+ hidden
3431
+ (change)="onImportFile($event)"
3432
+ />
3433
+
3434
+ <button class="mkbd-btn mkbd-btn-tonal" type="button" [matMenuTriggerFor]="exportMenu">
3435
+ <mkb-icon name="download" />
3436
+ Exportar
3437
+ <mkb-icon name="expand" />
3438
+ </button>
3439
+ <mat-menu #exportMenu="matMenu">
3440
+ <button mat-menu-item type="button" (click)="exportConfig()">
3441
+ <span class="mkbd-menu-item">
3442
+ <strong>Exportar config</strong>
3443
+ <small>BoardConfig — o que o runtime consome</small>
3444
+ </span>
3445
+ </button>
3446
+ <button mat-menu-item type="button" (click)="exportDesign()">
3447
+ <span class="mkbd-menu-item">
3448
+ <strong>Exportar design</strong>
3449
+ <small>Config + tema, para reabrir aqui</small>
3450
+ </span>
3451
+ </button>
3452
+ <button mat-menu-item type="button" [disabled]="!hasTheme()" (click)="exportCss()">
3453
+ <span class="mkbd-menu-item">
3454
+ <strong>Exportar CSS</strong>
3455
+ <small>Só os tokens alterados</small>
3456
+ </span>
3457
+ </button>
3458
+ </mat-menu>
3459
+
3460
+ @if (storageKey()) {
3461
+ <span class="mkbd-toolbar-sep"></span>
3462
+ <button class="mkbd-btn mkbd-btn-danger" type="button" (click)="clearDraft()">
3463
+ <mkb-icon name="trash" />
3464
+ Limpar rascunho
3465
+ </button>
3466
+ }
3467
+ </div>
3468
+ </div>
3469
+
3470
+ @if (importErrors().length) {
3471
+ <div class="mkbd-banner" role="alert">
3472
+ <mkb-icon name="alert-circle" />
3473
+ <div>
3474
+ <strong>Importação rejeitada</strong>
3475
+ <ul>
3476
+ @for (issue of importErrors(); track $index) {
3477
+ <li><code>{{ issue.path }}</code> {{ issue.message }}</li>
3478
+ }
3479
+ </ul>
3480
+ </div>
3481
+ <button class="mkbd-icon-btn" type="button" (click)="importErrors.set([])" aria-label="Fechar aviso">
3482
+ <mkb-icon name="close" />
3483
+ </button>
3484
+ </div>
3485
+ }
3486
+
3487
+ <div class="mkbd-body">
3488
+ <div class="mkbd-editors">
3489
+ <mat-tab-group class="mkbd-tabs" stretchTabs="false" animationDuration="0ms">
3490
+ <mat-tab label="Pipeline">
3491
+ <div class="mkbd-pane"><mkb-pipeline-editor /></div>
3492
+ </mat-tab>
3493
+ <mat-tab label="Cartão">
3494
+ <div class="mkbd-pane"><mkb-card-editor /></div>
3495
+ </mat-tab>
3496
+ <mat-tab label="Dados">
3497
+ <div class="mkbd-pane"><mkb-data-editor /></div>
3498
+ </mat-tab>
3499
+ <mat-tab label="Tema">
3500
+ <div class="mkbd-pane"><mkb-theme-editor /></div>
3501
+ </mat-tab>
3502
+ <mat-tab label="JSON">
3503
+ <div class="mkbd-pane">
3504
+ <p class="mkbd-hint">
3505
+ BoardConfig ao vivo. Edite e aplique — inválido não substitui o design atual.
3506
+ </p>
3507
+ <textarea class="mkbd-json" rows="22" spellcheck="false" [value]="store.exportConfigJson()" #jsonArea></textarea>
3508
+ <button class="mkbd-btn mkbd-btn-outline" type="button" (click)="applyJson(jsonArea)">
3509
+ Aplicar JSON
3510
+ </button>
3511
+ </div>
3512
+ </mat-tab>
3513
+ </mat-tab-group>
3514
+ </div>
3515
+
3516
+ <div class="mkbd-preview">
3517
+ <div class="mkbd-preview-head">
3518
+ <mkb-icon name="eye" class="mkbd-preview-eye" />
3519
+ <span class="mkbd-overline">Preview ao vivo</span>
3520
+ @if (store.errors().length) {
3521
+ <span class="mkbd-hint mkbd-preview-note">mostrando a última config válida</span>
3522
+ }
3523
+ </div>
3524
+ @if (store.errors().length) {
3525
+ <ul class="mkbd-issues">
3526
+ @for (issue of store.errors(); track $index) {
3527
+ <li><code>{{ issue.path }}</code> {{ issue.message }}</li>
3528
+ }
3529
+ </ul>
3530
+ }
3531
+ <div class="mkbd-preview-board" [style]="store.themeStyle()">
3532
+ <mos-kanban-board [board]="store.previewBoard()" />
3533
+ </div>
3534
+ </div>
3535
+ </div>
3536
+ `, styles: [":host{--mkbd-primary: var(--color-primary, #5e35b1);--mkbd-on-primary: var(--color-on-primary, #ffffff);--mkbd-primary-container: var(--color-primary-container, #ede7f6);--mkbd-primary-soft: color-mix(in srgb, var(--mkbd-primary) 8%, transparent);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 28%, #ffffff);--mkbd-surface: var(--color-surface, #f4f5f7);--mkbd-panel: var(--color-panel, #ffffff);--mkbd-panel-2: var(--color-panel-2, #f6f7f9);--mkbd-panel-3: var(--color-panel-3, #f1f2f5);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 70%, var(--mkbd-surface));--mkbd-border: var(--color-border, #e6e8ee);--mkbd-border-soft: var(--color-border-soft, #eef0f4);--mkbd-border-strong: var(--color-border-strong, #c9cdd6);--mkbd-fg: var(--color-foreground, #1e1f24);--mkbd-secondary: var(--color-secondary, #4a4d57);--mkbd-muted: var(--color-muted, #8b909c);--mkbd-muted-2: var(--color-muted-2, #a2a7b2);--mkbd-disabled: var(--color-disabled-fg, #b3b7c1);--mkbd-success: var(--color-success, #2e7d32);--mkbd-success-container: var(--color-success-container, #e8f5e9);--mkbd-error: var(--color-error-text, #c62828);--mkbd-error-container: var(--color-error-container, #fdecea);--mkbd-warning-text: var(--color-warning-text, #b76e00);--mkbd-warning-container: var(--color-warning-container, #fff4e0);--mkbd-radius-sm: var(--radius-sm, 8px);--mkbd-radius-md: var(--radius-md, 10px);--mkbd-radius-lg: var(--radius-lg, 12px);--mkbd-radius-pill: var(--radius-pill, 999px);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(20, 22, 30, .1));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4));--mkbd-dur: var(--dur-fast, .12s);--mkbd-ease: var(--ease-standard, cubic-bezier(.2, 0, 0, 1));--mkbd-font: var(--font-sans, \"Roboto\", system-ui, -apple-system, \"Segoe UI\", sans-serif);--mkbd-font-mono: var(--font-mono, \"Roboto Mono\", ui-monospace, \"SFMono-Regular\", Menlo, monospace);font-family:var(--mkbd-font);color:var(--mkbd-fg)}:host-context([data-theme=\"dark\"]){--mkbd-primary: var(--color-primary, #b39ddb);--mkbd-on-primary: var(--color-on-primary, #2a1258);--mkbd-primary-container: var(--color-primary-container, #4b3b80);--mkbd-primary-outline: color-mix(in srgb, var(--mkbd-primary) 40%, transparent);--mkbd-surface: var(--color-surface, #0e1116);--mkbd-panel: var(--color-panel, #14171d);--mkbd-panel-2: var(--color-panel-2, #1b1f27);--mkbd-panel-3: var(--color-panel-3, #222732);--mkbd-canvas: color-mix(in srgb, var(--mkbd-panel) 60%, var(--mkbd-surface));--mkbd-border: var(--color-border, #262b34);--mkbd-border-soft: var(--color-border-soft, #1e232b);--mkbd-border-strong: var(--color-border-strong, #3a4048);--mkbd-fg: var(--color-foreground, #e6e9ef);--mkbd-secondary: var(--color-secondary, #c2c7d0);--mkbd-muted: var(--color-muted, #9aa3b2);--mkbd-muted-2: var(--color-muted-2, #7c8494);--mkbd-disabled: var(--color-disabled-fg, #59606c);--mkbd-success: var(--color-success, #81c784);--mkbd-success-container: var(--color-success-container, #1e3a24);--mkbd-error: var(--color-error-text, #ef9a9a);--mkbd-error-container: var(--color-error-container, #3a1e1e);--mkbd-warning-text: var(--color-warning-text, #ffb74d);--mkbd-warning-container: var(--color-warning-container, #3a2c10);--mkbd-elevation-1: var(--elevation-1, 0 1px 3px rgba(0, 0, 0, .4));--mkbd-focus-ring: var(--focus-ring, 0 0 0 3px rgba(179, 157, 219, .55))}.mkbd-overline{font:500 11px var(--mkbd-font-mono);letter-spacing:.5px;text-transform:uppercase;color:var(--mkbd-muted)}.mkbd-hint{margin:0 0 10px;font-size:12px;line-height:1.45;color:var(--mkbd-muted)}.mkbd-section{display:flex;align-items:center;gap:8px;margin:22px 0 12px}.mkbd-section:first-child{margin-top:0}.mkbd-section:after{content:\"\";flex:1;height:1px;background:var(--mkbd-border-soft)}.mkbd-count{font:500 10px var(--mkbd-font-mono);color:var(--mkbd-primary);background:var(--mkbd-primary-container);padding:2px 8px;border-radius:var(--mkbd-radius-pill)}.mkbd-btn{display:inline-flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:var(--mkbd-radius-md);border:1px solid transparent;background:transparent;font:500 12.5px var(--mkbd-font);color:var(--mkbd-secondary);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-btn-outline{border-color:var(--mkbd-primary-outline);background:var(--mkbd-panel);color:var(--mkbd-primary)}.mkbd-btn-outline:hover:not(:disabled){background:var(--mkbd-primary-soft)}.mkbd-btn-tonal{background:var(--mkbd-primary-container);color:var(--mkbd-primary)}.mkbd-btn-tonal:hover:not(:disabled){background:color-mix(in srgb,var(--mkbd-primary) 16%,var(--mkbd-panel))}.mkbd-btn-tonal:disabled{background:var(--mkbd-panel-3)}.mkbd-btn-text:hover:not(:disabled){background:var(--mkbd-panel-3)}.mkbd-btn-danger{color:var(--mkbd-error)}.mkbd-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container)}.mkbd-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:7px;background:transparent;color:var(--mkbd-muted);font-size:19px;cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-icon-btn:hover:not(:disabled){background:var(--mkbd-panel-3);color:var(--mkbd-secondary)}.mkbd-icon-btn:disabled{color:var(--mkbd-disabled);cursor:default}.mkbd-icon-btn:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-icon-btn-danger{color:color-mix(in srgb,var(--mkbd-error) 45%,var(--mkbd-muted))}.mkbd-icon-btn-danger:hover:not(:disabled){background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:44px;margin-top:12px;border:1.5px dashed var(--mkbd-border-strong);border-radius:var(--mkbd-radius-lg);background:transparent;color:var(--mkbd-primary);font:500 13px var(--mkbd-font);cursor:pointer;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-add:hover{background:var(--mkbd-primary-soft);border-color:var(--mkbd-primary)}.mkbd-add:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 11px;border-radius:var(--mkbd-radius-pill);font:500 11px var(--mkbd-font);white-space:nowrap}.mkbd-chip-ok{background:var(--mkbd-success-container);color:var(--mkbd-success)}.mkbd-chip-error{background:var(--mkbd-error-container);color:var(--mkbd-error)}.mkbd-field{position:relative;display:flex;align-items:center;min-width:0;height:40px;padding:0 10px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field>.mkbd-label{position:absolute;top:-6px;left:8px;padding:0 4px;background:var(--mkbd-label-bg, var(--mkbd-panel));font-size:9.5px;line-height:1;color:var(--mkbd-muted);pointer-events:none;white-space:nowrap}.mkbd-field input,.mkbd-field select,.mkbd-field textarea{width:100%;min-width:0;border:none;outline:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);padding:0}.mkbd-field input::placeholder{color:var(--mkbd-disabled)}.mkbd-field select{appearance:none;cursor:pointer;padding-right:18px}.mkbd-field-select:after{content:\"\";position:absolute;right:12px;width:8px;height:8px;border-right:1.6px solid var(--mkbd-muted);border-bottom:1.6px solid var(--mkbd-muted);transform:translateY(-2px) rotate(45deg);pointer-events:none}.mkbd-field:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-field-mono input{font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-grow{flex:1}.mkbd-field-optional{border-style:dashed;border-color:var(--mkbd-border);background:var(--mkbd-panel-2)}.mkbd-field-optional>.mkbd-label{background:var(--mkbd-panel-2);color:var(--mkbd-muted-2)}.mkbd-field-optional input{text-align:center;font-family:var(--mkbd-font-mono);font-weight:500}.mkbd-field-optional:focus-within{border-style:solid;background:var(--mkbd-panel)}.mkbd-field-optional:focus-within>.mkbd-label{background:var(--mkbd-panel)}.mkbd-field textarea{height:100%;padding:8px 0;resize:vertical;font-family:var(--mkbd-font-mono);font-size:12px;line-height:1.5}.mkbd-field-area{height:auto;align-items:stretch;padding:2px 10px}.mkbd-check{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--mkbd-muted);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.mkbd-check input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;background:var(--mkbd-panel);cursor:pointer;position:relative;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease),border-color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-check input:checked{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-check input:checked:after{content:\"\";position:absolute;left:4.5px;top:1px;width:4px;height:8px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}.mkbd-check input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-check:has(input:checked){color:var(--mkbd-primary);font-weight:500}.mkbd-switch{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;color:var(--mkbd-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.mkbd-switch input{appearance:none;position:relative;width:38px;height:22px;margin:0;border-radius:var(--mkbd-radius-pill);background:var(--mkbd-border-strong);cursor:pointer;flex:none;transition:background var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:after{content:\"\";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--mkbd-panel);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-switch input:checked{background:var(--mkbd-primary)}.mkbd-switch input:checked:after{transform:translate(16px)}.mkbd-switch input:focus-visible{outline:none;box-shadow:var(--mkbd-focus-ring)}.mkbd-switch-boxed{height:40px;padding:0 14px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel)}.mkbd-swatch{position:relative;display:inline-flex;align-items:center;justify-content:center;width:42px;height:40px;padding:0;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-sm);background:var(--mkbd-panel);cursor:pointer;overflow:hidden}.mkbd-swatch input{position:absolute;inset:0;opacity:0;cursor:pointer}.mkbd-swatch span{width:20px;height:20px;border-radius:5px;box-shadow:inset 0 0 0 1px #0000001f}.mkbd-swatch:focus-within{border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}.mkbd-rows{display:flex;flex-direction:column;gap:10px}.mkbd-row{display:grid;align-items:center;gap:10px;padding:12px 12px 12px 8px;border:1px solid var(--mkbd-border);border-left:4px solid var(--mkbd-accent, var(--mkbd-border-strong));border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel);transition:border-color var(--mkbd-dur) var(--mkbd-ease),box-shadow var(--mkbd-dur) var(--mkbd-ease)}.mkbd-row-selected{border-color:var(--mkbd-primary);border-width:1.5px;padding:11.5px 11.5px 11.5px 7.5px;box-shadow:0 0 0 3px var(--mkbd-primary-soft)}.mkbd-handle{display:inline-flex;align-items:center;justify-content:center;color:var(--mkbd-disabled);font-size:19px;cursor:grab}.mkbd-row-ctrls{display:flex;align-items:center;gap:2px}.mkbd-feature{display:flex;align-items:center;gap:12px;margin-top:22px;padding:14px 16px;border:1px solid var(--mkbd-border);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-panel)}.mkbd-feature>mkb-icon{font-size:20px;color:var(--mkbd-primary)}.mkbd-feature-title{font-weight:500;font-size:13.5px}.mkbd-feature-desc{font-size:11.5px;color:var(--mkbd-muted)}.mkbd-feature>.mkbd-switch{margin-left:auto}.mkbd-options{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}.mkbd-options,.mkbd-stack,.mkbd-new-block{--mkbd-label-bg: var(--mkbd-canvas)}.mkbd-options>.mkbd-field,.mkbd-options>mkb-combo{flex:1;min-width:150px}.mkbd-stack{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:center}.mkbd-stack .mkbd-field,.mkbd-stack mkb-combo{width:190px}.mkbd-stack .mkbd-field-sm,.mkbd-stack mkb-combo.mkbd-field-sm{width:130px}.mkbd-stack .mkbd-field-grow,.mkbd-stack mkb-combo.mkbd-field-grow{flex:1;min-width:220px;width:auto}.mkbd-stack .mkbd-field-full{flex:1 0 100%;width:auto}.mkbd-combo-btn{display:flex;align-items:center;gap:6px;flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;color:inherit;font:400 12.5px var(--mkbd-font);text-align:left;cursor:pointer}.mkbd-combo-btn:focus-visible{outline:none}.mkbd-combo-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mkbd-combo-empty{color:var(--mkbd-disabled)}.mkbd-combo-caret{font-size:18px;color:var(--mkbd-muted);transition:transform var(--mkbd-dur) var(--mkbd-ease)}.mkbd-field-combo:focus-within{border-color:var(--mkbd-primary);border-width:1.5px;padding:0 9.5px}.mkbd-field-combo:focus-within>.mkbd-label{color:var(--mkbd-primary)}.mkbd-combo-open .mkbd-combo-caret{transform:rotate(180deg)}.mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:10px;border:1.5px solid var(--mkbd-border-strong);border-radius:4px;flex:none}.mkbd-menu-check-on{background:var(--mkbd-primary);border-color:var(--mkbd-primary)}.mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--mkbd-on-primary);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}\n", ":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--mkbd-surface)}.mkbd-toolbar{flex:none;display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:14px 20px 12px;background:var(--mkbd-panel);border-bottom:1px solid var(--mkbd-border-soft)}.mkbd-title{margin:0;font:500 17px var(--mkbd-font);letter-spacing:-.2px}.mkbd-toolbar-actions{margin-left:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap}.mkbd-toolbar-sep{width:1px;height:26px;background:var(--mkbd-border)}.mkbd-menu-item{display:flex;flex-direction:column;line-height:1.35}.mkbd-menu-item strong{font:500 13px var(--mkbd-font)}.mkbd-menu-item small{font-size:11px;color:var(--mkbd-muted)}.mkbd-banner{flex:none;display:flex;align-items:flex-start;gap:10px;margin:12px 20px 0;padding:12px 14px;border:1px solid var(--mkbd-error);border-radius:var(--mkbd-radius-lg);background:var(--mkbd-error-container);color:var(--mkbd-error);font-size:12px}.mkbd-banner>mkb-icon{font-size:20px;margin-top:1px}.mkbd-banner ul{margin:4px 0 0;padding-left:18px}.mkbd-banner strong{font:500 13px var(--mkbd-font)}.mkbd-banner>.mkbd-icon-btn{margin-left:auto;color:inherit}.mkbd-body{display:flex;flex:1;min-height:0}.mkbd-editors{flex:1;display:flex;flex-direction:column;min-width:0;background:var(--mkbd-canvas);border-right:1px solid var(--mkbd-border)}.mkbd-pane{padding:18px 20px 28px}.mkbd-tabs{flex:1;min-height:0}.mkbd-tabs ::ng-deep .mat-mdc-tab-header{background:var(--mkbd-panel);padding:0 12px;flex:none;border-bottom:1px solid var(--mkbd-border-soft)}.mkbd-tabs ::ng-deep .mat-mdc-tab{min-width:0;padding:0 14px}.mkbd-tabs ::ng-deep .mdc-tab__text-label{font:500 13.5px var(--mkbd-font);letter-spacing:0;color:var(--mkbd-muted);transition:color var(--mkbd-dur) var(--mkbd-ease)}.mkbd-tabs ::ng-deep .mdc-tab--active .mdc-tab__text-label{color:var(--mkbd-primary)}.mkbd-tabs ::ng-deep .mdc-tab-indicator__content--underline{border-top-width:3px;border-radius:3px 3px 0 0;border-color:var(--mkbd-primary)}.mkbd-tabs ::ng-deep .mat-mdc-tab-body-wrapper{flex:1;min-height:0}.mkbd-tabs ::ng-deep .mat-mdc-tab-body-content{overflow:auto}.mkbd-preview{flex:none;width:clamp(360px,42%,560px);display:flex;flex-direction:column;min-width:0;background:var(--mkbd-surface)}.mkbd-preview-head{flex:none;display:flex;align-items:center;gap:8px;padding:14px 18px 10px}.mkbd-preview-eye{font-size:16px;color:var(--mkbd-success)}.mkbd-preview-note{margin:0;text-transform:none}.mkbd-preview-board{flex:1;min-height:0;overflow:auto;padding:0 18px 16px}.mkbd-preview-board>mos-kanban-board{display:block;height:100%}.mkbd-issues{margin:0 18px 8px;padding:8px 12px 8px 26px;font-size:11.5px;color:var(--mkbd-error);background:var(--mkbd-error-container);border-radius:var(--mkbd-radius-md)}.mkbd-issues code,.mkbd-banner code{font-family:var(--mkbd-font-mono)}.mkbd-json{display:block;width:100%;margin-bottom:12px;padding:12px;border:1px solid var(--mkbd-border-strong);border-radius:var(--mkbd-radius-md);background:var(--mkbd-panel);color:var(--mkbd-fg);font:400 12px/1.5 var(--mkbd-font-mono);box-sizing:border-box;resize:vertical}.mkbd-json:focus-visible{outline:none;border-color:var(--mkbd-primary);box-shadow:var(--mkbd-focus-ring)}::ng-deep .mat-mdc-menu-panel.mkbd-menu{min-width:176px;padding:6px;border:1px solid var(--color-border, #e6e8ee);border-radius:var(--radius-xl, 14px);background:var(--color-panel, #ffffff);box-shadow:var(--elevation-2, 0 1px 2px rgba(20, 22, 30, .1), 0 2px 6px rgba(20, 22, 30, .08))}::ng-deep .mkbd-menu .mat-mdc-menu-content{padding:0;max-height:285px;overflow-y:auto;overscroll-behavior:contain}::ng-deep .mkbd-menu .mkbd-menu-search{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:8px;padding:2px 4px 8px;background:var(--color-panel, #ffffff)}::ng-deep .mkbd-menu .mkbd-menu-search input{flex:1;min-width:0;height:34px;padding:0 10px;border:1px solid var(--color-border-strong, #c9cdd6);border-radius:var(--radius-sm, 8px);background:var(--color-panel, #ffffff);color:var(--color-foreground, #1e1f24);font:400 12.5px var(--font-sans, \"Roboto\", system-ui, sans-serif);outline:none}::ng-deep .mkbd-menu .mkbd-menu-search input:focus{border-color:var(--color-primary, #5e35b1);box-shadow:var(--focus-ring, 0 0 0 3px rgba(94, 53, 177, .4))}::ng-deep .mkbd-menu .mkbd-menu-count{font:500 10px var(--font-mono, ui-monospace, monospace);color:var(--color-muted, #8b909c);padding-right:4px}::ng-deep .mkbd-menu .mkbd-menu-empty{margin:0;padding:10px;font-size:12px;color:var(--color-muted, #8b909c)}::ng-deep .mkbd-menu .mat-mdc-menu-item{display:flex;align-items:center;gap:12px;min-height:38px;padding:0 10px;border-radius:var(--radius-md, 10px);color:var(--color-secondary, #4a4d57);font:400 12.5px var(--font-sans, \"Roboto\", system-ui, sans-serif);letter-spacing:0}::ng-deep .mkbd-menu .mat-mdc-menu-item .mat-mdc-menu-item-text{font:inherit;display:flex;align-items:center;gap:10px}::ng-deep .mkbd-menu .mat-mdc-menu-item:hover:not([disabled]){background:color-mix(in srgb,var(--color-foreground, #1e1f24) 8%,transparent)}::ng-deep .mkbd-menu .mkbd-menu-item-active{background:var(--color-primary-container, #ede7f6);color:var(--color-on-primary-container, #2a1258);font-weight:500}::ng-deep .mkbd-menu .mat-mdc-menu-item[disabled]{color:var(--color-disabled-fg, #b3b7c1)}::ng-deep .mkbd-menu .mkbd-menu-item{display:flex;flex-direction:column;line-height:1.35}::ng-deep .mkbd-menu .mkbd-menu-item strong{font:500 13px var(--font-sans, sans-serif)}::ng-deep .mkbd-menu .mkbd-menu-item small{font-size:11px;color:var(--color-muted, #8b909c)}::ng-deep .mkbd-menu .mkbd-menu-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none;border:1.5px solid var(--color-border-strong, #c9cdd6);border-radius:4px}::ng-deep .mkbd-menu .mkbd-menu-check-on{background:var(--color-primary, #5e35b1);border-color:var(--color-primary, #5e35b1)}::ng-deep .mkbd-menu .mkbd-menu-check-on:after{content:\"\";width:4px;height:8px;margin-top:-2px;border:solid var(--color-on-primary, #ffffff);border-width:0 1.8px 1.8px 0;transform:rotate(45deg)}@media(max-width:900px){.mkbd-body{flex-direction:column}.mkbd-editors{border-right:none;border-bottom:1px solid var(--mkbd-border)}.mkbd-preview{width:auto;flex:1}}\n"] }]
3537
+ }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], registry: [{ type: i0.Input, args: [{ isSignal: true, alias: "registry", required: false }] }], storageKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "storageKey", required: false }] }], configChange: [{ type: i0.Output, args: ["configChange"] }], themeChange: [{ type: i0.Output, args: ["themeChange"] }] } });
3538
+
3539
+ /**
3540
+ * @mosaicoo/kanban/designer — tela OPT-IN de design do board.
3541
+ *
3542
+ * Entry point ISOLADO: só quem importa daqui paga por @angular/material e
3543
+ * @angular/forms (peers opcionais). O runtime (ui/adapters/core) não depende
3544
+ * de nada deste entry point.
3545
+ */
3546
+
3547
+ /**
3548
+ * Generated bundle index. Do not edit.
3549
+ */
3550
+
3551
+ export { BLOCK_FIELDS, BLOCK_TYPE_LABELS, DesignerStore, MosKanbanDesigner, TOKEN_GROUPS };