@inchurch/matcha-theme 22.38.2 → 22.38.3
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.
- package/abstracts/_colors.scss +291 -291
- package/abstracts/_elevation.scss +108 -108
- package/abstracts/_functions.scss +321 -321
- package/abstracts/_media-breakpoint.scss +26 -26
- package/abstracts/_theme-api.scss +224 -224
- package/abstracts/_typography.scss +128 -128
- package/base/_reset.scss +487 -487
- package/components/app-page-header.scss +260 -260
- package/components/matcha-accordion.scss +297 -297
- package/components/matcha-audio-player.scss +31 -31
- package/components/matcha-autocomplete.scss +145 -145
- package/components/matcha-avatar.scss +426 -426
- package/components/matcha-badge.scss +120 -120
- package/components/matcha-breadcrumb.scss +231 -231
- package/components/matcha-button-toggle.scss +484 -484
- package/components/matcha-buttons.scss +973 -973
- package/components/matcha-calendar.scss +253 -253
- package/components/matcha-cards.scss +212 -212
- package/components/matcha-chart-card.scss +53 -53
- package/components/matcha-checkbox.scss +266 -266
- package/components/matcha-chip.scss +311 -311
- package/components/matcha-color-pick.scss +34 -34
- package/components/matcha-command-palette.scss +316 -316
- package/components/matcha-crop.scss +419 -419
- package/components/matcha-date.scss +81 -81
- package/components/matcha-divider.scss +100 -100
- package/components/matcha-draggable.scss +23 -23
- package/components/matcha-drawer.scss +376 -376
- package/components/matcha-drop-image.scss +14 -14
- package/components/matcha-drop-list.scss +430 -430
- package/components/matcha-emoji.scss +69 -69
- package/components/matcha-empty-state.scss +230 -230
- package/components/matcha-file-uploader.scss +650 -637
- package/components/matcha-flag.scss +103 -103
- package/components/matcha-footer.scss +91 -91
- package/components/matcha-form-field.scss +883 -883
- package/components/matcha-form-section.scss +100 -100
- package/components/matcha-header.scss +135 -135
- package/components/matcha-highlight.scss +164 -164
- package/components/matcha-hint-text.scss +90 -90
- package/components/matcha-horizontal-tree.scss +247 -247
- package/components/matcha-icon.scss +111 -111
- package/components/matcha-image.scss +60 -60
- package/components/matcha-list.scss +211 -211
- package/components/matcha-menu.scss +99 -99
- package/components/matcha-modal.scss +210 -210
- package/components/matcha-nav.scss +770 -770
- package/components/matcha-notification.scss +417 -417
- package/components/matcha-option.scss +170 -170
- package/components/matcha-page-builder.scss +4196 -4196
- package/components/matcha-paginator.scss +699 -699
- package/components/matcha-panel.scss +216 -216
- package/components/matcha-period.scss +174 -174
- package/components/matcha-profile-card.scss +50 -50
- package/components/matcha-progress-bar.scss +355 -355
- package/components/matcha-radio.scss +325 -325
- package/components/matcha-ripple.scss +7 -7
- package/components/matcha-scrollbar.scss +33 -33
- package/components/matcha-scrollbox-shadow.scss +120 -120
- package/components/matcha-section.scss +102 -102
- package/components/matcha-select-multiple.scss +56 -56
- package/components/matcha-select.scss +629 -629
- package/components/matcha-skeleton.scss +182 -182
- package/components/matcha-slide-toggle.scss +369 -369
- package/components/matcha-slider.scss +285 -285
- package/components/matcha-snack-bar.scss +259 -259
- package/components/matcha-spin.scss +164 -164
- package/components/matcha-spinner.scss +97 -97
- package/components/matcha-stepper.scss +376 -376
- package/components/matcha-table-cell.scss +107 -107
- package/components/matcha-table.scss +722 -722
- package/components/matcha-tabs.scss +642 -642
- package/components/matcha-text-editor.scss +111 -111
- package/components/matcha-time.scss +33 -33
- package/components/matcha-timepicker.scss +13 -13
- package/components/matcha-toolbar.scss +366 -366
- package/components/matcha-tooltip.scss +235 -235
- package/components/matcha-tree-view.scss +636 -636
- package/layout/matcha-page-layout.scss +778 -778
- package/main.scss +334 -334
- package/package.json +1 -1
- package/tokens/_animations-tokens.scss +37 -37
- package/tokens/_breakpoints-tokens.scss +35 -35
- package/tokens/_color-tokens.scss +288 -288
- package/tokens/_elevation-tokens.scss +33 -33
- package/tokens/_emit-tokens.scss +329 -329
- package/tokens/_material-palette.scss +1149 -1149
- package/tokens/_primitives.scss +98 -98
- package/tokens/_semantic-aliases.scss +120 -120
- package/tokens/_spacing-tokens.scss +94 -94
- package/tokens/_static-tokens.scss +137 -137
- package/tokens/_typography-tokens.scss +65 -65
- package/vendors/charts.scss +90 -90
|
@@ -1,722 +1,722 @@
|
|
|
1
|
-
@use "sass:map";
|
|
2
|
-
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// matcha-table — `<table matcha-table>` directive (1:1 Figma DSV3 15641:275)
|
|
5
|
-
//
|
|
6
|
-
// API canon:
|
|
7
|
-
// <table matcha-table size="comfortable" striped hover bordered stickyHeader
|
|
8
|
-
// [stickyStart]="N" [stickyEnd]="N" [loading]="isLoading">
|
|
9
|
-
// <thead><tr><th>...</th></tr></thead>
|
|
10
|
-
// <tbody><tr><td>...</td></tr></tbody>
|
|
11
|
-
// </table>
|
|
12
|
-
//
|
|
13
|
-
// Companion directives (a11y automática):
|
|
14
|
-
// [matcha-table-sortable] em <th> — aria-sort + tabindex + keyboard
|
|
15
|
-
// [rowClick] em <tr> — AÇÃO na linha (abrir modal, selecionar). Só o
|
|
16
|
-
// binding já ativa tudo (tabindex + Enter/Space
|
|
17
|
-
// + hover accent na linha inteira)
|
|
18
|
-
//
|
|
19
|
-
// Navegação (leva pra outra página) NÃO é [rowClick]:
|
|
20
|
-
// <a matcha-cell-link [routerLink]> dentro do <td> — âncora de verdade, então
|
|
21
|
-
// ctrl+clique/clique do meio/botão direito funcionam e o resto da linha segue
|
|
22
|
-
// selecionável. Ponteiro e tom accent aparecem só sobre a âncora, pintando a linha
|
|
23
|
-
// inteira. Os dois no mesmo <tr> é proibido pelo canon (dois hovers competindo).
|
|
24
|
-
//
|
|
25
|
-
// Helpers CSS-only:
|
|
26
|
-
// td.numeric → tabular-nums
|
|
27
|
-
// td.truncate → ellipsis (text overflow)
|
|
28
|
-
// td[data-align] → alinhamento (data-alinhamento / td.text-{center,right} deprecated)
|
|
29
|
-
// tr.equal/.plus/.minus → variant semantic accent (cor via CSS var)
|
|
30
|
-
// tr.child-item → indent + accent esmaecido
|
|
31
|
-
// tr.is-selected → highlight
|
|
32
|
-
// =============================================================================
|
|
33
|
-
|
|
34
|
-
@mixin matcha-table-modern($theme) {
|
|
35
|
-
|
|
36
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
37
|
-
// CSS vars do componente — única fonte de verdade. ZERO literal hardcoded
|
|
38
|
-
// fora deste bloco. Consumer override qualquer um no escopo do <table>.
|
|
39
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
40
|
-
.matcha-table {
|
|
41
|
-
// ── Dimensions ────────────────────────────────────────────────────────
|
|
42
|
-
// Calibrado pra density moderna (Stripe/Linear/Notion). Comfortable era 52
|
|
43
|
-
// antes — apertado em telas wide. 58px equilibra densidade × respiro.
|
|
44
|
-
--matcha-table-cell-height-compact: var(--matcha-space-500, 40px);
|
|
45
|
-
--matcha-table-cell-height-comfortable: 58px;
|
|
46
|
-
--matcha-table-cell-height-spacious: var(--matcha-space-800, 64px);
|
|
47
|
-
// Padding uniforme L/R — assimétrico cria sensação de "primeira coluna
|
|
48
|
-
// afastada do resto". 16px ambos lados é canon moderno.
|
|
49
|
-
--matcha-table-cell-padding-x-left: var(--matcha-space-200, 16px);
|
|
50
|
-
--matcha-table-cell-padding-x-right: var(--matcha-space-200, 16px);
|
|
51
|
-
--matcha-table-cell-min-width: var(--matcha-space-1500, 120px);
|
|
52
|
-
--matcha-table-paginator-spacing: var(--matcha-space-300, 24px);
|
|
53
|
-
|
|
54
|
-
// ── Typography (modern density Stripe/Linear) ─────────────────────────
|
|
55
|
-
--matcha-table-font-size: 13px;
|
|
56
|
-
--matcha-table-font-line-height: 18px;
|
|
57
|
-
--matcha-table-header-font-size: var(--matcha-text-body-sm, 12px);
|
|
58
|
-
--matcha-table-header-font-line-height: var(--matcha-leading-body-sm, 16px);
|
|
59
|
-
--matcha-table-header-letter-spacing: 0.04em;
|
|
60
|
-
|
|
61
|
-
// ── Borders / radius ──────────────────────────────────────────────────
|
|
62
|
-
--matcha-table-border-color: var(--matcha-color-interaction-disabled-border);
|
|
63
|
-
--matcha-table-border-header: var(--matcha-border-thin, 2px);
|
|
64
|
-
--matcha-table-border-row: var(--matcha-border-hairline, 1px);
|
|
65
|
-
--matcha-table-bordered-radius: var(--matcha-radius-md, 4px);
|
|
66
|
-
// Escala de card (não a mesma de --matcha-table-bordered-radius, que é só
|
|
67
|
-
// pro inset border fino) — roundedTop arredonda o CONTAINER inteiro.
|
|
68
|
-
--matcha-table-rounded-top-radius: var(--matcha-radius-xl, 16px);
|
|
69
|
-
|
|
70
|
-
// ── Surface colors ────────────────────────────────────────────────────
|
|
71
|
-
--matcha-table-cell-bg: var(--matcha-color-surface-card);
|
|
72
|
-
--matcha-table-row-bg-selected: var(--matcha-color-accent-alpha-12,
|
|
73
|
-
rgba(var(--matcha-color-accent), 0.12));
|
|
74
|
-
--matcha-table-row-bg-striped: var(--matcha-color-surface-card-alt,
|
|
75
|
-
rgba(var(--matcha-color-fg), 0.02));
|
|
76
|
-
// Hover NÃO usa surface-table-row-hover token (tá próximo demais de surface-card
|
|
77
|
-
// em dark e fica imperceptível). Calibrado pra delta visível mesmo sobre stripe.
|
|
78
|
-
// CSS custom property values são TEXTO LITERAL pro Sass — fn calls Sass
|
|
79
|
-
// dentro NÃO são avaliadas. Precisa interpolação `#{}` pra forçar Sass a
|
|
80
|
-
// evaluar `var(--matcha-color-fg)` ANTES do output. Sem isso, o valor sai
|
|
81
|
-
// literal no bundle (ex: `rgba(var(--matcha-color-fg), 0.12)`) e o browser
|
|
82
|
-
// descarta como invalid CSS (= chevron invisível, hover sem cor, etc).
|
|
83
|
-
--matcha-table-row-bg-hover: rgba(var(--matcha-color-fg), 0.12);
|
|
84
|
-
--matcha-table-row-bg-hover-striped: rgba(var(--matcha-color-fg), 0.18);
|
|
85
|
-
--matcha-table-header-bg-hover: rgba(var(--matcha-color-fg), 0.10);
|
|
86
|
-
// Hover da linha que NAVEGA: tom accent, disparado só quando o ponteiro está
|
|
87
|
-
// sobre a âncora da célula (ver "Row navegável" adiante). Fora dela a linha usa
|
|
88
|
-
// o hover neutro acima — é esse contraste que diz ao usuário onde clicar.
|
|
89
|
-
--matcha-table-row-bg-hover-accent: var(--matcha-color-accent-surface-hover);
|
|
90
|
-
|
|
91
|
-
// ── Sort indicator colors ─────────────────────────────────────────────
|
|
92
|
-
// Inactive usa alpha 0.45 no foreground — claramente VISÍVEL como "ali tem
|
|
93
|
-
// sort", sem competir com texto do header. Hover/ativo passa pra accent full.
|
|
94
|
-
--matcha-table-sort-icon-color: rgba(var(--matcha-color-fg), 0.45);
|
|
95
|
-
--matcha-table-sort-icon-color-active: var(--matcha-color-accent);
|
|
96
|
-
--matcha-table-sort-icon-size: var(--matcha-space-250, 20px);
|
|
97
|
-
|
|
98
|
-
// ── Empty cell placeholder ────────────────────────────────────────────
|
|
99
|
-
--matcha-table-empty-cell-text: var(--matcha-color-text-muted,
|
|
100
|
-
rgba(var(--matcha-color-fg), 0.5));
|
|
101
|
-
|
|
102
|
-
// ── Variant accent (semantic row) ─────────────────────────────────────
|
|
103
|
-
--matcha-table-variant-accent-width: var(--matcha-space-050, 4px);
|
|
104
|
-
--matcha-table-row-accent-child-opacity: 0.5;
|
|
105
|
-
--matcha-table-selected-accent-width: var(--matcha-border-thin, 2px);
|
|
106
|
-
--matcha-table-selected-accent-color: var(--matcha-color-accent);
|
|
107
|
-
|
|
108
|
-
// ── Column width hints (utility classes col-*) ────────────────────────
|
|
109
|
-
--matcha-table-col-checkbox-width: var(--matcha-space-600, 48px);
|
|
110
|
-
--matcha-table-col-id-width: var(--matcha-space-1000, 80px);
|
|
111
|
-
--matcha-table-col-narrow-width: var(--matcha-space-1500, 120px);
|
|
112
|
-
--matcha-table-col-medium-width: var(--matcha-space-2500, 200px);
|
|
113
|
-
// Pino da coluna de Ações (matcha-cell-action) — mesma escala de
|
|
114
|
-
// --matcha-table-col-id-width (80px), token próprio pra não acoplar
|
|
115
|
-
// semanticamente coisas diferentes que hoje só coincidem em valor.
|
|
116
|
-
--matcha-table-col-actions-width: var(--matcha-space-1000, 80px);
|
|
117
|
-
|
|
118
|
-
// ── States / animations ───────────────────────────────────────────────
|
|
119
|
-
--matcha-table-disabled-opacity: var(--matcha-state-disabled-opacity, 0.5);
|
|
120
|
-
--matcha-table-loading-pulse-duration: var(--matcha-duration-slow, 1500ms);
|
|
121
|
-
--matcha-table-loading-pulse-opacity-min: 0.5;
|
|
122
|
-
--matcha-table-transition-duration: var(--matcha-duration-instant, 80ms);
|
|
123
|
-
--matcha-table-focus-ring-width: var(--matcha-state-focus-ring-width, 2px);
|
|
124
|
-
--matcha-table-focus-ring-color: var(--matcha-color-accent);
|
|
125
|
-
|
|
126
|
-
// ── Empty state row (matcha-table-empty directive) ────────────────────
|
|
127
|
-
--matcha-table-empty-padding-y: var(--matcha-space-500, 40px);
|
|
128
|
-
--matcha-table-empty-padding-x: var(--matcha-space-300, 24px);
|
|
129
|
-
|
|
130
|
-
// ── Resize handle (matcha-table-resizable directive) ──────────────────
|
|
131
|
-
--matcha-table-resize-handle-width: var(--matcha-space-100, 8px);
|
|
132
|
-
--matcha-table-resize-indicator-width: var(--matcha-border-hairline, 1px);
|
|
133
|
-
--matcha-table-resize-indicator-height: 50%;
|
|
134
|
-
--matcha-table-resize-indicator-top: 25%;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// ── Base — display table nativo + typography via vars ─────────────────
|
|
138
|
-
.matcha-table {
|
|
139
|
-
display: table;
|
|
140
|
-
width: 100%;
|
|
141
|
-
// separate (não collapse) + spacing 0 → visualmente idêntico (zero gap
|
|
142
|
-
// entre cells), mas `border-collapse: collapse` é conhecido por quebrar
|
|
143
|
-
// `position: sticky` em <th>/<td> em vários browsers — especialmente
|
|
144
|
-
// quando a cell precisa ficar sticky nos DOIS eixos ao mesmo tempo (linha
|
|
145
|
-
// + coluna, o canto stickyHeader × stickyStart/stickyEnd). Só existe
|
|
146
|
-
// border-bottom no arquivo (nenhum border-top) — sem risco de borda dupla.
|
|
147
|
-
border-collapse: separate;
|
|
148
|
-
border-spacing: 0;
|
|
149
|
-
font-family: var(--matcha-font-family);
|
|
150
|
-
font-size: var(--matcha-table-font-size);
|
|
151
|
-
line-height: var(--matcha-table-font-line-height);
|
|
152
|
-
font-weight: var(--matcha-weight-regular, 400);
|
|
153
|
-
color: var(--matcha-color-text-secondary,
|
|
154
|
-
color-mix(in srgb, var(--matcha-color-fg) 70%, transparent));
|
|
155
|
-
|
|
156
|
-
// ── Header cells (text/primary, border-bottom 2px, height 64) ────────
|
|
157
|
-
thead th {
|
|
158
|
-
box-sizing: border-box;
|
|
159
|
-
height: var(--matcha-table-cell-height-comfortable);
|
|
160
|
-
min-width: var(--matcha-table-cell-min-width);
|
|
161
|
-
padding: 0
|
|
162
|
-
var(--matcha-table-cell-padding-x-right)
|
|
163
|
-
0
|
|
164
|
-
var(--matcha-table-cell-padding-x-left);
|
|
165
|
-
background: var(--matcha-table-cell-bg);
|
|
166
|
-
color: var(--matcha-color-text-primary,
|
|
167
|
-
var(--matcha-color-fg));
|
|
168
|
-
// Header menor que body — hierarquia "metadado" vs "conteúdo".
|
|
169
|
-
font-size: var(--matcha-table-header-font-size);
|
|
170
|
-
line-height: var(--matcha-table-header-font-line-height);
|
|
171
|
-
font-weight: var(--matcha-weight-semibold, 600);
|
|
172
|
-
letter-spacing: var(--matcha-table-header-letter-spacing);
|
|
173
|
-
text-align: left;
|
|
174
|
-
vertical-align: middle;
|
|
175
|
-
border-bottom: var(--matcha-table-border-header) solid
|
|
176
|
-
var(--matcha-table-border-color);
|
|
177
|
-
|
|
178
|
-
// Alinhamento — data-align é o canon DSV3; data-alinhamento + utility
|
|
179
|
-
// classes seguem aceitos (deprecated, remoção em ciclo futuro)
|
|
180
|
-
&[data-align="center"], &[data-alinhamento="center"], &.text-center { text-align: center; }
|
|
181
|
-
&[data-align="right"], &[data-alinhamento="right"], &.text-right { text-align: right; }
|
|
182
|
-
|
|
183
|
-
// ── Sortable hint ([matcha-table-sortable] directive seta os attrs) ──
|
|
184
|
-
&[data-sortable] {
|
|
185
|
-
cursor: pointer;
|
|
186
|
-
user-select: none;
|
|
187
|
-
// SEMPRE reserva espaço pro chevron (mesmo inativo) — chevron entra/sai
|
|
188
|
-
// só via opacity. Sem padding condicional → texto NÃO desloca no hover.
|
|
189
|
-
padding-right: calc(var(--matcha-table-cell-padding-x-right) +
|
|
190
|
-
var(--matcha-table-sort-icon-size));
|
|
191
|
-
position: relative;
|
|
192
|
-
|
|
193
|
-
// Hover NÃO muda bg do header — bg-change era o que fazia o user
|
|
194
|
-
// perceber "movimento" quando o chevron entrava ao mesmo tempo.
|
|
195
|
-
// Manter header estático no hover, só chevron aparece com opacity.
|
|
196
|
-
// Cursor pointer + chevron fade já comunicam interatividade.
|
|
197
|
-
|
|
198
|
-
// Sort indicators — SVG 1:1 com `matcha/icon/arrow` (figma-icons.ts).
|
|
199
|
-
// Estado inativo (none) = INVISÍVEL (opacity 0). Aparece no hover do header
|
|
200
|
-
// com opacity faded, full quando ativo (asc/desc). Pattern canon Stripe/Linear:
|
|
201
|
-
// sortable em todas as colunas, mas indicador só na que tá ordenando.
|
|
202
|
-
&::after {
|
|
203
|
-
content: '';
|
|
204
|
-
position: absolute;
|
|
205
|
-
right: var(--matcha-table-cell-padding-x-right);
|
|
206
|
-
top: 50%;
|
|
207
|
-
transform: translateY(-50%);
|
|
208
|
-
width: var(--matcha-table-sort-icon-size);
|
|
209
|
-
height: var(--matcha-table-sort-icon-size);
|
|
210
|
-
background: var(--matcha-table-sort-icon-color);
|
|
211
|
-
transition: background-color var(--matcha-table-transition-duration) linear;
|
|
212
|
-
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 7.82499L6.1 12.725C5.9 12.925 5.66667 13.0208 5.4 13.0125C5.13333 13.0042 4.9 12.9 4.7 12.7C4.51667 12.5 4.42083 12.2667 4.4125 12C4.40417 11.7333 4.5 11.5 4.7 11.3L11.3 4.69999C11.4 4.59999 11.5083 4.52915 11.625 4.48749C11.7417 4.44582 11.8667 4.42499 12 4.42499C12.1333 4.42499 12.2583 4.44582 12.375 4.48749C12.4917 4.52915 12.6 4.59999 12.7 4.69999L19.3 11.3C19.4833 11.4833 19.575 11.7125 19.575 11.9875C19.575 12.2625 19.4833 12.5 19.3 12.7C19.1 12.9 18.8625 13 18.5875 13C18.3125 13 18.075 12.9 17.875 12.7L13 7.82499V19C13 19.2833 12.9042 19.5208 12.7125 19.7125C12.5208 19.9042 12.2833 20 12 20C11.7167 20 11.4792 19.9042 11.2875 19.7125C11.0958 19.5208 11 19.2833 11 19V7.82499Z'/></svg>")
|
|
213
|
-
center/contain no-repeat;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Hover no header — chevron escurece pra foreground full (já visível
|
|
217
|
-
// muted antes via alpha 0.45). Reforça que tá interativo.
|
|
218
|
-
&:hover::after {
|
|
219
|
-
background: var(--matcha-color-text-primary,
|
|
220
|
-
var(--matcha-color-fg));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Padding-right SEMPRE reserva espaço pro chevron. Antes ajustava
|
|
224
|
-
// condicionalmente (sem padding extra no inativo) — causava text
|
|
225
|
-
// "dançar" 20px ao hover quando padding crescia pra acomodar arrow.
|
|
226
|
-
// Mantém estável: chevron entra via opacity, sem reflow do texto.
|
|
227
|
-
|
|
228
|
-
&[data-sort-direction="asc"]::after {
|
|
229
|
-
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 7.82499L6.1 12.725C5.9 12.925 5.66667 13.0208 5.4 13.0125C5.13333 13.0042 4.9 12.9 4.7 12.7C4.51667 12.5 4.42083 12.2667 4.4125 12C4.40417 11.7333 4.5 11.5 4.7 11.3L11.3 4.69999C11.4 4.59999 11.5083 4.52915 11.625 4.48749C11.7417 4.44582 11.8667 4.42499 12 4.42499C12.1333 4.42499 12.2583 4.44582 12.375 4.48749C12.4917 4.52915 12.6 4.59999 12.7 4.69999L19.3 11.3C19.4833 11.4833 19.575 11.7125 19.575 11.9875C19.575 12.2625 19.4833 12.5 19.3 12.7C19.1 12.9 18.8625 13 18.5875 13C18.3125 13 18.075 12.9 17.875 12.7L13 7.82499V19C13 19.2833 12.9042 19.5208 12.7125 19.7125C12.5208 19.9042 12.2833 20 12 20C11.7167 20 11.4792 19.9042 11.2875 19.7125C11.0958 19.5208 11 19.2833 11 19V7.82499Z'/></svg>")
|
|
230
|
-
center/contain no-repeat;
|
|
231
|
-
background: var(--matcha-table-sort-icon-color-active);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
&[data-sort-direction="desc"]::after {
|
|
235
|
-
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 16.175V5C11 4.71667 11.0958 4.47917 11.2875 4.2875C11.4792 4.09583 11.7167 4 12 4C12.2833 4 12.5208 4.09583 12.7125 4.2875C12.9042 4.47917 13 4.71667 13 5V16.175L17.9 11.275C18.1 11.075 18.3333 10.9792 18.6 10.9875C18.8667 10.9958 19.1 11.1 19.3 11.3C19.4833 11.5 19.5792 11.7333 19.5875 12C19.5958 12.2667 19.5 12.5 19.3 12.7L12.7 19.3C12.6 19.4 12.4917 19.4708 12.375 19.5125C12.2583 19.5542 12.1333 19.575 12 19.575C11.8667 19.575 11.7417 19.5542 11.625 19.5125C11.5083 19.4708 11.4 19.4 11.3 19.3L4.7 12.7C4.51667 12.5167 4.425 12.2875 4.425 12.0125C4.425 11.7375 4.51667 11.5 4.7 11.3C4.9 11.1 5.1375 11 5.4125 11C5.6875 11 5.925 11.1 6.125 11.3L11 16.175Z'/></svg>")
|
|
236
|
-
center/contain no-repeat;
|
|
237
|
-
background: var(--matcha-table-sort-icon-color-active);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Header right-aligned com sort — chevron vem ANTES do texto (canon).
|
|
241
|
-
&[data-align="right"], &[data-alinhamento="right"], &.text-right {
|
|
242
|
-
padding-right: var(--matcha-table-cell-padding-x-right);
|
|
243
|
-
padding-left: calc(var(--matcha-table-cell-padding-x-left) +
|
|
244
|
-
var(--matcha-table-sort-icon-size));
|
|
245
|
-
|
|
246
|
-
&::after {
|
|
247
|
-
right: auto;
|
|
248
|
-
left: var(--matcha-table-cell-padding-x-left);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Focus ring quando keyboard-navigated (tabindex via directive).
|
|
253
|
-
&:focus-visible {
|
|
254
|
-
outline: var(--matcha-table-focus-ring-width) solid
|
|
255
|
-
var(--matcha-table-focus-ring-color);
|
|
256
|
-
outline-offset: calc(-1 * var(--matcha-table-focus-ring-width));
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// ── Body cells ────────────────────────────────────────────────────────
|
|
262
|
-
tbody td {
|
|
263
|
-
box-sizing: border-box;
|
|
264
|
-
height: var(--matcha-table-cell-height-comfortable);
|
|
265
|
-
min-width: var(--matcha-table-cell-min-width);
|
|
266
|
-
padding: 0
|
|
267
|
-
var(--matcha-table-cell-padding-x-right)
|
|
268
|
-
0
|
|
269
|
-
var(--matcha-table-cell-padding-x-left);
|
|
270
|
-
background: var(--matcha-table-cell-bg);
|
|
271
|
-
color: var(--matcha-color-text-secondary,
|
|
272
|
-
color-mix(in srgb, var(--matcha-color-fg) 70%, transparent));
|
|
273
|
-
vertical-align: middle;
|
|
274
|
-
border-bottom: var(--matcha-table-border-row) solid
|
|
275
|
-
var(--matcha-table-border-color);
|
|
276
|
-
transition: background-color var(--matcha-table-transition-duration) linear;
|
|
277
|
-
|
|
278
|
-
&[data-align="center"], &[data-alinhamento="center"], &.text-center { text-align: center; }
|
|
279
|
-
&[data-align="right"], &[data-alinhamento="right"], &.text-right { text-align: right; }
|
|
280
|
-
|
|
281
|
-
// Helper: tabular-nums (alinha decimais)
|
|
282
|
-
&[data-numeric], &.numeric {
|
|
283
|
-
font-variant-numeric: tabular-nums;
|
|
284
|
-
font-feature-settings: 'tnum';
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Helper: ellipsis (texto longo)
|
|
288
|
-
&[data-truncate], &.truncate {
|
|
289
|
-
max-width: 0;
|
|
290
|
-
white-space: nowrap;
|
|
291
|
-
overflow: hidden;
|
|
292
|
-
text-overflow: ellipsis;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Helper: cells vazias preenchidas com "—" muted (canon moderno).
|
|
296
|
-
&:empty::after {
|
|
297
|
-
content: '—';
|
|
298
|
-
color: var(--matcha-table-empty-cell-text);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// ── Column width hints (aplicar em <th> — <td> herda pela coluna) ─────
|
|
303
|
-
thead th,
|
|
304
|
-
tbody td {
|
|
305
|
-
// min-width igual ao width — sem isso, a regra base thead th/tbody td
|
|
306
|
-
// (min-width:120px) vence e a coluna nunca encolhe pro valor pretendido
|
|
307
|
-
// (mesmo bug achado e corrigido em .col-actions).
|
|
308
|
-
&.col-checkbox { width: var(--matcha-table-col-checkbox-width); min-width: var(--matcha-table-col-checkbox-width); text-align: center; }
|
|
309
|
-
&.col-id { width: var(--matcha-table-col-id-width); }
|
|
310
|
-
&.col-narrow { width: var(--matcha-table-col-narrow-width); }
|
|
311
|
-
&.col-medium { width: var(--matcha-table-col-medium-width); }
|
|
312
|
-
// Actions / icon-buttons — pinada em --matcha-table-col-actions-width (80px).
|
|
313
|
-
// Children inline-flex, centralizados (título "Ações" no header também
|
|
314
|
-
// centraliza — text-align: center vale pro conteúdo das duas linhas).
|
|
315
|
-
//
|
|
316
|
-
// Importante: `.matcha-button` tem `display: flex` (block-level) que faria
|
|
317
|
-
// os icon-buttons empilharem verticalmente. Override via selector descendant
|
|
318
|
-
// com specificity maior pra forçar inline-flex no contexto de actions cell.
|
|
319
|
-
&.col-actions {
|
|
320
|
-
width: var(--matcha-table-col-actions-width);
|
|
321
|
-
// min-width base da tbody td/thead th é 120px (--matcha-table-cell-min-width)
|
|
322
|
-
// — maior que os 80px daqui, e min-width sempre vence sobre width no box
|
|
323
|
-
// model. Sem este override, a coluna ficava presa em 120px (achado real).
|
|
324
|
-
min-width: var(--matcha-table-col-actions-width);
|
|
325
|
-
white-space: nowrap;
|
|
326
|
-
text-align: center;
|
|
327
|
-
|
|
328
|
-
> .matcha-button,
|
|
329
|
-
> button[matcha-icon-button],
|
|
330
|
-
> * {
|
|
331
|
-
display: inline-flex;
|
|
332
|
-
vertical-align: middle;
|
|
333
|
-
}
|
|
334
|
-
> * + * {
|
|
335
|
-
margin-left: var(--matcha-space-050, 4px);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
// Greedy = espaço residual (default, classe explícita pra documentação).
|
|
339
|
-
&.col-greedy { width: auto; }
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// ── Paginator alinhado após table (convention) ────────────────────────
|
|
343
|
-
// Sem margin-top — paginator gruda no border-bottom da última row.
|
|
344
|
-
// Spacing visual vem dos paddings internos do próprio matcha-paginator.
|
|
345
|
-
.matcha-table-paginator,
|
|
346
|
-
& + matcha-paginator {
|
|
347
|
-
display: block;
|
|
348
|
-
margin-top: 0;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// ── Row clickable ([rowClick] directive — só o binding já ativa tudo) ─
|
|
352
|
-
tbody tr.matcha-row-clickable {
|
|
353
|
-
cursor: pointer;
|
|
354
|
-
|
|
355
|
-
&:hover td {
|
|
356
|
-
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
&:focus-visible {
|
|
360
|
-
outline: var(--matcha-table-focus-ring-width) solid
|
|
361
|
-
var(--matcha-table-focus-ring-color);
|
|
362
|
-
outline-offset: calc(-1 * var(--matcha-table-focus-ring-width));
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// ── Modifiers via atributo no host (Angular @HostBinding, ver
|
|
367
|
-
// table.component.ts) ──────────────────────────────────────────────────
|
|
368
|
-
// Cada modifier tem 2 seletores alternativos: `&[x]` (forma legado — o
|
|
369
|
-
// host JÁ É `.matcha-table`, self) e `matcha-table[x] &` (forma elemento
|
|
370
|
-
// — o atributo mora no host `<matcha-table>`, mas o alvo real é o filho
|
|
371
|
-
// `.matcha-table` dentro do wrapper; CSS alcança via descendente, não
|
|
372
|
-
// precisa o atributo estar duplicado no filho).
|
|
373
|
-
// Striped usa :where() pra dropar specificity do :nth-child — hover vence.
|
|
374
|
-
&[striped] tbody tr:where(:nth-child(even)) td,
|
|
375
|
-
matcha-table[striped] & tbody tr:where(:nth-child(even)) td {
|
|
376
|
-
--matcha-table-cell-bg: var(--matcha-table-row-bg-striped);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
&[hover] tbody tr:hover td,
|
|
380
|
-
matcha-table[hover] & tbody tr:hover td {
|
|
381
|
-
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Stripe-aware hover: row PAR ganha alpha mais forte pra preservar stripe.
|
|
385
|
-
&[striped] tbody tr:where(:nth-child(even)).matcha-row-clickable:hover td,
|
|
386
|
-
matcha-table[striped] & tbody tr:where(:nth-child(even)).matcha-row-clickable:hover td,
|
|
387
|
-
&[striped][hover] tbody tr:where(:nth-child(even)):hover td,
|
|
388
|
-
matcha-table[striped][hover] & tbody tr:where(:nth-child(even)):hover td {
|
|
389
|
-
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover-striped);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// Hover accent de linha clicável: a diretiva [rowClick] já sobrescreve
|
|
393
|
-
// --matcha-table-row-bg-hover(-striped) inline no próprio <tr> (ver
|
|
394
|
-
// table-clickable-row.directive.ts) — nenhuma regra de tema necessária
|
|
395
|
-
// aqui, o estilo inline já vence qualquer especificidade.
|
|
396
|
-
|
|
397
|
-
// ── Row navegável (`<a matcha-cell-link>` na célula) ───────────────────
|
|
398
|
-
// A linha que LEVA PRA OUTRA PÁGINA não é clicável inteira: quem navega é uma
|
|
399
|
-
// âncora de verdade na célula, pra que ctrl+clique, clique do meio e o menu do
|
|
400
|
-
// botão direito funcionem — e pra que o resto da linha continue selecionável
|
|
401
|
-
// com o mouse (com a linha toda clicável, não dava pra copiar texto da tabela).
|
|
402
|
-
//
|
|
403
|
-
// O feedback visual é o inverso do rowClick: ponteiro e tom accent aparecem só
|
|
404
|
-
// quando o mouse está sobre a âncora, e aí a linha INTEIRA pinta. Fora dela vale
|
|
405
|
-
// o hover neutro de sempre.
|
|
406
|
-
//
|
|
407
|
-
// Pinta via --matcha-table-cell-bg em TODOS os td da linha (mesmo caminho do
|
|
408
|
-
// hover normal), não com background-color no <tr>: em tabela striped o fundo
|
|
409
|
-
// mora no td, e um background no tr ficaria por baixo dele — o resultado seria
|
|
410
|
-
// uma célula colorida e o resto não.
|
|
411
|
-
//
|
|
412
|
-
// Depois das regras de striped de propósito: mesma especificidade, e ordem de
|
|
413
|
-
// origem decide. `:has()` já é usado em ~10 componentes do tema.
|
|
414
|
-
// O estilo BASE da âncora é global (base/_reset.scss) — ela também aparece em
|
|
415
|
-
// card de listagem, fora de qualquer tabela. Aqui fica só o que é da tabela: o
|
|
416
|
-
// realce da linha inteira.
|
|
417
|
-
a[matcha-cell-link]:focus-visible {
|
|
418
|
-
outline: var(--matcha-table-focus-ring-width) solid
|
|
419
|
-
var(--matcha-table-focus-ring-color);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
tbody tr:has(a[matcha-cell-link]:hover) td,
|
|
423
|
-
tbody tr:has(a[matcha-cell-link]:focus-visible) td {
|
|
424
|
-
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover-accent);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// O ALVO é a CÉLULA inteira, não só o texto do nome.
|
|
428
|
-
//
|
|
429
|
-
// A âncora envolve o nome, e em título curto isso vira um alvo de poucos pixels —
|
|
430
|
-
// reclamação de quem usa, medida em séries. O `::after` esticado resolve sem trocar
|
|
431
|
-
// a âncora por handler de clique: o href continua existindo, então ctrl+clique,
|
|
432
|
-
// clique do meio e "abrir em nova aba" seguem funcionando, e o foco de teclado
|
|
433
|
-
// continua sendo o do link.
|
|
434
|
-
//
|
|
435
|
-
// De quebra conserta o hover: a regra acima só pinta a linha quando o mouse está
|
|
436
|
-
// sobre o TEXTO. Com a área esticada, pinta ao entrar na célula — que é o que faz
|
|
437
|
-
// a linha parecer clicável.
|
|
438
|
-
//
|
|
439
|
-
// Escopado em `.matcha-table td` de propósito: `a[matcha-cell-link]` também aparece
|
|
440
|
-
// em card de listagem, fora de tabela, e lá o link deve seguir do tamanho do texto.
|
|
441
|
-
//
|
|
442
|
-
// O custo é a seleção de texto DENTRO desta célula. No resto da linha continua
|
|
443
|
-
// funcionando, que é a diferença para a linha toda clicável.
|
|
444
|
-
td:has(a[matcha-cell-link]) {
|
|
445
|
-
position: relative;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
td a[matcha-cell-link]::after {
|
|
449
|
-
content: '';
|
|
450
|
-
position: absolute;
|
|
451
|
-
inset: 0;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
tbody tr.is-selected td {
|
|
455
|
-
--matcha-table-cell-bg: var(--matcha-table-row-bg-selected);
|
|
456
|
-
}
|
|
457
|
-
// Selected row ganha border-left accent — affordance canon Linear/Notion.
|
|
458
|
-
// No <tr> → não some com stickyStart. Usa ::after pra coexistir com
|
|
459
|
-
// ::before do variant accent sem conflito.
|
|
460
|
-
tbody tr.is-selected {
|
|
461
|
-
position: relative;
|
|
462
|
-
|
|
463
|
-
&::after {
|
|
464
|
-
content: '';
|
|
465
|
-
position: absolute;
|
|
466
|
-
top: 0;
|
|
467
|
-
left: 0;
|
|
468
|
-
width: var(--matcha-table-selected-accent-width);
|
|
469
|
-
height: 100%;
|
|
470
|
-
background: var(--matcha-table-selected-accent-color);
|
|
471
|
-
pointer-events: none;
|
|
472
|
-
z-index: 2; // acima do variant accent (z-index 1)
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Bordered — box-shadow inset em vez de border real (não clipa shadows
|
|
477
|
-
// externos das sticky cols, que projetam pra fora da <table>).
|
|
478
|
-
// Conhecido: em alguns casos (sticky-header/colunas fixas, forma
|
|
479
|
-
// elemento) o background opaco das cells pode encobrir parte deste
|
|
480
|
-
// traço — não resolvido nesta rodada (fora do escopo desta tarefa); se
|
|
481
|
-
// precisar de borda garantida num caso desses, use a utility class de
|
|
482
|
-
// borda (ex.: `b-1`) direto no consumo do componente.
|
|
483
|
-
&[bordered] {
|
|
484
|
-
box-shadow: inset 0 0 0 var(--matcha-table-border-row)
|
|
485
|
-
var(--matcha-table-border-color);
|
|
486
|
-
border-radius: var(--matcha-table-bordered-radius);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Sticky header (vertical scroll). Forma legado: o host (a própria table) é
|
|
490
|
-
// o container de scroll. Default do componente é overflow-y:hidden (só
|
|
491
|
-
// horizontal é fallback passivo — dois scrolls na tela atrapalham mobile);
|
|
492
|
-
// stickyHeader é opt-in EXPLÍCITO, reabilita overflow-y:auto de propósito
|
|
493
|
-
// + altura máxima (sem isso não há o que rolar, o header não tem contra o
|
|
494
|
-
// que grudar). Altura configurável via var (default 70vh).
|
|
495
|
-
&[sticky-header],
|
|
496
|
-
matcha-table[sticky-header] & {
|
|
497
|
-
max-height: var(--matcha-table-sticky-header-max-height, 70vh);
|
|
498
|
-
overflow-y: auto;
|
|
499
|
-
}
|
|
500
|
-
&[sticky-header] thead th,
|
|
501
|
-
matcha-table[sticky-header] & thead th {
|
|
502
|
-
position: sticky;
|
|
503
|
-
top: 0;
|
|
504
|
-
z-index: 1;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Size variants (data-size cascateia altura)
|
|
508
|
-
&[data-size="compact"] thead th,
|
|
509
|
-
&[data-size="compact"] tbody td { height: var(--matcha-table-cell-height-compact); }
|
|
510
|
-
&[data-size="spacious"] thead th,
|
|
511
|
-
&[data-size="spacious"] tbody td { height: var(--matcha-table-cell-height-spacious); }
|
|
512
|
-
|
|
513
|
-
// ── Sticky columns (start/end) — canon scroll horizontal ──────────────
|
|
514
|
-
// Performance: nada de box-shadow com blur nem background-image (gradient)
|
|
515
|
-
// aqui — são caros de repaint/compositar MULTIPLICADOS por linha (uma
|
|
516
|
-
// tabela de 40+ linhas com 2 colunas sticky = 80 elementos), e causavam
|
|
517
|
-
// queda de FPS real no scroll (medido em produção). Custo mínimo:
|
|
518
|
-
// background-color sólido (fixo, não acompanha hover/tint — troca-se
|
|
519
|
-
// fidelidade visual por performance) + border 1px sólida no lugar da
|
|
520
|
-
// sombra de scroll-edge (borda é essencialmente grátis pro compositor,
|
|
521
|
-
// sombra com blur não é).
|
|
522
|
-
//
|
|
523
|
-
// :not([sticky-header])/:not(matcha-table[sticky-header] &) — combinar
|
|
524
|
-
// sticky column COM sticky header exige que a cell de CANTO (cabeçalho da
|
|
525
|
-
// coluna fixa) fique sticky nos dois eixos (top E left/right) ao mesmo
|
|
526
|
-
// tempo — inconsistente entre browsers em cells de <table> (documentado
|
|
527
|
-
// no JSDoc do componente). Em vez de deixar o canto quebrado, desliga a
|
|
528
|
-
// coluna fixa inteira quando stickyHeader está ativo — só o header fixo
|
|
529
|
-
// (mais universalmente útil) permanece. `sticky-header` agora é atributo
|
|
530
|
-
// no host — o 2º `:not()` cobre o caso em que o host é o wrapper (forma
|
|
531
|
-
// elemento, `sticky-header` não está no `.matcha-table` em si, está no
|
|
532
|
-
// `<matcha-table>` ancestral). `data-sticky-start`/`-end` continuam só no
|
|
533
|
-
// nó real (mirrorAttributesToRealTable), não precisam de alternativa.
|
|
534
|
-
@for $i from 1 through 4 {
|
|
535
|
-
&[data-sticky-start="#{$i}"]:not([sticky-header]):not(matcha-table[sticky-header] &) {
|
|
536
|
-
thead th:nth-child(-n+#{$i}),
|
|
537
|
-
tbody tr td:nth-child(-n+#{$i}) {
|
|
538
|
-
position: sticky;
|
|
539
|
-
z-index: 2;
|
|
540
|
-
background-color: var(--matcha-color-surface-card);
|
|
541
|
-
}
|
|
542
|
-
// Última cell do grupo sticky-start marca o scroll-edge com borda fina.
|
|
543
|
-
thead th:nth-child(#{$i}),
|
|
544
|
-
tbody tr td:nth-child(#{$i}) {
|
|
545
|
-
border-right: var(--matcha-border-hairline, 1px) solid var(--matcha-color-surface-border);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
&[data-sticky-end="#{$i}"]:not([sticky-header]):not(matcha-table[sticky-header] &) {
|
|
550
|
-
thead th:nth-last-child(-n+#{$i}),
|
|
551
|
-
tbody tr td:nth-last-child(-n+#{$i}) {
|
|
552
|
-
position: sticky;
|
|
553
|
-
z-index: 2;
|
|
554
|
-
background-color: var(--matcha-color-surface-card);
|
|
555
|
-
}
|
|
556
|
-
thead th:nth-last-child(#{$i}),
|
|
557
|
-
tbody tr td:nth-last-child(#{$i}) {
|
|
558
|
-
border-left: var(--matcha-border-hairline, 1px) solid var(--matcha-color-surface-border);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
&[data-sticky-start]:not([sticky-header]):not(matcha-table[sticky-header] &) thead th:first-child,
|
|
564
|
-
&[data-sticky-start]:not([sticky-header]):not(matcha-table[sticky-header] &) tbody tr td:first-child { left: 0; }
|
|
565
|
-
&[data-sticky-end]:not([sticky-header]):not(matcha-table[sticky-header] &) thead th:last-child,
|
|
566
|
-
&[data-sticky-end]:not([sticky-header]):not(matcha-table[sticky-header] &) tbody tr td:last-child { right: 0; }
|
|
567
|
-
|
|
568
|
-
// ── Variant accent (semantic row coloring) ────────────────────────────
|
|
569
|
-
// Defaults canon Figma DSV3: equal=info, plus=success, minus=danger.
|
|
570
|
-
// Accent vive no <tr> → NÃO some com stickyStart.
|
|
571
|
-
// `position: relative` em <tr> suportado em Chrome 80+, FF 87+, Safari 14+.
|
|
572
|
-
tr.equal { --matcha-table-row-accent-color: var(--matcha-color-info); }
|
|
573
|
-
tr.plus { --matcha-table-row-accent-color: var(--matcha-color-success); }
|
|
574
|
-
tr.minus { --matcha-table-row-accent-color: var(--matcha-color-danger); }
|
|
575
|
-
|
|
576
|
-
tbody tr[data-variant],
|
|
577
|
-
tbody tr.equal,
|
|
578
|
-
tbody tr.plus,
|
|
579
|
-
tbody tr.minus {
|
|
580
|
-
position: relative;
|
|
581
|
-
|
|
582
|
-
&::before {
|
|
583
|
-
content: '';
|
|
584
|
-
position: absolute;
|
|
585
|
-
top: 0;
|
|
586
|
-
left: 0;
|
|
587
|
-
width: var(--matcha-table-variant-accent-width);
|
|
588
|
-
height: 100%;
|
|
589
|
-
background: var(--matcha-table-row-accent-color, transparent);
|
|
590
|
-
pointer-events: none;
|
|
591
|
-
z-index: 1; // acima do bg da cell, abaixo do sticky shadow
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// Child row (indent + accent esmaecido) — pattern tree/hierarquia.
|
|
596
|
-
tbody tr.child-item::before {
|
|
597
|
-
opacity: var(--matcha-table-row-accent-child-opacity);
|
|
598
|
-
}
|
|
599
|
-
tbody tr.child-item td:first-child {
|
|
600
|
-
padding-left: calc(var(--matcha-table-cell-padding-x-left) +
|
|
601
|
-
var(--matcha-space-200, 16px));
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// ── Loading state global — pulse + aria-busy ─────────────────────────
|
|
605
|
-
&[loading] tbody tr,
|
|
606
|
-
matcha-table[loading] & tbody tr {
|
|
607
|
-
animation: matcha-table-loading-pulse
|
|
608
|
-
var(--matcha-table-loading-pulse-duration)
|
|
609
|
-
ease-in-out infinite;
|
|
610
|
-
pointer-events: none;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// ── Disabled state — row/cell ─────────────────────────────────────────
|
|
614
|
-
// Pattern canon Material/Polaris. A11y: também aplicar aria-disabled.
|
|
615
|
-
tbody tr[disabled], tbody tr.is-disabled,
|
|
616
|
-
tbody td[disabled], tbody td.is-disabled {
|
|
617
|
-
opacity: var(--matcha-table-disabled-opacity);
|
|
618
|
-
pointer-events: none;
|
|
619
|
-
cursor: not-allowed;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// ── Per-row loading (matcha-table-loading directive) ─────────────────
|
|
623
|
-
// Pulse só naquela row — optimistic save/delete sem bloquear a tabela.
|
|
624
|
-
tbody tr.is-loading {
|
|
625
|
-
animation: matcha-table-loading-pulse
|
|
626
|
-
var(--matcha-table-loading-pulse-duration)
|
|
627
|
-
ease-in-out infinite;
|
|
628
|
-
pointer-events: none;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// ── Empty state row (matcha-table-empty directive) ────────────────────
|
|
632
|
-
// Container pra <matcha-empty-state>. Directive seta colspan automático.
|
|
633
|
-
tbody tr.is-empty td {
|
|
634
|
-
padding: var(--matcha-table-empty-padding-y) var(--matcha-table-empty-padding-x);
|
|
635
|
-
text-align: center;
|
|
636
|
-
background: var(--matcha-table-cell-bg);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
// ── Resizable column (matcha-table-resizable directive) ───────────────
|
|
640
|
-
// Handle invisível na borda direita. Hover mostra cursor + barra discreta.
|
|
641
|
-
thead th.is-resizable {
|
|
642
|
-
position: relative;
|
|
643
|
-
|
|
644
|
-
&::before {
|
|
645
|
-
content: '';
|
|
646
|
-
position: absolute;
|
|
647
|
-
top: var(--matcha-table-resize-indicator-top);
|
|
648
|
-
right: 0;
|
|
649
|
-
width: var(--matcha-table-resize-indicator-width);
|
|
650
|
-
height: var(--matcha-table-resize-indicator-height);
|
|
651
|
-
background: var(--matcha-table-border-color);
|
|
652
|
-
opacity: 0;
|
|
653
|
-
transition: opacity var(--matcha-table-transition-duration) linear;
|
|
654
|
-
}
|
|
655
|
-
&:hover::before { opacity: 1; }
|
|
656
|
-
}
|
|
657
|
-
thead th.is-resizable::after {
|
|
658
|
-
// Override do ::after do sort-indicator: handle de resize ocupa a borda.
|
|
659
|
-
// Col sortable + resizable é raro — consumer escolhe uma.
|
|
660
|
-
content: '';
|
|
661
|
-
position: absolute;
|
|
662
|
-
top: 0;
|
|
663
|
-
right: calc(-1 * var(--matcha-table-resize-handle-width) / 2);
|
|
664
|
-
width: var(--matcha-table-resize-handle-width);
|
|
665
|
-
height: 100%;
|
|
666
|
-
cursor: col-resize;
|
|
667
|
-
z-index: 3;
|
|
668
|
-
background: transparent;
|
|
669
|
-
mask: none;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// Sticky header — forma ELEMENTO (`<matcha-table>`, ver table.component.ts).
|
|
674
|
-
// Aqui quem rola de verdade é `.matcha-table__scroll` (o wrapper), não a
|
|
675
|
-
// `<table class="matcha-table">` interna — a altura máxima precisa ir no
|
|
676
|
-
// wrapper. `sticky-header` mora no HOST `<matcha-table>` (@HostBinding,
|
|
677
|
-
// não mais na `<table>` filha) — como o host é ANCESTRAL do wrapper, um
|
|
678
|
-
// descendente simples já alcança, sem precisar de `:has()`.
|
|
679
|
-
matcha-table[sticky-header] > .matcha-table__scroll {
|
|
680
|
-
max-height: var(--matcha-table-sticky-header-max-height, 70vh);
|
|
681
|
-
overflow-y: auto;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// roundedTop — regra TOP-LEVEL (fora do bloco .matcha-table acima): alcança
|
|
685
|
-
// o host na forma legado (self, `.matcha-table[rounded-top]`, o próprio
|
|
686
|
-
// `<table>` é a superfície visual) e o wrapper de scroll na forma elemento
|
|
687
|
-
// (descendente a partir do host `<matcha-table rounded-top>` — só o
|
|
688
|
-
// wrapper precisa do radius, ele já clipa a `<table>` interna via
|
|
689
|
-
// overflow non-visible, a `<table>` em si não precisa do próprio radius).
|
|
690
|
-
//
|
|
691
|
-
// Fallback inline no 2º var() é OBRIGATÓRIO: --matcha-table-rounded-top-radius
|
|
692
|
-
// é declarada dentro do bloco `.matcha-table { }` acima — na forma elemento
|
|
693
|
-
// `.matcha-table__scroll` é PAI de `.matcha-table` (o wrapper envolve a
|
|
694
|
-
// table real), não descendente. CSS custom property só desce a árvore, não
|
|
695
|
-
// sobe — sem o fallback aqui a var nunca resolve nesse elemento (bug
|
|
696
|
-
// silencioso: sem erro, só o border-radius nunca aparece). O fallback ainda
|
|
697
|
-
// respeita um override do consumer, se ele setar a var em algum ancestral
|
|
698
|
-
// real do wrapper (ex.: no próprio host `<matcha-table>` ou em `:root`).
|
|
699
|
-
.matcha-table[rounded-top] {
|
|
700
|
-
border-top-left-radius: var(--matcha-table-rounded-top-radius);
|
|
701
|
-
border-top-right-radius: var(--matcha-table-rounded-top-radius);
|
|
702
|
-
}
|
|
703
|
-
matcha-table[rounded-top] .matcha-table__scroll {
|
|
704
|
-
border-top-left-radius: var(--matcha-table-rounded-top-radius, var(--matcha-radius-xl, 16px));
|
|
705
|
-
border-top-right-radius: var(--matcha-table-rounded-top-radius, var(--matcha-radius-xl, 16px));
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
@keyframes matcha-table-loading-pulse {
|
|
709
|
-
0%, 100% { opacity: 1; }
|
|
710
|
-
50% { opacity: var(--matcha-table-loading-pulse-opacity-min); }
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
// ── Reduced motion ────────────────────────────────────────────────────
|
|
714
|
-
@media (prefers-reduced-motion: reduce) {
|
|
715
|
-
.matcha-table tbody td,
|
|
716
|
-
.matcha-table[loading] tbody tr,
|
|
717
|
-
matcha-table[loading] .matcha-table tbody tr {
|
|
718
|
-
transition: none;
|
|
719
|
-
animation: none;
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
}
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// matcha-table — `<table matcha-table>` directive (1:1 Figma DSV3 15641:275)
|
|
5
|
+
//
|
|
6
|
+
// API canon:
|
|
7
|
+
// <table matcha-table size="comfortable" striped hover bordered stickyHeader
|
|
8
|
+
// [stickyStart]="N" [stickyEnd]="N" [loading]="isLoading">
|
|
9
|
+
// <thead><tr><th>...</th></tr></thead>
|
|
10
|
+
// <tbody><tr><td>...</td></tr></tbody>
|
|
11
|
+
// </table>
|
|
12
|
+
//
|
|
13
|
+
// Companion directives (a11y automática):
|
|
14
|
+
// [matcha-table-sortable] em <th> — aria-sort + tabindex + keyboard
|
|
15
|
+
// [rowClick] em <tr> — AÇÃO na linha (abrir modal, selecionar). Só o
|
|
16
|
+
// binding já ativa tudo (tabindex + Enter/Space
|
|
17
|
+
// + hover accent na linha inteira)
|
|
18
|
+
//
|
|
19
|
+
// Navegação (leva pra outra página) NÃO é [rowClick]:
|
|
20
|
+
// <a matcha-cell-link [routerLink]> dentro do <td> — âncora de verdade, então
|
|
21
|
+
// ctrl+clique/clique do meio/botão direito funcionam e o resto da linha segue
|
|
22
|
+
// selecionável. Ponteiro e tom accent aparecem só sobre a âncora, pintando a linha
|
|
23
|
+
// inteira. Os dois no mesmo <tr> é proibido pelo canon (dois hovers competindo).
|
|
24
|
+
//
|
|
25
|
+
// Helpers CSS-only:
|
|
26
|
+
// td.numeric → tabular-nums
|
|
27
|
+
// td.truncate → ellipsis (text overflow)
|
|
28
|
+
// td[data-align] → alinhamento (data-alinhamento / td.text-{center,right} deprecated)
|
|
29
|
+
// tr.equal/.plus/.minus → variant semantic accent (cor via CSS var)
|
|
30
|
+
// tr.child-item → indent + accent esmaecido
|
|
31
|
+
// tr.is-selected → highlight
|
|
32
|
+
// =============================================================================
|
|
33
|
+
|
|
34
|
+
@mixin matcha-table-modern($theme) {
|
|
35
|
+
|
|
36
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
37
|
+
// CSS vars do componente — única fonte de verdade. ZERO literal hardcoded
|
|
38
|
+
// fora deste bloco. Consumer override qualquer um no escopo do <table>.
|
|
39
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
40
|
+
.matcha-table {
|
|
41
|
+
// ── Dimensions ────────────────────────────────────────────────────────
|
|
42
|
+
// Calibrado pra density moderna (Stripe/Linear/Notion). Comfortable era 52
|
|
43
|
+
// antes — apertado em telas wide. 58px equilibra densidade × respiro.
|
|
44
|
+
--matcha-table-cell-height-compact: var(--matcha-space-500, 40px);
|
|
45
|
+
--matcha-table-cell-height-comfortable: 58px;
|
|
46
|
+
--matcha-table-cell-height-spacious: var(--matcha-space-800, 64px);
|
|
47
|
+
// Padding uniforme L/R — assimétrico cria sensação de "primeira coluna
|
|
48
|
+
// afastada do resto". 16px ambos lados é canon moderno.
|
|
49
|
+
--matcha-table-cell-padding-x-left: var(--matcha-space-200, 16px);
|
|
50
|
+
--matcha-table-cell-padding-x-right: var(--matcha-space-200, 16px);
|
|
51
|
+
--matcha-table-cell-min-width: var(--matcha-space-1500, 120px);
|
|
52
|
+
--matcha-table-paginator-spacing: var(--matcha-space-300, 24px);
|
|
53
|
+
|
|
54
|
+
// ── Typography (modern density Stripe/Linear) ─────────────────────────
|
|
55
|
+
--matcha-table-font-size: 13px;
|
|
56
|
+
--matcha-table-font-line-height: 18px;
|
|
57
|
+
--matcha-table-header-font-size: var(--matcha-text-body-sm, 12px);
|
|
58
|
+
--matcha-table-header-font-line-height: var(--matcha-leading-body-sm, 16px);
|
|
59
|
+
--matcha-table-header-letter-spacing: 0.04em;
|
|
60
|
+
|
|
61
|
+
// ── Borders / radius ──────────────────────────────────────────────────
|
|
62
|
+
--matcha-table-border-color: var(--matcha-color-interaction-disabled-border);
|
|
63
|
+
--matcha-table-border-header: var(--matcha-border-thin, 2px);
|
|
64
|
+
--matcha-table-border-row: var(--matcha-border-hairline, 1px);
|
|
65
|
+
--matcha-table-bordered-radius: var(--matcha-radius-md, 4px);
|
|
66
|
+
// Escala de card (não a mesma de --matcha-table-bordered-radius, que é só
|
|
67
|
+
// pro inset border fino) — roundedTop arredonda o CONTAINER inteiro.
|
|
68
|
+
--matcha-table-rounded-top-radius: var(--matcha-radius-xl, 16px);
|
|
69
|
+
|
|
70
|
+
// ── Surface colors ────────────────────────────────────────────────────
|
|
71
|
+
--matcha-table-cell-bg: var(--matcha-color-surface-card);
|
|
72
|
+
--matcha-table-row-bg-selected: var(--matcha-color-accent-alpha-12,
|
|
73
|
+
rgba(var(--matcha-color-accent), 0.12));
|
|
74
|
+
--matcha-table-row-bg-striped: var(--matcha-color-surface-card-alt,
|
|
75
|
+
rgba(var(--matcha-color-fg), 0.02));
|
|
76
|
+
// Hover NÃO usa surface-table-row-hover token (tá próximo demais de surface-card
|
|
77
|
+
// em dark e fica imperceptível). Calibrado pra delta visível mesmo sobre stripe.
|
|
78
|
+
// CSS custom property values são TEXTO LITERAL pro Sass — fn calls Sass
|
|
79
|
+
// dentro NÃO são avaliadas. Precisa interpolação `#{}` pra forçar Sass a
|
|
80
|
+
// evaluar `var(--matcha-color-fg)` ANTES do output. Sem isso, o valor sai
|
|
81
|
+
// literal no bundle (ex: `rgba(var(--matcha-color-fg), 0.12)`) e o browser
|
|
82
|
+
// descarta como invalid CSS (= chevron invisível, hover sem cor, etc).
|
|
83
|
+
--matcha-table-row-bg-hover: rgba(var(--matcha-color-fg), 0.12);
|
|
84
|
+
--matcha-table-row-bg-hover-striped: rgba(var(--matcha-color-fg), 0.18);
|
|
85
|
+
--matcha-table-header-bg-hover: rgba(var(--matcha-color-fg), 0.10);
|
|
86
|
+
// Hover da linha que NAVEGA: tom accent, disparado só quando o ponteiro está
|
|
87
|
+
// sobre a âncora da célula (ver "Row navegável" adiante). Fora dela a linha usa
|
|
88
|
+
// o hover neutro acima — é esse contraste que diz ao usuário onde clicar.
|
|
89
|
+
--matcha-table-row-bg-hover-accent: var(--matcha-color-accent-surface-hover);
|
|
90
|
+
|
|
91
|
+
// ── Sort indicator colors ─────────────────────────────────────────────
|
|
92
|
+
// Inactive usa alpha 0.45 no foreground — claramente VISÍVEL como "ali tem
|
|
93
|
+
// sort", sem competir com texto do header. Hover/ativo passa pra accent full.
|
|
94
|
+
--matcha-table-sort-icon-color: rgba(var(--matcha-color-fg), 0.45);
|
|
95
|
+
--matcha-table-sort-icon-color-active: var(--matcha-color-accent);
|
|
96
|
+
--matcha-table-sort-icon-size: var(--matcha-space-250, 20px);
|
|
97
|
+
|
|
98
|
+
// ── Empty cell placeholder ────────────────────────────────────────────
|
|
99
|
+
--matcha-table-empty-cell-text: var(--matcha-color-text-muted,
|
|
100
|
+
rgba(var(--matcha-color-fg), 0.5));
|
|
101
|
+
|
|
102
|
+
// ── Variant accent (semantic row) ─────────────────────────────────────
|
|
103
|
+
--matcha-table-variant-accent-width: var(--matcha-space-050, 4px);
|
|
104
|
+
--matcha-table-row-accent-child-opacity: 0.5;
|
|
105
|
+
--matcha-table-selected-accent-width: var(--matcha-border-thin, 2px);
|
|
106
|
+
--matcha-table-selected-accent-color: var(--matcha-color-accent);
|
|
107
|
+
|
|
108
|
+
// ── Column width hints (utility classes col-*) ────────────────────────
|
|
109
|
+
--matcha-table-col-checkbox-width: var(--matcha-space-600, 48px);
|
|
110
|
+
--matcha-table-col-id-width: var(--matcha-space-1000, 80px);
|
|
111
|
+
--matcha-table-col-narrow-width: var(--matcha-space-1500, 120px);
|
|
112
|
+
--matcha-table-col-medium-width: var(--matcha-space-2500, 200px);
|
|
113
|
+
// Pino da coluna de Ações (matcha-cell-action) — mesma escala de
|
|
114
|
+
// --matcha-table-col-id-width (80px), token próprio pra não acoplar
|
|
115
|
+
// semanticamente coisas diferentes que hoje só coincidem em valor.
|
|
116
|
+
--matcha-table-col-actions-width: var(--matcha-space-1000, 80px);
|
|
117
|
+
|
|
118
|
+
// ── States / animations ───────────────────────────────────────────────
|
|
119
|
+
--matcha-table-disabled-opacity: var(--matcha-state-disabled-opacity, 0.5);
|
|
120
|
+
--matcha-table-loading-pulse-duration: var(--matcha-duration-slow, 1500ms);
|
|
121
|
+
--matcha-table-loading-pulse-opacity-min: 0.5;
|
|
122
|
+
--matcha-table-transition-duration: var(--matcha-duration-instant, 80ms);
|
|
123
|
+
--matcha-table-focus-ring-width: var(--matcha-state-focus-ring-width, 2px);
|
|
124
|
+
--matcha-table-focus-ring-color: var(--matcha-color-accent);
|
|
125
|
+
|
|
126
|
+
// ── Empty state row (matcha-table-empty directive) ────────────────────
|
|
127
|
+
--matcha-table-empty-padding-y: var(--matcha-space-500, 40px);
|
|
128
|
+
--matcha-table-empty-padding-x: var(--matcha-space-300, 24px);
|
|
129
|
+
|
|
130
|
+
// ── Resize handle (matcha-table-resizable directive) ──────────────────
|
|
131
|
+
--matcha-table-resize-handle-width: var(--matcha-space-100, 8px);
|
|
132
|
+
--matcha-table-resize-indicator-width: var(--matcha-border-hairline, 1px);
|
|
133
|
+
--matcha-table-resize-indicator-height: 50%;
|
|
134
|
+
--matcha-table-resize-indicator-top: 25%;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── Base — display table nativo + typography via vars ─────────────────
|
|
138
|
+
.matcha-table {
|
|
139
|
+
display: table;
|
|
140
|
+
width: 100%;
|
|
141
|
+
// separate (não collapse) + spacing 0 → visualmente idêntico (zero gap
|
|
142
|
+
// entre cells), mas `border-collapse: collapse` é conhecido por quebrar
|
|
143
|
+
// `position: sticky` em <th>/<td> em vários browsers — especialmente
|
|
144
|
+
// quando a cell precisa ficar sticky nos DOIS eixos ao mesmo tempo (linha
|
|
145
|
+
// + coluna, o canto stickyHeader × stickyStart/stickyEnd). Só existe
|
|
146
|
+
// border-bottom no arquivo (nenhum border-top) — sem risco de borda dupla.
|
|
147
|
+
border-collapse: separate;
|
|
148
|
+
border-spacing: 0;
|
|
149
|
+
font-family: var(--matcha-font-family);
|
|
150
|
+
font-size: var(--matcha-table-font-size);
|
|
151
|
+
line-height: var(--matcha-table-font-line-height);
|
|
152
|
+
font-weight: var(--matcha-weight-regular, 400);
|
|
153
|
+
color: var(--matcha-color-text-secondary,
|
|
154
|
+
color-mix(in srgb, var(--matcha-color-fg) 70%, transparent));
|
|
155
|
+
|
|
156
|
+
// ── Header cells (text/primary, border-bottom 2px, height 64) ────────
|
|
157
|
+
thead th {
|
|
158
|
+
box-sizing: border-box;
|
|
159
|
+
height: var(--matcha-table-cell-height-comfortable);
|
|
160
|
+
min-width: var(--matcha-table-cell-min-width);
|
|
161
|
+
padding: 0
|
|
162
|
+
var(--matcha-table-cell-padding-x-right)
|
|
163
|
+
0
|
|
164
|
+
var(--matcha-table-cell-padding-x-left);
|
|
165
|
+
background: var(--matcha-table-cell-bg);
|
|
166
|
+
color: var(--matcha-color-text-primary,
|
|
167
|
+
var(--matcha-color-fg));
|
|
168
|
+
// Header menor que body — hierarquia "metadado" vs "conteúdo".
|
|
169
|
+
font-size: var(--matcha-table-header-font-size);
|
|
170
|
+
line-height: var(--matcha-table-header-font-line-height);
|
|
171
|
+
font-weight: var(--matcha-weight-semibold, 600);
|
|
172
|
+
letter-spacing: var(--matcha-table-header-letter-spacing);
|
|
173
|
+
text-align: left;
|
|
174
|
+
vertical-align: middle;
|
|
175
|
+
border-bottom: var(--matcha-table-border-header) solid
|
|
176
|
+
var(--matcha-table-border-color);
|
|
177
|
+
|
|
178
|
+
// Alinhamento — data-align é o canon DSV3; data-alinhamento + utility
|
|
179
|
+
// classes seguem aceitos (deprecated, remoção em ciclo futuro)
|
|
180
|
+
&[data-align="center"], &[data-alinhamento="center"], &.text-center { text-align: center; }
|
|
181
|
+
&[data-align="right"], &[data-alinhamento="right"], &.text-right { text-align: right; }
|
|
182
|
+
|
|
183
|
+
// ── Sortable hint ([matcha-table-sortable] directive seta os attrs) ──
|
|
184
|
+
&[data-sortable] {
|
|
185
|
+
cursor: pointer;
|
|
186
|
+
user-select: none;
|
|
187
|
+
// SEMPRE reserva espaço pro chevron (mesmo inativo) — chevron entra/sai
|
|
188
|
+
// só via opacity. Sem padding condicional → texto NÃO desloca no hover.
|
|
189
|
+
padding-right: calc(var(--matcha-table-cell-padding-x-right) +
|
|
190
|
+
var(--matcha-table-sort-icon-size));
|
|
191
|
+
position: relative;
|
|
192
|
+
|
|
193
|
+
// Hover NÃO muda bg do header — bg-change era o que fazia o user
|
|
194
|
+
// perceber "movimento" quando o chevron entrava ao mesmo tempo.
|
|
195
|
+
// Manter header estático no hover, só chevron aparece com opacity.
|
|
196
|
+
// Cursor pointer + chevron fade já comunicam interatividade.
|
|
197
|
+
|
|
198
|
+
// Sort indicators — SVG 1:1 com `matcha/icon/arrow` (figma-icons.ts).
|
|
199
|
+
// Estado inativo (none) = INVISÍVEL (opacity 0). Aparece no hover do header
|
|
200
|
+
// com opacity faded, full quando ativo (asc/desc). Pattern canon Stripe/Linear:
|
|
201
|
+
// sortable em todas as colunas, mas indicador só na que tá ordenando.
|
|
202
|
+
&::after {
|
|
203
|
+
content: '';
|
|
204
|
+
position: absolute;
|
|
205
|
+
right: var(--matcha-table-cell-padding-x-right);
|
|
206
|
+
top: 50%;
|
|
207
|
+
transform: translateY(-50%);
|
|
208
|
+
width: var(--matcha-table-sort-icon-size);
|
|
209
|
+
height: var(--matcha-table-sort-icon-size);
|
|
210
|
+
background: var(--matcha-table-sort-icon-color);
|
|
211
|
+
transition: background-color var(--matcha-table-transition-duration) linear;
|
|
212
|
+
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 7.82499L6.1 12.725C5.9 12.925 5.66667 13.0208 5.4 13.0125C5.13333 13.0042 4.9 12.9 4.7 12.7C4.51667 12.5 4.42083 12.2667 4.4125 12C4.40417 11.7333 4.5 11.5 4.7 11.3L11.3 4.69999C11.4 4.59999 11.5083 4.52915 11.625 4.48749C11.7417 4.44582 11.8667 4.42499 12 4.42499C12.1333 4.42499 12.2583 4.44582 12.375 4.48749C12.4917 4.52915 12.6 4.59999 12.7 4.69999L19.3 11.3C19.4833 11.4833 19.575 11.7125 19.575 11.9875C19.575 12.2625 19.4833 12.5 19.3 12.7C19.1 12.9 18.8625 13 18.5875 13C18.3125 13 18.075 12.9 17.875 12.7L13 7.82499V19C13 19.2833 12.9042 19.5208 12.7125 19.7125C12.5208 19.9042 12.2833 20 12 20C11.7167 20 11.4792 19.9042 11.2875 19.7125C11.0958 19.5208 11 19.2833 11 19V7.82499Z'/></svg>")
|
|
213
|
+
center/contain no-repeat;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Hover no header — chevron escurece pra foreground full (já visível
|
|
217
|
+
// muted antes via alpha 0.45). Reforça que tá interativo.
|
|
218
|
+
&:hover::after {
|
|
219
|
+
background: var(--matcha-color-text-primary,
|
|
220
|
+
var(--matcha-color-fg));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Padding-right SEMPRE reserva espaço pro chevron. Antes ajustava
|
|
224
|
+
// condicionalmente (sem padding extra no inativo) — causava text
|
|
225
|
+
// "dançar" 20px ao hover quando padding crescia pra acomodar arrow.
|
|
226
|
+
// Mantém estável: chevron entra via opacity, sem reflow do texto.
|
|
227
|
+
|
|
228
|
+
&[data-sort-direction="asc"]::after {
|
|
229
|
+
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 7.82499L6.1 12.725C5.9 12.925 5.66667 13.0208 5.4 13.0125C5.13333 13.0042 4.9 12.9 4.7 12.7C4.51667 12.5 4.42083 12.2667 4.4125 12C4.40417 11.7333 4.5 11.5 4.7 11.3L11.3 4.69999C11.4 4.59999 11.5083 4.52915 11.625 4.48749C11.7417 4.44582 11.8667 4.42499 12 4.42499C12.1333 4.42499 12.2583 4.44582 12.375 4.48749C12.4917 4.52915 12.6 4.59999 12.7 4.69999L19.3 11.3C19.4833 11.4833 19.575 11.7125 19.575 11.9875C19.575 12.2625 19.4833 12.5 19.3 12.7C19.1 12.9 18.8625 13 18.5875 13C18.3125 13 18.075 12.9 17.875 12.7L13 7.82499V19C13 19.2833 12.9042 19.5208 12.7125 19.7125C12.5208 19.9042 12.2833 20 12 20C11.7167 20 11.4792 19.9042 11.2875 19.7125C11.0958 19.5208 11 19.2833 11 19V7.82499Z'/></svg>")
|
|
230
|
+
center/contain no-repeat;
|
|
231
|
+
background: var(--matcha-table-sort-icon-color-active);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
&[data-sort-direction="desc"]::after {
|
|
235
|
+
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 16.175V5C11 4.71667 11.0958 4.47917 11.2875 4.2875C11.4792 4.09583 11.7167 4 12 4C12.2833 4 12.5208 4.09583 12.7125 4.2875C12.9042 4.47917 13 4.71667 13 5V16.175L17.9 11.275C18.1 11.075 18.3333 10.9792 18.6 10.9875C18.8667 10.9958 19.1 11.1 19.3 11.3C19.4833 11.5 19.5792 11.7333 19.5875 12C19.5958 12.2667 19.5 12.5 19.3 12.7L12.7 19.3C12.6 19.4 12.4917 19.4708 12.375 19.5125C12.2583 19.5542 12.1333 19.575 12 19.575C11.8667 19.575 11.7417 19.5542 11.625 19.5125C11.5083 19.4708 11.4 19.4 11.3 19.3L4.7 12.7C4.51667 12.5167 4.425 12.2875 4.425 12.0125C4.425 11.7375 4.51667 11.5 4.7 11.3C4.9 11.1 5.1375 11 5.4125 11C5.6875 11 5.925 11.1 6.125 11.3L11 16.175Z'/></svg>")
|
|
236
|
+
center/contain no-repeat;
|
|
237
|
+
background: var(--matcha-table-sort-icon-color-active);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Header right-aligned com sort — chevron vem ANTES do texto (canon).
|
|
241
|
+
&[data-align="right"], &[data-alinhamento="right"], &.text-right {
|
|
242
|
+
padding-right: var(--matcha-table-cell-padding-x-right);
|
|
243
|
+
padding-left: calc(var(--matcha-table-cell-padding-x-left) +
|
|
244
|
+
var(--matcha-table-sort-icon-size));
|
|
245
|
+
|
|
246
|
+
&::after {
|
|
247
|
+
right: auto;
|
|
248
|
+
left: var(--matcha-table-cell-padding-x-left);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Focus ring quando keyboard-navigated (tabindex via directive).
|
|
253
|
+
&:focus-visible {
|
|
254
|
+
outline: var(--matcha-table-focus-ring-width) solid
|
|
255
|
+
var(--matcha-table-focus-ring-color);
|
|
256
|
+
outline-offset: calc(-1 * var(--matcha-table-focus-ring-width));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ── Body cells ────────────────────────────────────────────────────────
|
|
262
|
+
tbody td {
|
|
263
|
+
box-sizing: border-box;
|
|
264
|
+
height: var(--matcha-table-cell-height-comfortable);
|
|
265
|
+
min-width: var(--matcha-table-cell-min-width);
|
|
266
|
+
padding: 0
|
|
267
|
+
var(--matcha-table-cell-padding-x-right)
|
|
268
|
+
0
|
|
269
|
+
var(--matcha-table-cell-padding-x-left);
|
|
270
|
+
background: var(--matcha-table-cell-bg);
|
|
271
|
+
color: var(--matcha-color-text-secondary,
|
|
272
|
+
color-mix(in srgb, var(--matcha-color-fg) 70%, transparent));
|
|
273
|
+
vertical-align: middle;
|
|
274
|
+
border-bottom: var(--matcha-table-border-row) solid
|
|
275
|
+
var(--matcha-table-border-color);
|
|
276
|
+
transition: background-color var(--matcha-table-transition-duration) linear;
|
|
277
|
+
|
|
278
|
+
&[data-align="center"], &[data-alinhamento="center"], &.text-center { text-align: center; }
|
|
279
|
+
&[data-align="right"], &[data-alinhamento="right"], &.text-right { text-align: right; }
|
|
280
|
+
|
|
281
|
+
// Helper: tabular-nums (alinha decimais)
|
|
282
|
+
&[data-numeric], &.numeric {
|
|
283
|
+
font-variant-numeric: tabular-nums;
|
|
284
|
+
font-feature-settings: 'tnum';
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Helper: ellipsis (texto longo)
|
|
288
|
+
&[data-truncate], &.truncate {
|
|
289
|
+
max-width: 0;
|
|
290
|
+
white-space: nowrap;
|
|
291
|
+
overflow: hidden;
|
|
292
|
+
text-overflow: ellipsis;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Helper: cells vazias preenchidas com "—" muted (canon moderno).
|
|
296
|
+
&:empty::after {
|
|
297
|
+
content: '—';
|
|
298
|
+
color: var(--matcha-table-empty-cell-text);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ── Column width hints (aplicar em <th> — <td> herda pela coluna) ─────
|
|
303
|
+
thead th,
|
|
304
|
+
tbody td {
|
|
305
|
+
// min-width igual ao width — sem isso, a regra base thead th/tbody td
|
|
306
|
+
// (min-width:120px) vence e a coluna nunca encolhe pro valor pretendido
|
|
307
|
+
// (mesmo bug achado e corrigido em .col-actions).
|
|
308
|
+
&.col-checkbox { width: var(--matcha-table-col-checkbox-width); min-width: var(--matcha-table-col-checkbox-width); text-align: center; }
|
|
309
|
+
&.col-id { width: var(--matcha-table-col-id-width); }
|
|
310
|
+
&.col-narrow { width: var(--matcha-table-col-narrow-width); }
|
|
311
|
+
&.col-medium { width: var(--matcha-table-col-medium-width); }
|
|
312
|
+
// Actions / icon-buttons — pinada em --matcha-table-col-actions-width (80px).
|
|
313
|
+
// Children inline-flex, centralizados (título "Ações" no header também
|
|
314
|
+
// centraliza — text-align: center vale pro conteúdo das duas linhas).
|
|
315
|
+
//
|
|
316
|
+
// Importante: `.matcha-button` tem `display: flex` (block-level) que faria
|
|
317
|
+
// os icon-buttons empilharem verticalmente. Override via selector descendant
|
|
318
|
+
// com specificity maior pra forçar inline-flex no contexto de actions cell.
|
|
319
|
+
&.col-actions {
|
|
320
|
+
width: var(--matcha-table-col-actions-width);
|
|
321
|
+
// min-width base da tbody td/thead th é 120px (--matcha-table-cell-min-width)
|
|
322
|
+
// — maior que os 80px daqui, e min-width sempre vence sobre width no box
|
|
323
|
+
// model. Sem este override, a coluna ficava presa em 120px (achado real).
|
|
324
|
+
min-width: var(--matcha-table-col-actions-width);
|
|
325
|
+
white-space: nowrap;
|
|
326
|
+
text-align: center;
|
|
327
|
+
|
|
328
|
+
> .matcha-button,
|
|
329
|
+
> button[matcha-icon-button],
|
|
330
|
+
> * {
|
|
331
|
+
display: inline-flex;
|
|
332
|
+
vertical-align: middle;
|
|
333
|
+
}
|
|
334
|
+
> * + * {
|
|
335
|
+
margin-left: var(--matcha-space-050, 4px);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// Greedy = espaço residual (default, classe explícita pra documentação).
|
|
339
|
+
&.col-greedy { width: auto; }
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── Paginator alinhado após table (convention) ────────────────────────
|
|
343
|
+
// Sem margin-top — paginator gruda no border-bottom da última row.
|
|
344
|
+
// Spacing visual vem dos paddings internos do próprio matcha-paginator.
|
|
345
|
+
.matcha-table-paginator,
|
|
346
|
+
& + matcha-paginator {
|
|
347
|
+
display: block;
|
|
348
|
+
margin-top: 0;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ── Row clickable ([rowClick] directive — só o binding já ativa tudo) ─
|
|
352
|
+
tbody tr.matcha-row-clickable {
|
|
353
|
+
cursor: pointer;
|
|
354
|
+
|
|
355
|
+
&:hover td {
|
|
356
|
+
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
&:focus-visible {
|
|
360
|
+
outline: var(--matcha-table-focus-ring-width) solid
|
|
361
|
+
var(--matcha-table-focus-ring-color);
|
|
362
|
+
outline-offset: calc(-1 * var(--matcha-table-focus-ring-width));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ── Modifiers via atributo no host (Angular @HostBinding, ver
|
|
367
|
+
// table.component.ts) ──────────────────────────────────────────────────
|
|
368
|
+
// Cada modifier tem 2 seletores alternativos: `&[x]` (forma legado — o
|
|
369
|
+
// host JÁ É `.matcha-table`, self) e `matcha-table[x] &` (forma elemento
|
|
370
|
+
// — o atributo mora no host `<matcha-table>`, mas o alvo real é o filho
|
|
371
|
+
// `.matcha-table` dentro do wrapper; CSS alcança via descendente, não
|
|
372
|
+
// precisa o atributo estar duplicado no filho).
|
|
373
|
+
// Striped usa :where() pra dropar specificity do :nth-child — hover vence.
|
|
374
|
+
&[striped] tbody tr:where(:nth-child(even)) td,
|
|
375
|
+
matcha-table[striped] & tbody tr:where(:nth-child(even)) td {
|
|
376
|
+
--matcha-table-cell-bg: var(--matcha-table-row-bg-striped);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
&[hover] tbody tr:hover td,
|
|
380
|
+
matcha-table[hover] & tbody tr:hover td {
|
|
381
|
+
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Stripe-aware hover: row PAR ganha alpha mais forte pra preservar stripe.
|
|
385
|
+
&[striped] tbody tr:where(:nth-child(even)).matcha-row-clickable:hover td,
|
|
386
|
+
matcha-table[striped] & tbody tr:where(:nth-child(even)).matcha-row-clickable:hover td,
|
|
387
|
+
&[striped][hover] tbody tr:where(:nth-child(even)):hover td,
|
|
388
|
+
matcha-table[striped][hover] & tbody tr:where(:nth-child(even)):hover td {
|
|
389
|
+
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover-striped);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Hover accent de linha clicável: a diretiva [rowClick] já sobrescreve
|
|
393
|
+
// --matcha-table-row-bg-hover(-striped) inline no próprio <tr> (ver
|
|
394
|
+
// table-clickable-row.directive.ts) — nenhuma regra de tema necessária
|
|
395
|
+
// aqui, o estilo inline já vence qualquer especificidade.
|
|
396
|
+
|
|
397
|
+
// ── Row navegável (`<a matcha-cell-link>` na célula) ───────────────────
|
|
398
|
+
// A linha que LEVA PRA OUTRA PÁGINA não é clicável inteira: quem navega é uma
|
|
399
|
+
// âncora de verdade na célula, pra que ctrl+clique, clique do meio e o menu do
|
|
400
|
+
// botão direito funcionem — e pra que o resto da linha continue selecionável
|
|
401
|
+
// com o mouse (com a linha toda clicável, não dava pra copiar texto da tabela).
|
|
402
|
+
//
|
|
403
|
+
// O feedback visual é o inverso do rowClick: ponteiro e tom accent aparecem só
|
|
404
|
+
// quando o mouse está sobre a âncora, e aí a linha INTEIRA pinta. Fora dela vale
|
|
405
|
+
// o hover neutro de sempre.
|
|
406
|
+
//
|
|
407
|
+
// Pinta via --matcha-table-cell-bg em TODOS os td da linha (mesmo caminho do
|
|
408
|
+
// hover normal), não com background-color no <tr>: em tabela striped o fundo
|
|
409
|
+
// mora no td, e um background no tr ficaria por baixo dele — o resultado seria
|
|
410
|
+
// uma célula colorida e o resto não.
|
|
411
|
+
//
|
|
412
|
+
// Depois das regras de striped de propósito: mesma especificidade, e ordem de
|
|
413
|
+
// origem decide. `:has()` já é usado em ~10 componentes do tema.
|
|
414
|
+
// O estilo BASE da âncora é global (base/_reset.scss) — ela também aparece em
|
|
415
|
+
// card de listagem, fora de qualquer tabela. Aqui fica só o que é da tabela: o
|
|
416
|
+
// realce da linha inteira.
|
|
417
|
+
a[matcha-cell-link]:focus-visible {
|
|
418
|
+
outline: var(--matcha-table-focus-ring-width) solid
|
|
419
|
+
var(--matcha-table-focus-ring-color);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
tbody tr:has(a[matcha-cell-link]:hover) td,
|
|
423
|
+
tbody tr:has(a[matcha-cell-link]:focus-visible) td {
|
|
424
|
+
--matcha-table-cell-bg: var(--matcha-table-row-bg-hover-accent);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// O ALVO é a CÉLULA inteira, não só o texto do nome.
|
|
428
|
+
//
|
|
429
|
+
// A âncora envolve o nome, e em título curto isso vira um alvo de poucos pixels —
|
|
430
|
+
// reclamação de quem usa, medida em séries. O `::after` esticado resolve sem trocar
|
|
431
|
+
// a âncora por handler de clique: o href continua existindo, então ctrl+clique,
|
|
432
|
+
// clique do meio e "abrir em nova aba" seguem funcionando, e o foco de teclado
|
|
433
|
+
// continua sendo o do link.
|
|
434
|
+
//
|
|
435
|
+
// De quebra conserta o hover: a regra acima só pinta a linha quando o mouse está
|
|
436
|
+
// sobre o TEXTO. Com a área esticada, pinta ao entrar na célula — que é o que faz
|
|
437
|
+
// a linha parecer clicável.
|
|
438
|
+
//
|
|
439
|
+
// Escopado em `.matcha-table td` de propósito: `a[matcha-cell-link]` também aparece
|
|
440
|
+
// em card de listagem, fora de tabela, e lá o link deve seguir do tamanho do texto.
|
|
441
|
+
//
|
|
442
|
+
// O custo é a seleção de texto DENTRO desta célula. No resto da linha continua
|
|
443
|
+
// funcionando, que é a diferença para a linha toda clicável.
|
|
444
|
+
td:has(a[matcha-cell-link]) {
|
|
445
|
+
position: relative;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
td a[matcha-cell-link]::after {
|
|
449
|
+
content: '';
|
|
450
|
+
position: absolute;
|
|
451
|
+
inset: 0;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
tbody tr.is-selected td {
|
|
455
|
+
--matcha-table-cell-bg: var(--matcha-table-row-bg-selected);
|
|
456
|
+
}
|
|
457
|
+
// Selected row ganha border-left accent — affordance canon Linear/Notion.
|
|
458
|
+
// No <tr> → não some com stickyStart. Usa ::after pra coexistir com
|
|
459
|
+
// ::before do variant accent sem conflito.
|
|
460
|
+
tbody tr.is-selected {
|
|
461
|
+
position: relative;
|
|
462
|
+
|
|
463
|
+
&::after {
|
|
464
|
+
content: '';
|
|
465
|
+
position: absolute;
|
|
466
|
+
top: 0;
|
|
467
|
+
left: 0;
|
|
468
|
+
width: var(--matcha-table-selected-accent-width);
|
|
469
|
+
height: 100%;
|
|
470
|
+
background: var(--matcha-table-selected-accent-color);
|
|
471
|
+
pointer-events: none;
|
|
472
|
+
z-index: 2; // acima do variant accent (z-index 1)
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Bordered — box-shadow inset em vez de border real (não clipa shadows
|
|
477
|
+
// externos das sticky cols, que projetam pra fora da <table>).
|
|
478
|
+
// Conhecido: em alguns casos (sticky-header/colunas fixas, forma
|
|
479
|
+
// elemento) o background opaco das cells pode encobrir parte deste
|
|
480
|
+
// traço — não resolvido nesta rodada (fora do escopo desta tarefa); se
|
|
481
|
+
// precisar de borda garantida num caso desses, use a utility class de
|
|
482
|
+
// borda (ex.: `b-1`) direto no consumo do componente.
|
|
483
|
+
&[bordered] {
|
|
484
|
+
box-shadow: inset 0 0 0 var(--matcha-table-border-row)
|
|
485
|
+
var(--matcha-table-border-color);
|
|
486
|
+
border-radius: var(--matcha-table-bordered-radius);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Sticky header (vertical scroll). Forma legado: o host (a própria table) é
|
|
490
|
+
// o container de scroll. Default do componente é overflow-y:hidden (só
|
|
491
|
+
// horizontal é fallback passivo — dois scrolls na tela atrapalham mobile);
|
|
492
|
+
// stickyHeader é opt-in EXPLÍCITO, reabilita overflow-y:auto de propósito
|
|
493
|
+
// + altura máxima (sem isso não há o que rolar, o header não tem contra o
|
|
494
|
+
// que grudar). Altura configurável via var (default 70vh).
|
|
495
|
+
&[sticky-header],
|
|
496
|
+
matcha-table[sticky-header] & {
|
|
497
|
+
max-height: var(--matcha-table-sticky-header-max-height, 70vh);
|
|
498
|
+
overflow-y: auto;
|
|
499
|
+
}
|
|
500
|
+
&[sticky-header] thead th,
|
|
501
|
+
matcha-table[sticky-header] & thead th {
|
|
502
|
+
position: sticky;
|
|
503
|
+
top: 0;
|
|
504
|
+
z-index: 1;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Size variants (data-size cascateia altura)
|
|
508
|
+
&[data-size="compact"] thead th,
|
|
509
|
+
&[data-size="compact"] tbody td { height: var(--matcha-table-cell-height-compact); }
|
|
510
|
+
&[data-size="spacious"] thead th,
|
|
511
|
+
&[data-size="spacious"] tbody td { height: var(--matcha-table-cell-height-spacious); }
|
|
512
|
+
|
|
513
|
+
// ── Sticky columns (start/end) — canon scroll horizontal ──────────────
|
|
514
|
+
// Performance: nada de box-shadow com blur nem background-image (gradient)
|
|
515
|
+
// aqui — são caros de repaint/compositar MULTIPLICADOS por linha (uma
|
|
516
|
+
// tabela de 40+ linhas com 2 colunas sticky = 80 elementos), e causavam
|
|
517
|
+
// queda de FPS real no scroll (medido em produção). Custo mínimo:
|
|
518
|
+
// background-color sólido (fixo, não acompanha hover/tint — troca-se
|
|
519
|
+
// fidelidade visual por performance) + border 1px sólida no lugar da
|
|
520
|
+
// sombra de scroll-edge (borda é essencialmente grátis pro compositor,
|
|
521
|
+
// sombra com blur não é).
|
|
522
|
+
//
|
|
523
|
+
// :not([sticky-header])/:not(matcha-table[sticky-header] &) — combinar
|
|
524
|
+
// sticky column COM sticky header exige que a cell de CANTO (cabeçalho da
|
|
525
|
+
// coluna fixa) fique sticky nos dois eixos (top E left/right) ao mesmo
|
|
526
|
+
// tempo — inconsistente entre browsers em cells de <table> (documentado
|
|
527
|
+
// no JSDoc do componente). Em vez de deixar o canto quebrado, desliga a
|
|
528
|
+
// coluna fixa inteira quando stickyHeader está ativo — só o header fixo
|
|
529
|
+
// (mais universalmente útil) permanece. `sticky-header` agora é atributo
|
|
530
|
+
// no host — o 2º `:not()` cobre o caso em que o host é o wrapper (forma
|
|
531
|
+
// elemento, `sticky-header` não está no `.matcha-table` em si, está no
|
|
532
|
+
// `<matcha-table>` ancestral). `data-sticky-start`/`-end` continuam só no
|
|
533
|
+
// nó real (mirrorAttributesToRealTable), não precisam de alternativa.
|
|
534
|
+
@for $i from 1 through 4 {
|
|
535
|
+
&[data-sticky-start="#{$i}"]:not([sticky-header]):not(matcha-table[sticky-header] &) {
|
|
536
|
+
thead th:nth-child(-n+#{$i}),
|
|
537
|
+
tbody tr td:nth-child(-n+#{$i}) {
|
|
538
|
+
position: sticky;
|
|
539
|
+
z-index: 2;
|
|
540
|
+
background-color: var(--matcha-color-surface-card);
|
|
541
|
+
}
|
|
542
|
+
// Última cell do grupo sticky-start marca o scroll-edge com borda fina.
|
|
543
|
+
thead th:nth-child(#{$i}),
|
|
544
|
+
tbody tr td:nth-child(#{$i}) {
|
|
545
|
+
border-right: var(--matcha-border-hairline, 1px) solid var(--matcha-color-surface-border);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
&[data-sticky-end="#{$i}"]:not([sticky-header]):not(matcha-table[sticky-header] &) {
|
|
550
|
+
thead th:nth-last-child(-n+#{$i}),
|
|
551
|
+
tbody tr td:nth-last-child(-n+#{$i}) {
|
|
552
|
+
position: sticky;
|
|
553
|
+
z-index: 2;
|
|
554
|
+
background-color: var(--matcha-color-surface-card);
|
|
555
|
+
}
|
|
556
|
+
thead th:nth-last-child(#{$i}),
|
|
557
|
+
tbody tr td:nth-last-child(#{$i}) {
|
|
558
|
+
border-left: var(--matcha-border-hairline, 1px) solid var(--matcha-color-surface-border);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
&[data-sticky-start]:not([sticky-header]):not(matcha-table[sticky-header] &) thead th:first-child,
|
|
564
|
+
&[data-sticky-start]:not([sticky-header]):not(matcha-table[sticky-header] &) tbody tr td:first-child { left: 0; }
|
|
565
|
+
&[data-sticky-end]:not([sticky-header]):not(matcha-table[sticky-header] &) thead th:last-child,
|
|
566
|
+
&[data-sticky-end]:not([sticky-header]):not(matcha-table[sticky-header] &) tbody tr td:last-child { right: 0; }
|
|
567
|
+
|
|
568
|
+
// ── Variant accent (semantic row coloring) ────────────────────────────
|
|
569
|
+
// Defaults canon Figma DSV3: equal=info, plus=success, minus=danger.
|
|
570
|
+
// Accent vive no <tr> → NÃO some com stickyStart.
|
|
571
|
+
// `position: relative` em <tr> suportado em Chrome 80+, FF 87+, Safari 14+.
|
|
572
|
+
tr.equal { --matcha-table-row-accent-color: var(--matcha-color-info); }
|
|
573
|
+
tr.plus { --matcha-table-row-accent-color: var(--matcha-color-success); }
|
|
574
|
+
tr.minus { --matcha-table-row-accent-color: var(--matcha-color-danger); }
|
|
575
|
+
|
|
576
|
+
tbody tr[data-variant],
|
|
577
|
+
tbody tr.equal,
|
|
578
|
+
tbody tr.plus,
|
|
579
|
+
tbody tr.minus {
|
|
580
|
+
position: relative;
|
|
581
|
+
|
|
582
|
+
&::before {
|
|
583
|
+
content: '';
|
|
584
|
+
position: absolute;
|
|
585
|
+
top: 0;
|
|
586
|
+
left: 0;
|
|
587
|
+
width: var(--matcha-table-variant-accent-width);
|
|
588
|
+
height: 100%;
|
|
589
|
+
background: var(--matcha-table-row-accent-color, transparent);
|
|
590
|
+
pointer-events: none;
|
|
591
|
+
z-index: 1; // acima do bg da cell, abaixo do sticky shadow
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Child row (indent + accent esmaecido) — pattern tree/hierarquia.
|
|
596
|
+
tbody tr.child-item::before {
|
|
597
|
+
opacity: var(--matcha-table-row-accent-child-opacity);
|
|
598
|
+
}
|
|
599
|
+
tbody tr.child-item td:first-child {
|
|
600
|
+
padding-left: calc(var(--matcha-table-cell-padding-x-left) +
|
|
601
|
+
var(--matcha-space-200, 16px));
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// ── Loading state global — pulse + aria-busy ─────────────────────────
|
|
605
|
+
&[loading] tbody tr,
|
|
606
|
+
matcha-table[loading] & tbody tr {
|
|
607
|
+
animation: matcha-table-loading-pulse
|
|
608
|
+
var(--matcha-table-loading-pulse-duration)
|
|
609
|
+
ease-in-out infinite;
|
|
610
|
+
pointer-events: none;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// ── Disabled state — row/cell ─────────────────────────────────────────
|
|
614
|
+
// Pattern canon Material/Polaris. A11y: também aplicar aria-disabled.
|
|
615
|
+
tbody tr[disabled], tbody tr.is-disabled,
|
|
616
|
+
tbody td[disabled], tbody td.is-disabled {
|
|
617
|
+
opacity: var(--matcha-table-disabled-opacity);
|
|
618
|
+
pointer-events: none;
|
|
619
|
+
cursor: not-allowed;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// ── Per-row loading (matcha-table-loading directive) ─────────────────
|
|
623
|
+
// Pulse só naquela row — optimistic save/delete sem bloquear a tabela.
|
|
624
|
+
tbody tr.is-loading {
|
|
625
|
+
animation: matcha-table-loading-pulse
|
|
626
|
+
var(--matcha-table-loading-pulse-duration)
|
|
627
|
+
ease-in-out infinite;
|
|
628
|
+
pointer-events: none;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// ── Empty state row (matcha-table-empty directive) ────────────────────
|
|
632
|
+
// Container pra <matcha-empty-state>. Directive seta colspan automático.
|
|
633
|
+
tbody tr.is-empty td {
|
|
634
|
+
padding: var(--matcha-table-empty-padding-y) var(--matcha-table-empty-padding-x);
|
|
635
|
+
text-align: center;
|
|
636
|
+
background: var(--matcha-table-cell-bg);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// ── Resizable column (matcha-table-resizable directive) ───────────────
|
|
640
|
+
// Handle invisível na borda direita. Hover mostra cursor + barra discreta.
|
|
641
|
+
thead th.is-resizable {
|
|
642
|
+
position: relative;
|
|
643
|
+
|
|
644
|
+
&::before {
|
|
645
|
+
content: '';
|
|
646
|
+
position: absolute;
|
|
647
|
+
top: var(--matcha-table-resize-indicator-top);
|
|
648
|
+
right: 0;
|
|
649
|
+
width: var(--matcha-table-resize-indicator-width);
|
|
650
|
+
height: var(--matcha-table-resize-indicator-height);
|
|
651
|
+
background: var(--matcha-table-border-color);
|
|
652
|
+
opacity: 0;
|
|
653
|
+
transition: opacity var(--matcha-table-transition-duration) linear;
|
|
654
|
+
}
|
|
655
|
+
&:hover::before { opacity: 1; }
|
|
656
|
+
}
|
|
657
|
+
thead th.is-resizable::after {
|
|
658
|
+
// Override do ::after do sort-indicator: handle de resize ocupa a borda.
|
|
659
|
+
// Col sortable + resizable é raro — consumer escolhe uma.
|
|
660
|
+
content: '';
|
|
661
|
+
position: absolute;
|
|
662
|
+
top: 0;
|
|
663
|
+
right: calc(-1 * var(--matcha-table-resize-handle-width) / 2);
|
|
664
|
+
width: var(--matcha-table-resize-handle-width);
|
|
665
|
+
height: 100%;
|
|
666
|
+
cursor: col-resize;
|
|
667
|
+
z-index: 3;
|
|
668
|
+
background: transparent;
|
|
669
|
+
mask: none;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Sticky header — forma ELEMENTO (`<matcha-table>`, ver table.component.ts).
|
|
674
|
+
// Aqui quem rola de verdade é `.matcha-table__scroll` (o wrapper), não a
|
|
675
|
+
// `<table class="matcha-table">` interna — a altura máxima precisa ir no
|
|
676
|
+
// wrapper. `sticky-header` mora no HOST `<matcha-table>` (@HostBinding,
|
|
677
|
+
// não mais na `<table>` filha) — como o host é ANCESTRAL do wrapper, um
|
|
678
|
+
// descendente simples já alcança, sem precisar de `:has()`.
|
|
679
|
+
matcha-table[sticky-header] > .matcha-table__scroll {
|
|
680
|
+
max-height: var(--matcha-table-sticky-header-max-height, 70vh);
|
|
681
|
+
overflow-y: auto;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// roundedTop — regra TOP-LEVEL (fora do bloco .matcha-table acima): alcança
|
|
685
|
+
// o host na forma legado (self, `.matcha-table[rounded-top]`, o próprio
|
|
686
|
+
// `<table>` é a superfície visual) e o wrapper de scroll na forma elemento
|
|
687
|
+
// (descendente a partir do host `<matcha-table rounded-top>` — só o
|
|
688
|
+
// wrapper precisa do radius, ele já clipa a `<table>` interna via
|
|
689
|
+
// overflow non-visible, a `<table>` em si não precisa do próprio radius).
|
|
690
|
+
//
|
|
691
|
+
// Fallback inline no 2º var() é OBRIGATÓRIO: --matcha-table-rounded-top-radius
|
|
692
|
+
// é declarada dentro do bloco `.matcha-table { }` acima — na forma elemento
|
|
693
|
+
// `.matcha-table__scroll` é PAI de `.matcha-table` (o wrapper envolve a
|
|
694
|
+
// table real), não descendente. CSS custom property só desce a árvore, não
|
|
695
|
+
// sobe — sem o fallback aqui a var nunca resolve nesse elemento (bug
|
|
696
|
+
// silencioso: sem erro, só o border-radius nunca aparece). O fallback ainda
|
|
697
|
+
// respeita um override do consumer, se ele setar a var em algum ancestral
|
|
698
|
+
// real do wrapper (ex.: no próprio host `<matcha-table>` ou em `:root`).
|
|
699
|
+
.matcha-table[rounded-top] {
|
|
700
|
+
border-top-left-radius: var(--matcha-table-rounded-top-radius);
|
|
701
|
+
border-top-right-radius: var(--matcha-table-rounded-top-radius);
|
|
702
|
+
}
|
|
703
|
+
matcha-table[rounded-top] .matcha-table__scroll {
|
|
704
|
+
border-top-left-radius: var(--matcha-table-rounded-top-radius, var(--matcha-radius-xl, 16px));
|
|
705
|
+
border-top-right-radius: var(--matcha-table-rounded-top-radius, var(--matcha-radius-xl, 16px));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
@keyframes matcha-table-loading-pulse {
|
|
709
|
+
0%, 100% { opacity: 1; }
|
|
710
|
+
50% { opacity: var(--matcha-table-loading-pulse-opacity-min); }
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// ── Reduced motion ────────────────────────────────────────────────────
|
|
714
|
+
@media (prefers-reduced-motion: reduce) {
|
|
715
|
+
.matcha-table tbody td,
|
|
716
|
+
.matcha-table[loading] tbody tr,
|
|
717
|
+
matcha-table[loading] .matcha-table tbody tr {
|
|
718
|
+
transition: none;
|
|
719
|
+
animation: none;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|