@hkdigital/lib-sveltekit 0.0.92 → 0.0.94

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
@@ -66,7 +66,7 @@ Vite should include postcss-import, but the only solution to get it working for
66
66
  For example:
67
67
 
68
68
  ```css
69
- /* src/app.css */
69
+ /* src/app.postcss */
70
70
  @import '../node_modules/@hkdigital/lib-sveltekit/dist/css/utilities.postcss';
71
71
  ```
72
72
 
@@ -79,10 +79,7 @@ export default class ImageScene {
79
79
  });
80
80
 
81
81
  /**
82
- * Construct AudioScene
83
- *
84
- * @param {object} _
85
- * @param {AudioContext} _.audioContext
82
+ * Construct ImageScene
86
83
  */
87
84
  constructor() {
88
85
  const state = this.#state;
@@ -113,6 +113,11 @@
113
113
  ...attrs
114
114
  } = $props();
115
115
 
116
+ if( !imageMeta )
117
+ {
118
+ throw new Error('Missing [imageMeta]');
119
+ }
120
+
116
121
  // let show = $state(false);
117
122
 
118
123
  /** @type {HTMLDivElement|undefined} */
@@ -1,5 +1,5 @@
1
1
  <script>
2
- /** @typedef {import('../../types/imagetools.js').ImageMeta} ImageMeta */
2
+ /** @typedef {import('../../config/typedef.js').ImageMeta} ImageMeta */
3
3
 
4
4
  import { ImageVariantsLoader } from '../../classes/svelte/image/index.js';
5
5
 
@@ -1,5 +1,5 @@
1
1
  export default ResponsiveImage;
