@hashrytech/quick-components-kit 0.16.0 → 0.16.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @hashrytech/quick-components-kit
2
2
 
3
+ ## 0.16.2
4
+
5
+ ### Patch Changes
6
+
7
+ - addition: portal action
8
+
9
+ ## 0.16.1
10
+
11
+ ### Patch Changes
12
+
13
+ - patch: disable-scroll patch to not add a scrollbar if one is not present to start with
14
+
3
15
  ## 0.16.0
4
16
 
5
17
  ### Minor Changes
@@ -13,9 +13,12 @@ export function disableScroll(node, enabled = true) {
13
13
  const originalBodyWidth = document.body.style.width;
14
14
  const originalTop = document.body.style.top;
15
15
  const originalOverflow = document.documentElement.style.overflowY;
16
+ const hasVerticalScrollbar = document.documentElement.scrollHeight > document.documentElement.clientHeight;
16
17
  function applyLock() {
17
18
  document.body.style.top = `-${scrollTop}px`;
18
- document.documentElement.style.overflowY = 'scroll';
19
+ if (hasVerticalScrollbar) {
20
+ document.documentElement.style.overflowY = 'scroll'; // ensure layout doesn't shift
21
+ }
19
22
  document.body.style.position = 'fixed';
20
23
  document.body.style.width = '100%';
21
24
  }
@@ -0,0 +1,7 @@
1
+ export type PortalOptions = {
2
+ target?: HTMLElement;
3
+ prepend?: boolean;
4
+ };
5
+ export declare function portal(node: HTMLElement, { target, prepend }?: PortalOptions): {
6
+ destroy(): void;
7
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Svelte action to "portal" an element into a different part of the DOM.
3
+ *
4
+ * Useful for rendering components (e.g. modals, tooltips, dropdowns) outside of their natural DOM position,
5
+ * such as appending them to `document.body` or a dedicated overlay container.
6
+ *
7
+ * Supports optional `prepend` behavior to insert at the top of the target.
8
+ *
9
+ * @example
10
+ * ```svelte
11
+ * <div use:portal>Portaled content</div>
12
+ * ```
13
+ *
14
+ * @example With options:
15
+ * ```svelte
16
+ * <div use:portal={{ target: document.getElementById('modal-root'), prepend: true }}>
17
+ * Portaled to #modal-root at the top
18
+ * </div>
19
+ * ```
20
+ *
21
+ * @param node - The HTML element to be portaled.
22
+ * @param options - Optional config:
23
+ * - `target`: The DOM node to portal into (defaults to `document.body`)
24
+ * - `prepend`: Whether to insert at the beginning instead of appending (default: true)
25
+ */
26
+ import { browser } from '$app/environment';
27
+ export function portal(node, { target = browser ? document.body : undefined, prepend = true } = {}) {
28
+ if (prepend) {
29
+ target?.prepend(node);
30
+ }
31
+ else {
32
+ target?.appendChild(node);
33
+ }
34
+ return {
35
+ destroy() {
36
+ if (target?.contains(node)) {
37
+ target?.removeChild(node);
38
+ }
39
+ }
40
+ };
41
+ }
@@ -106,7 +106,7 @@ The `<Overlay>` component is used to darken the background and optionally block
106
106
  <Overlay {transitionDuration} {disableBodyScroll} class={overlayClasses} onclick={() => open = false} />
107
107
 
108
108
  <div role="dialog" aria-modal="true" aria-label={ariaLabel} tabindex="{open ? 0 : -1}" aria-hidden="{!open}" use:stopInteraction={{ stop: true, prevent: true, events: [''] }}
109
- class={twMerge("fixed flex flex-col items-center gap-2 bg-white outline-0 focus:outline-0 active:outline-focus-primary focus:outline-focus-primary overflow-y-auto", postionClasses[position], props.class)}
109
+ class={twMerge("fixed flex flex-col items-center gap-2 bg-white outline-0 focus:outline-0 active:outline-focus-primary focus:outline-focus-primary overflow-y-auto z-50", postionClasses[position], props.class)}
110
110
  in:fly={transitionProperties}
111
111
  out:fly={transitionProperties}
112
112
  use:onKeydown={{key: "Escape", callback: handleKeydown}}>
@@ -34,12 +34,15 @@
34
34
  </script>
35
35
 
36
36
  {#if open}
37
- <Overlay transitionDuration={overlayTransitionDuration} {disableBodyScroll} class={overlayClasses} onclick={() => open = false} />
37
+ <Overlay transitionDuration={overlayTransitionDuration} {disableBodyScroll} class={overlayClasses} onclick={() => open = false}>
38
38
 
39
39
  <div role="dialog" aria-modal="true" aria-label={ariaLabel} tabindex="{open ? 0 : -1}" aria-hidden="{!open}"
40
- class={twMerge("fixed bg-white rounded top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 outline-0 focus:outline-0 active:outline-focus-primary focus:outline-focus-primary overflow-y-auto w-full max-w-md h-96", props.class)}
40
+ class={twMerge("fixed bg-white rounded top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 outline-0 focus:outline-0 active:outline-focus-primary focus:outline-focus-primary overflow-y-auto w-full max-w-md h-96 z-50", props.class)}
41
41
  use:onKeydown={{key: "Escape", callback: handleKeydown}}>
42
42
  {@render children?.()}
43
43
  </div>
44
+
45
+ </Overlay>
44
46
  {/if}
45
47
 
48
+
@@ -3,7 +3,7 @@
3
3
  import type { ClassNameValue } from 'tailwind-merge';
4
4
  import { fade } from 'svelte/transition';
5
5
  import {twMerge} from 'tailwind-merge';
6
- import { disableScroll } from '../../actions/disable-scroll.js';
6
+ import { disableScroll } from '../../actions/disable-scroll.js';
7
7
 
8
8
  export type OverlayProps = {
9
9
  disableBodyScroll?: boolean;
@@ -20,7 +20,7 @@
20
20
  let { disableBodyScroll=true, transitionDuration=100, ariaLabel="Overlay", onclick, children, ...props }: OverlayProps = $props();
21
21
  </script>
22
22
 
23
- <div transition:fade={{duration: transitionDuration}} class={twMerge("fixed top-0 left-0 right-0 bottom-0 bg-overlay-primary", props.class)} role="presentation" {onclick} use:disableScroll={disableBodyScroll}>
23
+ <div transition:fade={{duration: transitionDuration}} class={twMerge("fixed top-0 left-0 right-0 bottom-0 bg-overlay-primary z-40", props.class)} role="presentation" {onclick} use:disableScroll={disableBodyScroll}>
24
24
  {@render children?.()}
25
25
  </div>
26
26
 
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export * from './actions/on-keydown.js';
14
14
  export * from './actions/lock-scroll.js';
15
15
  export * from './actions/scroll-to.js';
16
16
  export * from './actions/stop-interaction.js';
17
+ export * from './actions/portal.js';
17
18
  export * from './modules/fetch-client.js';
18
19
  export * from './modules/api-proxy.js';
19
20
  export * from './modules/crypto.js';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export * from './actions/on-keydown.js';
16
16
  export * from './actions/lock-scroll.js';
17
17
  export * from './actions/scroll-to.js';
18
18
  export * from './actions/stop-interaction.js';
19
+ export * from './actions/portal.js';
19
20
  export * from './modules/fetch-client.js';
20
21
  export * from './modules/api-proxy.js';
21
22
  export * from './modules/crypto.js';
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/hashrytech/quick-components-kit.git"
7
7
  },
8
- "version": "0.16.0",
8
+ "version": "0.16.2",
9
9
  "license": "MIT",
10
10
  "author": "Hashry Tech",
11
11
  "files": [