@lumen-design/affix 0.0.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.
@@ -0,0 +1,97 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+ import type { AffixPosition } from './types'
4
+ import { onMount, onDestroy } from 'svelte'
5
+
6
+ interface AffixProps {
7
+ offset?: number
8
+ position?: AffixPosition
9
+ target?: string
10
+ zIndex?: number
11
+ onchange?: (fixed: boolean) => void
12
+ children?: Snippet
13
+ class?: string
14
+ }
15
+
16
+ let { offset = 0, position = 'top', target, zIndex = 100, onchange, children, class: cls = '', ...attrs }: AffixProps = $props()
17
+
18
+ let fixed = $state(false)
19
+ let affixRef: HTMLDivElement | null = $state(null)
20
+ let placeholderRef: HTMLDivElement | null = $state(null)
21
+ let container: HTMLElement | Window = $state(window)
22
+ let width = $state(0)
23
+ let height = $state(0)
24
+ let fixedTop = $state<number | undefined>(undefined)
25
+ let fixedBottom = $state<number | undefined>(undefined)
26
+
27
+ const updateFixed = (): void => {
28
+ if (!affixRef) return
29
+
30
+ const rect = (placeholderRef || affixRef).getBoundingClientRect()
31
+ const containerRect = container === window ? { top: 0, bottom: window.innerHeight } : (container as HTMLElement).getBoundingClientRect()
32
+
33
+ let shouldFix = false
34
+
35
+ if (position === 'top') {
36
+ shouldFix = rect.top - containerRect.top < offset
37
+ if (shouldFix) {
38
+ fixedTop = containerRect.top + offset
39
+ fixedBottom = undefined
40
+ }
41
+ } else {
42
+ shouldFix = containerRect.bottom - rect.bottom < offset
43
+ if (shouldFix) {
44
+ fixedBottom = window.innerHeight - containerRect.bottom + offset
45
+ fixedTop = undefined
46
+ }
47
+ }
48
+
49
+ if (shouldFix !== fixed) {
50
+ fixed = shouldFix
51
+ onchange?.(fixed)
52
+ }
53
+
54
+ if (fixed) {
55
+ width = rect.width
56
+ height = rect.height
57
+ }
58
+ }
59
+
60
+ onMount(() => {
61
+ if (target) {
62
+ const el = document.querySelector(target)
63
+ if (el) container = el as HTMLElement
64
+ }
65
+
66
+ const scrollEl = container === window ? window : container
67
+ scrollEl.addEventListener('scroll', updateFixed, { passive: true })
68
+ window.addEventListener('resize', updateFixed, { passive: true })
69
+ updateFixed()
70
+ })
71
+
72
+ onDestroy(() => {
73
+ const scrollEl = container === window ? window : container
74
+ scrollEl.removeEventListener('scroll', updateFixed)
75
+ window.removeEventListener('resize', updateFixed)
76
+ })
77
+
78
+ const classes = $derived(`lm-affix${fixed ? ' is-fixed' : ''}${cls ? ` ${cls}` : ''}`)
79
+
80
+ const affixStyle = $derived.by(() => {
81
+ if (!fixed) return undefined
82
+ const styles: string[] = [`z-index: ${zIndex}`, `width: ${width}px`]
83
+ if (fixedTop !== undefined) styles.push(`top: ${fixedTop}px`)
84
+ if (fixedBottom !== undefined) styles.push(`bottom: ${fixedBottom}px`)
85
+ return styles.join('; ')
86
+ })
87
+
88
+ const placeholderStyle = $derived(fixed ? `width: ${width}px; height: ${height}px` : undefined)
89
+ </script>
90
+
91
+ <div bind:this={placeholderRef} style={placeholderStyle}>
92
+ <div bind:this={affixRef} class={classes} style={affixStyle} {...attrs}>
93
+ {#if children}
94
+ {@render children()}
95
+ {/if}
96
+ </div>
97
+ </div>
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import Affix from './Affix.svelte';
2
+ export { Affix };
3
+ export default Affix;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@lumen-design/affix",
3
+ "version": "0.0.2",
4
+ "description": "Affix component for Lumen UI",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "svelte": "./dist/index.js",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "svelte-package -i src -o dist --types",
21
+ "build:watch": "svelte-package -i src -o dist --types -w"
22
+ },
23
+ "devDependencies": {
24
+ "@sveltejs/package": "^2.5.7",
25
+ "svelte": "5.48.2"
26
+ },
27
+ "peerDependencies": {
28
+ "svelte": "^5.0.0"
29
+ }
30
+ }