@ffid-br/tailor-ui 0.6.0 → 0.7.1

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/dist/style.css CHANGED
@@ -26,71 +26,289 @@
26
26
  :where(:root) {
27
27
  /* Seguem os tokens do Tailwind do app: quem já troca --color-tailor-green pela
28
28
  cor do cliente (accounts, brandTheme) leva o cabeçalho junto. */
29
- --tailor-marca-primaria: var(--color-tailor-green, var(--tailor-green));
30
- --tailor-marca-primaria-texto: var(--color-tailor-ink, var(--tailor-ink));
31
- --tailor-marca-texto: var(--tailor-black);
32
- --tailor-marca-texto-suave: #666666;
33
- --tailor-marca-borda: #E5E5E5;
34
- --tailor-marca-fundo: transparent;
35
- --tailor-marca-fonte-titulo: var(--tailor-font);
36
- --tailor-marca-fonte-texto: var(--tailor-font);
37
- --tailor-marca-peso-titulo: 500;
38
- --tailor-marca-caixa-titulo: none;
39
- --tailor-marca-raio: 0;
29
+ --tailor-brand-primary: var(--color-tailor-green, var(--tailor-green));
30
+ --tailor-brand-primary-text: var(--color-tailor-ink, var(--tailor-ink));
31
+ --tailor-brand-text: var(--tailor-black);
32
+ --tailor-brand-text-muted: #666666;
33
+ --tailor-brand-border: #E5E5E5;
34
+ --tailor-brand-background: transparent;
35
+ --tailor-brand-heading-font: var(--tailor-font);
36
+ --tailor-brand-body-font: var(--tailor-font);
37
+ --tailor-brand-heading-weight: 500;
38
+ --tailor-brand-heading-case: none;
39
+ --tailor-brand-radius: 0;
40
40
  }
41
41
  :where(.dark, [data-theme="dark"]) {
42
- --tailor-marca-primaria-texto: var(--color-tailor-green, var(--tailor-green));
43
- --tailor-marca-texto: var(--tailor-white);
44
- --tailor-marca-texto-suave: #A3A3A3;
45
- --tailor-marca-borda: rgba(255, 255, 255, 0.1);
42
+ --tailor-brand-primary-text: var(--color-tailor-green, var(--tailor-green));
43
+ --tailor-brand-text: var(--tailor-white);
44
+ --tailor-brand-text-muted: #A3A3A3;
45
+ --tailor-brand-border: rgba(255, 255, 255, 0.1);
46
46
  }
47
- .tailor-marca { display: contents; }
47
+ .tailor-brand { display: contents; }
48
48
 
49
- /* TailorPageHeader — cada medida tem a sua variável --tailor-cabecalho-*. */
49
+ /* TailorPageHeader — cada medida tem a sua variável --tailor-header-*. */
50
50
  .tailor-ph {
51
51
  display: flex; flex-direction: column; gap: 21px;
52
- padding: var(--tailor-cabecalho-padding, 0 0 21px);
53
- background: var(--tailor-cabecalho-fundo, var(--tailor-marca-fundo));
54
- border-bottom: var(--tailor-cabecalho-regua, 1px solid var(--tailor-marca-borda));
55
- color: var(--tailor-marca-texto);
56
- font-family: var(--tailor-marca-fonte-texto);
52
+ padding: var(--tailor-header-padding, 0 0 21px);
53
+ background: var(--tailor-header-background, var(--tailor-brand-background));
54
+ border-bottom: var(--tailor-header-rule, 1px solid var(--tailor-brand-border));
55
+ color: var(--tailor-brand-text);
56
+ font-family: var(--tailor-brand-body-font);
57
57
  }
58
- .tailor-ph__linha { display: flex; flex-direction: column; gap: 21px; }
58
+ .tailor-ph__row { display: flex; flex-direction: column; gap: 21px; }
59
59
  @media (min-width: 640px) {
60
- .tailor-ph__linha { flex-direction: row; align-items: flex-end; justify-content: space-between; }
60
+ .tailor-ph__row { flex-direction: row; align-items: flex-end; justify-content: space-between; }
61
61
  }
