@flytedan/flytebot-design-system 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flytedan/flytebot-design-system",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "flytedesk Design System — shared component library, tokens, and business-logic kits for flytedesk apps.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -176,6 +176,56 @@
176
176
  background: var(--surface);
177
177
  box-shadow: var(--e-1);
178
178
  }
179
+ /* Tone on a quiet (ghost/outline) icon button: the glyph carries it, on hover too. */
180
+ .fd-btn-icon.is-ok:not(.fd-btn-icon-solid),
181
+ .fd-btn-icon.is-ok:not(.fd-btn-icon-solid):hover {
182
+ color: var(--ok-text);
183
+ }
184
+ .fd-btn-icon.is-danger:not(.fd-btn-icon-solid),
185
+ .fd-btn-icon.is-danger:not(.fd-btn-icon-solid):hover {
186
+ color: var(--danger-text);
187
+ }
188
+ /* Solid: a real fill in the tone's colour. The fills and inks are the --btn-solid-*
189
+ tokens (tokens.css), struck per theme so the glyph clears 4.5:1 on the fill and the
190
+ fill clears 3:1 against both a default and a danger-toned EntityRow card, at rest,
191
+ hovered and pressed. The tone classes only swap which token set is in play. */
192
+ .fd-btn-icon-solid {
193
+ --btn-solid-bg: var(--btn-solid-neutral-bg);
194
+ --btn-solid-bg-hover: var(--btn-solid-neutral-bg-hover);
195
+ --btn-solid-bg-active: var(--btn-solid-neutral-bg-active);
196
+ --btn-solid-ink: var(--btn-solid-neutral-ink);
197
+ background: var(--btn-solid-bg);
198
+ color: var(--btn-solid-ink);
199
+ border-color: transparent;
200
+ box-shadow: var(--e-1);
201
+ }
202
+ .fd-btn-icon-solid.is-ok {
203
+ --btn-solid-bg: var(--btn-solid-ok-bg);
204
+ --btn-solid-bg-hover: var(--btn-solid-ok-bg-hover);
205
+ --btn-solid-bg-active: var(--btn-solid-ok-bg-active);
206
+ --btn-solid-ink: var(--btn-solid-ok-ink);
207
+ }
208
+ .fd-btn-icon-solid.is-danger {
209
+ --btn-solid-bg: var(--btn-solid-danger-bg);
210
+ --btn-solid-bg-hover: var(--btn-solid-danger-bg-hover);
211
+ --btn-solid-bg-active: var(--btn-solid-danger-bg-active);
212
+ --btn-solid-ink: var(--btn-solid-danger-ink);
213
+ }
214
+ .fd-btn-icon-solid:hover,
215
+ .fd-btn-icon-solid.is-ok:hover,
216
+ .fd-btn-icon-solid.is-danger:hover {
217
+ background: var(--btn-solid-bg-hover);
218
+ color: var(--btn-solid-ink);
219
+ }
220
+ .fd-btn-icon-solid:active {
221
+ background: var(--btn-solid-bg-active);
222
+ box-shadow: none;
223
+ }
224
+ /* foundations.css gives every button:focus-visible the focus ring; restated after
225
+ :active so pressing a focused solid button cannot reset the ring away. */
226
+ .fd-btn-icon-solid:focus-visible {
227
+ box-shadow: var(--focus-ring);
228
+ }
179
229
  .fd-btn-icon-sm {
180
230
  width: var(--control-h-sm);
181
231
  height: var(--control-h-sm);
@@ -2261,19 +2311,32 @@
2261
2311
  flex-direction: column;
2262
2312
  animation: fd-drawer-in var(--dur-panel) var(--ease-out) both;
2263
2313
  }
