@flytedan/flytebot-design-system 0.49.1 → 0.50.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.49.1",
3
+ "version": "0.50.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",
@@ -1163,6 +1163,10 @@
1163
1163
  place-items: center;
1164
1164
  width: 18px;
1165
1165
  height: 18px;
1166
+ /* MP-282: fixed at 18×18 on purpose (a real hit target) — never one of the flex items a
1167
+ squeezed .fd-tag shrinks to make room for a long label (see .fd-filterbar .fd-tag-label
1168
+ below), so it stays visible and clickable at any chip width. */
1169
+ flex: none;
1166
1170
  border-radius: var(--r-full);
1167
1171
  background: var(--border);
1168
1172
  color: var(--text-2);
@@ -1610,7 +1614,7 @@
1610
1614
  .fd-soon-cone-mark i {
1611
1615
  font-size: 11px;
1612
1616
  }
1613
- /* z-index is set inline by ComingSoon.tsx via useOverlayLayer (see Popover.tsx). */
1617
+ /* z-index is set inline by ComingSoon.tsx via useLayerZIndex (kits/layerStack.tsx). */
1614
1618
  .fd-soon-hovercard {
1615
1619
  transform: none;
1616
1620
  box-shadow: 0 18px 48px rgba(11, 13, 17, 0.26);
@@ -2048,6 +2052,14 @@
2048
2052
  color: var(--text);
2049
2053
  vertical-align: middle;
2050
2054
  }
2055
+ /* SMS-50: a link-variant Button in a cell (a name that acts on its row) is text, not a control:
2056
+ it wraps like the text around it and reads left-aligned. A Button on its own never wraps
2057
+ (`white-space: nowrap`), so a long name kept its row on one line and stretched the table
2058
+ past its card. */
2059
+ .fd-table td .fd-btn-link {
2060
+ white-space: normal;
2061
+ text-align: left;
2062
+ }
2051
2063
  .fd-table td.is-num {
2052
2064
  text-align: right;
2053
2065
  font-variant-numeric: tabular-nums lining-nums;
@@ -2482,7 +2494,7 @@
2482
2494
  }
2483
2495
 
2484
2496
  /* ============ Overlays ============ */
2485
- /* z-index is set inline by Modal.tsx/Drawer.tsx via useOverlayLayer (see Popover.tsx). */
2497
+ /* z-index is set inline by Modal.tsx/Drawer.tsx via useLayerZIndex (kits/layerStack.tsx). */
2486
2498
  .fd-scrim {
2487
2499
  position: fixed;
2488
2500
  inset: 0;
@@ -2617,7 +2629,7 @@
2617
2629
  border-top: 1px solid var(--border);
2618
2630
  background: var(--surface-2);
2619
2631
  }
