@picked/svelte 0.0.1-dev.1770256874555 → 0.0.1-dev.1770787109735
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/dist/components/LazyImage.svelte +191 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/hooks/field.d.ts +5 -2
- package/dist/hooks/field.js +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/plugins/devtools/components/ExperienceInstanceListItem.svelte +2 -0
- package/dist/plugins/devtools/components/ExperienceInstancesTable.svelte +1 -0
- package/dist/plugins/devtools/plugin.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLImgAttributes } from 'svelte/elements'
|
|
3
|
+
import { onMount } from 'svelte'
|
|
4
|
+
|
|
5
|
+
type CommonProps = Omit<HTMLImgAttributes, 'src' | 'loading' | 'width' | 'height'> & {
|
|
6
|
+
src: string
|
|
7
|
+
loading?: 'eager' | 'lazy'
|
|
8
|
+
alt: string
|
|
9
|
+
sizes?: string
|
|
10
|
+
objectFit?: string
|
|
11
|
+
loader?: (params: { src: string; width: number }) => string | undefined
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type FillProps = {
|
|
15
|
+
fill: true
|
|
16
|
+
width?: never
|
|
17
|
+
height?: never
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type FixedSizeProps = {
|
|
21
|
+
fill?: false
|
|
22
|
+
width: number
|
|
23
|
+
height: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type Props = (CommonProps & FillProps) | (CommonProps & FixedSizeProps)
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
src,
|
|
30
|
+
width,
|
|
31
|
+
height,
|
|
32
|
+
loading = 'lazy',
|
|
33
|
+
alt,
|
|
34
|
+
sizes = '100vw',
|
|
35
|
+
objectFit = 'cover',
|
|
36
|
+
fill = false,
|
|
37
|
+
loader,
|
|
38
|
+
...restProps
|
|
39
|
+
}: Props = $props()
|
|
40
|
+
|
|
41
|
+
let imgElement = $state<HTMLImageElement | undefined>(undefined)
|
|
42
|
+
let placeholderElement = $state<HTMLDivElement | undefined>(undefined)
|
|
43
|
+
let isLoaded = $state(false)
|
|
44
|
+
let isInView = $state(false)
|
|
45
|
+
let observer: IntersectionObserver | undefined
|
|
46
|
+
|
|
47
|
+
const aspectRatio = $derived.by(() =>
|
|
48
|
+
!fill && typeof width === 'number' && typeof height === 'number' && height !== 0
|
|
49
|
+
? width / height
|
|
50
|
+
: undefined,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const SUPPORTED_SIZES = [
|
|
54
|
+
16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840,
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
function findClosestSize(targetSize: number): number {
|
|
58
|
+
const roundedTargetSize = Math.round(targetSize)
|
|
59
|
+
return SUPPORTED_SIZES.reduce(
|
|
60
|
+
(prev, curr) =>
|
|
61
|
+
Math.abs(curr - roundedTargetSize) < Math.abs(prev - roundedTargetSize) ? curr : prev,
|
|
62
|
+
SUPPORTED_SIZES[0],
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isConvincelyDomain(url: URL): boolean {
|
|
67
|
+
try {
|
|
68
|
+
return url.hostname.endsWith('.convincely.io')
|
|
69
|
+
} catch {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getOptimizedImageUrl(imageSrc: string, targetWidth: number): string {
|
|
75
|
+
try {
|
|
76
|
+
// If a custom loader is provided, use it first
|
|
77
|
+
if (loader) {
|
|
78
|
+
const result = loader({ src: imageSrc, width: targetWidth })
|
|
79
|
+
if (result !== undefined) {
|
|
80
|
+
return result
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const url = new URL(imageSrc, import.meta.url)
|
|
85
|
+
|
|
86
|
+
// Handle Convincely domain optimization through the image optimization service
|
|
87
|
+
if (isConvincelyDomain(url)) {
|
|
88
|
+
const encodedUrl = encodeURIComponent(url.toString())
|
|
89
|
+
const optimizedSize = findClosestSize(targetWidth)
|
|
90
|
+
return `https://img.convincely.io/_next/image?url=${encodedUrl}&w=${optimizedSize}&q=75`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// For other domains, return the original URL
|
|
94
|
+
return getImgUrl(imageSrc)
|
|
95
|
+
} catch {
|
|
96
|
+
// If URL parsing fails, fall back to original behavior
|
|
97
|
+
return getImgUrl(imageSrc)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getImgUrl(imageSrc: string): string {
|
|
102
|
+
// Skip base64 images
|
|
103
|
+
if (imageSrc.startsWith('data:')) {
|
|
104
|
+
return imageSrc
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const baseUrl = new URL(import.meta.url).origin
|
|
108
|
+
return imageSrc.startsWith('http') ? imageSrc : `${baseUrl}${imageSrc}`
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function handleLoad() {
|
|
112
|
+
isLoaded = true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
onMount(() => {
|
|
116
|
+
if (loading === 'lazy') {
|
|
117
|
+
const elementToObserve = placeholderElement || imgElement
|
|
118
|
+
if (elementToObserve) {
|
|
119
|
+
observer = new IntersectionObserver(
|
|
120
|
+
(entries) => {
|
|
121
|
+
entries.forEach((entry) => {
|
|
122
|
+
if (entry.isIntersecting) {
|
|
123
|
+
isInView = true
|
|
124
|
+
observer?.unobserve(entry.target)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
rootMargin: '50px',
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
observer.observe(elementToObserve)
|
|
134
|
+
|
|
135
|
+
return () => {
|
|
136
|
+
observer?.disconnect()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} else if (loading === 'eager') {
|
|
140
|
+
isInView = true
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
const shouldLoadImage = $derived(loading === 'eager' || isInView)
|
|
145
|
+
|
|
146
|
+
const widthCandidates = $derived.by(() => {
|
|
147
|
+
if (typeof width === 'number' && Number.isFinite(width)) {
|
|
148
|
+
const filtered = SUPPORTED_SIZES.filter((w) => w <= width)
|
|
149
|
+
return filtered.length ? filtered : [width]
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return SUPPORTED_SIZES
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
const srcSet = $derived.by(() =>
|
|
156
|
+
widthCandidates.map((w) => `${getOptimizedImageUrl(src, w)} ${w}w`).join(', '),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
const fallbackSrc = $derived.by(() => getOptimizedImageUrl(src, widthCandidates[0]))
|
|
160
|
+
</script>
|
|
161
|
+
|
|
162
|
+
{#if shouldLoadImage}
|
|
163
|
+
<img
|
|
164
|
+
{...restProps}
|
|
165
|
+
bind:this={imgElement}
|
|
166
|
+
src={fallbackSrc}
|
|
167
|
+
srcset={srcSet}
|
|
168
|
+
{sizes}
|
|
169
|
+
width={fill ? undefined : width}
|
|
170
|
+
height={fill ? undefined : height}
|
|
171
|
+
{alt}
|
|
172
|
+
style:aspect-ratio={aspectRatio}
|
|
173
|
+
style:object-fit={objectFit}
|
|
174
|
+
style:position={fill ? 'absolute' : undefined}
|
|
175
|
+
style:inset={fill ? 0 : undefined}
|
|
176
|
+
{loading}
|
|
177
|
+
onload={handleLoad}
|
|
178
|
+
class={restProps.class}
|
|
179
|
+
data-loaded={isLoaded}
|
|
180
|
+
data-testid="lazy-image-element"
|
|
181
|
+
/>
|
|
182
|
+
{:else}
|
|
183
|
+
<div
|
|
184
|
+
bind:this={placeholderElement}
|
|
185
|
+
style:aspect-ratio={aspectRatio}
|
|
186
|
+
style:position={fill ? 'absolute' : undefined}
|
|
187
|
+
style:inset={fill ? 0 : undefined}
|
|
188
|
+
aria-label={alt}
|
|
189
|
+
data-testid="lazy-image-placeholder"
|
|
190
|
+
></div>
|
|
191
|
+
{/if}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as LazyImage } from './LazyImage.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{default as f}from"./LazyImage.svelte";export{f as LazyImage};
|
package/dist/hooks/field.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { Field, FieldValue } from '@picked/client';
|
|
1
|
+
import { Field, FieldValue, FieldOptionArray, JsonValue } from '@picked/client';
|
|
2
2
|
import { Store } from 'effector';
|
|
3
3
|
export interface GetFieldResponse {
|
|
4
|
-
value: Store<FieldValue>;
|
|
5
4
|
field: Store<Field | null>;
|
|
5
|
+
value: Store<FieldValue>;
|
|
6
|
+
options: Store<FieldOptionArray<JsonValue> | null>;
|
|
7
|
+
isLoading: Store<boolean>;
|
|
8
|
+
error: Store<string | null>;
|
|
6
9
|
}
|
|
7
10
|
export declare function getField(id: string): GetFieldResponse;
|
package/dist/hooks/field.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getPicked as
|
|
1
|
+
import{getPicked as i}from"./client.js";function r(t){const o=i();o.fields.resolve(t);const s=o.fields.getByFieldId(t);return{field:o.fields.getById(t),value:o.responses.getByFieldId(t),options:s.map(e=>e.options),isLoading:s.map(e=>e.status==="loading"||e.status==="idle"),error:s.map(e=>e.error??null)}}export{r as getField};
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { getPicked, getExperience } from './client';
|
|
2
|
+
export { getField } from './field';
|
|
2
3
|
export { getPredicate, getPredicateResult } from './predicate';
|
|
3
4
|
export { getFeature, getFeatureResult } from './feature';
|
|
4
5
|
export { getAction, getActionResult } from './action';
|
package/dist/hooks/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getExperience as r,getPicked as o}from"./client.js";import{getPredicate as
|
|
1
|
+
import{getExperience as r,getPicked as o}from"./client.js";import{getField as p}from"./field.js";import{getPredicate as x,getPredicateResult as a}from"./predicate.js";import{getFeature as n,getFeatureResult as s}from"./feature.js";import{getAction as i,getActionResult as u}from"./action.js";import{getStep as d,setStepContext as l}from"./step.js";import{getContextScope as C,setContextScope as R,useUnit as y}from"./stores.js";import{createLocalStorageStore as k,createSessionStorageStore as q}from"./storage.js";import{getTrackRecommendationPresentEvent as E}from"./events.js";import{createQuery as v,queryCache as L,queryPresets as Q}from"./create-query/index.js";export{k as createLocalStorageStore,v as createQuery,q as createSessionStorageStore,i as getAction,u as getActionResult,C as getContextScope,r as getExperience,n as getFeature,s as getFeatureResult,p as getField,o as getPicked,x as getPredicate,a as getPredicateResult,d as getStep,E as getTrackRecommendationPresentEvent,L as queryCache,Q as queryPresets,R as setContextScope,l as setStepContext,y as useUnit};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{adaptSvelteComponent as
|
|
1
|
+
import{adaptSvelteComponent as o,isValidAdaptedComponent as t}from"./component.js";import{default as d}from"./components/LazyImage.svelte";export{d as LazyImage,o as adaptSvelteComponent,t as isValidAdaptedComponent};
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
const nextStepNodes = experienceInstance.nextReachableStepNodesStore
|
|
9
9
|
const stepsToOrigin = experienceInstance.stepsToOriginStore
|
|
10
10
|
const stepsToLeaf = experienceInstance.stepsToLeafStore
|
|
11
|
+
const isOpen = experienceInstance.isOpenStore
|
|
11
12
|
|
|
12
13
|
$: totalNextStepNodes = $nextStepNodes.length
|
|
13
14
|
</script>
|
|
14
15
|
|
|
15
16
|
<tr>
|
|
16
17
|
<td>{experienceInstance.experienceId}</td>
|
|
18
|
+
<td><button onclick={() => experienceInstance.toggleOpen()}>{$isOpen}</button></td>
|
|
17
19
|
<td>{$currentNode?.id || ''}</td>
|
|
18
20
|
<td>{$currentNode?.type || ''}</td>
|
|
19
21
|
<td>{$currentStep?.id || ''}</td>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{supportsDocument as c,isPickedRoot as
|
|
1
|
+
import{supportsDocument as c,isPickedRoot as a}from"@picked/client";import{createExperiencePlugin as g}from"@picked/client/plugins/create-experience";import{devtoolsExperience as r}from"./experience.js";const m=()=>[{name:"svelte-devtools",setup:t=>{if(!c())return;const s=t.experienceInstances.getByExperienceId(r.id),i=e=>{if(!(!e.target||!("tagName"in e.target)||typeof e.target.tagName!="string")&&e.key==="."&&!["INPUT","TEXTAREA"].includes(e.target.tagName)&&!(e.currentTarget instanceof HTMLElement&&a(e.currentTarget))&&!(e.target instanceof HTMLElement&&a(e.target))){const n=s.getState();n.length>0?n.forEach(o=>o.toggleOpen()):t.launchExperienceById(r.id)}};document.addEventListener("keydown",i),t.eventBus.watch(e=>{e.type==="ready"&&t.launchExperienceById(r.id)})}},g({experiences:[r]})];export{m as svelteDevtoolsPlugin};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@picked/svelte",
|
|
3
|
-
"version": "0.0.1-dev.
|
|
3
|
+
"version": "0.0.1-dev.1770787109735",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"d3": "^7.9.0"
|
|
6
6
|
},
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
],
|
|
76
76
|
"module": "./dist/index.js",
|
|
77
77
|
"peerDependencies": {
|
|
78
|
-
"@picked/client": "0.0.1-dev.
|
|
78
|
+
"@picked/client": "0.0.1-dev.1770787109735",
|
|
79
79
|
"effector": "^23.3.0",
|
|
80
80
|
"svelte": "^5.34.3"
|
|
81
81
|
},
|