2314
+ /* Tooltip's trigger wrapper. It takes no room of its own: it hugs its one child. */
2315
+ .fd-tooltip-anchor {
2316
+ display: inline-flex;
2317
+ flex: none;
2318
+ min-width: 0;
2319
+ }
2320
+ /* Portaled to document.body and placed by Tooltip.tsx (fixed, anchored geometry), so no
2321
+ overflow: hidden ancestor of the trigger can clip it. It sits above popovers (140) so a
2322
+ tip on something inside a popover is still visible. Short labels stay on one line
2323
+ (max-content); a sentence wraps at a readable measure instead of running off-screen. */
2264
2324
  .fd-tooltip {
2265
- position: absolute;
2266
- z-index: 100;
2325
+ position: fixed;
2326
+ z-index: 150;
2327
+ width: max-content;
2328
+ max-width: min(280px, calc(100vw - 16px));
2267
2329
  background: var(--n-900);
2268
2330
  color: #fff;
2269
2331
  font-size: var(--body-sm-size);
2270
2332
  font-weight: var(--w-medium);
2333
+ line-height: 1.4;
2271
2334
  padding: 7px 10px;
2272
2335
  border-radius: var(--r-sm);
2273
2336
  box-shadow: var(--e-2);
2274
- white-space: nowrap;
2337
+ white-space: normal;
2338
+ text-wrap: pretty;
2275
2339
  animation: fd-pop var(--dur-fast) var(--ease-out) both;
2276
- pointer-events: none;
2277
2340
  }
2278
2341
  .fd-toast {
2279
2342
  display: flex;
@@ -2409,32 +2472,75 @@
2409
2472
  box-shadow: var(--e-3);
2410
2473
  animation: fd-pop-in 160ms var(--ease-out) both;
2411
2474
  transform-origin: top center;
2412
- /* max-height (set inline by Popover.tsx) sizes to content by default, capped only
2413
- at the real available room to the viewport edge so this is a last-resort
2414
- scroller for that legitimate viewport-collision case, not a content clipper.
2415
- overflow-x stays hidden so children never poke past the rounded corners. */
2475
+ /* THE SURFACE NEVER SCROLLS. max-height (set inline by Popover.tsx) caps it at the
2476
+ real room between the anchor and the viewport edge; what does not fit is scrolled
2477
+ inside .fd-pop-body, never by the surface itself a surface that scrolls as a whole
2478
+ carries its footer action below the fold and stacks a second scrollbar on any list
2479
+ inside it. overflow: hidden also keeps children inside the rounded corners. */
2480
+ overflow: hidden;
2481
+ display: flex;
2482
+ flex-direction: column;
2483
+ }
2484
+ /* Pinned regions. flex: none so the body is the only thing that gives up height. */
2485
+ .fd-pop-header,
2486
+ .fd-pop-footer {
2487
+ flex: none;
2488
+ padding: var(--s-12) var(--s-16);
2489
+ }
2490
+ .fd-pop-header {
2491
+ border-bottom: 1px solid var(--border);
2492
+ }
2493
+ .fd-pop-footer {
2494
+ display: flex;
2495
+ align-items: center;
2496
+ justify-content: flex-end;
2497
+ flex-wrap: wrap;
2498
+ gap: var(--s-8);
2499
+ border-top: 1px solid var(--border);
2500
+ }
2501
+ /* The one scroll region. min-height: 0 is what lets it shrink below its content inside
2502
+ the capped surface instead of pushing the footer out. It is itself a flex column so
2503
+ that a child owning a scroll region of its own (a Menu frame, a Select listbox) can
2504
+ take min-height: 0 too and shrink into the body — the child scrolls, the body does
2505
+ not, and there is still exactly one scrollbar. */
2506
+ .fd-pop-body {
2507
+ flex: 1 1 auto;
2508
+ min-height: 0;
2416
2509
  overflow-x: hidden;
2417
2510
  overflow-y: auto;
2511
+ overscroll-behavior: contain;
2418
2512
  display: flex;
2419
2513
  flex-direction: column;
2420
2514
  }
2515
+ /* Ordinary content never shrinks inside the body — it overflows it, and the body scrolls.
2516
+ (Without this, any child with overflow set would be squeezed and clipped instead.)
2517
+ Only a region that scrolls itself opts back in: .fd-pop-list and .fd-menu-frame, both
2518
+ declared later in this file. */
2519
+ .fd-pop-body > * {
2520
+ flex-shrink: 0;
2521
+ }
2421
2522
  .fd-pop.is-up {
2422
2523
  top: auto;
2423
2524
  bottom: calc(100% + 6px);
2424
2525
  transform-origin: bottom center;
2425
2526
  }
