@flytedan/flytebot-design-system 0.8.2 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flytedan/flytebot-design-system",
3
- "version": "0.8.2",
3
+ "version": "0.9.1",
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",
@@ -3787,8 +3787,11 @@
3787
3787
  /* Shorter than the row's own fixed slot, not 100% of it — the leftover space
3788
3788
  at the bottom of each slot is what reads as a gap between cards, without
3789
3789
  touching itemHeight itself (that number is load-bearing for the
3790
- scroll/virtualization math in VirtualList.tsx, not just visual spacing). */
3791
- height: calc(100% - 6px);
3790
+ scroll/virtualization math in VirtualList.tsx, not just visual spacing).
3791
+ The size comes from VirtualList's `rowGap` prop via this custom property,
3792
+ since the right gap depends on how tall and heavy the row is; the literal
3793
+ fallback only applies to markup that sets neither. */
3794
+ height: calc(100% - var(--fd-vlist-gap, 6px));
3792
3795
  }
3793
3796
  /* A freshly-added row (e.g. the destination side right after a move) gets a brief
3794
3797
  fade/scale-in instead of popping in instantly. Scale/opacity only — never
@@ -3851,18 +3854,127 @@
3851
3854
  better with the tighter radius; --e-1/--e-2 are the same elevation tokens). */
3852
3855
  .fd-erow {
3853
3856
  background: var(--surface-2);
3854
- border: 1px solid var(--border);
3857
+ border: 1px solid var(--erow-border);
3855
3858
  border-radius: var(--r-md);
3856
3859
  box-shadow: var(--e-1);
3857
3860
  transition:
3858
3861
  box-shadow var(--dur-fast) var(--ease),
3859
3862
  border-color var(--dur-fast) var(--ease),
3863
+ background var(--dur-fast) var(--ease),
3860
3864
  transform var(--dur-fast) var(--ease);
3861
3865
  }
3862
3866
  .fd-erow:hover {
3863
- border-color: var(--border-strong);
3867
+ border-color: var(--erow-border-hover);
3864
3868
  box-shadow: var(--e-2);
3865
3869
  }
3870
+ /* The row's one non-default state colour: this row exists but can't be used
3871
+ (a school with no sellable inventory). Fill, border and title all move, so
3872
+ it survives being scanned at a glance down a long list — a border-only
3873
+ treatment disappears at 60px row pitch. Tokens are --erow-danger-*, defined
3874
+ for both grounds; on dark the fill can't separate from a near-black panel by
3875
+ luminance, so the border and the title colour carry it there. */
3876
+ .fd-erow-danger {
3877
+ background: var(--erow-danger-fill);
3878
+ border-color: var(--erow-danger-border);
3879
+ }
3880
+ .fd-erow-danger:hover {
3881
+ border-color: var(--erow-danger-border);
3882
+ }
3883
+ .fd-erow-danger .fd-erow-title {
3884
+ color: var(--erow-danger-text);
3885
+ }
3886
+
3887
+ /* The row's own two-line body: title line, then the aligned metric strip. The
3888
+ strip line only exists when there are metrics or an accessory, so a plain
3889
+ name-only row is still exactly one line tall. */
3890
+ .fd-erow-body {
3891
+ flex: 1;
3892
+ min-width: 0;
3893
+ display: flex;
3894
+ flex-direction: column;
3895
+ justify-content: center;
3896
+ gap: 3px;
3897
+ }
3898
+ .fd-erow-titleline {
3899
+ display: flex;
3900
+ align-items: baseline;
3901
+ gap: 8px;
3902
+ min-width: 0;
3903
+ }
3904
+ /* The title keeps a floor and the meta is what gives way. Previously the title was
3905
+ "flex: 1; min-width: 0" against a "flex: none" meta, which means the title is the
3906
+ ONLY thing that can shrink — so in a narrow panel (a two-pane transfer list at ~245px
3907
+ per side) a row carrying three figures squeezed the school name to zero width and the
3908
+ row lost its identity entirely. A row you cannot name is a row you cannot act on,
3909
+ which makes the name the last thing that should go, not the first. */
3910
+ .fd-erow-title {
3911
+ flex: 1 1 auto;
3912
+ min-width: 45%;
3913
+ font-weight: var(--w-semibold);
3914
+ color: var(--text);
3915
+ white-space: nowrap;
3916
+ overflow: hidden;
3917
+ text-overflow: ellipsis;
3918
+ }
3919
+ .fd-erow-meta {
3920
+ flex: 0 1 auto;
3921
+ min-width: 0;
3922
+ font-size: var(--overline-size);
3923
+ color: var(--text-muted);
3924
+ white-space: nowrap;
3925
+ overflow: hidden;
3926
+ text-overflow: ellipsis;
3927
+ }
3928
+ .fd-erow-strip {
3929
+ display: flex;
3930
+ align-items: center;
3931
+ gap: 10px;
3932
+ min-width: 0;
3933
+ }
3934
+ /* Fixed-width cells, not auto-sized ones: the whole point of the strip is that
3935
+ the same column lands at the same x on every row (and on the totals line in
3936
+ TransferList's footer, which renders this very component with the same
3937
+ widths), which auto width cannot give you when the numbers differ in digits. */
3938
+ .fd-erow-metrics {
3939
+ display: flex;
3940
+ align-items: center;
3941
+ min-width: 0;
3942
+ /* Cells are fixed-width, so a strip wider than the row it's in has to lose the
3943
+ tail rather than push it: without this the overflowing cells paint straight
3944
+ through whatever is pinned to the end of the strip. Clipping the last column
3945
+ is the right failure here — the alternative is columns that shift row to row,
3946
+ which is the one thing an aligned strip must never do. */
3947
+ overflow: hidden;
3948
+ }
3949
+ .fd-erow-metric {
3950
+ display: inline-flex;
3951
+ align-items: center;
3952
+ gap: 4px;
3953
+ flex: none;
3954
+ font-size: var(--overline-size);
3955
+ color: var(--text-2);
3956
+ white-space: nowrap;
3957
+ overflow: hidden;
3958
+ }
3959
+ .fd-erow-metric > .ph {
3960
+ font-size: 12px;
3961
+ color: var(--text-muted);
3962
+ flex: none;
3963
+ }
3964
+ .fd-erow-metric-value {
3965
+ font-weight: var(--w-medium);
3966
+ overflow: hidden;
3967
+ text-overflow: ellipsis;
3968
+ }
3969
+ .fd-erow-metric.is-danger > .ph {
3970
+ color: var(--danger-text);
3971
+ }
3972
+ .fd-erow-accessory {
3973
+ margin-left: auto;
3974
+ flex: none;
3975
+ display: inline-flex;
3976
+ align-items: center;
3977
+ }
3866
3978
  .fd-erow[draggable="true"]:active {
3867
3979
  cursor: grabbing;
3868
3980
  }