2
- export type ImageMeta = any;
2
+ export type ImageMeta = import("../../config/typedef.js").ImageMeta;
3
3
  declare const ResponsiveImage: import("svelte").Component<{
4
4
  base?: string;
5
5
  classes?: string;
@@ -1,4 +1,5 @@
1
+ export { default as ImageBox } from "./ImageBox.svelte";
1
2
  export { default as ResponsiveImage } from "./ResponsiveImage.svelte";
2
3
  declare const _default: {};
3
4
  export default _default;
4
- export type ImageMeta = any;
5
+ export type ImageMeta = import("../../config/typedef.js").ImageMeta;
@@ -1,5 +1,6 @@
1
- /** @typedef {import('../../types/imagetools.js').ImageMeta} ImageMeta */
1
+ /** @typedef {import('../../config/typedef.js').ImageMeta} ImageMeta */
2
2
 
3
+ export { default as ImageBox } from './ImageBox.svelte';
3
4
  export { default as ResponsiveImage } from './ResponsiveImage.svelte';
4
5
 
5
6
  export default {};
@@ -0,0 +1,175 @@
1
+ <!-- CompareLeftRight.svelte -->
2
+ <script>
3
+ /** @type {HTMLElement | null} */
4
+ let container = $state(null);
5
+ let isMouseDown = $state(false);
6
+ let position = $state(50);
7
+
8
+ /** @type {{
9
+ leftContent?: import('svelte').Snippet,
10
+ rightContent?: import('svelte').Snippet,
11
+ classes?: string,
12
+ dividerColor?: string,
13
+ handleColor?: string
14
+ } & Record<string, any>} */
15
+ let {
16
+ leftContent,
17
+ rightContent,
18
+ classes = '',
19
+ dividerColor = 'bg-surface-500',
20
+ handleColor = 'bg-surface-700',
21
+ ...attrs
22
+ } = $props();
23
+
24
+ const leftStyle = $derived(`clip-path: inset(0 ${100 - position}% 0 0)`);
25
+ const rightStyle = $derived(`clip-path: inset(0 0 0 ${position}%)`);
26
+ const dividerStyle = $derived(`left: ${position}%`);
27
+
28
+ /**
29
+ * Updates the position with keyboard navigation
30
+ * @param {number} newPosition - The new position to set
31
+ */
32
+ function updatePosition(newPosition) {
33
+ position = Math.max(0, Math.min(100, newPosition));
34
+ }
35
+
36
+ /**
37
+ * Handles the mouse down event on the divider
38
+ * @param {MouseEvent} event - The mouse event
39
+ */
40
+ function handleMouseDown(event) {
41
+ event.preventDefault();
42
+ isMouseDown = true;
43
+ }
44
+
45
+ /**
46
+ * Updates the divider position based on mouse movement
47
+ * @param {MouseEvent} event - The mouse event
48
+ */
49
+ function handleMouseMove(event) {
50
+ if (!isMouseDown || !container) return;
51
+
52
+ const rect = container.getBoundingClientRect();
53
+ const x = Math.min(Math.max(0, event.clientX - rect.left), rect.width);
54
+ updatePosition((x / rect.width) * 100);
55
+ }
56
+
57
+ /**
58
+ * Handles keyboard navigation for the slider
59
+ * @param {KeyboardEvent} event - The keyboard event
60
+ */
61
+ function handleKeyDown(event) {
62
+ const step = event.shiftKey ? 10 : 1;
63
+
64
+ switch (event.key) {
65
+ case 'ArrowLeft':
66
+ case 'ArrowDown':
67
+ event.preventDefault();
68
+ updatePosition(position - step);
69
+ break;
70
+ case 'ArrowRight':
71
+ case 'ArrowUp':
72
+ event.preventDefault();
73
+ updatePosition(position + step);
74
+ break;
75
+ case 'Home':
76
+ event.preventDefault();
77
+ updatePosition(0);
78
+ break;
79
+ case 'End':
80
+ event.preventDefault();
81
+ updatePosition(100);
82
+ break;
83
+ case 'PageDown':
84
+ event.preventDefault();
85
+ updatePosition(position - 10);
86
+ break;
87
+ case 'PageUp':
88
+ event.preventDefault();
89
+ updatePosition(position + 10);
90
+ break;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Resets the mouse down state
96
+ */
97
+ function handleMouseUp() {
98
+ isMouseDown = false;
99
+ }
100
+
101
+ // Effect to handle document-level mouse events
102
+ $effect(() => {
103
+ if (isMouseDown) {
104
+ document.addEventListener('mousemove', handleMouseMove);
105
+ document.addEventListener('mouseup', handleMouseUp);
106
+ }
107
+
108
+ return () => {
109
+ document.removeEventListener('mousemove', handleMouseMove);
110
+ document.removeEventListener('mouseup', handleMouseUp);
111
+ };
112
+ });
113
+ </script>
114
+
115
+ <div
116
+ bind:this={container}
117
+ class="relative flex h-full w-full overflow-hidden {classes}"
118
+ role="group"
119
+ aria-label="Content comparison"
120
+ {...attrs}
121
+ >
122
+ <!-- Content container - both pieces of content are positioned absolutely -->
123
+ <div class="relative h-full w-full">
124
+ <!-- Left content -->
125
+ <div
126
+ class="absolute h-full w-full"
127
+ style={leftStyle}
128
+ >
129
+ {@render leftContent()}
130
+ </div>
131
+
132
+ <!-- Right content -->
133
+ <div
134
+ class="absolute h-full w-full"
135
+ style={rightStyle}
136
+ >
137
+ {@render rightContent()}
138
+ </div>
139
+ </div>
140
+
141
+ <!-- Slider control -->
142
+ <div
143
+ class="absolute inset-y-0 z-10 flex w-1 cursor-col-resize items-center justify-center {dividerColor}"
144
+ style={dividerStyle}
145
+ >
146
+ <!-- Vertical separator line -->
147
+ <div class="absolute inset-y-0 w-0.5 bg-current opacity-50"></div>
148
+
149
+ <button
150
+ class="flex h-10 w-10 items-center justify-center rounded-full shadow-lg hover:scale-110 transition-transform focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 {handleColor}"
151
+ on:mousedown={handleMouseDown}
152
+ on:keydown={handleKeyDown}
153
+ role="slider"
154
+ aria-orientation="vertical"
155
+ aria-valuenow={position}
156
+ aria-valuemin={0}
157
+ aria-valuemax={100}
158
+ aria-label="Adjust divider position"
159
+ >
160
+ <svg
161
+ class="h-6 w-6 stroke-surface-50"
162
+ viewBox="0 0 24 24"
163
+ fill="none"
164
+ stroke="currentColor"
165
+ stroke-width="2"
166
+ stroke-linecap="round"
167
+ stroke-linejoin="round"
168
+ >
169
+ <path d="M7 16l-4-4 4-4" />
170
+ <path d="M17 8l4 4-4 4" />
171
+ <path d="M3 12h18" />
172
+ </svg>
173
+ </button>
174
+ </div>
175
+ </div>
@@ -0,0 +1,8 @@
1
+ export default CompareLeftRight;
2
+ declare const CompareLeftRight: import("svelte").Component<{
3
+ leftContent?: import("svelte").Snippet;
4
+ rightContent?: import("svelte").Snippet;
5
+ classes?: string;
6
+ dividerColor?: string;
7
+ handleColor?: string;
8
+ } & Record<string, any>, {}, "">;
@@ -0,0 +1 @@
1
+ export { default as CompareLeftRight } from "./CompareLeftRight.svelte";
@@ -0,0 +1 @@
1
+ export { default as CompareLeftRight } from "./CompareLeftRight.svelte";
@@ -1,9 +1,3 @@
1
- // export interface ImageMeta {
2
- // src: string;
3
- // width: number;
4
- // height: number;
5
- // }
6
-
7
1
  type ImageMeta = import('./typedef.js').ImageMeta;
8
2
 
9
3
  declare module '*?responsive' {
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-sveltekit",
3
- "version": "0.0.92",
4
- "author": "Jens Kleinhout, HKdigital (https://hkdigital.nl)",
3
+ "version": "0.0.94",
4
+ "author": {
5
+ "name": "HKdigital",
6
+ "url": "https://hkdigital.nl"
7
+ },
5
8
  "license": "ISC",
6
9
  "repository": {
7
10
  "type": "git",
@@ -45,14 +48,23 @@
45
48
  "types": "./dist/index.d.ts",
46
49
  "type": "module",
47
50
  "exports": {
51
+ ".": {
52
+ "types": "./dist/index.d.ts",
53
+ "svelte": "./dist/index.js",
54
+ "default": "./dist/index.js"
55
+ },
48
56
  "./*": "./dist/*"
49
57
  },
50
58
  "peerDependencies": {
51
59
  "@sveltejs/kit": "^2.15.2",
52
- "svelte": "^5.0.0"
60
+ "svelte": "^5.0.0",
61
+ "runed": "^0.23.0",
62
+ "valibot": "^0.42.1"
53
63
  },
54
64
  "devDependencies": {
55
65
  "@playwright/test": "^1.49.1",
66
+ "@skeletonlabs/skeleton": "3.0.0-next.2",
67
+ "@skeletonlabs/skeleton-svelte": "1.0.0-next.4",
56
68
  "@sveltejs/adapter-auto": "^3.3.1",
57
69
  "@sveltejs/package": "^2.3.7",
58
70
  "@sveltejs/vite-plugin-svelte": "^5.0.3",
@@ -64,6 +76,8 @@
64
76
  "eslint-plugin-svelte": "^2.46.1",
65
77
  "globals": "^15.14.0",
66
78
  "jsdom": "^26.0.0",
79
+ "postcss": "^8.5.1",
80
+ "postcss-mixins": "^11.0.3",
67
81
  "prettier": "^3.4.2",
68
82
  "prettier-plugin-svelte": "^3.3.3",
69
83
  "prettier-plugin-tailwindcss": "^0.6.9",
@@ -78,8 +92,6 @@
78
92
  "vitest": "^2.1.8"
79
93
  },
80
94
  "dependencies": {
81
- "runed": "^0.23.0",
82
- "valibot": "^0.42.1",
83
95
  "zod": "^3.24.1"
84
96
  }
85
97
  }
@@ -1,162 +0,0 @@
1
- <script>
2
- import { onMount } from 'svelte';
3
-
4
- /**
5
- * @example
6
- * import { EnhancedImage }
7
- * from '$lib/components/EnhancedImage/index.js';
8
- *
9
- * <EnhancedImage
10
- * classes="aspect-video max-h-svh w-full border-8 border-pink-500"
11
- * src={NeonLightsOff}
12
- * onload={() => {
13
- * console.log('loaded');
14
- * }}
15
- * />
16
- */
17
-
18
- /**
19
- * @type {{
20
- * base?: string,
21
- * bg?: string,
22
- * classes?: string,
23
- * overflow?: string,
24
- * aspect?: string,
25
- * fit?: string,
26
- * position?: string,
27
- * src: string | import('$lib/typedef/image.js').Picture,
28
- * alt?: string,
29
- * onload?: ( e: (Event|{ type: string, target: HTMLImageElement }) ) => void,
30
- * onerror?: ( e: (Event|{ type: string, target: HTMLImageElement }) ) => void,
31
- * loading?: string
32
- * } & { [attr: string]: * }}
33
- */
34
- let {
35
- // Style
36
- base,
37
- bg,
38
- classes,
39
-
40
- overflow = 'overflow-clip',
41
- aspect,
42
-
43
- fit = 'contain',
44
- position = 'left top',
45
-
46
- src,
47
- alt = '',
48
- onload,
49
- onerror,
50
- loading,
51
-
52
- // Attributes
53
- ...attrs
54
- } = $props();
55
-
56
- // let show = $state(false);
57
-
58
- /** @type {HTMLDivElement|undefined} */
59
- let imgBoxElem = $state();
60
-
61
- /** @type {HTMLImageElement|undefined} */
62
- let imgElem = $state();
63
-
64
- /** @type {string | import('$lib/typedef/image.js').Picture} */
65
- let src_;
66
-
67
- $effect(() => {
68
- if (src_ && src !== src_) {
69
- throw new Error('Property [src] change is not supported');
70
- }
71
- });
72
-
73
- let aspectStyle = $state('');
74
-
75
- // > Event names
76
- const LOAD = 'load';
77
- const ERROR = 'error';
78
-
79
- // > onMount
80
-
81
- onMount(() => {
82
- // show = true;
83
-
84
- imgElem = imgBoxElem?.getElementsByTagName('img')[0];
85
-
86
- if (!imgElem) {
87
- throw new Error('Missing IMG element');
88
- }
89
-
90
- // > Auto set box aspect to same as image aspect if not set
91
-
92
- if (!aspect) {
93
- aspectStyle = `${imgElem.width / imgElem.height}`;
94
- } else {
95
- aspectStyle = '';
96
- }
97
-
98
- // > Register image onload and onerror handlers
99
-
100
- /** @type {( e: Event ) => void} */
101
- let onloadFn;
102
-
103
- if (onload) {
104
- if (imgElem?.complete) {
105
- onload({ type: LOAD, target: imgElem });
106
- } else {
107
- onloadFn = onload;
108
- imgElem?.addEventListener(LOAD, onloadFn);
109
- }
110
- }
111
-
112
- /** @type {( e: Event ) => void} */
113
- let onerrorFn;
114
-
115
- if (onerror) {
116
- onerrorFn = onerror;
117
- imgElem?.addEventListener(ERROR, onerrorFn);
118
- }
119
-
120
- return () => {
121
- if (onloadFn) {
122
- imgElem?.removeEventListener(LOAD, onloadFn);
123
- }
124
-
125
- if (onerrorFn) {
126
- imgElem?.removeEventListener(ERROR, onerrorFn);
127
- }
128
- };
129
- });
130
- </script>
131
-
132
- <div
133
- data-hk-enhanced-image
134
- bind:this={imgBoxElem}
135
- class="{base} {bg} {aspect} {overflow} {classes}"
136
- style:--fit={fit}
137
- style:--pos={position}
138
- style:aspect-ratio={aspectStyle}
139
- {...attrs}
140
- >
141
- <enhanced:img {src} {alt} />
142
- </div>
143
-
144
- <style>
145
- [data-hk-enhanced-image],
146
- :global([data-hk-enhanced-image] picture),
147
- :global([data-hk-enhanced-image] img) {
148
- display: block;
149
- width: 100%;
150
- height: 100%;
151
- }
152
- :global([data-hk-enhanced-image] picture),
153
- :global([data-hk-enhanced-image] img) {
154
- max-width: 100%;
155
- max-height: 100%;
156
- }
157
-
158
- :global([data-hk-enhanced-image] img) {
159
- object-fit: var(--fit);
160
- object-position: var(--pos);
161
- }
162
- </style>