@ibobbyts/svelte-ui-utils 0.5.2 → 0.5.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/README.md CHANGED
@@ -890,6 +890,27 @@ inside a theme root:
890
890
  }
891
891
  ```
892
892
 
893
+ ### Overlay surface tokens
894
+
895
+ Dropdown menus render as floating overlays: they step the page background up
896
+ (`--suu-color-elevated`, derived from the surface/bg palette) and lift off the
897
+ page with `--suu-shadow-overlay` (a deep shadow plus a hairline ring so the
898
+ outline stays readable over host grid lines). Both resolve against the current
899
+ theme palette automatically.
900
+
901
+ Inside the menu, row semantics come from `--suu-dropdown-*` tokens declared on
902
+ `.suu-dropdown`: `--suu-dropdown-option-separator` (faint line between
903
+ options), `--suu-dropdown-group-border` / `--suu-dropdown-group-bg` /
904
+ `--suu-dropdown-group-text` (the section header band), and
905
+ `--suu-dropdown-option-hover-bg` / `--suu-dropdown-option-selected-bg` /
906
+ `--suu-dropdown-option-selected-hover-bg`. They are palette-derived color
907
+ mixes, so light and dark themes keep the same hierarchy: panel frame > group
908
+ band boundary > option separator, and selected > hover. Only override them for
909
+ a deliberately different overlay treatment.
910
+
911
+ 下拉选项默认最小行高为 36px,分组标题为 32px;长文本仍可撑高。
912
+ 分组通过中性底色、加粗标题和组内选项缩进区分,未分组的选项不缩进。
913
+
893
914
  ### Corner-radius tokens
894
915
 
895
916
  All non-zero component corner radii come from the token definitions in
@@ -65,7 +65,11 @@
65
65
  export let onTriggerClick: DropdownTriggerClickHandler | undefined = undefined;
66
66
 
67
67
  const viewportMargin = 20;
68
- const menuGap = 6;
68
+ const menuGap = 4;
69
+ // The menu overhangs the trigger horizontally so its edges break from the
70
+ // host layout's lines (table column borders, adjacent inputs) and read as an
71
+ // independent floating layer instead of a continuation of the grid.
72
+ const menuOutset = 4;
69
73
  const instanceId = ++dropdownInstanceCount;
70
74
 
71
75
  let open = false;
@@ -783,12 +787,12 @@
783
787
  )}px`;
784
788
  if (menuAlign === 'right') {
785
789
  portalMenuLeft = undefined;
786
- portalMenuRight = `${Math.round(window.innerWidth - rect.right)}px`;
790
+ portalMenuRight = `${Math.max(0, Math.round(window.innerWidth - rect.right - menuOutset))}px`;
787
791
  } else {
788
- portalMenuLeft = `${Math.round(rect.left)}px`;
792
+ portalMenuLeft = `${Math.max(0, Math.round(rect.left - menuOutset))}px`;
789
793
  portalMenuRight = undefined;
790
794
  }
791
- portalMenuWidth = `${Math.round(rect.width)}px`;
795
+ portalMenuWidth = `${Math.round(rect.width + menuOutset * 2)}px`;
792
796
  }
793
797
 