2527
+ /* A list that scrolls inside a popover body. No max-height of its own: the surface is
2528
+ already capped by the viewport (and by Popover's maxHeight when a caller wants it
2529
+ shorter), and a second fixed cap here is exactly what used to put a scrollbar inside
2530
+ a scrollbar. */
2426
2531
  .fd-pop-list {
2532
+ flex: 1 1 auto;
2533
+ min-height: 0;
2427
2534
  overflow-y: auto;
2428
- max-height: 320px;
2535
+ overscroll-behavior: contain;
2429
2536
  padding: 5px;
2430
2537
  }
2538
+ /* A popover's search row. It sits in the popover header, which owns the padding and the
2539
+ hairline below it. */
2431
2540
  .fd-pop-search {
2432
2541
  display: flex;
2433
2542
  align-items: center;
2434
2543
  gap: 8px;
2435
- padding: 9px 12px;
2436
- border-bottom: 1px solid var(--border);
2437
- flex: none;
2438
2544
  }
2439
2545
  .fd-pop-search input {
2440
2546
  border: none;
@@ -3969,6 +4075,42 @@
3969
4075
  .fd-erow-metric.is-danger > .ph {
3970
4076
  color: var(--danger-text);
3971
4077
  }
4078
+ /* A metric that carries a tooltip is a real button (focusable, tappable, and skipped by
4079
+ TransferList's drag arming) that must still look exactly like its plain neighbours —
4080
+ so the UA button chrome goes, and a dotted underline on the figure is the one hint
4081
+ that there is more to read. */
4082
+ button.fd-erow-metric {
4083
+ appearance: none;
4084
+ margin: 0;
4085
+ padding: 0;
4086
+ border: 0;
4087
+ background: none;
4088
+ font: inherit;
4089
+ font-size: var(--overline-size);
4090
+ line-height: inherit;
4091
+ text-align: left;
4092
+ border-radius: var(--r-xs);
4093
+ cursor: help;
4094
+ }
4095
+ /* The strip clips its overflow (see .fd-erow-metrics), which would shear off the
4096
+ standard outset focus ring — so this one ring is drawn inside the cell. */
4097
+ button.fd-erow-metric:focus-visible {
4098
+ box-shadow: inset 0 0 0 2px var(--blue-500);
4099
+ }
4100
+ .fd-erow-metric.is-described .fd-erow-metric-value {
4101
+ text-decoration: underline dotted;
4102
+ text-decoration-color: var(--text-muted);
4103
+ text-underline-offset: 2px;
4104
+ }
4105
+ /* The row's action is a real 44px target wherever a finger is the pointer or the screen
4106
+ is narrow. The default card is 64px tall, so it fits without growing the row. */
4107
+ @media (pointer: coarse), (max-width: 768px) {
4108
+ .fd-erow-action.fd-btn-icon-sm {
4109
+ width: var(--control-h-md);
4110
+ height: var(--control-h-md);
4111
+ font-size: 18px;
4112
+ }
4113
+ }
3972
4114
  .fd-erow-accessory {
3973
4115
  margin-left: auto;
3974
4116
  flex: none;
@@ -4533,6 +4675,17 @@
4533
4675
  .fd-menu {
4534
4676
  outline: none;
4535
4677
  }
4678
+ /* A Menu is one shrinkable frame: header and footer pinned, items scrolling between. */
4679
+ .fd-menu-frame {
4680
+ flex: 1 1 auto;
4681
+ min-height: 0;
4682
+ display: flex;
4683
+ flex-direction: column;
4684
+ }
4685
+ .fd-menu-header,
4686
+ .fd-menu-footer {
4687
+ flex: none;
4688
+ }
4536
4689
  .fd-menu-item {
4537
4690
  align-items: center;
4538
4691
  }
@@ -5791,10 +5944,6 @@
5791
5944
  color: var(--chat-text);
5792
5945
  font-weight: var(--w-semibold);
5793
5946
  }
5794
- .fdc-usage-foot {
5795
- border-top: 1px solid var(--border);
5796
- padding-top: 10px;
5797
- }
5798
5947
  .fdc-usage-clear {
5799
5948
  display: inline-flex;
5800
5949
  align-items: center;
package/styles/tokens.css CHANGED
@@ -90,6 +90,16 @@
90
90
  --erow-danger-border:#EFB7B1;
91
91
  --erow-danger-text:#7A241D;
92
92
 
93
+ /* Solid icon button (IconButton variant="solid") — the filled action, e.g. the add /
94
+ remove button on every EntityRow. Per tone: rest, hover (darker), pressed (darker
95
+ still) and the glyph ink. Measured, not eyeballed, in every state: white ink on the
96
+ fill is 5.02:1 or better (the weakest is neutral at rest), and the fill is 4.29:1 or
97
+ better against each ground it sits on — --surface-2 (#F7F8FA), --erow-danger-fill
98
+ (#FCE9E6) and --surface — so the button reads as a button on a red row as well. */
99
+ --btn-solid-neutral-bg:#2272BA;--btn-solid-neutral-bg-hover:#1A5B96;--btn-solid-neutral-bg-active:#144674;--btn-solid-neutral-ink:#FFFFFF;
100
+ --btn-solid-ok-bg:#1E7A4C;--btn-solid-ok-bg-hover:#18663F;--btn-solid-ok-bg-active:#145A38;--btn-solid-ok-ink:#FFFFFF;
101
+ --btn-solid-danger-bg:#B93A31;--btn-solid-danger-bg-hover:#9E2F27;--btn-solid-danger-bg-active:#862720;--btn-solid-danger-ink:#FFFFFF;
102
+
93
103
  --ok-fill:#DFF3E8;--ok-border:#A8DDC2;--ok-text:#0E5233;--ok-solid:#34A26B;--ok-emph:#57C68C;
94
104
  --warn-fill:#FDF1DA;--warn-border:#F0D49A;--warn-text:#6B4A05;--warn-solid:#C8890B;
95
105
  --danger-fill:#FCE7E5;--danger-border:#F2BDB8;--danger-text:#7A241D;--danger-solid:#D0473D;
@@ -236,6 +246,16 @@
236
246
  --erow-danger-border:#7A342C;
237
247
  --erow-danger-text:#F0A79F;
238
248
 
249
+ /* Solid icon button — see the :root block above. On dark ground a dark fill cannot
250
+ separate from a near-black card, so the fills go LIGHT and the ink goes dark, and
251
+ hover steps lighter rather than darker, pressed a step darker. In every state the dark
252
+ ink on the fill is 4.80:1 or better (the weakest is ok pressed) and the fill is 4.76:1
253
+ or better against --surface-2 (#1B1F27), --erow-danger-fill (#331813) and --surface
254
+ (the weakest is danger pressed on a danger row). */
255
+ --btn-solid-neutral-bg:#6FA8E8;--btn-solid-neutral-bg-hover:#8FBEF0;--btn-solid-neutral-bg-active:#5A98DE;--btn-solid-neutral-ink:#0B1B2A;
256
+ --btn-solid-ok-bg:#3FB37A;--btn-solid-ok-bg-hover:#57C68C;--btn-solid-ok-bg-active:#35A26D;--btn-solid-ok-ink:#0B2A1B;
257
+ --btn-solid-danger-bg:#E8776D;--btn-solid-danger-bg-hover:#F08A80;--btn-solid-danger-bg-active:#D9685E;--btn-solid-danger-ink:#2A0B08;
258
+
239
259
  /* chat kit — see the :root block above */
240
260
  --chat-code-bg:#12151B;
241
261
  --code-kw:#B3A6F0;--code-str:#E9C377;--code-num:#EFA8BE;--code-com:#6C7686;