@ibobbyts/svelte-ui-utils 0.5.1 → 0.5.2

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.
@@ -715,6 +715,26 @@
715
715
  resolvedPlacement = availableBelow >= availableAbove ? 'down' : 'up';
716
716
  }
717
717
 
718
+ // The panel is only part of the menu: the search box and the menu borders
719
+ // also consume viewport budget. When the whole budget goes to the panel, the
720
+ // total menu grows taller than the available space and an upward portal menu
721
+ // computes a negative top that escapes the viewport. The difference between
722
+ // the rendered menu and its panel is exactly that non-panel chrome, whatever
723
+ // the current max-height is.
724
+ function measureMenuChromeHeight(): number {
725
+ if (!menuElement || typeof window === 'undefined') {
726
+ return 0;
727
+ }
728
+ const panelElement = menuElement.querySelector<HTMLElement>('.suu-dropdown__panel');
729
+ if (!panelElement) {
730
+ return 0;
731
+ }
732
+ return Math.max(
733
+ 0,
734
+ menuElement.getBoundingClientRect().height - panelElement.getBoundingClientRect().height
735
+ );
736
+ }
737
+
718
738
  async function updateViewportPanelMaxHeight() {
719
739
  await tick();
720
740
 
@@ -742,7 +762,8 @@
742
762
  resolvedPlacement === 'up'
743
763
  ? rect.top - viewportMargin - menuGap
744
764
  : window.innerHeight - rect.bottom - viewportMargin - menuGap;
745
- viewportPanelMaxHeight = `${Math.max(0, Math.floor(available))}px`;
765
+ const availablePanelHeight = available - measureMenuChromeHeight();
766
+ viewportPanelMaxHeight = `${Math.max(0, Math.floor(availablePanelHeight))}px`;
746
767
  // Apply the value directly before measuring: the reactive style binding on
747
768
  // this node only lands in the next flush, so the first upward open would
748
769
  // otherwise measure the fallback 100vh height and place the menu above the
@@ -1053,7 +1074,7 @@
1053
1074
  aria-expanded={!collapsedGroupIndexes.has(groupIndex)}
1054
1075
  on:click|stopPropagation={() => toggleGroup(groupIndex)}
1055
1076
  >
1056
- <span>{group.label}</span>
1077
+ <span class="suu-dropdown__group-title">{group.label}</span>
1057
1078
  <span class="suu-dropdown__group-chevron" aria-hidden="true"></span>
1058
1079
  </button>
1059
1080
  {/if}
@@ -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;AA67BtB,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;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"}
package/dist/style.css CHANGED
@@ -1030,6 +1030,10 @@
1030
1030
  border-radius: var(--suu-radius);
1031
1031
  background: var(--suu-color-bg);
1032
1032
  box-shadow: 0 18px 42px rgb(15 23 42 / 0.16);
1033
+ /* Reset inherited host whitespace (e.g. a nowrap table cell) so every menu
1034
+ text — group titles, status labels — wraps by default; the single-line
1035
+ fit-content rules set nowrap explicitly where needed. */
1036
+ white-space: normal;
1033
1037
  }
1034
1038
 
1035
1039
  .suu-dropdown__menu--portal {
@@ -1074,13 +1078,17 @@
1074
1078
  min-width: max-content;
1075
1079
  }
1076
1080
 
1077
- .suu-dropdown__menu--fit-content .suu-dropdown__option {
1081
+ /* The single-line rules assume the menu stretches to its longest option, which
1082
+ only a non-portal menu does; a portal menu keeps the trigger's fixed width,
1083
+ so its options fall back to the base two-line wrapping label instead of
1084
+ being clipped at the menu edge. */
1085
+ .suu-dropdown__menu--fit-content:not(.suu-dropdown__menu--portal) .suu-dropdown__option {
1078
1086
  width: auto;
1079
1087
  min-width: 100%;
1080
1088
  white-space: nowrap;
1081
1089
  }
1082
1090
 
1083
- .suu-dropdown__menu--fit-content .suu-dropdown__option .suu-dropdown__label {
1091
+ .suu-dropdown__menu--fit-content:not(.suu-dropdown__menu--portal) .suu-dropdown__option .suu-dropdown__label {
1084
1092
  overflow: visible;
1085
1093
  text-overflow: clip;
1086
1094
  display: block;
@@ -1119,7 +1127,17 @@
1119
1127
  justify-content: space-between;
1120
1128
  }
1121
1129
 
1130
+ /* A long group title must wrap inside a narrow menu: a flex item keeps its
1131
+ min-content width by default, which pushes unbroken names (IDs, hashes)
1132
+ past the menu edge instead of folding them. */
1133
+ .suu-dropdown__group-title {
1134
+ flex: 1 1 auto;
1135
+ min-width: 0;
1136
+ overflow-wrap: break-word;
1137
+ }
1138
+
1122
1139
  .suu-dropdown__group-chevron {
1140
+ flex-shrink: 0;
1123
1141
  width: 7px;
1124
1142
  height: 7px;
1125
1143
  border-right: 2px solid currentColor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibobbyts/svelte-ui-utils",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Reusable Svelte 5 UI utilities for dialogs, toast notifications, dropdowns, and data tables.",
5
5
  "type": "module",
6
6
  "license": "MIT",