794
798
  function portalMenu(node: HTMLDivElement, enabled: boolean) {
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/Dropdown.svelte.ts"],"names":[],"mappings":"AAOA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,KAAK,EAER,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EAGnB,iBAAiB,EAGjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,8BAA8B,EAC9B,2BAA2B,EAC3B,iBAAiB,EACjB,2BAA2B,EAE5B,MAAM,YAAY,CAAC;AAk9BtB,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,QAAQ;SAXw3B,MAAM,GAAG,SAAS;YAAU,iBAAiB;;cAA8C,cAAc,EAAE;mBAAiB,mBAAmB,EAAE,GAAG,SAAS;IACniC,sFAAsF,mBAAkB,cAAc,EAAE;+BAA6B,MAAM,GAAG,OAAO,GAAG,MAAM;;iBAAuC,kBAAkB;mBAAiB,uBAAuB;kBAAgB,mBAAmB,GAAG,SAAS;;;wBAAoG,MAAM,GAAG,SAAS;kBAAgB,MAAM,GAAG,SAAS;eAAa,UAAU;kBAAgB,MAAM,GAAG,SAAS;oBAAkB,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;gBAAc,iBAAiB;gBAAc,iBAAiB;;;;WAAuG,MAAM,GAAG,SAAS;;YAAsC,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;;eAAqC,8BAA8B,GAAG,SAAS;qBAAmB,2BAA2B,GAAG,SAAS;qBAAmB,2BAA2B,GAAG,SAAS;;;;;kBAUtiC,CAAC;AAC5E,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,QAAQ,CAAC,CAAC;AAChD,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/Dropdown.svelte.ts"],"names":[],"mappings":"AAOA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,KAAK,EAER,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EAGnB,iBAAiB,EAGjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,8BAA8B,EAC9B,2BAA2B,EAC3B,iBAAiB,EACjB,2BAA2B,EAE5B,MAAM,YAAY,CAAC;AAs9BtB,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,QAAQ;SAXw3B,MAAM,GAAG,SAAS;YAAU,iBAAiB;;cAA8C,cAAc,EAAE;mBAAiB,mBAAmB,EAAE,GAAG,SAAS;IACniC,sFAAsF,mBAAkB,cAAc,EAAE;+BAA6B,MAAM,GAAG,OAAO,GAAG,MAAM;;iBAAuC,kBAAkB;mBAAiB,uBAAuB;kBAAgB,mBAAmB,GAAG,SAAS;;;wBAAoG,MAAM,GAAG,SAAS;kBAAgB,MAAM,GAAG,SAAS;eAAa,UAAU;kBAAgB,MAAM,GAAG,SAAS;oBAAkB,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;gBAAc,iBAAiB;gBAAc,iBAAiB;;;;WAAuG,MAAM,GAAG,SAAS;;YAAsC,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;;eAAqC,8BAA8B,GAAG,SAAS;qBAAmB,2BAA2B,GAAG,SAAS;qBAAmB,2BAA2B,GAAG,SAAS;;;;;kBAUtiC,CAAC;AAC5E,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,QAAQ,CAAC,CAAC;AAChD,eAAe,QAAQ,CAAC"}
package/dist/style.css CHANGED
@@ -12,6 +12,14 @@
12
12
  --suu-color-warning: #d97706;
13
13
  --suu-color-info: #2563eb;
14
14
  --suu-shadow: 0 12px 30px rgb(15 23 42 / 0.14);
15
+ /* Overlay surfaces (dropdown menus) float above the page: they step the page
16
+ background up toward the surface color instead of reusing it and get a
17
+ deep shadow plus a hairline ring so their outline stays readable even
18
+ where host grid lines (table borders, adjacent inputs) run under them.
19
+ The elevated token references the base palette lazily, so theme and
20
+ consumer-side remaps of surface/border apply automatically. */
21
+ --suu-color-elevated: color-mix(in srgb, var(--suu-color-surface) 45%, var(--suu-color-bg));
22
+ --suu-shadow-overlay: 0 12px 32px rgb(15 23 42 / 0.2), 0 0 0 1px rgb(15 23 42 / 0.06);
15
23
  --suu-radius-xs: 4px;
16
24
  --suu-radius-sm: 6px;
17
25
  --suu-radius-md: 8px;
@@ -37,6 +45,7 @@
37
45
  --suu-color-warning: #fbbf24;
38
46
  --suu-color-info: #60a5fa;
39
47
  --suu-shadow: 0 16px 34px rgb(0 0 0 / 0.32);
48
+ --suu-shadow-overlay: 0 12px 32px rgb(0 0 0 / 0.45), 0 0 0 1px rgb(255 255 255 / 0.025);
40
49
  }
41
50
 
