@joewinke/jatui 0.2.13 → 0.2.17
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.
|
@@ -183,10 +183,19 @@
|
|
|
183
183
|
const flipUp = spaceBelow < estPanelHeight && spaceAbove > spaceBelow;
|
|
184
184
|
// Clamp left so a right-edge trigger doesn't push the panel off-screen.
|
|
185
185
|
const left = Math.max(8, Math.min(rect.left, window.innerWidth - width - 8));
|
|
186
|
+
// .sd-panel's class rule always sets `top: 100%`, so each branch must
|
|
187
|
+
// explicitly reset the property it isn't using — otherwise the flip-up
|
|
188
|
+
// branch ends up with both top (100% = viewport height) and bottom set
|
|
189
|
+
// while height is auto, which over-constrains to a negative (clamped
|
|
190
|
+
// to 0) height and the whole panel silently renders invisible.
|
|
186
191
|
const vertical = flipUp
|
|
187
|
-
? `bottom: ${window.innerHeight - rect.top + 4}px;`
|
|
188
|
-
: `top: ${rect.bottom + 4}px;`;
|
|
189
|
-
|
|
192
|
+
? `bottom: ${window.innerHeight - rect.top + 4}px; top: auto;`
|
|
193
|
+
: `top: ${rect.bottom + 4}px; bottom: auto;`;
|
|
194
|
+
// min-width override is required: .sd-panel's class rule sets
|
|
195
|
+
// `min-width: max(100%, 14rem)`, and for a position:fixed element
|
|
196
|
+
// that 100% resolves against the viewport, not the trigger — without
|
|
197
|
+
// this override the panel balloons to ~100vw wide.
|
|
198
|
+
panelStyle = `position: fixed; z-index: 9999; ${vertical} left: ${left}px; width: ${width}px; min-width: ${width}px; margin-top: 0;`;
|
|
190
199
|
}
|
|
191
200
|
document.addEventListener('mousedown', handleClickOutside);
|
|
192
201
|
tick().then(() => { searchInput?.focus(); scrollHighlightedIntoView(); });
|
|
@@ -14,14 +14,22 @@
|
|
|
14
14
|
slots,
|
|
15
15
|
loading = false,
|
|
16
16
|
onSelect,
|
|
17
|
+
selectedSlot = null,
|
|
17
18
|
accentColor = 'primary',
|
|
18
19
|
}: {
|
|
19
20
|
slots: TimeSlot[];
|
|
20
21
|
loading?: boolean;
|
|
21
22
|
onSelect: (slot: TimeSlot) => void;
|
|
23
|
+
/** The currently-selected slot — rendered with an active highlight.
|
|
24
|
+
* Compared by start-time value (not object identity) so a re-fetched
|
|
25
|
+
* slots array still matches the selection. */
|
|
26
|
+
selectedSlot?: TimeSlot | null;
|
|
22
27
|
accentColor?: string;
|
|
23
28
|
} = $props();
|
|
24
29
|
|
|
30
|
+
const isSelected = (slot: TimeSlot): boolean =>
|
|
31
|
+
selectedSlot != null && slot.start.getTime() === selectedSlot.start.getTime();
|
|
32
|
+
|
|
25
33
|
const groupedSlots = $derived(() => {
|
|
26
34
|
const morning: TimeSlot[] = [];
|
|
27
35
|
const afternoon: TimeSlot[] = [];
|
|
@@ -97,7 +105,9 @@
|
|
|
97
105
|
disabled={!slot.available}
|
|
98
106
|
class="py-3 px-4 rounded-lg text-[0.9375rem] font-medium transition-all duration-200
|
|
99
107
|
{slot.available
|
|
100
|
-
?
|
|
108
|
+
? isSelected(slot)
|
|
109
|
+
? `bg-${accentColor} text-${accentColor}-content ring-2 ring-${accentColor} ring-offset-2 ring-offset-base-100 font-semibold`
|
|
110
|
+
: `bg-base-200/50 hover:bg-${accentColor} hover:text-${accentColor}-content`
|
|
101
111
|
: 'bg-base-200/20 text-base-content/30 cursor-not-allowed line-through'}"
|
|
102
112
|
>
|
|
103
113
|
{formatTime(slot.start)}
|
|
@@ -122,7 +132,9 @@
|
|
|
122
132
|
disabled={!slot.available}
|
|
123
133
|
class="py-3 px-4 rounded-lg text-[0.9375rem] font-medium transition-all duration-200
|
|
124
134
|
{slot.available
|
|
125
|
-
?
|
|
135
|
+
? isSelected(slot)
|
|
136
|
+
? `bg-${accentColor} text-${accentColor}-content ring-2 ring-${accentColor} ring-offset-2 ring-offset-base-100 font-semibold`
|
|
137
|
+
: `bg-base-200/50 hover:bg-${accentColor} hover:text-${accentColor}-content`
|
|
126
138
|
: 'bg-base-200/20 text-base-content/30 cursor-not-allowed line-through'}"
|
|
127
139
|
>
|
|
128
140
|
{formatTime(slot.start)}
|
|
@@ -148,7 +160,9 @@
|
|
|
148
160
|
disabled={!slot.available}
|
|
149
161
|
class="py-3 px-4 rounded-lg text-[0.9375rem] font-medium transition-all duration-200
|
|
150
162
|
{slot.available
|
|
151
|
-
?
|
|
163
|
+
? isSelected(slot)
|
|
164
|
+
? `bg-${accentColor} text-${accentColor}-content ring-2 ring-${accentColor} ring-offset-2 ring-offset-base-100 font-semibold`
|
|
165
|
+
: `bg-base-200/50 hover:bg-${accentColor} hover:text-${accentColor}-content`
|
|
152
166
|
: 'bg-base-200/20 text-base-content/30 cursor-not-allowed line-through'}"
|
|
153
167
|
>
|
|
154
168
|
{formatTime(slot.start)}
|
|
@@ -9,6 +9,10 @@ type $$ComponentProps = {
|
|
|
9
9
|
slots: TimeSlot[];
|
|
10
10
|
loading?: boolean;
|
|
11
11
|
onSelect: (slot: TimeSlot) => void;
|
|
12
|
+
/** The currently-selected slot — rendered with an active highlight.
|
|
13
|
+
* Compared by start-time value (not object identity) so a re-fetched
|
|
14
|
+
* slots array still matches the selection. */
|
|
15
|
+
selectedSlot?: TimeSlot | null;
|
|
12
16
|
accentColor?: string;
|
|
13
17
|
};
|
|
14
18
|
declare const TimeSlotPicker: import("svelte").Component<$$ComponentProps, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joewinke/jatui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared Svelte 5 component library for JAT projects",
|
|
6
6
|
"type": "module",
|
|
@@ -67,10 +67,10 @@
|
|
|
67
67
|
"build": "vite build",
|
|
68
68
|
"build:site": "npm run package && vite build",
|
|
69
69
|
"preview": "vite preview",
|
|
70
|
-
"package": "svelte-
|
|
71
|
-
"test:dist": "vitest run --config vitest.dist.config.ts",
|
|
70
|
+
"package": "svelte-package --input src/lib --output dist && node scripts/compile-rune-modules.mjs",
|
|
72
71
|
"check:demos": "node scripts/check-demo-coverage.mjs",
|
|
73
72
|
"guard": "node scripts/check-demo-coverage.mjs",
|
|
73
|
+
"test:dist": "vitest run --config vitest.dist.config.ts",
|
|
74
74
|
"prepublishOnly": "node scripts/guard-ci-publish.mjs && npm run package"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
@@ -159,10 +159,7 @@
|
|
|
159
159
|
"svelte": "^5.0.0",
|
|
160
160
|
"tailwindcss": "^4.0.0",
|
|
161
161
|
"typescript": "^5.0.0",
|
|
162
|
-
"vite": "^6.0.0"
|
|
163
|
-
"@vitest/browser": "^3.2.0",
|
|
164
|
-
"playwright": "^1.53.0",
|
|
165
|
-
"vitest": "^3.2.0"
|
|
162
|
+
"vite": "^6.0.0"
|
|
166
163
|
},
|
|
167
164
|
"dependencies": {
|
|
168
165
|
"diff": "^9.0.0",
|