@@ -3914,6 +4026,159 @@
3914
4026
  box-shadow: var(--e-2);
3915
4027
  color: var(--brand);
3916
4028
  }
4029
+ /* TransferList's per-side slots. The footer is where a running totals line goes;
4030
+ it sits on the panel, not on a card, and is separated by a rule rather than a
4031
+ gap so it reads as a summary OF the list rather than another row IN it. */
4032
+ .fd-tlist-header {
4033
+ display: flex;
4034
+ align-items: center;
4035
+ gap: 8px;
4036
+ min-width: 0;
4037
+ }
4038
+ .fd-tlist-footer {
4039
+ display: flex;
4040
+ align-items: center;
4041
+ gap: 10px;
4042
+ min-width: 0;
4043
+ padding-top: 8px;
4044
+ /* Indented to the x a row's own body starts at, so a totals strip in here lands
4045
+ under the columns it totals rather than a card's width to the left of them.
4046
+ The sum is the card's border and padding-left plus the drag grip and its gap
4047
+ — every row in a TransferList is a drag source, so it is the same on all of
4048
+ them. Spelled out rather than collapsed to 37px so it stays checkable against
4049
+ .fd-erow if that padding ever moves. */
4050
+ padding-left: calc(1px + 12px + 14px + 10px);
4051
+ border-top: 1px solid var(--border);
4052
+ font-size: var(--overline-size);
4053
+ color: var(--text-2);
4054
+ }
4055
+
4056
+ /* --- ScoreMeter — a small categorical 0-100 bar, optionally a trigger ------ */
4057
+ .fd-scoremeter {
4058
+ display: inline-flex;
4059
+ align-items: center;
4060
+ gap: 7px;
4061
+ }
4062
+ .fd-scoremeter-rail {
4063
+ display: block;
4064
+ flex: none;
4065
+ }
4066
+ .fd-scoremeter-value {
4067
+ font-size: var(--overline-size);
4068
+ font-weight: var(--w-semibold);
4069
+ color: var(--text-2);
4070
+ min-width: 2ch;
4071
+ text-align: right;
4072
+ }
4073
+ /* The trigger is a real button (keyboard-operable, and skipped by TransferList's
4074
+ drag arming, which ignores any pointerdown inside a button) — so it has to be
4075
+ stripped of the browser's own button chrome and given this kit's own. */
4076
+ .fd-scoremeter-button {
4077
+ appearance: none;
4078
+ background: transparent;
4079
+ border: 1px solid transparent;
4080
+ border-radius: var(--r-sm);
4081
+ padding: 2px 5px;
4082
+ margin: -2px -5px;
4083
+ cursor: pointer;
4084
+ transition:
4085
+ background var(--dur-fast) var(--ease),
4086
+ border-color var(--dur-fast) var(--ease);
4087
+ }
4088
+ .fd-scoremeter-button:hover {
4089
+ background: var(--surface-3);
4090
+ border-color: var(--border);
4091
+ }
4092
+ .fd-scoremeter-button.is-open {
4093
+ background: var(--surface-brand);
4094
+ border-color: var(--border-brand);
4095
+ }
4096
+
4097
+ /* --- importance scale: the tag, and the score breakdown it appears in ------ */
4098
+ .fd-imp-tag {
4099
+ display: inline-flex;
4100
+ align-items: center;
4101
+ gap: 4px;
4102
+ flex: none;
4103
+ padding: 2px 7px;
4104
+ border: 1px solid transparent;
4105
+ border-radius: var(--r-full);
4106
+ font-size: var(--overline-size);
4107
+ line-height: var(--overline-lh);
4108
+ font-weight: var(--w-semibold);
4109
+ white-space: nowrap;
4110
+ }
4111
+ .fd-imp-tag > .ph {
4112
+ font-size: 12px;
4113
+ }
4114
+ .fd-imp-tag.is-md {
4115
+ padding: 4px 10px;
4116
+ font-size: var(--label-size);
4117
+ }
4118
+ .fd-imp-tag.is-md > .ph {
4119
+ font-size: 14px;
4120
+ }
4121
+ .fd-prefbreak {
4122
+ display: flex;
4123
+ flex-direction: column;
4124
+ gap: 10px;
4125
+ min-width: 0;
4126
+ }
4127
+ .fd-prefbreak-head {
4128
+ display: flex;
4129
+ align-items: baseline;
4130
+ justify-content: space-between;
4131
+ gap: 10px;
4132
+ }
4133
+ .fd-prefbreak-score {
4134
+ font-size: var(--h4-size);
4135
+ font-weight: var(--w-bold);
4136
+ color: var(--text);
4137
+ }
4138
+ .fd-prefbreak-list {
4139
+ list-style: none;
4140
+ margin: 0;
4141
+ padding: 0;
4142
+ display: flex;
4143
+ flex-direction: column;
4144
+ gap: 8px;
4145
+ }
4146
+ .fd-prefbreak-item {
4147
+ display: flex;
4148
+ align-items: flex-start;
4149
+ gap: 8px;
4150
+ min-width: 0;
4151
+ }
4152
+ /* A criterion that earned nothing is dimmed rather than hidden — the reason a
4153
+ score is low is exactly the rows that contributed zero. */
4154
+ .fd-prefbreak-item.is-unmet {
4155
+ opacity: 0.55;
4156
+ }
4157
+ .fd-prefbreak-text {
4158
+ flex: 1;
4159
+ min-width: 0;
4160
+ display: flex;
4161
+ flex-direction: column;
4162
+ gap: 2px;
4163
+ }
4164
+ .fd-prefbreak-label {
4165
+ font-size: var(--body-sm-size);
4166
+ line-height: var(--body-sm-lh);
4167
+ color: var(--text);
4168
+ }
4169
+ .fd-prefbreak-note {
4170
+ font-size: var(--overline-size);
4171
+ color: var(--text-muted);
4172
+ }
4173
+ .fd-prefbreak-val {
4174
+ flex: none;
4175
+ font-size: var(--body-sm-size);
4176
+ color: var(--text-2);
4177
+ }
4178
+ .fd-prefbreak-sep {
4179
+ color: var(--text-muted);
4180
+ padding: 0 2px;
4181
+ }
3917
4182
 