2620
- /* z-index is set inline by Drawer.tsx (and its scrim's) via useOverlayLayer (see Popover.tsx). */
2632
+ /* z-index is set inline by Drawer.tsx (and its scrim's) via useLayerZIndex (kits/layerStack.tsx). */
2621
2633
  .fd-drawer {
2622
2634
  position: fixed;
2623
2635
  top: 0;
@@ -2642,7 +2654,7 @@
2642
2654
  /* Portaled to document.body and placed by Tooltip.tsx (fixed, anchored geometry), so no
2643
2655
  overflow: hidden ancestor of the trigger can clip it. Short labels stay on one line
2644
2656
  (max-content); a sentence wraps at a readable measure instead of running off-screen.
2645
- z-index is set inline by Tooltip.tsx via useOverlayLayer (see Popover.tsx). */
2657
+ z-index is set inline by Tooltip.tsx via useLayerZIndex (kits/layerStack.tsx). */
2646
2658
  .fd-tooltip {
2647
2659
  position: fixed;
2648
2660
  width: max-content;
@@ -2782,7 +2794,7 @@
2782
2794
  position: relative;
2783
2795
  }
2784
2796
  .fd-pop {
2785
- /* z-index is set inline by Popover.tsx via useOverlayLayer (see Popover.tsx). */
2797
+ /* z-index is set inline by Popover.tsx via useLayerZIndex (kits/layerStack.tsx). */
2786
2798
  position: absolute;
2787
2799
  top: calc(100% + 6px);
2788
2800
  left: 0;
@@ -2961,24 +2973,126 @@
2961
2973
  transform: rotate(180deg);
2962
2974
  }
2963
2975
 
2964
- /* ============ FilterBar (MP-243) ============ */
2965
- /* The bar itself: a wrapping row of chips plus the trailing "Filter" trigger. Kept as its
2966
- own class (rather than composing .fd-row/.fd-wrap utilities) because inline-flex, not
2967
- flex, is load-bearing here — a consumer drops FilterBar into a toolbar row alongside
2968
- other inline elements, and a flex (block-level) root would claim the full row width. */
2976
+ /* ============ FilterBar (MP-243, SMS-50) ============ */
2977
+ /* The bar is two columns on one wrapping row: the MAIN column, which is the "Filter" trigger
2978
+ (its own column, always first) beside the chips (a wrapping area of their own, taking the room
2979
+ left over), and an optional `actions` slot pinned to the right edge (`margin-left: auto`).
2980
+ The columns top-align, so however many lines the chips wrap onto, the trigger and the actions
2981
+ never move. The main column never wraps its two children under each other, at any width; when
2982
+ the row is too narrow for main and actions together (main keeps a floor of
2983
+ --filterbar-main-min), the actions wrap onto a row of their own and stay right-aligned.
2984
+
2985
+ It is a block-level flex box that fills the row it is put in, and `min-width: 0` lets it
2986
+ shrink inside a flex parent instead of forcing that parent wider. (Until SMS-50 it was
2987
+ inline-flex with `max-width: 100%`: an inline-flex box's shrink-to-fit width comes from its
2988
+ UNWRAPPED content, so wrapping only worked once something capped it. A block-level flex box
2989
+ takes its width from its container, which is what makes wrapping, and the chips column's
2990
+ own width, well defined.) */
2969
2991
  .fd-filterbar {
2970
- display: inline-flex;
2992
+ --filterbar-main-min: 20rem;
2993
+ /* The most a chip may take. A longer value is shortened in the middle (MiddleEllipsis). */
2994
+ --filterbar-chip-max: 15rem;
2995
+ display: flex;
2996
+ flex: 1 1 auto;
2997
+ flex-wrap: wrap;
2998
+ align-items: flex-start;
2999
+ gap: var(--s-sm) var(--s-md);
3000
+ min-width: 0;
3001
+ }
3002
+ .fd-filterbar-main {
3003
+ flex: 1 1 var(--filterbar-main-min);
3004
+ min-width: 0;
3005
+ display: flex;
3006
+ align-items: flex-start;
3007
+ gap: var(--s-sm) var(--s-md);
3008
+ }
3009
+ /* A bar with nothing to show in it (no Filter button, no chips: the options have not loaded yet)
3010
+ gives up its main column entirely, so the actions are not pushed onto a row of their own by a
3011
+ column that holds nothing. */
3012
+ .fd-filterbar-main:not(:has(.fd-filterbar-trigger, .fd-tag)) {
3013
+ display: none;
3014
+ }
3015
+ .fd-filterbar-trigger {
3016
+ flex: none;
3017
+ }
3018
+ .fd-filterbar-chips {
3019
+ flex: 1 1 0;
3020
+ min-width: 0;
3021
+ display: flex;
2971
3022
  flex-wrap: wrap;
2972
3023
  align-items: center;
3024
+ align-content: center;
2973
3025
  gap: var(--s-sm);
2974
- /* MP-243: an inline-flex box's shrink-to-fit width is computed from its UNWRAPPED
2975
- content first — flex-wrap only kicks in once something already caps the box's own
2976
- width, which an inline-flex element does not get for free from its containing block
2977
- the way a block-level flex does. Without this, enough chips run the bar past the
2978
- viewport edge instead of wrapping onto a second line, at any width narrow enough to
2979
- matter (found opening three fields' chips on a 375px viewport). */
3026
+ /* One chip row centres on the Filter button (a control-h-md button) beside it. */
3027
+ min-height: var(--control-h-md);
3028
+ }
3029
+ .fd-filterbar-actions {
3030
+ flex: none;
3031
+ margin-left: auto;
3032
+ display: flex;
3033
+ flex-wrap: wrap;
3034
+ align-items: flex-start;
3035
+ justify-content: flex-end;
3036
+ gap: var(--s-sm) var(--s-md);
2980
3037
  max-width: 100%;
2981
3038
  }
3039
+ /* MP-282: seen live at 375px — a chip whose value is long (a full campaign name) painted
3040
+ 637px wide inside a 297px-wide bar instead of respecting it, because .fd-tag is `flex:
3041
+ none; white-space: nowrap; max-width: none` with nothing to clamp it, and the ONLY thing
3042
+ that then hid the overflow was the page's own ancestor .fd-card `overflow: hidden` —
3043
+ which silently clipped the chip's × remove control right along with the label.
3044
+ Scoped to FilterBar's own chips, not `.fd-tag`/`.fd-tag-label` themselves: "never wider
3045
+ than this row" is FilterBar's rule, not Tag's. Tag is also used by RoadmapTimeline (a
3046
+ milestone label) and ApiSpecBrowser (an HTTP method, a module name, a screen path) —
3047
+ short, already-bounded-by-their-own-layout content where this bug was never observed and
3048
+ a forced max-width + ellipsis would only truncate text that fits today for no reason.
3049
+
3050
+ The bound goes on .fd-filterbar-chip, the actual flex item of the chips column (the extra
3051
+ <span> FilterBar.tsx wraps `.fd-tag` in for select/multiSelect/range/date's chip, so React
3052
+ keeps one stable DOM node across the editing/non-editing transition). A percentage
3053
+ `max-width` on the button ALONE does nothing: this item's own width is shrink-to-fit
3054
+ (`auto`) with a default `min-width: auto`, which for non-wrapping text equals the label's
3055
+ full intrinsic width, so the percentage would resolve against a size derived from the very
3056
+ content it is meant to clamp (CSS2.1 §10.2: undefined; real browsers ignore it).
3057
+ `min-width: 0` on the flex item breaks that cycle, and `max-width` here is a plain length
3058
+ bounded by the row, so the chip is never wider than --filterbar-chip-max nor than the row
3059
+ it wraps in (SMS-50: was "the row" only, so a long value ran the whole row wide). */
3060
+ .fd-filterbar-chip {
3061
+ min-width: 0;
3062
+ max-width: min(100%, var(--filterbar-chip-max));
3063
+ }
3064
+ .fd-filterbar .fd-tag {
3065
+ max-width: 100%;
3066
+ min-width: 0;
3067
+ }
3068
+ /* Tag.tsx always wraps its children in this span (see Tag.tsx's own MP-282 comment) so
3069
+ there is something block-level (flex items are blockified, .fd-tag is inline-flex) to
3070
+ hang the ellipsis off. `min-width: 0` is needed because this label is itself a flex item
3071
+ of .fd-tag. The full text stays as the label's actual text content regardless of what is
3072
+ painted — that's what keeps the button's accessible name (computed from content, not from
3073
+ what's painted) the whole value; Tag's `title` prop (FilterBar passes the same full value)
3074
+ covers the hover-tooltip half of that same requirement. */
3075
+ .fd-filterbar .fd-tag-label {
3076
+ overflow: hidden;
3077
+ white-space: nowrap;
3078
+ min-width: 0;
3079
+ }
3080
+ /* MiddleEllipsis (SMS-50): the head shrinks and ends in "…"; the tail never shrinks, so the end
3081
+ of a long value stays visible ("Flytedesk Spr…ement (na)"). `white-space: pre` keeps a space
3082
+ at the seam between the two spans, which a flex item would otherwise strip. */
3083
+ .fd-mid-ellipsis {
3084
+ display: flex;
3085
+ min-width: 0;
3086
+ white-space: pre;
3087
+ }
3088
+ .fd-mid-ellipsis-head {
3089
+ min-width: 0;
3090
+ overflow: hidden;
3091
+ text-overflow: ellipsis;
3092
+ }
3093
+ .fd-mid-ellipsis-tail {
3094
+ flex: none;
3095
+ }
2982
3096
  /* The text field's own inline "chip that is also an input" — its editing state reuses
2983
3097
  .fd-tag's box but swaps in the selected/brand treatment .fd-tag[aria-pressed] already
2984
3098
  defines elsewhere, and the raw <input> inside is stripped of its own chrome so it reads
@@ -3840,9 +3954,11 @@
3840
3954
  stroke: var(--border-strong);
3841
3955
  stroke-width: 1;
3842
3956
  }
3957
+ /* SMS-50: 10px, and it stays 10px — TrendChart draws its SVG in real pixels at the container's
3958
+ width (viewBox === rendered size), so this is what paints, never multiplied by the card. */
3843
3959
  .fd-trend-axis-label {
3844
3960
  fill: var(--text-muted);
3845
- font-size: 10.5px;
3961
+ font-size: 10px;
3846
3962
  font-family: var(--font-sans);
3847
3963
  }
3848
3964
  .fd-trend-line {
@@ -7176,7 +7292,7 @@ button.fd-erow-metric:focus-visible {
7176
7292
  border: 1.5px solid var(--surface);
7177
7293
  animation: fd-badge-pop 260ms var(--ease) both;
7178
7294
  }
7179
- /* z-index is set inline by ModeSwitch.tsx via useOverlayLayer (see Popover.tsx). */
7295
+ /* z-index is set inline by ModeSwitch.tsx via useInlinePanel, from useLayerZIndex (kits/layerStack.tsx). */
7180
7296
  .fd-mode-pop {
7181
7297
  position: absolute;
7182
7298
  top: calc(100% + 8px);