42
51
  .suu-visually-hidden {
@@ -895,6 +904,16 @@
895
904
 
896
905
  .suu-dropdown {
897
906
  --suu-dropdown-space: 14px;
907
+ /* Menu row semantics, all derived from the theme palette so light and dark
908
+ keep the same ladder: panel frame > group band boundary > option
909
+ separator, and selected > hover. */
910
+ --suu-dropdown-option-separator: color-mix(in srgb, var(--suu-color-border) 24%, transparent);
911
+ --suu-dropdown-group-border: color-mix(in srgb, var(--suu-color-border) 80%, transparent);
912
+ --suu-dropdown-group-bg: color-mix(in srgb, var(--suu-color-muted) 18%, var(--suu-color-elevated));
913
+ --suu-dropdown-group-text: var(--suu-color-text);
914
+ --suu-dropdown-option-hover-bg: color-mix(in srgb, var(--suu-color-muted) 7%, var(--suu-color-elevated));
915
+ --suu-dropdown-option-selected-bg: color-mix(in srgb, var(--suu-color-accent) 12%, var(--suu-color-elevated));
916
+ --suu-dropdown-option-selected-hover-bg: color-mix(in srgb, var(--suu-color-accent) 18%, var(--suu-color-elevated));
898
917
 
899
918
  position: relative;
900
919
  display: inline-flex;
@@ -1018,18 +1037,24 @@
1018
1037
  transform: translateY(-20%) rotate(45deg);
1019
1038
  }
1020
1039
 
1040
+ /* The menu is a floating overlay, not a table that grew downward: its
1041
+ background steps above the page, the shadow ring keeps the outline readable
1042
+ where host grid lines run under it, and it overhangs the trigger by 4px on
1043
+ each side so its edges never sit on the same lines as the surrounding
1044
+ layout. Internal lines follow the --suu-dropdown-* row tokens so the
1045
+ ladder stays: panel frame > group band boundary > option separator. */
1021
1046
  .suu-dropdown__menu {
1022
1047
  position: absolute;
1023
- top: calc(100% + 6px);
1024
- right: 0;
1048
+ top: calc(100% + 4px);
1049
+ right: -4px;
1025
1050
  left: auto;
1026
1051
  z-index: 100;
1027
- min-width: 100%;
1052
+ min-width: calc(100% + 8px);
1028
1053
  overflow: hidden;
1029
1054
  border: 1px solid var(--suu-color-border);
1030
1055
  border-radius: var(--suu-radius);
1031
- background: var(--suu-color-bg);
1032
- box-shadow: 0 18px 42px rgb(15 23 42 / 0.16);
1056
+ background: var(--suu-color-elevated);
1057
+ box-shadow: var(--suu-shadow-overlay);
1033
1058
  /* Reset inherited host whitespace (e.g. a nowrap table cell) so every menu
1034
1059
  text — group titles, status labels — wraps by default; the single-line
1035
1060
  fit-content rules set nowrap explicitly where needed. */
@@ -1057,17 +1082,17 @@
1057
1082
 
1058
1083
  .suu-dropdown__menu--left:not(.suu-dropdown__menu--portal) {
1059
1084
  right: auto;
1060
- left: 0;
1085
+ left: -4px;
1061
1086
  }
1062
1087
 
1063
1088
  .suu-dropdown__menu--right:not(.suu-dropdown__menu--portal) {
1064
- right: 0;
1089
+ right: -4px;
1065
1090
  left: auto;
1066
1091
  }
1067
1092
 
1068
1093
  .suu-dropdown__menu--up:not(.suu-dropdown__menu--portal) {
1069
1094
  top: auto;
1070
- bottom: calc(100% + 6px);
1095
+ bottom: calc(100% + 4px);
1071
1096
  }
1072
1097
 
1073
1098
  .suu-dropdown__menu--fit-content:not(.suu-dropdown__menu--portal) {
@@ -1102,26 +1127,31 @@
1102
1127
  max-height: var(--suu-dropdown-panel-max-height, 100vh);
1103
1128
  overflow-y: auto;
1104
1129
  overflow-x: hidden;
1105
- background: var(--suu-color-bg);
1130
+ background: var(--suu-color-elevated);
1106
1131
  overscroll-behavior: contain;
1107
1132
  }
1108
1133
 
1109
1134
  .suu-dropdown__group + .suu-dropdown__group {
1110
- border-top: 1px solid var(--suu-color-border);
1135
+ border-top: 1px solid var(--suu-dropdown-group-border);
1111
1136
  }
1112
1137
 
1138
+ /* 分组用中性底色和粗体形成标题带,避免与蓝色选中态混淆。
1139
+ font 简写必须位于字号和字重之前,防止覆盖标题层级。 */
1113
1140
  .suu-dropdown__group-label {
1114
1141
  display: flex;
1115
1142
  width: 100%;
1116
1143
  border: 0;
1117
- padding: 8px 14px 6px;
1118
- background: var(--suu-color-surface);
1119
- color: var(--suu-color-muted);
1144
+ border-bottom: 1px solid var(--suu-dropdown-group-border);
1145
+ min-height: 32px;
1146
+ padding: 6px 14px;
1147
+ background: var(--suu-dropdown-group-bg);
1148
+ color: var(--suu-dropdown-group-text);
1120
1149
  cursor: pointer;
1121
- font-size: 0.75em;
1150
+ font: inherit;
1151
+ font-size: 0.8125em;
1122
1152
  font-weight: 700;
1153
+ line-height: 1.3;
1123
1154
  letter-spacing: 0.02em;
1124
- font: inherit;
1125
1155
  text-align: left;
1126
1156
  align-items: center;
1127
1157
  justify-content: space-between;
@@ -1150,12 +1180,15 @@
1150
1180
  transform: rotate(45deg);
1151
1181
  }
1152
1182
 
1183
+ /* 收紧单行选项的留白,长名称仍由内容撑高;分隔线保持弱于分组边界。 */
1153
1184
  .suu-dropdown__option {
1154
- display: block;
1185
+ display: flex;
1186
+ align-items: center;
1155
1187
  width: 100%;
1156
- padding: 9px 14px;
1188
+ min-height: 36px;
1189
+ padding: 6px 14px;
1157
1190
  border: 0;
1158
- border-bottom: 1px solid var(--suu-color-border);
1191
+ border-bottom: 1px solid var(--suu-dropdown-option-separator);
1159
1192
  background: transparent;
1160
1193
  color: var(--suu-color-text);
1161
1194
  cursor: pointer;
@@ -1163,14 +1196,13 @@
1163
1196
  text-align: left;
1164
1197
  }
1165
1198
 
1166
- .suu-dropdown__option--group-first {
1167
- border-top: 1px solid var(--suu-color-border);
1199
+ /* 仅有标题的组选项缩进,未分组的「未选择」等操作保持原始对齐。 */
1200
+ .suu-dropdown__group-label ~ .suu-dropdown__option {
1201
+ padding-inline-start: 24px;
1168
1202
  }
1169
1203
 
1170
1204
  .suu-dropdown--multiselect .suu-dropdown__option {
1171
- display: flex;
1172
1205
  gap: 10px;
1173
- align-items: center;
1174
1206
  }
1175
1207
 
1176
1208
  .suu-dropdown__checkbox {
@@ -1207,15 +1239,24 @@
1207
1239
  .suu-dropdown__option:hover,
1208
1240
  .suu-dropdown__option:focus-visible,
1209
1241
  .suu-dropdown__option--active {
1210
- background: var(--suu-color-surface);
1242
+ background: var(--suu-dropdown-option-hover-bg);
1211
1243
  outline: none;
1212
1244
  }
1213
1245
 
1246
+ /* The selected row is a clear area, not just colored text; hover on top of it
1247
+ deepens the tint one step so the two states stay distinguishable. */
1214
1248
  .suu-dropdown__option[aria-selected='true'] {
1249
+ background: var(--suu-dropdown-option-selected-bg);
1215
1250
  color: var(--suu-color-accent);
1216
1251
  font-weight: 700;
1217
1252
  }
1218
1253
 
1254
+ .suu-dropdown__option[aria-selected='true']:hover,
1255
+ .suu-dropdown__option[aria-selected='true']:focus-visible,
1256
+ .suu-dropdown__option[aria-selected='true'].suu-dropdown__option--active {
1257
+ background: var(--suu-dropdown-option-selected-hover-bg);
1258
+ }
1259
+
1219
1260
  .suu-dropdown__option--disabled,
1220
1261
  .suu-dropdown__option:disabled {
1221
1262
  cursor: not-allowed;
@@ -1228,8 +1269,8 @@
1228
1269
  gap: 8px;
1229
1270
  align-items: center;
1230
1271
  padding: 8px 14px;
1231
- border-bottom: 1px solid var(--suu-color-border);
1232
- background: var(--suu-color-bg);
1272
+ border-bottom: 1px solid var(--suu-dropdown-group-border);
1273
+ background: var(--suu-color-surface);
1233
1274
  }
1234
1275
 
1235
1276
  .suu-dropdown__search-icon {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibobbyts/svelte-ui-utils",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Reusable Svelte 5 UI utilities for dialogs, toast notifications, dropdowns, and data tables.",
5
5
  "type": "module",
6
6
  "license": "MIT",