@txstate-mws/svelte-components 1.5.2 → 1.5.4

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.
@@ -4,6 +4,7 @@ export interface GlueArgs<T extends GlueAlignStore = GlueAlignStore> {
4
4
  target: HTMLElement;
5
5
  align?: GlueAlignOpts;
6
6
  cover?: boolean;
7
+ gap?: number;
7
8
  adjustparentheight?: boolean;
8
9
  store?: SettableSubject<T>;
9
10
  }
@@ -11,7 +12,7 @@ export interface GlueAlignStore {
11
12
  valign: 'bottom' | 'top';
12
13
  halign: 'left' | 'right';
13
14
  }
14
- export declare function glue(el: HTMLElement, { target, align, cover, adjustparentheight, store }: GlueArgs): {
15
- update({ target: utarget, align: ualign, cover: ucover, store: ustore }: GlueArgs): void;
15
+ export declare function glue(el: HTMLElement, { target, align, cover, gap, adjustparentheight, store }: GlueArgs): {
16
+ update({ target: utarget, align: ualign, cover: ucover, gap: ugap, store: ustore }: GlueArgs): void;
16
17
  destroy(): void;
17
18
  };
@@ -1,6 +1,6 @@
1
1
  import { watchForMutations } from '../util/index.js';
2
2
  import { equal } from 'txstate-utils';
3
- export function glue(el, { target, align = 'auto', cover = false, adjustparentheight = false, store }) {
3
+ export function glue(el, { target, align = 'auto', cover = false, gap = 0, adjustparentheight = false, store }) {
4
4
  let halign;
5
5
  let valign;
6
6
  const parent = el.offsetParent;
@@ -34,7 +34,7 @@ export function glue(el, { target, align = 'auto', cover = false, adjustparenthe
34
34
  const targetHeight = rect.height;
35
35
  if (autoalign === 'bottomleft') {
36
36
  requestAnimationFrame(() => {
37
- el.style.top = `${rect.top + (cover ? 0 : targetHeight)}px`;
37
+ el.style.top = `${rect.top + (cover ? 0 : targetHeight) + gap}px`;
38
38
  el.style.left = `${rect.left}px`;
39
39
  el.style.bottom = '';
40
40
  el.style.right = '';
@@ -45,7 +45,7 @@ export function glue(el, { target, align = 'auto', cover = false, adjustparenthe
45
45
  }
46
46
  else if (autoalign === 'bottomright') {
47
47
  requestAnimationFrame(() => {
48
- el.style.top = `${rect.top + (cover ? 0 : targetHeight)}px`;
48
+ el.style.top = `${rect.top + (cover ? 0 : targetHeight) + gap}px`;
49
49
  el.style.left = '';
50
50
  el.style.bottom = '';
51
51
  el.style.right = `${rect.right}px`;
@@ -58,7 +58,7 @@ export function glue(el, { target, align = 'auto', cover = false, adjustparenthe
58
58
  requestAnimationFrame(() => {
59
59
  el.style.top = '';
60
60
  el.style.left = `${rect.left}px`;
61
- el.style.bottom = `${rect.bottom + (cover ? 0 : targetHeight)}px`;
61
+ el.style.bottom = `${rect.bottom + (cover ? 0 : targetHeight) + gap}px`;
62
62
  el.style.right = '';
63
63
  adjustParentHeight();
64
64
  });
@@ -69,7 +69,7 @@ export function glue(el, { target, align = 'auto', cover = false, adjustparenthe
69
69
  requestAnimationFrame(() => {
70
70
  el.style.top = '';
71
71
  el.style.left = '';
72
- el.style.bottom = `${rect.bottom + (cover ? 0 : targetHeight)}px`;
72
+ el.style.bottom = `${rect.bottom + (cover ? 0 : targetHeight) + gap}px`;
73
73
  el.style.right = `${rect.right}px`;
74
74
  adjustParentHeight();
75
75
  });
@@ -81,9 +81,10 @@ export function glue(el, { target, align = 'auto', cover = false, adjustparenthe
81
81
  const { destroy: watchDestroy } = watchForMutations(reposition);
82
82
  document.addEventListener('scroll', reposition, { capture: true });
83
83
  return {
84
- update({ target: utarget, align: ualign = 'auto', cover: ucover = false, store: ustore }) {
84
+ update({ target: utarget, align: ualign = 'auto', cover: ucover = false, gap: ugap = 0, store: ustore }) {
85
85
  align = ualign;
86
86
  cover = ucover;
87
+ gap = ugap;
87
88
  if (ustore && ustore !== store) {
88
89
  ustore.update(v => ({ ...v, valign, halign }));
89
90
  store = ustore;
@@ -4,6 +4,7 @@ import type { ElementOffsets } from '../util/index.js';
4
4
  interface OffsetConfig<T extends ElementOffsets = ElementOffsets> {
5
5
  debounce?: boolean | number;
6
6
  store?: WritableSubject<T>;
7
+ container?: HTMLElement | 'nearest';
7
8
  }
8
9
  export declare class OffsetStore extends Store<ElementOffsets> {
9
10
  constructor(initialState?: ElementOffsets);
@@ -1,5 +1,5 @@
1
1
  import { Store } from '@txstate-mws/svelte-store';
2
- import { debounced, watchForPositionChange } from '../util/index.js';
2
+ import { debounced, watchForPositionChangeInContainer } from '../util/index.js';
3
3
  export class OffsetStore extends Store {
4
4
  constructor(initialState) {
5
5
  super(initialState ?? { top: 0, right: 0, bottom: 0, left: 0 });
@@ -16,9 +16,11 @@ export function offset(el, config) {
16
16
  el.dispatchEvent(new CustomEvent('offset', { detail: current }));
17
17
  }
18
18
  let resolvedchange = config?.debounce ? debounced(lookforoffsetchange, config.debounce) : lookforoffsetchange;
19
- const { destroy, update } = watchForPositionChange(el, resolvedchange);
19
+ const offsetContainer = !config?.container ? document.body : (config.container === 'nearest' ? el.offsetParent ?? document.body : config.container);
20
+ const { destroy, update } = watchForPositionChangeInContainer(el, offsetContainer, resolvedchange);
20
21
  return {
21
22
  update(newConfig) {
23
+ const offsetContainer = !config?.container ? document.body : (config.container === 'nearest' ? el.offsetParent ?? document.body : config.container);
22
24
  if (newConfig?.debounce === true)
23
25
  newConfig.debounce = 100;
24
26
  if (newConfig?.store !== config?.store) {
@@ -26,7 +28,7 @@ export function offset(el, config) {
26
28
  }
27
29
  if (newConfig?.debounce !== config?.debounce) {
28
30
  resolvedchange = newConfig?.debounce ? debounced(lookforoffsetchange, newConfig.debounce) : lookforoffsetchange;
29
- update(el, resolvedchange);
31
+ update(el, offsetContainer, resolvedchange);
30
32
  }
31
33
  config = newConfig;
32
34
  },
@@ -6,11 +6,12 @@
6
6
  controlled by the parent component via the `getOptions` function that will be used as a
7
7
  debounced callback on the contents of the text input.
8
8
  -->
9
- <script>import { createEventDispatcher } from 'svelte';
9
+ <script>import { createEventDispatcher, onMount } from 'svelte';
10
10
  import { randomid, Cache } from 'txstate-utils';
11
11
  import ScreenReaderOnly from './ScreenReaderOnly.svelte';
12
12
  import DefaultPopupMenu from './PopupMenu.svelte';
13
13
  import { modifierKey, selectionIsLeft } from '../util';
14
+ import { SafeStore } from '@txstate-mws/svelte-store';
14
15
  export let name;
15
16
  /**
16
17
  * Function to pass to the component that tells it how to use the text in the text input to determine what
@@ -51,7 +52,9 @@ const dispatch = createEventDispatcher();
51
52
  const optionsCache = new Cache(async (ipt) => {
52
53
  return await getOptions(ipt);
53
54
  }, { freshseconds: 5 });
54
- $: selectedSet = new Set(selected.map(s => s.value));
55
+ const selectedStore = new SafeStore(selected);
56
+ $: $selectedStore = selected;
57
+ $: selectedSet = new Set($selectedStore.map(s => s.value));
55
58
  // Stop showing our menu if the maxSelections limit has been reached.
56
59
  $: if (maxSelections > 1 && selected.length >= maxSelections && menushown)
57
60
  menushown = false;
@@ -137,6 +140,12 @@ function reactToHilite(..._) {
137
140
  inputelement.removeAttribute('aria-activedescendant');
138
141
  }
139
142
  $: reactToHilite(hilitedpill, id);
143
+ let gap = 0;
144
+ onMount(() => {
145
+ const ul = inputelement.closest('.multiselect-selected');
146
+ if (ul != null)
147
+ gap = ((ul.offsetHeight - ul.clientHeight) / 2) + parseInt(window.getComputedStyle(ul).paddingBottom);
148
+ });
140
149
  </script>
141
150
 
142
151
  <fieldset>
@@ -166,7 +175,7 @@ $: reactToHilite(hilitedpill, id);
166
175
  <slot></slot>
167
176
  </fieldset>
168
177
  <svelte:component this={PopupMenu} bind:menushown bind:hilited={popuphilited} bind:value={popupvalue} align='bottomleft'
169
- {usePortal} {loading} {emptyText}
178
+ {usePortal} {loading} {emptyText} {gap}
170
179
  {menuContainerClass} {menuClass} {menuItemClass} {menuItemHilitedClass} {menuDividerClass}
171
180
  items={options} buttonelement={inputelement}
172
181
  on:change={addSelection}/>
@@ -34,6 +34,8 @@ of when this is useful is when you are trying to round corners of your button an
34
34
  menu is above or below your button so you know which corners to round and which to leave square. Note that
35
35
  the values do not update when the menu is hidden, so you may need to rely on `menushown` as well. */
36
36
  export let computedalign = new Store({ valign: 'bottom', halign: 'left' });
37
+ /** Create some spacing between the specified button element and the menu, in pixels */
38
+ export let gap = 0;
37
39
  /** Set to `true` if you want the parent element's styling to increase its minHeight when necessary. Useful
38
40
  for parent elements not styled for variable size children and which you want override the the size of. */
39
41
  export let adjustparentheight = false;
@@ -255,7 +257,7 @@ $: hasSelected = showSelected && items.some(itm => 'value' in itm && itm.value =
255
257
 
256
258
  {#if menushown}
257
259
  <div use:portal={usePortal === true ? undefined : (usePortal || null)}
258
- use:glue={{ target: buttonelement, align, cover, adjustparentheight, store: computedalign }}
260
+ use:glue={{ target: buttonelement, align, cover, gap, adjustparentheight, store: computedalign }}
259
261
  class={menuContainerClass}>
260
262
  <ul bind:this={menuelement} id={menuid} role='listbox' style={width ? `width: ${width}` : ''}
261
263
  class={menuClass} class:hasSelected class:defaultmenu={!menuClass && !menuContainerClass}
@@ -22,6 +22,7 @@ declare const __propDef: {
22
22
  of when this is useful is when you are trying to round corners of your button and need to know whether the
23
23
  menu is above or below your button so you know which corners to round and which to leave square. Note that
24
24
  the values do not update when the menu is hidden, so you may need to rely on `menushown` as well. */ computedalign?: Store<GlueAlignStore> | undefined;
25
+ /** Create some spacing between the specified button element and the menu, in pixels */ gap?: number | undefined;
25
26
  /** Set to `true` if you want the parent element's styling to increase its minHeight when necessary. Useful
26
27
  for parent elements not styled for variable size children and which you want override the the size of. */ adjustparentheight?: boolean | undefined;
27
28
  /** If the menu would be clipped by an `overflow: hidden`, you can set this prop and it will be placed in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@txstate-mws/svelte-components",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Svelte components that are generically useful.",
5
5
  "scripts": {
6
6
  "prepublishOnly": "svelte-package",