3918
4183
  /* uniform staging strip — one row, scrolls sideways */
3919
4184
  .fd-filestrip {
package/styles/tokens.css CHANGED
@@ -63,6 +63,33 @@
63
63
  --csi-ramp-1:#F1F4F5;--csi-ramp-2:#D9EDE6;--csi-ramp-3:#A9DECB;
64
64
  --csi-ramp-4:#6CC7AE;--csi-ramp-5:#2E9E85;--csi-ramp-6:#0B5F50;
65
65
 
66
+ /* criterion importance — the five-level planner priority scale, ordered
67
+ Nudge < Lean < Priority < Driver < Deal-breaker on a slate -> blue -> indigo
68
+ -> amber -> red ramp. Same shape as the CSI ramp above (fill/edge/text/mark
69
+ per stop) because it is used the same two ways: `mark` is the solid the meter
70
+ segments and glyphs are drawn in, `fill`+`edge` tint a criterion card's
71
+ background and border, `text` is the AA-safe label colour ON that fill.
72
+ Deliberately NOT aliases of --info/--warn/--danger: importance is an ordered
73
+ scale, not a status, and a Driver criterion is not a warning. */
74
+ --imp-1-fill:#EEF0F3;--imp-1-edge:#D2D7DF;--imp-1-text:#414958;--imp-1-mark:#7C8698;
75
+ --imp-2-fill:#DEEBF7;--imp-2-edge:#C3DDF1;--imp-2-text:#144674;--imp-2-mark:#2272BA;
76
+ --imp-3-fill:#E7E3F8;--imp-3-edge:#C9C1EE;--imp-3-text:#342A6B;--imp-3-mark:#6E5BC9;
77
+ --imp-4-fill:#FDF1DA;--imp-4-edge:#F0D49A;--imp-4-text:#6B4A05;--imp-4-mark:#BD800A;
78
+ --imp-5-fill:#FCE7E5;--imp-5-edge:#F2BDB8;--imp-5-text:#7A241D;--imp-5-mark:#D0473D;
79
+
80
+ /* EntityRow — the list card's own hairline, and its one non-default row tone.
81
+ The border is a purpose-built token rather than --border because an EntityRow
82
+ card is --surface-2 sitting on a --surface panel, and those two differ by only
83
+ 1.06:1 in light mode: the gap between two cards is invisible unless the
84
+ hairline itself carries it. --erow-border is 1.46:1 against the panel and
85
+ 1.38:1 against the card (vs --border's 1.23 / 1.16), which is what actually
86
+ makes the gap read. --erow-border-hover keeps a distinct hover step on top. */
87
+ --erow-border:#CFD6E0;
88
+ --erow-border-hover:#B6C0CE;
89
+ --erow-danger-fill:#FCE9E6;
90
+ --erow-danger-border:#EFB7B1;
91
+ --erow-danger-text:#7A241D;
92
+
66
93
  --ok-fill:#DFF3E8;--ok-border:#A8DDC2;--ok-text:#0E5233;--ok-solid:#34A26B;--ok-emph:#57C68C;
67
94
  --warn-fill:#FDF1DA;--warn-border:#F0D49A;--warn-text:#6B4A05;--warn-solid:#C8890B;
68
95
  --danger-fill:#FCE7E5;--danger-border:#F2BDB8;--danger-text:#7A241D;--danger-solid:#D0473D;
@@ -190,6 +217,25 @@
190
217
  --danger-fill:#2E1512;--danger-border:#5E2A24;--danger-text:#F0A79F;
191
218
  --info-fill:#12283D;--info-border:#1E3F5E;--info-text:#9CC7EC;
192
219
 
220
+ /* importance ramp on dark ground — see the :root block above for what each stop
221
+ is for. Same five hues, re-struck so `text` stays AA on `fill` and `mark`
222
+ clears 3:1 against the dark meter rail (--surface-3). */
223
+ --imp-1-fill:#23272E;--imp-1-edge:#333A44;--imp-1-text:#A3ACB9;--imp-1-mark:#8892A0;
224
+ --imp-2-fill:#12283D;--imp-2-edge:#1E3F5E;--imp-2-text:#9CC7EC;--imp-2-mark:#6FA8E8;
225
+ --imp-3-fill:#221C3D;--imp-3-edge:#372E5C;--imp-3-text:#BFB4F2;--imp-3-mark:#9B8DE0;
226
+ --imp-4-fill:#2C2210;--imp-4-edge:#5C4614;--imp-4-text:#E9C377;--imp-4-mark:#E0A93F;
227
+ --imp-5-fill:#2E1512;--imp-5-edge:#5E2A24;--imp-5-text:#F0A79F;--imp-5-mark:#E2756B;
228
+
229
+ /* EntityRow — see the :root block above. On dark ground the hairline does even
230
+ more of the work (1.56:1 against the panel), since --surface-2 and --surface
231
+ sit only 1.09:1 apart here too. A dark red row fill cannot separate from a
232
+ near-black panel by luminance, so the danger row reads by border and hue. */
233
+ --erow-border:#333A44;
234
+ --erow-border-hover:#4A5260;
235
+ --erow-danger-fill:#331813;
236
+ --erow-danger-border:#7A342C;
237
+ --erow-danger-text:#F0A79F;
238
+
193
239
  /* chat kit — see the :root block above */
194
240
  --chat-code-bg:#12151B;
195
241
  --code-kw:#B3A6F0;--code-str:#E9C377;--code-num:#EFA8BE;--code-com:#6C7686;