@alacris/ui 0.5.0 → 0.5.1
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 +4 -4
- package/package.json +1 -1
- package/src/components/ui-date-picker.js +7 -7
- package/src/components/ui-dialog.js +7 -7
- package/src/components/ui-drawer.js +18 -10
- package/src/components/ui-sheet.js +18 -10
- package/src/components/ui-side-sheet.js +18 -10
- package/src/components/ui-swipe-row.js +2 -0
package/README.md
CHANGED
|
@@ -46,10 +46,10 @@ The published package is plain ESM. Point an import map at a pinned CDN build of
|
|
|
46
46
|
<script type="importmap">
|
|
47
47
|
{
|
|
48
48
|
"imports": {
|
|
49
|
-
"@alacris/core": "https://cdn.jsdelivr.net/npm/@alacris/core@0.11.
|
|
50
|
-
"@alacris/ui": "https://cdn.jsdelivr.net/npm/@alacris/ui@0.5.
|
|
51
|
-
"@alacris/ui/theme": "https://cdn.jsdelivr.net/npm/@alacris/ui@0.5.
|
|
52
|
-
"@alacris/ui/components/": "https://cdn.jsdelivr.net/npm/@alacris/ui@0.5.
|
|
49
|
+
"@alacris/core": "https://cdn.jsdelivr.net/npm/@alacris/core@0.11.5/dist/alacris.js",
|
|
50
|
+
"@alacris/ui": "https://cdn.jsdelivr.net/npm/@alacris/ui@0.5.1/src/index.js",
|
|
51
|
+
"@alacris/ui/theme": "https://cdn.jsdelivr.net/npm/@alacris/ui@0.5.1/src/theme/index.js",
|
|
52
|
+
"@alacris/ui/components/": "https://cdn.jsdelivr.net/npm/@alacris/ui@0.5.1/src/components/"
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
</script>
|
package/package.json
CHANGED
|
@@ -36,7 +36,7 @@ import { sys } from '../tokens/sys.js';
|
|
|
36
36
|
import { base } from './base.js';
|
|
37
37
|
import { formBind } from '../util/form.js';
|
|
38
38
|
import { presence } from '../motion/presence.js';
|
|
39
|
-
import { animate, fx } from '../motion/animate.js';
|
|
39
|
+
import { animate, fx, releaseFill } from '../motion/animate.js';
|
|
40
40
|
import { autoUpdate } from '../util/position.js';
|
|
41
41
|
import { escapeLayer } from '../util/keys.js';
|
|
42
42
|
import { popupEvent } from '../util/popup.js';
|
|
@@ -279,12 +279,7 @@ const styles = css`
|
|
|
279
279
|
place-items: center;
|
|
280
280
|
}
|
|
281
281
|
.scrim { position: absolute; inset: 0; background: ${t.scrim}; }
|
|
282
|
-
@keyframes ui-date-picker-in {
|
|
283
|
-
from { transform: scale(0.8); }
|
|
284
|
-
to { transform: none; }
|
|
285
|
-
}
|
|
286
282
|
.modal-surface {
|
|
287
|
-
animation: ui-date-picker-in ${sys.duration.medium2} ${sys.easing.emphasizedDecelerate};
|
|
288
283
|
position: relative;
|
|
289
284
|
display: flex;
|
|
290
285
|
flex-direction: column;
|
|
@@ -714,12 +709,17 @@ define('ui-date-picker', {
|
|
|
714
709
|
${calGrid}
|
|
715
710
|
</div>`;
|
|
716
711
|
|
|
712
|
+
const modalSurfaceRef = (el) => {
|
|
713
|
+
modalSurfaceEl = el;
|
|
714
|
+
releaseFill(animate(el, fx.scaleIn, { duration: 'medium2', easing: 'emphasizedDecelerate' }));
|
|
715
|
+
};
|
|
716
|
+
|
|
717
717
|
const modalView = () => html`
|
|
718
718
|
<div class="overlay">
|
|
719
719
|
<div class="scrim" aria-hidden="true" @click=${closePanel}></div>
|
|
720
720
|
<div class="modal-surface" part="panel" role="dialog" aria-modal="true"
|
|
721
721
|
aria-label=${() => label() || 'Choose date'}
|
|
722
|
-
ref=${
|
|
722
|
+
ref=${modalSurfaceRef}>
|
|
723
723
|
<div class="headline">${() => (range() ? 'Select dates' : 'Select date')}</div>
|
|
724
724
|
<div class="picked">${pickedLabel}</div>
|
|
725
725
|
<div class="cal-header">
|
|
@@ -29,7 +29,7 @@ import { define, html, css, vars, effect, onCleanup, signal } from '@alacris/cor
|
|
|
29
29
|
import { sys } from '../tokens/sys.js';
|
|
30
30
|
import { base } from './base.js';
|
|
31
31
|
import { presence } from '../motion/presence.js';
|
|
32
|
-
import { animate, fx } from '../motion/animate.js';
|
|
32
|
+
import { animate, fx, releaseFill } from '../motion/animate.js';
|
|
33
33
|
import { focusTrap, scrollLock } from '../util/focus.js';
|
|
34
34
|
|
|
35
35
|
const t = vars('ui-dialog', {
|
|
@@ -51,12 +51,7 @@ const styles = css`
|
|
|
51
51
|
place-items: center;
|
|
52
52
|
}
|
|
53
53
|
.scrim { position: absolute; inset: 0; background: ${t.scrim}; }
|
|
54
|
-
@keyframes ui-dialog-in {
|
|
55
|
-
from { transform: scale(0.8); }
|
|
56
|
-
to { transform: none; }
|
|
57
|
-
}
|
|
58
54
|
.surface {
|
|
59
|
-
animation: ui-dialog-in ${sys.duration.medium2} ${sys.easing.emphasizedDecelerate};
|
|
60
55
|
position: relative;
|
|
61
56
|
display: flex;
|
|
62
57
|
flex-direction: column;
|
|
@@ -146,13 +141,18 @@ define('ui-dialog', {
|
|
|
146
141
|
sync();
|
|
147
142
|
};
|
|
148
143
|
|
|
144
|
+
const surfaceRef = (el) => {
|
|
145
|
+
surfaceEl = el;
|
|
146
|
+
releaseFill(animate(el, fx.scaleIn, { duration: 'medium2', easing: 'emphasizedDecelerate' }));
|
|
147
|
+
};
|
|
148
|
+
|
|
149
149
|
const view = () => html`
|
|
150
150
|
<div class="overlay">
|
|
151
151
|
<div class="scrim" part="scrim" aria-hidden="true" @click=${() => requestClose('scrim')}></div>
|
|
152
152
|
<div class="surface" part="surface" role="dialog" aria-modal="true"
|
|
153
153
|
aria-labelledby=${() => (hasHeadline() ? 'headline' : null)}
|
|
154
154
|
aria-label=${() => (hasHeadline() ? null : (label() || 'Dialog'))}
|
|
155
|
-
tabindex="-1" ref=${
|
|
155
|
+
tabindex="-1" ref=${surfaceRef}>
|
|
156
156
|
<div class="headline" part="headline" id="headline"
|
|
157
157
|
ref=${(el) => hasSlot(el.querySelector('slot'), (has) => {
|
|
158
158
|
hasHeadline.set(has);
|
|
@@ -116,9 +116,11 @@ define('ui-drawer', {
|
|
|
116
116
|
};
|
|
117
117
|
|
|
118
118
|
// Trap focus + lock scroll exactly while the modal drawer is open.
|
|
119
|
+
let closingViaSwipe = false;
|
|
119
120
|
let prevActive = null;
|
|
120
121
|
effect(() => {
|
|
121
122
|
if (open() && variant() === 'modal') {
|
|
123
|
+
closingViaSwipe = false;
|
|
122
124
|
prevActive = document.activeElement;
|
|
123
125
|
document.addEventListener('keydown', onDocKeydown, true);
|
|
124
126
|
if (!unlock) unlock = scrollLock();
|
|
@@ -143,7 +145,7 @@ define('ui-drawer', {
|
|
|
143
145
|
|
|
144
146
|
// The panel slides out while the presence overlay (scrim included) fades.
|
|
145
147
|
effect(() => {
|
|
146
|
-
if (!open() && surfaceEl?.isConnected) {
|
|
148
|
+
if (!open() && surfaceEl?.isConnected && !closingViaSwipe) {
|
|
147
149
|
animate(surfaceEl, slideOut(), { duration: 'short4', easing: 'emphasizedAccelerate' });
|
|
148
150
|
}
|
|
149
151
|
});
|
|
@@ -161,6 +163,7 @@ define('ui-drawer', {
|
|
|
161
163
|
return true;
|
|
162
164
|
},
|
|
163
165
|
onStart() {
|
|
166
|
+
el.getAnimations?.()?.forEach((a) => a.cancel());
|
|
164
167
|
el.style.transition = 'none';
|
|
165
168
|
},
|
|
166
169
|
onMove({ dx }) {
|
|
@@ -183,29 +186,34 @@ define('ui-drawer', {
|
|
|
183
186
|
const shouldDismiss = !cancelled && dismissDirection;
|
|
184
187
|
|
|
185
188
|
if (shouldDismiss) {
|
|
189
|
+
closingViaSwipe = true;
|
|
186
190
|
const targetTransform = isEnd ? 'translateX(100%)' : 'translateX(-100%)';
|
|
187
191
|
const remaining = Math.max(0, w - Math.abs(dx));
|
|
188
192
|
const ms = Math.min(300, Math.max(120, Math.round(remaining / (Math.max(Math.abs(vx), 0.8)))));
|
|
189
193
|
if (scrimEl) {
|
|
190
194
|
animate(scrimEl, fx.fadeOut, { duration: ms, easing: 'emphasizedAccelerate' });
|
|
191
195
|
}
|
|
192
|
-
|
|
196
|
+
animate(el, [
|
|
193
197
|
{ transform: el.style.transform || `translateX(${dx}px)` },
|
|
194
198
|
{ transform: targetTransform },
|
|
195
|
-
], { duration: ms, easing: 'emphasizedAccelerate' });
|
|
196
|
-
|
|
197
|
-
requestClose('swipe');
|
|
198
|
-
});
|
|
199
|
+
], { duration: ms, easing: 'emphasizedAccelerate', fill: 'forwards' });
|
|
200
|
+
requestClose('swipe');
|
|
199
201
|
} else {
|
|
200
202
|
if (scrimEl) {
|
|
201
|
-
animate(scrimEl, [{ opacity: scrimEl.style.opacity || '0.5' }, { opacity: 1 }], {
|
|
203
|
+
const scrimSnap = animate(scrimEl, [{ opacity: scrimEl.style.opacity || '0.5' }, { opacity: 1 }], {
|
|
202
204
|
duration: 'short4', easing: 'emphasizedDecelerate',
|
|
203
|
-
})
|
|
205
|
+
});
|
|
206
|
+
scrimSnap.finished.then(() => {
|
|
207
|
+
try { scrimSnap.cancel(); } catch {}
|
|
208
|
+
if (scrimEl) scrimEl.style.opacity = '';
|
|
209
|
+
});
|
|
204
210
|
}
|
|
205
|
-
animate(el, [
|
|
211
|
+
const snapAnim = animate(el, [
|
|
206
212
|
{ transform: el.style.transform || `translateX(${dx}px)` },
|
|
207
213
|
{ transform: 'translateX(0)' },
|
|
208
|
-
], { duration: 'short4', easing: 'emphasizedDecelerate' })
|
|
214
|
+
], { duration: 'short4', easing: 'emphasizedDecelerate' });
|
|
215
|
+
snapAnim.finished.then(() => {
|
|
216
|
+
try { snapAnim.cancel(); } catch {}
|
|
209
217
|
if (el) el.style.transform = '';
|
|
210
218
|
});
|
|
211
219
|
}
|
|
@@ -134,9 +134,11 @@ define('ui-sheet', {
|
|
|
134
134
|
if (e.key === 'Escape') requestClose('esc');
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
+
let closingViaSwipe = false;
|
|
137
138
|
let prevActive = null;
|
|
138
139
|
effect(() => {
|
|
139
140
|
if (open() && variant() !== 'standard') {
|
|
141
|
+
closingViaSwipe = false;
|
|
140
142
|
prevActive = document.activeElement;
|
|
141
143
|
document.addEventListener('keydown', onDocKeydown, true);
|
|
142
144
|
unlock = scrollLock();
|
|
@@ -150,7 +152,7 @@ define('ui-sheet', {
|
|
|
150
152
|
prevActive = null;
|
|
151
153
|
unlock?.();
|
|
152
154
|
unlock = null;
|
|
153
|
-
if (surfaceEl?.isConnected) {
|
|
155
|
+
if (surfaceEl?.isConnected && !closingViaSwipe) {
|
|
154
156
|
animate(surfaceEl, fx.sheetOut, { duration: 'short4', easing: 'emphasizedAccelerate' });
|
|
155
157
|
}
|
|
156
158
|
}
|
|
@@ -185,6 +187,7 @@ define('ui-sheet', {
|
|
|
185
187
|
return true;
|
|
186
188
|
},
|
|
187
189
|
onStart() {
|
|
190
|
+
el.getAnimations?.()?.forEach((a) => a.cancel());
|
|
188
191
|
el.style.transition = 'none';
|
|
189
192
|
},
|
|
190
193
|
onMove({ dy }) {
|
|
@@ -204,28 +207,33 @@ define('ui-sheet', {
|
|
|
204
207
|
const shouldDismiss = !cancelled && (vy > 0.4 || dy > h * 0.35);
|
|
205
208
|
|
|
206
209
|
if (shouldDismiss) {
|
|
210
|
+
closingViaSwipe = true;
|
|
207
211
|
const remaining = Math.max(0, h - dy);
|
|
208
212
|
const ms = Math.min(300, Math.max(120, Math.round(remaining / (Math.max(vy, 0.8)))));
|
|
209
213
|
if (scrimEl) {
|
|
210
214
|
animate(scrimEl, fx.fadeOut, { duration: ms, easing: 'emphasizedAccelerate' });
|
|
211
215
|
}
|
|
212
|
-
|
|
216
|
+
animate(el, [
|
|
213
217
|
{ transform: el.style.transform || `translateY(${dy}px)` },
|
|
214
218
|
{ transform: 'translateY(100%)' },
|
|
215
|
-
], { duration: ms, easing: 'emphasizedAccelerate' });
|
|
216
|
-
|
|
217
|
-
requestClose('swipe');
|
|
218
|
-
});
|
|
219
|
+
], { duration: ms, easing: 'emphasizedAccelerate', fill: 'forwards' });
|
|
220
|
+
requestClose('swipe');
|
|
219
221
|
} else {
|
|
220
222
|
if (scrimEl) {
|
|
221
|
-
animate(scrimEl, [{ opacity: scrimEl.style.opacity || '0.5' }, { opacity: 1 }], {
|
|
223
|
+
const scrimSnap = animate(scrimEl, [{ opacity: scrimEl.style.opacity || '0.5' }, { opacity: 1 }], {
|
|
222
224
|
duration: 'short4', easing: 'emphasizedDecelerate',
|
|
223
|
-
})
|
|
225
|
+
});
|
|
226
|
+
scrimSnap.finished.then(() => {
|
|
227
|
+
try { scrimSnap.cancel(); } catch {}
|
|
228
|
+
if (scrimEl) scrimEl.style.opacity = '';
|
|
229
|
+
});
|
|
224
230
|
}
|
|
225
|
-
animate(el, [
|
|
231
|
+
const snapAnim = animate(el, [
|
|
226
232
|
{ transform: el.style.transform || `translateY(${dy}px)` },
|
|
227
233
|
{ transform: 'translateY(0)' },
|
|
228
|
-
], { duration: 'short4', easing: 'emphasizedDecelerate' })
|
|
234
|
+
], { duration: 'short4', easing: 'emphasizedDecelerate' });
|
|
235
|
+
snapAnim.finished.then(() => {
|
|
236
|
+
try { snapAnim.cancel(); } catch {}
|
|
229
237
|
if (el) el.style.transform = '';
|
|
230
238
|
});
|
|
231
239
|
}
|
|
@@ -136,9 +136,11 @@ define('ui-side-sheet', {
|
|
|
136
136
|
if (e.key === 'Escape') requestClose('esc');
|
|
137
137
|
};
|
|
138
138
|
|
|
139
|
+
let closingViaSwipe = false;
|
|
139
140
|
let prevActive = null;
|
|
140
141
|
effect(() => {
|
|
141
142
|
if (open() && variant() !== 'standard') {
|
|
143
|
+
closingViaSwipe = false;
|
|
142
144
|
prevActive = document.activeElement;
|
|
143
145
|
document.addEventListener('keydown', onDocKeydown, true);
|
|
144
146
|
unlock = scrollLock();
|
|
@@ -155,7 +157,7 @@ define('ui-side-sheet', {
|
|
|
155
157
|
}
|
|
156
158
|
});
|
|
157
159
|
effect(() => {
|
|
158
|
-
if (!open() && surfaceEl?.isConnected) {
|
|
160
|
+
if (!open() && surfaceEl?.isConnected && !closingViaSwipe) {
|
|
159
161
|
animate(surfaceEl, slideOut(), { duration: 'short4', easing: 'emphasizedAccelerate' });
|
|
160
162
|
}
|
|
161
163
|
});
|
|
@@ -179,6 +181,7 @@ define('ui-side-sheet', {
|
|
|
179
181
|
return true;
|
|
180
182
|
},
|
|
181
183
|
onStart() {
|
|
184
|
+
el.getAnimations?.()?.forEach((a) => a.cancel());
|
|
182
185
|
el.style.transition = 'none';
|
|
183
186
|
},
|
|
184
187
|
onMove({ dx }) {
|
|
@@ -201,29 +204,34 @@ define('ui-side-sheet', {
|
|
|
201
204
|
const shouldDismiss = !cancelled && dismissDirection;
|
|
202
205
|
|
|
203
206
|
if (shouldDismiss) {
|
|
207
|
+
closingViaSwipe = true;
|
|
204
208
|
const targetTransform = isEnd ? 'translateX(100%)' : 'translateX(-100%)';
|
|
205
209
|
const remaining = Math.max(0, w - Math.abs(dx));
|
|
206
210
|
const ms = Math.min(300, Math.max(120, Math.round(remaining / (Math.max(Math.abs(vx), 0.8)))));
|
|
207
211
|
if (scrimEl) {
|
|
208
212
|
animate(scrimEl, fx.fadeOut, { duration: ms, easing: 'emphasizedAccelerate' });
|
|
209
213
|
}
|
|
210
|
-
|
|
214
|
+
animate(el, [
|
|
211
215
|
{ transform: el.style.transform || `translateX(${dx}px)` },
|
|
212
216
|
{ transform: targetTransform },
|
|
213
|
-
], { duration: ms, easing: 'emphasizedAccelerate' });
|
|
214
|
-
|
|
215
|
-
requestClose('swipe');
|
|
216
|
-
});
|
|
217
|
+
], { duration: ms, easing: 'emphasizedAccelerate', fill: 'forwards' });
|
|
218
|
+
requestClose('swipe');
|
|
217
219
|
} else {
|
|
218
220
|
if (scrimEl) {
|
|
219
|
-
animate(scrimEl, [{ opacity: scrimEl.style.opacity || '0.5' }, { opacity: 1 }], {
|
|
221
|
+
const scrimSnap = animate(scrimEl, [{ opacity: scrimEl.style.opacity || '0.5' }, { opacity: 1 }], {
|
|
220
222
|
duration: 'short4', easing: 'emphasizedDecelerate',
|
|
221
|
-
})
|
|
223
|
+
});
|
|
224
|
+
scrimSnap.finished.then(() => {
|
|
225
|
+
try { scrimSnap.cancel(); } catch {}
|
|
226
|
+
if (scrimEl) scrimEl.style.opacity = '';
|
|
227
|
+
});
|
|
222
228
|
}
|
|
223
|
-
animate(el, [
|
|
229
|
+
const snapAnim = animate(el, [
|
|
224
230
|
{ transform: el.style.transform || `translateX(${dx}px)` },
|
|
225
231
|
{ transform: 'translateX(0)' },
|
|
226
|
-
], { duration: 'short4', easing: 'emphasizedDecelerate' })
|
|
232
|
+
], { duration: 'short4', easing: 'emphasizedDecelerate' });
|
|
233
|
+
snapAnim.finished.then(() => {
|
|
234
|
+
try { snapAnim.cancel(); } catch {}
|
|
227
235
|
if (el) el.style.transform = '';
|
|
228
236
|
});
|
|
229
237
|
}
|
|
@@ -97,6 +97,7 @@ define('ui-swipe-row', {
|
|
|
97
97
|
{ transform: targetTransform },
|
|
98
98
|
], { duration: ms, easing });
|
|
99
99
|
return anim.finished.then(() => {
|
|
100
|
+
try { anim.cancel(); } catch {}
|
|
100
101
|
if (contentEl) contentEl.style.transform = targetTransform;
|
|
101
102
|
});
|
|
102
103
|
};
|
|
@@ -163,6 +164,7 @@ define('ui-swipe-row', {
|
|
|
163
164
|
return true;
|
|
164
165
|
},
|
|
165
166
|
onStart() {
|
|
167
|
+
el.getAnimations?.()?.forEach((a) => a.cancel());
|
|
166
168
|
if (currentOpen === 'end') startOffset = -getEndWidth();
|
|
167
169
|
else if (currentOpen === 'start') startOffset = getStartWidth();
|
|
168
170
|
else startOffset = 0;
|