62
- .tailor-ph__principal { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
63
- .tailor-ph__voltar {
62
+ .tailor-ph__main { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
63
+ .tailor-ph__back {
64
64
  display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: none; cursor: pointer;
65
- font: inherit; font-size: 13px; color: var(--tailor-marca-texto-suave); text-decoration: none; border-radius: var(--tailor-marca-raio);
66
- }
67
- .tailor-ph__voltar:hover, .tailor-ph__trilha-link:hover { color: var(--tailor-marca-texto); }
68
- .tailor-ph__trilha ol { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; padding: 0; list-style: none; font-size: 13px; color: var(--tailor-marca-texto-suave); }
69
- .tailor-ph__trilha li { display: flex; align-items: center; gap: 6px; }
70
- .tailor-ph__trilha-link { color: inherit; text-decoration: none; }
71
- .tailor-ph__trilha [aria-current="page"] { color: var(--tailor-marca-texto); }
72
- .tailor-ph__voltar:focus-visible, .tailor-ph__trilha-link:focus-visible { outline: 3px solid var(--tailor-marca-primaria); outline-offset: 2px; }
73
- .tailor-ph__sobretitulo {
65
+ font: inherit; font-size: 13px; color: var(--tailor-brand-text-muted); text-decoration: none; border-radius: var(--tailor-brand-radius);
66
+ }
67
+ .tailor-ph__back:hover, .tailor-ph__breadcrumb-link:hover { color: var(--tailor-brand-text); }
68
+ .tailor-ph__breadcrumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; padding: 0; list-style: none; font-size: 13px; color: var(--tailor-brand-text-muted); }
69
+ .tailor-ph__breadcrumbs li { display: flex; align-items: center; gap: 6px; }
70
+ .tailor-ph__breadcrumb-link { color: inherit; text-decoration: none; }
71
+ .tailor-ph__breadcrumbs [aria-current="page"] { color: var(--tailor-brand-text); }
72
+ .tailor-ph__back:focus-visible, .tailor-ph__breadcrumb-link:focus-visible { outline: 3px solid var(--tailor-brand-primary); outline-offset: 2px; }
73
+ .tailor-ph__eyebrow {
74
74
  display: flex; align-items: center; gap: 8px; margin: 5px 0 0;
75
75
  font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
76
- color: var(--tailor-marca-primaria-texto);
76
+ color: var(--tailor-brand-primary-text);
77
77
  }
78
- .tailor-ph__ponto { width: 8px; height: 8px; background: var(--tailor-marca-primaria); border-radius: var(--tailor-marca-raio); }
79
- .tailor-ph__titulo-linha { display: flex; flex-wrap: wrap; align-items: center; gap: 13px; }
80
- .tailor-ph__titulo {
78
+ .tailor-ph__dot { width: 8px; height: 8px; background: var(--tailor-brand-primary); border-radius: var(--tailor-brand-radius); }
79
+ .tailor-ph__title-row { display: flex; flex-wrap: wrap; align-items: center; gap: 13px; }
80
+ .tailor-ph__title {
81
81
  margin: 0; line-height: 1.1;
82
- font-family: var(--tailor-marca-fonte-titulo); font-weight: var(--tailor-marca-peso-titulo);
83
- text-transform: var(--tailor-marca-caixa-titulo);
84
- font-size: var(--tailor-cabecalho-tamanho-titulo, clamp(26px, 4vw, 42px));
85
- }
86
- .tailor-ph__descricao { margin: 0; max-width: 610px; font-size: 16px; line-height: 1.618; color: var(--tailor-marca-texto-suave); }
87
- .tailor-ph__lateral { display: flex; flex-shrink: 0; flex-wrap: wrap; align-items: center; gap: 13px; }
88
- .tailor-ph__indicador { text-align: right; }
89
- .tailor-ph__indicador-valor { display: block; font-size: 26px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; font-family: var(--tailor-marca-fonte-titulo); }
90
- .tailor-ph__indicador-rotulo { display: block; margin-top: 8px; font-size: 13px; color: var(--tailor-marca-texto-suave); }
91
- .tailor-ph__extra { min-width: 0; }
92
-
93
- /* TailorLoader — a malha pequena se desenha a partir do ponto e some, em 2φ (3,236s). */
82
+ font-family: var(--tailor-brand-heading-font); font-weight: var(--tailor-brand-heading-weight);
83
+ text-transform: var(--tailor-brand-heading-case);
84
+ font-size: var(--tailor-header-title-size, clamp(26px, 4vw, 42px));
85
+ }
86
+ .tailor-ph__description { margin: 0; max-width: 610px; font-size: 16px; line-height: 1.618; color: var(--tailor-brand-text-muted); }
87
+ .tailor-ph__aside { display: flex; flex-shrink: 0; flex-wrap: wrap; align-items: center; gap: 13px; }
88
+ .tailor-ph__stat { text-align: right; }
89
+ .tailor-ph__stat-value { display: block; font-size: 26px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; font-family: var(--tailor-brand-heading-font); }
90
+ .tailor-ph__stat-label { display: block; margin-top: 8px; font-size: 13px; color: var(--tailor-brand-text-muted); }
91
+ .tailor-ph__below { min-width: 0; }
92
+
93
+ /* TailorTabela — relatório. Medidas em --tailor-table-*, cores da marca. */
94
+ .tailor-table {
95
+ border: 1px solid var(--tailor-brand-border); background: var(--tailor-table-background, transparent);
96
+ color: var(--tailor-brand-text); font-family: var(--tailor-brand-body-font); border-radius: var(--tailor-brand-radius);
97
+ }
98
+ .tailor-table__scroll { overflow-x: auto; }
99
+ .tailor-table table { width: 100%; border-collapse: collapse; font-size: var(--tailor-table-font, 14px); }
100
+ .tailor-table__caption { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
101
+ .tailor-table th {
102
+ padding: var(--tailor-table-header-padding, 10px 13px); white-space: nowrap;
103
+ font-size: 10px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase;
104
+ color: var(--tailor-brand-text-muted); background: var(--tailor-table-header, color-mix(in srgb, var(--tailor-brand-text) 3%, transparent));
105
+ border-bottom: 1px solid var(--tailor-brand-border);
106
+ }
107
+ .tailor-table__sticky th { position: sticky; top: var(--tailor-table-top, 0); z-index: 1; background: var(--tailor-table-sticky-top, var(--tailor-white)); }
108
+ :where(.dark, [data-theme="dark"]) .tailor-table__sticky th { background: var(--tailor-table-sticky-top, var(--tailor-black)); }
109
+ .tailor-table td { padding: var(--tailor-table-padding, 10px 13px); border-top: 1px solid var(--tailor-brand-border); }
110
+ .tailor-table tbody tr:first-child td { border-top: 0; }
111
+ .tailor-table tbody tr:hover td { background: color-mix(in srgb, var(--tailor-brand-primary) 6%, transparent); }
112
+ .tailor-table--right { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
113
+ .tailor-table--center { text-align: center; }
114
+ .tailor-table--left { text-align: left; }
115
+ .tailor-table__id { white-space: nowrap; font-family: ui-monospace, "Roboto Mono", Menlo, monospace; font-size: 12px; }
116
+ .tailor-table__sort { display: inline-flex; align-items: center; gap: 4px; padding: 0; border: 0; background: none; font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; cursor: pointer; }
117
+ .tailor-table__sort:hover { color: var(--tailor-brand-text); }
118
+ .tailor-table__arrow { opacity: 0.35; }
119
+ .tailor-table__arrow--active { opacity: 1; color: var(--tailor-brand-primary-text); }
120
+ .tailor-table__clickable { cursor: pointer; }
121
+ .tailor-table__clickable:focus-visible, .tailor-table button:focus-visible { outline: 3px solid var(--tailor-brand-primary); outline-offset: -3px; }
122
+ .tailor-table__state { padding: 34px 13px; text-align: center; color: var(--tailor-brand-text-muted); }
123
+ .tailor-table tfoot td { border-top: 1px solid var(--tailor-brand-text); font-weight: 600; }
124
+ .tailor-table__pagination {
125
+ display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px;
126
+ padding: 8px 13px; border-top: 1px solid var(--tailor-brand-border); font-size: 13px; color: var(--tailor-brand-text-muted);
127
+ }
128
+ .tailor-table__pages { display: flex; gap: 8px; }
129
+ .tailor-table__pagination button {
130
+ min-height: 34px; padding: 0 13px; border: 1px solid var(--tailor-brand-border); border-radius: var(--tailor-brand-radius);
131
+ background: transparent; color: var(--tailor-brand-text); font: inherit; cursor: pointer;
132
+ }
133
+ .tailor-table__pagination button:hover:not(:disabled) { border-color: var(--tailor-brand-text); }
134
+ .tailor-table__pagination button:disabled { opacity: 0.45; cursor: not-allowed; }
135
+
136
+ /* TailorLoader — o ponto corre a espiral Fibonacci (trechos 3, 5, 8, 13, 21, 34 = 84) com rastro, pulsa e volta. */
137
+ .tailor-loader__rastro { stroke-dasharray: 1; stroke-dashoffset: 1; animation: tailor-rastro 2.618s linear infinite; }
138
+ @keyframes tailor-rastro {
139
+ 0% { stroke-dashoffset: 1; opacity: 1; }
140
+ 80% { stroke-dashoffset: 0; opacity: 1; }
141
+ 100% { stroke-dashoffset: 0; opacity: 0; }
142
+ }
143
+ /* Cantos da espiral em fração do trecho de corrida (80%): 3, 8, 16, 29, 50, 84 de 84. */
144
+ .tailor-loader__corredor { animation: tailor-corredor 2.618s linear infinite; }
145
+ @keyframes tailor-corredor {
146
+ 0% { transform: translate(0, 0); opacity: 1; }
147
+ 2.857% { transform: translate(3px, 0); }
148
+ 7.619% { transform: translate(3px, -5px); }
149
+ 15.238% { transform: translate(-5px, -5px); }
150
+ 27.619% { transform: translate(-5px, 8px); }
151
+ 47.619% { transform: translate(16px, 8px); }
152
+ 80% { transform: translate(16px, -26px) scale(1); opacity: 1; }
153
+ 86% { transform: translate(16px, -26px) scale(2.2); opacity: 1; }
154
+ 92% { transform: translate(16px, -26px) scale(0); opacity: 0; }
155
+ 100% { transform: translate(0, 0) scale(1); opacity: 0; }
156
+ }
157
+ /* compact: o ponto dá a volta num quadrado de 13px. */
158
+ .tailor-loader__volta { background: var(--tailor-loader-dot, var(--tailor-brand-primary)); animation: tailor-volta 1.236s steps(1, end) infinite; }
159
+ @keyframes tailor-volta {
160
+ 0% { transform: translate(0, 0); }
161
+ 25% { transform: translate(8px, 0); }
162
+ 50% { transform: translate(8px, 8px); }
163
+ 75% { transform: translate(0, 8px); }
164
+ }
165
+ /* dot: o mesmo quadrado, em % para caber em qualquer tamanho de ícone (1em). */
166
+ .tailor-loader__dot { background: var(--tailor-loader-dot, var(--tailor-brand-primary)); animation: tailor-loader-dot 1.236s steps(1, end) infinite; }
167
+ @keyframes tailor-loader-dot {
168
+ 0% { transform: translate(0, 0); }
169
+ 25% { transform: translate(161.8%, 0); }
170
+ 50% { transform: translate(161.8%, 161.8%); }
171
+ 75% { transform: translate(0, 161.8%); }
172
+ }
173
+ /* Sucesso: a malha nasce verde do ponto, o ponto estoura e o check se desenha. Uma vez só. */
174
+ .tailor-loader__ok-malha .tailor-malha__linha { animation: tailor-ok-malha 0.618s var(--tailor-ease-in-out) both; }
175
+ @keyframes tailor-ok-malha { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; opacity: 0.5; } }
176
+ .tailor-loader__ok-ponto { transform-box: fill-box; transform-origin: center; animation: tailor-ok-ponto 0.382s var(--tailor-ease-in-out) both; }
177
+ @keyframes tailor-ok-ponto { 0% { transform: scale(1); } 50% { transform: scale(3); opacity: 1; } 100% { transform: scale(0); opacity: 0; } }
178
+ .tailor-loader__check { stroke-dasharray: 1; stroke-dashoffset: 1; animation: tailor-check 0.382s 0.3s var(--tailor-ease-in-out) both; }
179
+ @keyframes tailor-check { to { stroke-dashoffset: 0; } }
180
+
181
+ /* TailorEsqueleto — barras retas e a linha da marca varrendo de cima a baixo. */
182
+ .tailor-skeleton { position: relative; overflow: hidden; display: grid; gap: 13px; padding: 2px 0; }
183
+ .tailor-skeleton__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
184
+ .tailor-skeleton__bar { display: block; height: 13px; background: var(--tailor-skeleton-bar, #F2F2F2); }
185
+ .tailor-skeleton__bar--thin { height: 8px; }
186
+ .tailor-skeleton__bar--thick { height: 34px; }
187
+ .tailor-skeleton__row { display: grid; gap: 21px; padding: 8px 0; border-bottom: 1px solid var(--tailor-brand-border); }
188
+ .tailor-skeleton__row--header .tailor-skeleton__bar { height: 8px; }
189
+ .tailor-skeleton__cards { display: grid; gap: 13px; grid-template-columns: repeat(auto-fit, minmax(144px, 1fr)); }
190
+ .tailor-skeleton__card { display: grid; gap: 13px; padding: 21px; border: 1px solid var(--tailor-brand-border); }
191
+ .tailor-skeleton::after {
192
+ content: ''; position: absolute; left: 0; top: 0; width: 8px; height: 8px;
193
+ background: var(--tailor-brand-primary);
194
+ animation: tailor-skeleton-dot 2.618s var(--tailor-ease-in-out) infinite;
195
+ }
196
+ /* O ponto atravessa o topo uma vez e some; o resto fica parado. */
197
+ @keyframes tailor-skeleton-dot {
198
+ 0% { left: 0; opacity: 1; }
199
+ 61.8% { left: calc(100% - 8px); opacity: 1; }
200
+ 70%, 100% { left: calc(100% - 8px); opacity: 0; }
201
+ }
202
+ :where(.dark, [data-theme="dark"]) .tailor-skeleton { --tailor-skeleton-bar: #1F1F1F; }
203
+
204
+ /* TailorAvisos — caixa preta; a cor do tipo entra varrendo e recolhe na borda; barra do tempo. */
205
+ .tailor-toaster {
206
+ position: fixed; z-index: 1100; right: 21px; top: 21px; display: flex; flex-direction: column; gap: 8px;
207
+ width: min(377px, calc(100vw - 32px)); pointer-events: none;
208
+ }
209
+ @media (max-width: 640px) { .tailor-toaster { right: 16px; left: 16px; top: 16px; width: auto; } }
210
+ .tailor-toast {
211
+ --tailor-toast-color: var(--tailor-brand-primary);
212
+ position: relative; overflow: hidden; pointer-events: auto; display: flex; align-items: flex-start; gap: 13px;
213
+ padding: 16px 13px 18px 21px; background: #000; color: #fff; font-family: var(--tailor-font);
214
+ animation: tailor-toast-in 0.5s var(--tailor-ease-in-out) both;
215
+ }
216
+ .tailor-toast--error { --tailor-toast-color: #FF0040; }
217
+ .tailor-toast::before {
218
+ content: ''; position: absolute; left: 0; top: 0; bottom: 0; background: var(--tailor-toast-color);
219
+ width: 3px;
220
+ }
221
+ .tailor-toast > * { position: relative; }
222
+ /* O aviso abre a partir do ponto do ícone (centro do ícone de 21px: 31,5px da esquerda, 26,5px do topo). */
223
+ @keyframes tailor-toast-in { from { clip-path: inset(22.5px calc(100% - 35.5px) calc(100% - 30.5px) 27.5px); } to { clip-path: inset(0); } }
224
+ .tailor-toast__icon { width: 21px; height: 21px; flex-shrink: 0; overflow: visible; stroke: var(--tailor-toast-color); fill: var(--tailor-toast-color); }
225
+ .tailor-toast .tailor-loader__check { animation-delay: 0s; }
226
+ .tailor-toast__text { flex: 1; min-width: 0; }
227
+ .tailor-toast__title { margin: 0; font-size: 15px; font-weight: 500; line-height: 1.382; }
228
+ .tailor-toast__description { margin: 3px 0 0; font-size: 13px; line-height: 1.5; color: rgb(255 255 255 / 0.7); }
229
+ .tailor-toast__close {
230
+ margin: -5px -3px 0 0; width: 34px; height: 34px; flex-shrink: 0; border: 0; background: none; color: rgb(255 255 255 / 0.7);
231
+ font-size: 21px; line-height: 1; cursor: pointer;
232
+ }
233
+ .tailor-toast__close:hover { color: #fff; }
234
+ .tailor-toast__close:focus-visible { outline: 2px solid var(--tailor-toast-color); outline-offset: -2px; }
235
+ .tailor-toast__timer {
236
+ position: absolute !important; left: 0; right: 0; bottom: 0; height: 3px; background: var(--tailor-toast-color);
237
+ transform-origin: left; animation: tailor-toast-timer var(--tailor-toast-duration, 4s) linear both;
238
+ }
239
+ @keyframes tailor-toast-timer { from { transform: scaleX(1); } to { transform: scaleX(0); } }
240
+
241
+ /* TailorDigitando — o ponto da marca como cursor. */
242
+ .tailor-typewriter__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
243
+ .tailor-typewriter__cursor {
244
+ display: inline-block; width: 0.5em; height: 0.5em; margin-left: 0.12em; vertical-align: baseline;
245
+ background: var(--tailor-typewriter-cursor, var(--tailor-brand-primary));
246
+ }
247
+
248
+ /* TailorConclusao — a cor varre o painel, o ícone e o título se escrevem, e tudo recolhe no ponto. */
249
+ .tailor-result {
250
+ --tailor-result-color: var(--tailor-brand-primary);
251
+ --tailor-result-text: #000;
252
+ position: absolute; inset: 0; z-index: 20; display: flex; flex-direction: column; align-items: center; justify-content: center;
253
+ gap: 13px; padding: 34px 21px; text-align: center; font-family: var(--tailor-font);
254
+ background: var(--tailor-result-color); color: var(--tailor-result-text);
255
+ --tailor-typewriter-cursor: var(--tailor-result-text);
256
+ --tailor-result-x: 50%;
257
+ --tailor-result-y: 50%;
258
+ animation: tailor-result-in 0.5s var(--tailor-ease-in-out) both;
259
+ }
260
+ .tailor-result--error { --tailor-result-color: #FF0040; --tailor-result-text: #fff; }
261
+ .tailor-result--leaving { animation: tailor-result-out 0.618s var(--tailor-ease-in-out) both; }
262
+ /* O ponto: um quadrado de 8px no centro do botão de origem (ou do painel). */
263
+ @keyframes tailor-result-in {
264
+ from { clip-path: inset(calc(var(--tailor-result-y) - 4px) calc(100% - var(--tailor-result-x) - 4px) calc(100% - var(--tailor-result-y) - 4px) calc(var(--tailor-result-x) - 4px)); }
265
+ to { clip-path: inset(0); }
266
+ }
267
+ @keyframes tailor-result-out {
268
+ 0% { clip-path: inset(0); }
269
+ 70% { clip-path: inset(calc(var(--tailor-result-y) - 4px) calc(100% - var(--tailor-result-x) - 4px) calc(100% - var(--tailor-result-y) - 4px) calc(var(--tailor-result-x) - 4px)); opacity: 1; }
270
+ 100% { clip-path: inset(calc(var(--tailor-result-y) - 4px) calc(100% - var(--tailor-result-x) - 4px) calc(100% - var(--tailor-result-y) - 4px) calc(var(--tailor-result-x) - 4px)); opacity: 0; }
271
+ }
272
+ .tailor-result__icon { width: 55px; height: 55px; overflow: visible; stroke: var(--tailor-result-text); }
273
+ .tailor-result .tailor-loader__check { animation-delay: 0.45s; }
274
+ .tailor-result__title { margin: 0; min-height: 1.1em; font-size: 26px; font-weight: 500; line-height: 1.1; }
275
+ .tailor-result__description { font-size: 15px; line-height: 1.5; opacity: 0.8; }
276
+ .tailor-result__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 8px; }
277
+
278
+ /* TailorField — rótulo, controle e mensagem. Erro: borda e ponto vermelhos, um empurrão curto para chamar o olho. */
279
+ .tailor-field { display: grid; gap: 8px; font-family: var(--tailor-font); color: var(--tailor-brand-text); }
280
+ .tailor-field__label { display: flex; align-items: baseline; gap: 8px; font-size: 13px; font-weight: 500; }
281
+ .tailor-field__required { font-size: 12px; font-weight: 400; color: var(--tailor-brand-text-muted); }
282
+ .tailor-field__control {
283
+ min-height: 40px; width: 100%; padding: 0 13px; border: 1px solid var(--tailor-field-border, #999999); border-radius: var(--tailor-brand-radius, 0);
284
+ background: transparent; color: inherit; font: inherit; font-size: 15px;
285
+ }
286
+ textarea.tailor-field__control { padding: 8px 13px; min-height: 89px; }
287
+ .tailor-field__control:focus { outline: none; border-color: var(--tailor-brand-text); box-shadow: 0 0 0 3px color-mix(in srgb, var(--tailor-brand-primary) 60%, transparent); }
288
+ .tailor-field--error .tailor-field__control {
289
+ border-color: #FF0040; background: color-mix(in srgb, #FF0040 5%, transparent);
290
+ animation: tailor-field-nudge 0.382s var(--tailor-ease-out);
291
+ }
292
+ .tailor-field--error .tailor-field__control:focus { box-shadow: 0 0 0 3px color-mix(in srgb, #FF0040 35%, transparent); }
293
+ .tailor-field__error { display: flex; align-items: baseline; gap: 8px; margin: 0; font-size: 13px; font-weight: 500; color: #E0003A; }
294
+ .tailor-field__dot { flex-shrink: 0; width: 8px; height: 8px; background: #FF0040; transform: translateY(-1px); }
295
+ .tailor-field__hint { margin: 0; font-size: 13px; color: var(--tailor-brand-text-muted); }
296
+ :where(.dark, [data-theme="dark"]) .tailor-field__error { color: #FF7462; }
297
+ :where(.dark, [data-theme="dark"]) .tailor-field { --tailor-field-border: #666666; }
298
+ @keyframes tailor-field-nudge { 0%, 100% { transform: none; } 25% { transform: translateX(-5px); } 50% { transform: translateX(5px); } 75% { transform: translateX(-2px); } }
299
+
300
+ /* TailorUserMenu — o painel nasce do ponto no canto junto do avatar e recolhe nele. */
301
+ .tailor-user-menu__panel { animation: tailor-user-menu-in 0.382s var(--tailor-ease-out) both; }
302
+ .tailor-user-menu__panel--closing { animation: tailor-user-menu-out 0.236s var(--tailor-ease-in-out) both; }
303
+ .tailor-user-menu__panel::before {
304
+ content: ''; position: absolute; left: -1px; bottom: -1px; width: 8px; height: 8px; background: var(--tailor-brand-primary);
305
+ animation: tailor-user-menu-dot 0.618s var(--tailor-ease-in-out) both;
306
+ }
307
+ @keyframes tailor-user-menu-in { from { clip-path: inset(calc(100% - 8px) calc(100% - 8px) 0 0); } to { clip-path: inset(0); } }
308
+ @keyframes tailor-user-menu-out { from { clip-path: inset(0); } to { clip-path: inset(calc(100% - 8px) calc(100% - 8px) 0 0); } }
309
+ @keyframes tailor-user-menu-dot { 0%, 61.8% { opacity: 1; } 100% { opacity: 0; } }
310
+
311
+ /* PontoMalha e a malha da entrada: se desenham a partir do ponto e somem, em 2φ (3,236s). */
94
312
  .tailor-malha__linha {
95
313
  stroke-dasharray: 1;
96
314
  stroke-dashoffset: 1;
@@ -216,6 +434,15 @@
216
434
  /* Menos movimento: a informação continua, o movimento sai. */
217
435
  @media (prefers-reduced-motion: reduce) {
218
436
  .tailor-malha__linha { animation: none; stroke-dashoffset: 0; }
437
+ .tailor-loader__rastro, .tailor-loader__check, .tailor-loader__ok-malha .tailor-malha__linha { animation: none; stroke-dashoffset: 0; opacity: 1; }
438
+ .tailor-loader__corredor, .tailor-loader__volta, .tailor-loader__dot { animation: none; }
439
+ .tailor-loader__ok-ponto { animation: none; opacity: 0; }
440
+ .tailor-skeleton::after { animation: none; display: none; }
441
+ .tailor-field--error .tailor-field__control { animation: none; }
442
+ .tailor-user-menu__panel, .tailor-user-menu__panel--closing, .tailor-user-menu__panel::before { animation: none; }
443
+ .tailor-user-menu__panel::before { display: none; }
444
+ .tailor-toast { animation: none; }
445
+ .tailor-result, .tailor-result > * { animation: none !important; }
219
446
  .tailor-loader__reticencias::after { animation: none; content: '...'; }
220
447
  .tailor-ponto-pisca { animation: none; }
221
448
  .tailor-mascote__corpo, .tailor-mascote__olho, .tailor-mascote__verde { animation: none; }
@@ -2,7 +2,9 @@ import { default as React } from 'react';
2
2
  export type CinematicIntroProps = {
3
3
  /** Chamado ao fim da abertura, no "Pular" ou de imediato com menos movimento. */
4
4
  onComplete: () => void;
5
+ /** Linha curta acima do slogan, com o ponto verde. Sem ela, não aparece. */
5
6
  overline?: string;
7
+ /** Frase abaixo da marca (ex.: "Sua operação em outro nível"). Sem ela, não aparece. */
6
8
  slogan?: string;
7
9
  skipLabel?: string;
8
10
  /** Nome do produto abaixo da marca (ex.: "Pilot"). Omitido: só a marca. */
@@ -1,33 +1,33 @@
1
1
  import { default as React } from 'react';
2
2
  /**
3
- * A marca do cliente em variáveis CSS. Os componentes que leem `--tailor-marca-*`
4
- * (por enquanto o `TailorPageHeader`) trocam de cor, fonte e cantos sem mudar uma
3
+ * A marca do cliente em variáveis CSS. Os componentes que leem `--tailor-brand-*`
4
+ * (`TailorPageHeader`, `TailorTable`, avisos) trocam de cor, fonte e cantos sem mudar uma
5
5
  * linha de componente. Sem tema, valem os padrões Tailor do `style.css`.
6
6
  */
7
- export type TailorTema = {
7
+ export type TailorTheme = {
8
8
  /** Cor de destaque: o ponto do sobretítulo, a barra de foco. */
9
- primaria?: string;
9
+ primary?: string;
10
10
  /** Destaque como texto sobre o fundo (precisa de contraste; no Tailor é o verde-ink). */
11
- primariaTexto?: string;
12
- texto?: string;
13
- textoSuave?: string;
14
- borda?: string;
11
+ primaryText?: string;
12
+ text?: string;
13
+ textMuted?: string;
14
+ border?: string;
15
15
  /** Fundo do cabeçalho. Padrão: transparente (o cabeçalho é o começo da página). */
16
- fundo?: string;
17
- fonteTitulo?: string;
18
- fonteTexto?: string;
19
- pesoTitulo?: string | number;
16
+ background?: string;
17
+ headingFont?: string;
18
+ bodyFont?: string;
19
+ headingWeight?: string | number;
20
20
  /** `uppercase` para marcas que pedem título em caixa alta. */
21
- caixaTitulo?: 'none' | 'uppercase';
21
+ headingCase?: 'none' | 'uppercase';
22
22
  /** Cantos dos elementos com caixa (etiqueta, botão voltar). Tailor: 0. */
23
- raio?: string;
23
+ radius?: string;
24
24
  };
25
25
  /** O tema como objeto de variáveis, para `style` ou para montar um CSS do cliente. */
26
- export declare function temaParaVariaveis(tema: TailorTema): Record<string, string>;
27
- export type TailorMarcaProps = {
28
- tema: TailorTema;
26
+ export declare function themeToVars(theme: TailorTheme): Record<string, string>;
27
+ export type TailorBrandProps = {
28
+ theme: TailorTheme;
29
29
  /** Ajustes do tema escuro (`.dark` ou `[data-theme="dark"]` num ancestral). */
30
- escuro?: TailorTema;
30
+ dark?: TailorTheme;
31
31
  children: React.ReactNode;
32
32
  };
33
33
  /**
@@ -35,13 +35,13 @@ export type TailorMarcaProps = {
35
35
  * As variáveis vão num `<style>` com seletor próprio, e não em `style`, para o
36
36
  * tema escuro conseguir sobrescrever as do claro.
37
37
  */
38
- export declare function TailorMarca({ tema, escuro, children }: TailorMarcaProps): React.JSX.Element;
38
+ export declare function TailorBrand({ theme, dark, children }: TailorBrandProps): React.JSX.Element;
39
39
  /**
40
40
  * `account_info.whitelabel` do cliente (Mongo `clients`). Os campos além de
41
41
  * `colors.primary/secondary/background/text` e `logos.*` são a proposta para
42
42
  * completar a marca; enquanto não existirem, ficam os padrões Tailor.
43
43
  */
44
- export type WhitelabelDoCliente = {
44
+ export type TailorWhitelabel = {
45
45
  colors?: {
46
46
  primary?: string;
47
47
  secondary?: string;
@@ -74,13 +74,13 @@ export type WhitelabelDoCliente = {
74
74
  };
75
75
  };
76
76
  /** Razão de contraste WCAG entre duas cores hex. */
77
- export declare function contraste(a: string, b: string): number;
77
+ export declare function contrast(a: string, b: string): number;
78
78
  /**
79
79
  * Traduz o whitelabel do Mongo para o tema. Ignora o azul padrão do cadastro e
80
80
  * valores que não são hex. A primária só vira cor de texto se tiver contraste
81
81
  * AA sobre o fundo; senão o texto de destaque usa a cor de texto da marca.
82
82
  */
83
- export declare function temaDoWhitelabel(wl?: WhitelabelDoCliente | null): {
84
- tema: TailorTema;
85
- escuro?: TailorTema;
83
+ export declare function themeFromWhitelabel(wl?: TailorWhitelabel | null): {
84
+ theme: TailorTheme;
85
+ dark?: TailorTheme;
86
86
  };
@@ -0,0 +1,19 @@
1
+ import { default as React } from 'react';
2
+ export type TailorFieldProps = {
3
+ label: React.ReactNode;
4
+ /** Mensagem de erro. Com ela, o campo fica vermelho e a mensagem aparece abaixo, com o ponto. */
5
+ error?: React.ReactNode;
6
+ /** Ajuda abaixo do campo, quando não há erro. */
7
+ hint?: React.ReactNode;
8
+ /** Marca o campo como obrigatório (no rótulo e no `required` do controle). */
9
+ required?: boolean;
10
+ /** Um `input`, `select` ou `textarea` (ou componente que repasse as props). Recebe id, aria e a classe do campo. */
11
+ children: React.ReactElement;
12
+ className?: string;
13
+ };
14
+ /**
15
+ * Rótulo, controle e mensagem num lugar só. O erro aparece de uma vez (precisa
16
+ * ser lido já): borda vermelha, fundo levemente tingido e a mensagem com o
17
+ * ponto vermelho, ligada ao controle por `aria-describedby`.
18
+ */
19
+ export declare function TailorField({ label, error, hint, required, children, className }: TailorFieldProps): React.JSX.Element;
@@ -1,17 +1,36 @@
1
1
  import { default as React } from 'react';
2
2
  export type TailorLoaderProps = {
3
- /** Rótulo principal. Padrão: "Carregando". */
3
+ /** Rótulo principal. Padrão: o texto `loading` do idioma. */
4
4
  label?: string;
5
5
  /** Linha de apoio abaixo do rótulo (o que está sendo carregado, ou quanto falta). */
6
- detail?: string;
6
+ detail?: React.ReactNode;
7
+ /**
8
+ * Arte do parceiro ou do cliente acima do loader (`inline` e `overlay`), para a
9
+ * espera assinar com a marca dele. Ex.: `whitelabel.logos.rectangular_light`.
10
+ */
11
+ logo?: string;
12
+ /** Arte para fundo escuro (tema escuro e `overlay`). Sem ela, vale `logo`. */
13
+ logoDark?: string;
14
+ /** Frases que o ponto escreve e apaga em ciclo, abaixo do rótulo ("Cruzando dados", "Quase lá"). */
15
+ messages?: string[];
16
+ /** Progresso real, 0 a 100. Mostra a barra e o número. Sem ele, só a animação. */
17
+ progress?: number;
18
+ /** Etapas da carga; só aparecem com `progress` (sem ele não há etapa atual). */
19
+ steps?: string[];
7
20
  /**
8
21
  * `inline`: no lugar do conteúdo. `overlay`: tela inteira, bloqueia.
9
22
  * `compact`: uma linha (ponto + rótulo), para botões e listas.
10
- * `caixa`: numa caixa própria de 377px, com fundo e borda — para painéis
23
+ * `dot`: só o ponto, do tamanho da fonte (1em), no lugar de um ícone; o rótulo vai para o leitor de tela.
24
+ * `box`: numa caixa própria de 377px, com fundo e borda — para painéis
11
25
  * estreitos e fundos com estampa (chat), onde o inline ficaria transparente.
12
26
  */
13
- variant?: 'inline' | 'overlay' | 'compact' | 'caixa';
14
- /** Tira o respiro externo do `inline`/`caixa` (quem chama já tem espaçamento). */
27
+ /** `caixa` é o nome antigo de `box` (obsoleto). */
28
+ variant?: 'inline' | 'overlay' | 'compact' | 'box' | 'dot' | 'caixa';
29
+ /** Troca a corrida pelo sucesso animado (a malha nasce verde e o ponto vira check). Rótulo padrão: o texto `done` do idioma. */
30
+ success?: boolean;
31
+ /** Tira o respiro externo do `inline`/`box` (quem chama já tem espaçamento). */
32
+ noPadding?: boolean;
33
+ /** @deprecated use `noPadding`. */
15
34
  semRespiro?: boolean;
16
35
  className?: string;
17
36
  };
@@ -7,31 +7,31 @@ export type TailorPageHeaderLink = {
7
7
  };
8
8
  export type TailorPageHeaderProps = {
9
9
  /** ReactNode para permitir um acento dentro do título. */
10
- titulo: React.ReactNode;
10
+ title: React.ReactNode;
11
11
  /** Uma frase: o que se faz nesta tela. */
12
- descricao?: React.ReactNode;
12
+ description?: React.ReactNode;
13
13
  /** Seção ou contexto, com o ponto da marca. Sem ele, não aparece. */
14
- sobretitulo?: string;
14
+ eyebrow?: string;
15
15
  /** Trilha de navegação; o último item é a página atual. */
16
- trilha?: Array<{
17
- rotulo: string;
16
+ breadcrumbs?: Array<{
17
+ label: string;
18
18
  href?: string;
19
19
  }>;
20
20
  /** Link ou ação de voltar, acima de tudo. */
21
- voltar?: {
22
- rotulo: string;
21
+ back?: {
22
+ label: string;
23
23
  href?: string;
24
24
  onClick?: () => void;
25
25
  };
26
26
  /** Ao lado do título: status, plano, contagem. */
27
- etiqueta?: React.ReactNode;
27
+ badge?: React.ReactNode;
28
28
  /** Números do topo, quando ajudam a decidir o que fazer aqui. */
29
- indicadores?: Array<{
30
- rotulo: string;
31
- valor: React.ReactNode;
29
+ stats?: Array<{
30
+ label: string;
31
+ value: React.ReactNode;
32
32
  }>;
33
33
  /** Botões e busca, à direita. */
34
- acoes?: React.ReactNode;
34
+ actions?: React.ReactNode;
35
35
  /** Abaixo, na largura toda: abas, filtros, barra de busca. */
36
36
  children?: React.ReactNode;
37
37
  /** Link do roteador do app (ex.: `NavLink`). Repasse todas as props. Sem ele, sai um `<a href>`. */
@@ -39,9 +39,9 @@ export type TailorPageHeaderProps = {
39
39
  className?: string;
40
40
  };
41
41
  /**
42
- * O cabeçalho de página. Visual só por variáveis `--tailor-marca-*` e
43
- * `--tailor-cabecalho-*` (ver `TailorMarca`), para vestir a marca do cliente:
42
+ * O cabeçalho de página. Visual só por variáveis `--tailor-brand-*` e
43
+ * `--tailor-header-*` (ver `TailorBrand`), para vestir a marca do cliente:
44
44
  * cor de destaque, fontes, peso e caixa do título, cantos, fundo.
45
45
  * Padrão Tailor: sem card nem sombra, régua de 1px embaixo, título 26 → 42.
46
46
  */
47
- export declare function TailorPageHeader({ titulo, descricao, sobretitulo, trilha, voltar, etiqueta, indicadores, acoes, children, renderLink, className, }: TailorPageHeaderProps): React.JSX.Element;
47
+ export declare function TailorPageHeader({ title, description, eyebrow, breadcrumbs, back, badge, stats, actions, children, renderLink, className, }: TailorPageHeaderProps): React.JSX.Element;
@@ -0,0 +1,27 @@
1
+ import { default as React } from 'react';
2
+ export type TailorResultProps = {
3
+ status: 'success' | 'error';
4
+ /** No sucesso, escrito pelo ponto letra a letra; no erro, aparece inteiro. */
5
+ title: string;
6
+ description?: React.ReactNode;
7
+ /**
8
+ * O botão que disparou a ação. O painel nasce do ponto no centro dele e
9
+ * recolhe de volta para lá. Sem ele, o ponto fica no centro do painel.
10
+ */
11
+ origin?: React.RefObject<HTMLElement | null>;
12
+ /** ms até recolher e chamar `onClose`. Padrão: 1600 no sucesso; no erro não fecha sozinho. `false` desliga. */
13
+ closeAfter?: number | false;
14
+ /** Chamado depois que o painel recolhe no ponto: feche o modal aqui. */
15
+ onClose?: () => void;
16
+ /** Botões abaixo do texto (ex.: "Tentar de novo" no erro). */
17
+ actions?: React.ReactNode;
18
+ className?: string;
19
+ };
20
+ /**
21
+ * O fim de um modal ou formulário. O ponto do botão cresce até cobrir o painel
22
+ * com a cor do resultado, o ícone se desenha e o título aparece (escrito no
23
+ * sucesso, de uma vez no erro, que precisa ser lido já). Depois tudo recolhe no
24
+ * mesmo ponto e `onClose` fecha o modal. Cobre o pai, que precisa de
25
+ * `position: relative`.
26
+ */
27
+ export declare function TailorResult({ status, title, description, origin, closeAfter, onClose, actions, className }: TailorResultProps): React.JSX.Element;
@@ -113,11 +113,6 @@ export type TailorUserMenuProps = {
113
113
  /** Conteúdo livre no painel, antes das ações (tema, notificações push). */
114
114
  children?: ReactNode;
115
115
  };
116
- /**
117
- * Menu do usuário para o `rodape` da `TailorSidebar`. Botão que abre um painel
118
- * (padrão disclosure: aceita conteúdo livre, como o seletor de tema). Esc e
119
- * clique fora fecham; setas percorrem os itens.
120
- */
121
116
  export declare const TailorUserMenu: React.FC<TailorUserMenuProps>;
122
117
  export type TailorMobileBarProps = {
123
118
  /** Abre a gaveta: ligue no `aberto` da `TailorSidebar`. */
@@ -0,0 +1,19 @@
1
+ import { default as React } from 'react';
2
+ export type TailorSkeletonProps = {
3
+ /** `text`: parágrafo. `block`: um retângulo (gráfico, imagem). `table`: linhas e colunas. `cards`: indicadores lado a lado. */
4
+ shape?: 'text' | 'block' | 'table' | 'cards';
5
+ /** Linhas do texto ou da tabela, ou quantidade de cartões. */
6
+ lines?: number;
7
+ /** Colunas da tabela. */
8
+ columns?: number;
9
+ /** Altura do `block`. Padrão: 144px. */
10
+ height?: string;
11
+ /** Lido pelo leitor de tela. Padrão: o texto `loading` do idioma. */
12
+ label?: string;
13
+ className?: string;
14
+ };
15
+ /**
16
+ * O lugar do conteúdo enquanto ele chega: barras cinza retas e a linha verde
17
+ * varrendo de cima a baixo. Sem gradiente nem cantos (manual da marca).
18
+ */
19
+ export declare function TailorSkeleton({ shape, lines, columns, height, label, className }: TailorSkeletonProps): React.JSX.Element;