@aspect-ops/exon-ui 0.0.1 → 0.0.3
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 +438 -0
- package/dist/components/ActionSheet/ActionSheet.svelte +270 -0
- package/dist/components/ActionSheet/ActionSheet.svelte.d.ts +12 -0
- package/dist/components/ActionSheet/ActionSheetItem.svelte +151 -0
- package/dist/components/ActionSheet/ActionSheetItem.svelte.d.ts +10 -0
- package/dist/components/ActionSheet/index.d.ts +3 -0
- package/dist/components/ActionSheet/index.js +2 -0
- package/dist/components/Alert/Alert.svelte +165 -0
- package/dist/components/Alert/Alert.svelte.d.ts +11 -0
- package/dist/components/Alert/index.d.ts +1 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/AspectRatio/AspectRatio.svelte +42 -0
- package/dist/components/AspectRatio/AspectRatio.svelte.d.ts +9 -0
- package/dist/components/AspectRatio/index.d.ts +1 -0
- package/dist/components/AspectRatio/index.js +1 -0
- package/dist/components/Avatar/Avatar.svelte +147 -0
- package/dist/components/Avatar/Avatar.svelte.d.ts +12 -0
- package/dist/components/Avatar/AvatarGroup.svelte +153 -0
- package/dist/components/Avatar/AvatarGroup.svelte.d.ts +12 -0
- package/dist/components/Avatar/index.d.ts +2 -0
- package/dist/components/Avatar/index.js +2 -0
- package/dist/components/BottomSheet/BottomSheet.svelte +230 -0
- package/dist/components/BottomSheet/BottomSheet.svelte.d.ts +7 -0
- package/dist/components/BottomSheet/BottomSheetBody.svelte +20 -0
- package/dist/components/BottomSheet/BottomSheetBody.svelte.d.ts +7 -0
- package/dist/components/BottomSheet/BottomSheetHeader.svelte +27 -0
- package/dist/components/BottomSheet/BottomSheetHeader.svelte.d.ts +7 -0
- package/dist/components/BottomSheet/index.d.ts +3 -0
- package/dist/components/BottomSheet/index.js +3 -0
- package/dist/components/Box/Box.svelte +41 -0
- package/dist/components/Box/Box.svelte.d.ts +7 -0
- package/dist/components/Box/index.d.ts +1 -0
- package/dist/components/Box/index.js +1 -0
- package/dist/components/Card/Card.svelte +95 -0
- package/dist/components/Card/Card.svelte.d.ts +10 -0
- package/dist/components/Card/CardBody.svelte +32 -0
- package/dist/components/Card/CardBody.svelte.d.ts +7 -0
- package/dist/components/Card/CardFooter.svelte +34 -0
- package/dist/components/Card/CardFooter.svelte.d.ts +7 -0
- package/dist/components/Card/CardHeader.svelte +67 -0
- package/dist/components/Card/CardHeader.svelte.d.ts +9 -0
- package/dist/components/Card/index.d.ts +4 -0
- package/dist/components/Card/index.js +4 -0
- package/dist/components/Center/Center.svelte +28 -0
- package/dist/components/Center/Center.svelte.d.ts +8 -0
- package/dist/components/Center/index.d.ts +1 -0
- package/dist/components/Center/index.js +1 -0
- package/dist/components/Container/Container.svelte +58 -0
- package/dist/components/Container/Container.svelte.d.ts +10 -0
- package/dist/components/Container/index.d.ts +1 -0
- package/dist/components/Container/index.js +1 -0
- package/dist/components/Divider/Divider.svelte +38 -0
- package/dist/components/Divider/Divider.svelte.d.ts +9 -0
- package/dist/components/Divider/index.d.ts +1 -0
- package/dist/components/Divider/index.js +1 -0
- package/dist/components/EmptyState/EmptyState.svelte +164 -0
- package/dist/components/EmptyState/EmptyState.svelte.d.ts +12 -0
- package/dist/components/EmptyState/index.d.ts +1 -0
- package/dist/components/EmptyState/index.js +1 -0
- package/dist/components/FAB/FAB.svelte +242 -0
- package/dist/components/FAB/FAB.svelte.d.ts +9 -0
- package/dist/components/FAB/FABGroup.svelte +449 -0
- package/dist/components/FAB/FABGroup.svelte.d.ts +9 -0
- package/dist/components/FAB/index.d.ts +3 -0
- package/dist/components/FAB/index.js +2 -0
- package/dist/components/Grid/Grid.svelte +136 -0
- package/dist/components/Grid/Grid.svelte.d.ts +12 -0
- package/dist/components/Grid/GridItem.svelte +21 -0
- package/dist/components/Grid/GridItem.svelte.d.ts +7 -0
- package/dist/components/Grid/index.d.ts +2 -0
- package/dist/components/Grid/index.js +2 -0
- package/dist/components/List/List.svelte +42 -0
- package/dist/components/List/List.svelte.d.ts +18 -0
- package/dist/components/List/ListItem.svelte +139 -0
- package/dist/components/List/ListItem.svelte.d.ts +36 -0
- package/dist/components/List/index.d.ts +2 -0
- package/dist/components/List/index.js +2 -0
- package/dist/components/Modal/Modal.svelte +204 -0
- package/dist/components/Modal/Modal.svelte.d.ts +7 -0
- package/dist/components/Modal/ModalBody.svelte +50 -0
- package/dist/components/Modal/ModalBody.svelte.d.ts +7 -0
- package/dist/components/Modal/ModalFooter.svelte +37 -0
- package/dist/components/Modal/ModalFooter.svelte.d.ts +7 -0
- package/dist/components/Modal/ModalHeader.svelte +73 -0
- package/dist/components/Modal/ModalHeader.svelte.d.ts +7 -0
- package/dist/components/Modal/index.d.ts +4 -0
- package/dist/components/Modal/index.js +4 -0
- package/dist/components/Popover/Popover.svelte +14 -0
- package/dist/components/Popover/Popover.svelte.d.ts +7 -0
- package/dist/components/Popover/PopoverContent.svelte +63 -0
- package/dist/components/Popover/PopoverContent.svelte.d.ts +7 -0
- package/dist/components/Popover/PopoverTrigger.svelte +14 -0
- package/dist/components/Popover/PopoverTrigger.svelte.d.ts +7 -0
- package/dist/components/Popover/index.d.ts +3 -0
- package/dist/components/Popover/index.js +3 -0
- package/dist/components/Progress/ProgressBar.svelte +86 -0
- package/dist/components/Progress/ProgressBar.svelte.d.ts +11 -0
- package/dist/components/Progress/ProgressCircle.svelte +134 -0
- package/dist/components/Progress/ProgressCircle.svelte.d.ts +12 -0
- package/dist/components/Progress/Spinner.svelte +68 -0
- package/dist/components/Progress/Spinner.svelte.d.ts +8 -0
- package/dist/components/Progress/index.d.ts +3 -0
- package/dist/components/Progress/index.js +3 -0
- package/dist/components/PullToRefresh/PullToRefresh.svelte +304 -0
- package/dist/components/PullToRefresh/PullToRefresh.svelte.d.ts +20 -0
- package/dist/components/PullToRefresh/index.d.ts +1 -0
- package/dist/components/PullToRefresh/index.js +1 -0
- package/dist/components/SafeArea/SafeArea.svelte +33 -0
- package/dist/components/SafeArea/SafeArea.svelte.d.ts +7 -0
- package/dist/components/Select/Select.svelte +55 -12
- package/dist/components/Skeleton/Skeleton.svelte +59 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +10 -0
- package/dist/components/Skeleton/index.d.ts +1 -0
- package/dist/components/Skeleton/index.js +1 -0
- package/dist/components/Spacer/Spacer.svelte +56 -0
- package/dist/components/Spacer/Spacer.svelte.d.ts +6 -0
- package/dist/components/Spacer/index.d.ts +1 -0
- package/dist/components/Spacer/index.js +1 -0
- package/dist/components/Stack/Stack.svelte +117 -0
- package/dist/components/Stack/Stack.svelte.d.ts +13 -0
- package/dist/components/Stack/index.d.ts +1 -0
- package/dist/components/Stack/index.js +1 -0
- package/dist/components/SwipeActions/SwipeAction.svelte +43 -0
- package/dist/components/SwipeActions/SwipeAction.svelte.d.ts +8 -0
- package/dist/components/SwipeActions/SwipeActions.svelte +193 -0
- package/dist/components/SwipeActions/SwipeActions.svelte.d.ts +9 -0
- package/dist/components/SwipeActions/index.d.ts +2 -0
- package/dist/components/SwipeActions/index.js +2 -0
- package/dist/components/Switch/Switch.svelte +29 -9
- package/dist/components/Table/Table.svelte +175 -0
- package/dist/components/Table/Table.svelte.d.ts +38 -0
- package/dist/components/Table/TableBody.svelte +26 -0
- package/dist/components/Table/TableBody.svelte.d.ts +13 -0
- package/dist/components/Table/TableCell.svelte +85 -0
- package/dist/components/Table/TableCell.svelte.d.ts +28 -0
- package/dist/components/Table/TableHead.svelte +36 -0
- package/dist/components/Table/TableHead.svelte.d.ts +13 -0
- package/dist/components/Table/TableHeader.svelte +217 -0
- package/dist/components/Table/TableHeader.svelte.d.ts +32 -0
- package/dist/components/Table/TableRow.svelte +92 -0
- package/dist/components/Table/TableRow.svelte.d.ts +28 -0
- package/dist/components/Table/index.d.ts +6 -0
- package/dist/components/Table/index.js +6 -0
- package/dist/components/Tag/Tag.svelte +189 -0
- package/dist/components/Tag/Tag.svelte.d.ts +13 -0
- package/dist/components/Tag/index.d.ts +1 -0
- package/dist/components/Tag/index.js +1 -0
- package/dist/components/Toast/Toast.svelte +241 -0
- package/dist/components/Toast/Toast.svelte.d.ts +18 -0
- package/dist/components/Toast/ToastContainer.svelte +110 -0
- package/dist/components/Toast/ToastContainer.svelte.d.ts +8 -0
- package/dist/components/Toast/index.d.ts +3 -0
- package/dist/components/Toast/index.js +3 -0
- package/dist/components/Toast/toast.d.ts +13 -0
- package/dist/components/Toast/toast.js +55 -0
- package/dist/components/Tooltip/Tooltip.svelte +71 -0
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +7 -0
- package/dist/components/Tooltip/index.d.ts +2 -0
- package/dist/components/Tooltip/index.js +1 -0
- package/dist/index.d.ts +29 -1
- package/dist/index.js +32 -0
- package/dist/styles/tokens.css +5 -0
- package/dist/types/data-display.d.ts +93 -0
- package/dist/types/data-display.js +1 -0
- package/dist/types/feedback.d.ts +92 -0
- package/dist/types/feedback.js +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/layout.d.ts +57 -0
- package/dist/types/layout.js +1 -0
- package/dist/types/mobile.d.ts +91 -0
- package/dist/types/mobile.js +1 -0
- package/dist/utils/gestures.d.ts +219 -0
- package/dist/utils/gestures.js +492 -0
- package/dist/utils/haptics.d.ts +89 -0
- package/dist/utils/haptics.js +198 -0
- package/dist/utils/platform.d.ts +47 -0
- package/dist/utils/platform.js +156 -0
- package/package.json +1 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { PullToRefreshProps } from '../../types/index.js';
|
|
3
|
+
import { hapticImpact } from '../../utils/haptics.js';
|
|
4
|
+
|
|
5
|
+
interface Props extends PullToRefreshProps {
|
|
6
|
+
/** Controlled loading state (bindable) */
|
|
7
|
+
refreshing?: boolean;
|
|
8
|
+
/** Pull distance in pixels to trigger refresh (default: 80) */
|
|
9
|
+
threshold?: number;
|
|
10
|
+
/** Maximum pull distance in pixels (default: 150) */
|
|
11
|
+
maxPull?: number;
|
|
12
|
+
/** Disable pull-to-refresh functionality */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Additional CSS class */
|
|
15
|
+
class?: string;
|
|
16
|
+
/** Called when threshold reached and released */
|
|
17
|
+
onrefresh?: () => void;
|
|
18
|
+
/** Content to render inside */
|
|
19
|
+
children?: import('svelte').Snippet;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
refreshing = $bindable(false),
|
|
24
|
+
threshold = 80,
|
|
25
|
+
maxPull = 150,
|
|
26
|
+
disabled = false,
|
|
27
|
+
class: className = '',
|
|
28
|
+
onrefresh,
|
|
29
|
+
children
|
|
30
|
+
}: Props = $props();
|
|
31
|
+
|
|
32
|
+
// Touch tracking state
|
|
33
|
+
let pullDistance = $state(0);
|
|
34
|
+
let isPulling = $state(false);
|
|
35
|
+
let startY = $state(0);
|
|
36
|
+
let currentY = $state(0);
|
|
37
|
+
let containerEl: HTMLDivElement | undefined = $state();
|
|
38
|
+
let contentEl: HTMLDivElement | undefined = $state();
|
|
39
|
+
|
|
40
|
+
// Calculated values
|
|
41
|
+
const progress = $derived(Math.min(pullDistance / threshold, 1));
|
|
42
|
+
const indicatorRotation = $derived(progress * 360);
|
|
43
|
+
const indicatorY = $derived(Math.min(pullDistance, maxPull) - 40);
|
|
44
|
+
const indicatorOpacity = $derived(Math.min(progress, 1));
|
|
45
|
+
const isThresholdReached = $derived(pullDistance >= threshold);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if content is scrolled to the top
|
|
49
|
+
*/
|
|
50
|
+
function isAtScrollTop(): boolean {
|
|
51
|
+
if (!contentEl) return true;
|
|
52
|
+
return contentEl.scrollTop <= 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Apply resistance to pull distance for natural feel
|
|
57
|
+
*/
|
|
58
|
+
function applyResistance(distance: number): number {
|
|
59
|
+
if (distance <= 0) return 0;
|
|
60
|
+
// Diminishing returns after threshold
|
|
61
|
+
const resistance = distance > threshold ? 0.4 : 0.6;
|
|
62
|
+
return Math.min(distance * resistance, maxPull);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Handle touch start
|
|
67
|
+
*/
|
|
68
|
+
function handleTouchStart(e: TouchEvent) {
|
|
69
|
+
if (disabled || refreshing) return;
|
|
70
|
+
if (!isAtScrollTop()) return;
|
|
71
|
+
if (e.touches.length !== 1) return;
|
|
72
|
+
|
|
73
|
+
startY = e.touches[0].clientY;
|
|
74
|
+
currentY = startY;
|
|
75
|
+
isPulling = false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handle touch move
|
|
80
|
+
*/
|
|
81
|
+
function handleTouchMove(e: TouchEvent) {
|
|
82
|
+
if (disabled || refreshing) return;
|
|
83
|
+
if (e.touches.length !== 1) return;
|
|
84
|
+
|
|
85
|
+
const touchY = e.touches[0].clientY;
|
|
86
|
+
const rawDistance = touchY - startY;
|
|
87
|
+
|
|
88
|
+
// Only start pulling if we're at scroll top and pulling down
|
|
89
|
+
if (!isPulling) {
|
|
90
|
+
if (rawDistance > 0 && isAtScrollTop()) {
|
|
91
|
+
isPulling = true;
|
|
92
|
+
startY = touchY; // Reset start position when pull begins
|
|
93
|
+
} else {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Calculate pull distance with resistance
|
|
99
|
+
currentY = touchY;
|
|
100
|
+
const actualDistance = currentY - startY;
|
|
101
|
+
|
|
102
|
+
if (actualDistance > 0) {
|
|
103
|
+
pullDistance = applyResistance(actualDistance);
|
|
104
|
+
// Prevent scroll while pulling
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
} else {
|
|
107
|
+
// Reset if user pushes back up
|
|
108
|
+
pullDistance = 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Handle touch end
|
|
114
|
+
*/
|
|
115
|
+
async function handleTouchEnd() {
|
|
116
|
+
if (disabled) return;
|
|
117
|
+
|
|
118
|
+
if (isPulling && isThresholdReached && !refreshing) {
|
|
119
|
+
// Trigger haptic feedback
|
|
120
|
+
await hapticImpact('medium');
|
|
121
|
+
|
|
122
|
+
// Trigger refresh
|
|
123
|
+
refreshing = true;
|
|
124
|
+
onrefresh?.();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Animate back
|
|
128
|
+
isPulling = false;
|
|
129
|
+
|
|
130
|
+
if (!refreshing) {
|
|
131
|
+
pullDistance = 0;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Handle touch cancel
|
|
137
|
+
*/
|
|
138
|
+
function handleTouchCancel() {
|
|
139
|
+
isPulling = false;
|
|
140
|
+
if (!refreshing) {
|
|
141
|
+
pullDistance = 0;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Watch for refreshing state changes to reset pull distance
|
|
146
|
+
$effect(() => {
|
|
147
|
+
if (!refreshing && pullDistance > 0) {
|
|
148
|
+
pullDistance = 0;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
</script>
|
|
152
|
+
|
|
153
|
+
<div
|
|
154
|
+
bind:this={containerEl}
|
|
155
|
+
class="ptr-container {className}"
|
|
156
|
+
class:ptr-container--pulling={isPulling}
|
|
157
|
+
class:ptr-container--refreshing={refreshing}
|
|
158
|
+
class:ptr-container--disabled={disabled}
|
|
159
|
+
ontouchstart={handleTouchStart}
|
|
160
|
+
ontouchmove={handleTouchMove}
|
|
161
|
+
ontouchend={handleTouchEnd}
|
|
162
|
+
ontouchcancel={handleTouchCancel}
|
|
163
|
+
>
|
|
164
|
+
<!-- Pull indicator -->
|
|
165
|
+
<div
|
|
166
|
+
class="ptr-indicator"
|
|
167
|
+
class:ptr-indicator--visible={pullDistance > 0 || refreshing}
|
|
168
|
+
class:ptr-indicator--threshold-reached={isThresholdReached}
|
|
169
|
+
class:ptr-indicator--refreshing={refreshing}
|
|
170
|
+
style="transform: translateY({refreshing ? 20 : indicatorY}px); opacity: {refreshing
|
|
171
|
+
? 1
|
|
172
|
+
: indicatorOpacity};"
|
|
173
|
+
aria-hidden="true"
|
|
174
|
+
>
|
|
175
|
+
<div
|
|
176
|
+
class="ptr-spinner"
|
|
177
|
+
class:ptr-spinner--spinning={refreshing}
|
|
178
|
+
style="transform: rotate({refreshing ? 0 : indicatorRotation}deg);"
|
|
179
|
+
>
|
|
180
|
+
<svg viewBox="0 0 24 24" class="ptr-spinner__icon">
|
|
181
|
+
<path
|
|
182
|
+
d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46A7.93 7.93 0 0020 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74A7.93 7.93 0 004 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"
|
|
183
|
+
fill="currentColor"
|
|
184
|
+
/>
|
|
185
|
+
</svg>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
<!-- Content wrapper -->
|
|
190
|
+
<div
|
|
191
|
+
bind:this={contentEl}
|
|
192
|
+
class="ptr-content"
|
|
193
|
+
style="transform: translateY({refreshing ? threshold * 0.5 : pullDistance}px);"
|
|
194
|
+
>
|
|
195
|
+
{#if children}
|
|
196
|
+
{@render children()}
|
|
197
|
+
{/if}
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<style>
|
|
202
|
+
.ptr-container {
|
|
203
|
+
position: relative;
|
|
204
|
+
width: 100%;
|
|
205
|
+
height: 100%;
|
|
206
|
+
overflow: hidden;
|
|
207
|
+
touch-action: pan-y;
|
|
208
|
+
-webkit-overflow-scrolling: touch;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.ptr-container--disabled {
|
|
212
|
+
pointer-events: none;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.ptr-indicator {
|
|
216
|
+
position: absolute;
|
|
217
|
+
top: 0;
|
|
218
|
+
left: 50%;
|
|
219
|
+
transform: translateX(-50%);
|
|
220
|
+
display: flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
justify-content: center;
|
|
223
|
+
width: 40px;
|
|
224
|
+
height: 40px;
|
|
225
|
+
border-radius: 50%;
|
|
226
|
+
background: var(--color-bg, #ffffff);
|
|
227
|
+
box-shadow: var(
|
|
228
|
+
--shadow-md,
|
|
229
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
230
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06)
|
|
231
|
+
);
|
|
232
|
+
opacity: 0;
|
|
233
|
+
pointer-events: none;
|
|
234
|
+
z-index: 10;
|
|
235
|
+
margin-left: -20px;
|
|
236
|
+
transition: opacity 0.2s ease;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.ptr-indicator--visible {
|
|
240
|
+
opacity: 1;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.ptr-indicator--threshold-reached {
|
|
244
|
+
background: var(--color-primary-light, #dbeafe);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.ptr-indicator--refreshing {
|
|
248
|
+
background: var(--color-bg, #ffffff);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.ptr-spinner {
|
|
252
|
+
display: flex;
|
|
253
|
+
align-items: center;
|
|
254
|
+
justify-content: center;
|
|
255
|
+
width: 24px;
|
|
256
|
+
height: 24px;
|
|
257
|
+
color: var(--color-primary, #3b82f6);
|
|
258
|
+
transition: transform 0.1s linear;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.ptr-spinner--spinning {
|
|
262
|
+
animation: ptr-spin 1s linear infinite;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.ptr-spinner__icon {
|
|
266
|
+
width: 100%;
|
|
267
|
+
height: 100%;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.ptr-content {
|
|
271
|
+
position: relative;
|
|
272
|
+
width: 100%;
|
|
273
|
+
height: 100%;
|
|
274
|
+
overflow-y: auto;
|
|
275
|
+
overflow-x: hidden;
|
|
276
|
+
-webkit-overflow-scrolling: touch;
|
|
277
|
+
will-change: transform;
|
|
278
|
+
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.ptr-container--pulling .ptr-content {
|
|
282
|
+
transition: none;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.ptr-container--refreshing .ptr-content {
|
|
286
|
+
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* Spinning animation */
|
|
290
|
+
@keyframes ptr-spin {
|
|
291
|
+
0% {
|
|
292
|
+
transform: rotate(0deg);
|
|
293
|
+
}
|
|
294
|
+
100% {
|
|
295
|
+
transform: rotate(360deg);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* Ensure minimum touch target size (F20 standard) */
|
|
300
|
+
.ptr-indicator {
|
|
301
|
+
min-width: 44px;
|
|
302
|
+
min-height: 44px;
|
|
303
|
+
}
|
|
304
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PullToRefreshProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends PullToRefreshProps {
|
|
3
|
+
/** Controlled loading state (bindable) */
|
|
4
|
+
refreshing?: boolean;
|
|
5
|
+
/** Pull distance in pixels to trigger refresh (default: 80) */
|
|
6
|
+
threshold?: number;
|
|
7
|
+
/** Maximum pull distance in pixels (default: 150) */
|
|
8
|
+
maxPull?: number;
|
|
9
|
+
/** Disable pull-to-refresh functionality */
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** Additional CSS class */
|
|
12
|
+
class?: string;
|
|
13
|
+
/** Called when threshold reached and released */
|
|
14
|
+
onrefresh?: () => void;
|
|
15
|
+
/** Content to render inside */
|
|
16
|
+
children?: import('svelte').Snippet;
|
|
17
|
+
}
|
|
18
|
+
declare const PullToRefresh: import("svelte").Component<Props, {}, "refreshing">;
|
|
19
|
+
type PullToRefresh = ReturnType<typeof PullToRefresh>;
|
|
20
|
+
export default PullToRefresh;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as PullToRefresh } from './PullToRefresh.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as PullToRefresh } from './PullToRefresh.svelte';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SafeAreaEdge, SafeAreaProps } from '../../types/index.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends SafeAreaProps {
|
|
5
|
+
children?: import('svelte').Snippet;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
edges = ['top', 'right', 'bottom', 'left'],
|
|
10
|
+
class: className = '',
|
|
11
|
+
children
|
|
12
|
+
}: Props = $props();
|
|
13
|
+
|
|
14
|
+
// Derive style string based on which edges are selected
|
|
15
|
+
const style = $derived.by(() => {
|
|
16
|
+
const styles: string[] = [];
|
|
17
|
+
if (edges?.includes('top')) styles.push('padding-top: env(safe-area-inset-top)');
|
|
18
|
+
if (edges?.includes('right')) styles.push('padding-right: env(safe-area-inset-right)');
|
|
19
|
+
if (edges?.includes('bottom')) styles.push('padding-bottom: env(safe-area-inset-bottom)');
|
|
20
|
+
if (edges?.includes('left')) styles.push('padding-left: env(safe-area-inset-left)');
|
|
21
|
+
return styles.join('; ');
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<div class="safe-area {className}" {style}>
|
|
26
|
+
{@render children?.()}
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.safe-area {
|
|
31
|
+
box-sizing: border-box;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SafeAreaProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends SafeAreaProps {
|
|
3
|
+
children?: import('svelte').Snippet;
|
|
4
|
+
}
|
|
5
|
+
declare const SafeArea: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type SafeArea = ReturnType<typeof SafeArea>;
|
|
7
|
+
export default SafeArea;
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
</SelectPrimitive.Trigger>
|
|
80
80
|
|
|
81
81
|
<SelectPrimitive.Portal>
|
|
82
|
-
<SelectPrimitive.Content class="select__content" sideOffset={4}>
|
|
82
|
+
<SelectPrimitive.Content class="select__content" sideOffset={4} align="start">
|
|
83
83
|
<SelectPrimitive.Viewport class="select__viewport">
|
|
84
84
|
{#each options as option (option.value)}
|
|
85
85
|
<SelectPrimitive.Item
|
|
@@ -195,46 +195,89 @@
|
|
|
195
195
|
|
|
196
196
|
:global(.select__content) {
|
|
197
197
|
z-index: 50;
|
|
198
|
-
min-width: 8rem;
|
|
199
198
|
overflow: hidden;
|
|
200
199
|
border: 1px solid var(--color-border, #e5e7eb);
|
|
201
200
|
border-radius: var(--radius-md, 0.375rem);
|
|
202
201
|
background: var(--color-bg, #ffffff);
|
|
203
|
-
box-shadow: var(--shadow-
|
|
202
|
+
box-shadow: var(--shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));
|
|
204
203
|
font-family: var(--font-family, system-ui, -apple-system, sans-serif);
|
|
204
|
+
/* Match trigger width - bits-ui provides this CSS variable */
|
|
205
|
+
min-width: var(--bits-floating-anchor-width, 200px);
|
|
206
|
+
width: var(--bits-floating-anchor-width, auto);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
:global(.select__content[data-state='open']) {
|
|
210
|
+
animation: select-in 150ms ease-out;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
:global(.select__content[data-state='closed']) {
|
|
214
|
+
animation: select-out 100ms ease-in;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@keyframes -global-select-in {
|
|
218
|
+
from {
|
|
219
|
+
opacity: 0;
|
|
220
|
+
transform: translateY(-4px);
|
|
221
|
+
}
|
|
222
|
+
to {
|
|
223
|
+
opacity: 1;
|
|
224
|
+
transform: translateY(0);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@keyframes -global-select-out {
|
|
229
|
+
from {
|
|
230
|
+
opacity: 1;
|
|
231
|
+
transform: translateY(0);
|
|
232
|
+
}
|
|
233
|
+
to {
|
|
234
|
+
opacity: 0;
|
|
235
|
+
transform: translateY(-4px);
|
|
236
|
+
}
|
|
205
237
|
}
|
|
206
238
|
|
|
207
239
|
:global(.select__viewport) {
|
|
208
|
-
padding: var(--space-xs, 0.25rem);
|
|
240
|
+
padding: var(--space-xs, 0.25rem) 0;
|
|
241
|
+
max-height: 20rem;
|
|
242
|
+
overflow-y: auto;
|
|
209
243
|
}
|
|
210
244
|
|
|
211
245
|
:global(.select__item) {
|
|
212
246
|
display: flex;
|
|
213
247
|
align-items: center;
|
|
214
248
|
justify-content: space-between;
|
|
215
|
-
padding: 0.
|
|
216
|
-
border-radius: var(--radius-sm, 0.25rem);
|
|
249
|
+
padding: 0.625rem 1rem;
|
|
217
250
|
font-size: var(--text-sm, 0.875rem);
|
|
218
|
-
line-height: 1.
|
|
251
|
+
line-height: 1.5;
|
|
219
252
|
color: var(--color-text, #1f2937);
|
|
220
253
|
cursor: pointer;
|
|
221
254
|
outline: none;
|
|
222
|
-
transition:
|
|
255
|
+
transition:
|
|
256
|
+
background var(--transition-fast, 150ms ease),
|
|
257
|
+
color var(--transition-fast, 150ms ease);
|
|
223
258
|
}
|
|
224
259
|
|
|
225
260
|
:global(.select__item:hover),
|
|
226
261
|
:global(.select__item[data-highlighted]) {
|
|
227
|
-
background: var(--color-
|
|
262
|
+
background: var(--color-primary, #3b82f6);
|
|
263
|
+
color: var(--color-text-inverse, #ffffff);
|
|
228
264
|
}
|
|
229
265
|
|
|
230
266
|
:global(.select__item[data-selected]) {
|
|
231
|
-
background: var(--color-primary
|
|
232
|
-
color: var(--color-
|
|
267
|
+
background: var(--color-primary, #3b82f6);
|
|
268
|
+
color: var(--color-text-inverse, #ffffff);
|
|
233
269
|
}
|
|
234
270
|
|
|
235
271
|
:global(.select__item[data-disabled]) {
|
|
236
272
|
opacity: 0.5;
|
|
237
273
|
cursor: not-allowed;
|
|
274
|
+
background: transparent;
|
|
275
|
+
color: var(--color-text-muted, #9ca3af);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
:global(.select__item[data-disabled]:hover) {
|
|
279
|
+
background: transparent;
|
|
280
|
+
color: var(--color-text-muted, #9ca3af);
|
|
238
281
|
}
|
|
239
282
|
|
|
240
283
|
.select__item-text {
|
|
@@ -245,7 +288,7 @@
|
|
|
245
288
|
display: flex;
|
|
246
289
|
align-items: center;
|
|
247
290
|
justify-content: center;
|
|
248
|
-
color:
|
|
291
|
+
color: currentColor;
|
|
249
292
|
margin-left: var(--space-sm, 0.5rem);
|
|
250
293
|
}
|
|
251
294
|
</style>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SkeletonProps } from '../../types/index.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends SkeletonProps {
|
|
5
|
+
variant?: 'text' | 'circle' | 'rectangle';
|
|
6
|
+
width?: string;
|
|
7
|
+
height?: string;
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { variant = 'text', width, height, class: className = '' }: Props = $props();
|
|
12
|
+
|
|
13
|
+
// Determine default dimensions based on variant
|
|
14
|
+
const defaultWidth = $derived(
|
|
15
|
+
variant === 'text' ? '100%' : variant === 'circle' ? '2.5rem' : '100%'
|
|
16
|
+
);
|
|
17
|
+
const defaultHeight = $derived(
|
|
18
|
+
variant === 'text' ? '1rem' : variant === 'circle' ? '2.5rem' : '8rem'
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// Use provided dimensions or defaults
|
|
22
|
+
const finalWidth = $derived(width ?? defaultWidth);
|
|
23
|
+
const finalHeight = $derived(height ?? defaultHeight);
|
|
24
|
+
|
|
25
|
+
// Border radius based on variant
|
|
26
|
+
const borderRadius = $derived(
|
|
27
|
+
variant === 'circle'
|
|
28
|
+
? '50%'
|
|
29
|
+
: variant === 'text'
|
|
30
|
+
? 'var(--exon-radius-sm, 0.25rem)'
|
|
31
|
+
: 'var(--exon-radius-md, 0.375rem)'
|
|
32
|
+
);
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div
|
|
36
|
+
class="skeleton {className}"
|
|
37
|
+
aria-hidden="true"
|
|
38
|
+
role="presentation"
|
|
39
|
+
style="width: {finalWidth}; height: {finalHeight}; border-radius: {borderRadius};"
|
|
40
|
+
></div>
|
|
41
|
+
|
|
42
|
+
<style>
|
|
43
|
+
.skeleton {
|
|
44
|
+
display: block;
|
|
45
|
+
background: var(--exon-skeleton-bg, var(--color-neutral-200, #e5e7eb));
|
|
46
|
+
font-family: inherit;
|
|
47
|
+
animation: skeleton-pulse 1.5s ease-in-out infinite;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@keyframes skeleton-pulse {
|
|
51
|
+
0%,
|
|
52
|
+
100% {
|
|
53
|
+
opacity: 1;
|
|
54
|
+
}
|
|
55
|
+
50% {
|
|
56
|
+
opacity: 0.5;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SkeletonProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends SkeletonProps {
|
|
3
|
+
variant?: 'text' | 'circle' | 'rectangle';
|
|
4
|
+
width?: string;
|
|
5
|
+
height?: string;
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const Skeleton: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Skeleton = ReturnType<typeof Skeleton>;
|
|
10
|
+
export default Skeleton;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Skeleton } from './Skeleton.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Skeleton } from './Skeleton.svelte';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SpacerProps, SpacerSize } from '../../types/index.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends SpacerProps {}
|
|
5
|
+
|
|
6
|
+
let { size = 'md', class: className = '' }: Props = $props();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="spacer {className}" data-size={size} aria-hidden="true"></div>
|
|
10
|
+
|
|
11
|
+
<style>
|
|
12
|
+
.spacer {
|
|
13
|
+
font-family: inherit;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Fixed size spacers */
|
|
17
|
+
.spacer[data-size='xs'] {
|
|
18
|
+
height: var(--space-xs, 0.25rem);
|
|
19
|
+
width: var(--space-xs, 0.25rem);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.spacer[data-size='sm'] {
|
|
23
|
+
height: var(--space-sm, 0.5rem);
|
|
24
|
+
width: var(--space-sm, 0.5rem);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.spacer[data-size='md'] {
|
|
28
|
+
height: var(--space-md, 1rem);
|
|
29
|
+
width: var(--space-md, 1rem);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.spacer[data-size='lg'] {
|
|
33
|
+
height: var(--space-lg, 1.5rem);
|
|
34
|
+
width: var(--space-lg, 1.5rem);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.spacer[data-size='xl'] {
|
|
38
|
+
height: var(--space-xl, 2rem);
|
|
39
|
+
width: var(--space-xl, 2rem);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.spacer[data-size='2xl'] {
|
|
43
|
+
height: var(--space-2xl, 3rem);
|
|
44
|
+
width: var(--space-2xl, 3rem);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.spacer[data-size='3xl'] {
|
|
48
|
+
height: var(--space-3xl, 4rem);
|
|
49
|
+
width: var(--space-3xl, 4rem);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Fill mode - grows to fill available space in flex container */
|
|
53
|
+
.spacer[data-size='fill'] {
|
|
54
|
+
flex: 1;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Spacer } from './Spacer.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Spacer } from './Spacer.svelte';
|