@k2b/ui 0.18.0 → 0.19.0
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 +3 -2
- package/dist/browser/actions/ContextMenu.js +3 -1
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/Dropdown.js +91 -46
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +4 -1
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +1293 -534
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-behavior.js +9 -0
- package/dist/browser/chat/chat-behavior.js.map +1 -1
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/types.js.map +1 -1
- package/dist/browser/content/Calendar.js +579 -533
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/Lightbox.js +76 -40
- package/dist/browser/content/Lightbox.js.map +1 -1
- package/dist/browser/content/PdfPreview.js +146 -79
- package/dist/browser/content/PdfPreview.js.map +1 -1
- package/dist/browser/content/Timeline.js +1038 -0
- package/dist/browser/content/Timeline.js.map +1 -0
- package/dist/browser/content/VideoPlayer.js +29 -9
- package/dist/browser/content/VideoPlayer.js.map +1 -1
- package/dist/browser/content/chart-inspection.js +7 -2
- package/dist/browser/content/chart-inspection.js.map +1 -1
- package/dist/browser/content/index.js +1 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/content/timeline-model.js +579 -0
- package/dist/browser/content/timeline-model.js.map +1 -0
- package/dist/browser/feedback/dialog-core.js +26 -14
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/inputs/ChoiceChips.js +66 -0
- package/dist/browser/inputs/ChoiceChips.js.map +1 -0
- package/dist/browser/inputs/ChoiceGroups.js +53 -12
- package/dist/browser/inputs/ChoiceGroups.js.map +1 -1
- package/dist/browser/inputs/FileInputs.js +48 -33
- package/dist/browser/inputs/FileInputs.js.map +1 -1
- package/dist/browser/inputs/SignatureInput.js +558 -0
- package/dist/browser/inputs/SignatureInput.js.map +1 -0
- package/dist/browser/inputs/emoji/EmojiPicker.js +841 -0
- package/dist/browser/inputs/emoji/EmojiPicker.js.map +1 -0
- package/dist/browser/inputs/emoji/emoji-data.js +1903 -0
- package/dist/browser/inputs/emoji/emoji-data.js.map +1 -0
- package/dist/browser/inputs/emoji/emoji-index.js +209 -0
- package/dist/browser/inputs/emoji/emoji-index.js.map +1 -0
- package/dist/browser/inputs/emoji/emoji-messages.js +64 -0
- package/dist/browser/inputs/emoji/emoji-messages.js.map +1 -0
- package/dist/browser/inputs/index.js +5 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/inputs/markdown/actions.js +48 -2
- package/dist/browser/inputs/markdown/actions.js.map +1 -1
- package/dist/browser/inputs/markdown/code-zone.js +38 -2
- package/dist/browser/inputs/markdown/code-zone.js.map +1 -1
- package/dist/browser/inputs/signature-messages.js +39 -0
- package/dist/browser/inputs/signature-messages.js.map +1 -0
- package/dist/browser/inputs/signature.js +208 -0
- package/dist/browser/inputs/signature.js.map +1 -0
- package/dist/browser/internal/render-error.js +49 -0
- package/dist/browser/internal/render-error.js.map +1 -0
- package/dist/browser/intl/messages.js +108 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +321 -222
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/FloatingWindow.js +4 -1
- package/dist/browser/layout/FloatingWindow.js.map +1 -1
- package/dist/browser/layout/SidebarItemPreview.js +5 -1
- package/dist/browser/layout/SidebarItemPreview.js.map +1 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/surfaces/ResourceCard.js +212 -0
- package/dist/browser/surfaces/ResourceCard.js.map +1 -0
- package/dist/browser/surfaces/index.js +1 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/licenses/emojibase-data.txt +21 -0
- package/dist/ssr/actions/ContextMenu.js +3 -1
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +49 -12
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +4 -1
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +805 -214
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-behavior.js +9 -0
- package/dist/ssr/chat/chat-behavior.js.map +1 -1
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/types.js.map +1 -1
- package/dist/ssr/content/Calendar.js +183 -142
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/Lightbox.js +19 -5
- package/dist/ssr/content/Lightbox.js.map +1 -1
- package/dist/ssr/content/PdfPreview.js +77 -36
- package/dist/ssr/content/PdfPreview.js.map +1 -1
- package/dist/ssr/content/Timeline.js +804 -0
- package/dist/ssr/content/Timeline.js.map +1 -0
- package/dist/ssr/content/VideoPlayer.js +29 -9
- package/dist/ssr/content/VideoPlayer.js.map +1 -1
- package/dist/ssr/content/chart-inspection.js +7 -2
- package/dist/ssr/content/chart-inspection.js.map +1 -1
- package/dist/ssr/content/index.js +1 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/content/timeline-model.js +579 -0
- package/dist/ssr/content/timeline-model.js.map +1 -0
- package/dist/ssr/feedback/dialog-core.js +26 -14
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/inputs/ChoiceChips.js +66 -0
- package/dist/ssr/inputs/ChoiceChips.js.map +1 -0
- package/dist/ssr/inputs/ChoiceGroups.js +12 -4
- package/dist/ssr/inputs/ChoiceGroups.js.map +1 -1
- package/dist/ssr/inputs/FileInputs.js +19 -4
- package/dist/ssr/inputs/FileInputs.js.map +1 -1
- package/dist/ssr/inputs/SignatureInput.js +404 -0
- package/dist/ssr/inputs/SignatureInput.js.map +1 -0
- package/dist/ssr/inputs/emoji/EmojiPicker.js +551 -0
- package/dist/ssr/inputs/emoji/EmojiPicker.js.map +1 -0
- package/dist/ssr/inputs/emoji/emoji-data.js +1903 -0
- package/dist/ssr/inputs/emoji/emoji-data.js.map +1 -0
- package/dist/ssr/inputs/emoji/emoji-index.js +209 -0
- package/dist/ssr/inputs/emoji/emoji-index.js.map +1 -0
- package/dist/ssr/inputs/emoji/emoji-messages.js +64 -0
- package/dist/ssr/inputs/emoji/emoji-messages.js.map +1 -0
- package/dist/ssr/inputs/index.js +5 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/inputs/markdown/actions.js +48 -2
- package/dist/ssr/inputs/markdown/actions.js.map +1 -1
- package/dist/ssr/inputs/markdown/code-zone.js +38 -2
- package/dist/ssr/inputs/markdown/code-zone.js.map +1 -1
- package/dist/ssr/inputs/signature-messages.js +39 -0
- package/dist/ssr/inputs/signature-messages.js.map +1 -0
- package/dist/ssr/inputs/signature.js +208 -0
- package/dist/ssr/inputs/signature.js.map +1 -0
- package/dist/ssr/internal/render-error.js +49 -0
- package/dist/ssr/internal/render-error.js.map +1 -0
- package/dist/ssr/intl/messages.js +108 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +112 -41
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/FloatingWindow.js +4 -1
- package/dist/ssr/layout/FloatingWindow.js.map +1 -1
- package/dist/ssr/layout/SidebarItemPreview.js +5 -1
- package/dist/ssr/layout/SidebarItemPreview.js.map +1 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/surfaces/ResourceCard.js +115 -0
- package/dist/ssr/surfaces/ResourceCard.js.map +1 -0
- package/dist/ssr/surfaces/index.js +1 -0
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Dropdown.d.ts +13 -1
- package/dist/types/actions/FilterChip.d.ts +5 -0
- package/dist/types/chat/ChatComposer.d.ts +24 -1
- package/dist/types/chat/chat-behavior.d.ts +15 -0
- package/dist/types/chat/index.d.ts +1 -1
- package/dist/types/chat/types.d.ts +34 -0
- package/dist/types/content/Calendar.d.ts +28 -8
- package/dist/types/content/Lightbox.d.ts +8 -0
- package/dist/types/content/Timeline.d.ts +49 -0
- package/dist/types/content/index.d.ts +4 -2
- package/dist/types/content/timeline-model.d.ts +148 -0
- package/dist/types/feedback/dialog-core.d.ts +1 -1
- package/dist/types/inputs/ChoiceChips.d.ts +20 -0
- package/dist/types/inputs/ChoiceGroups.d.ts +11 -2
- package/dist/types/inputs/FileInputs.d.ts +6 -0
- package/dist/types/inputs/SignatureInput.d.ts +22 -0
- package/dist/types/inputs/emoji/EmojiPicker.d.ts +42 -0
- package/dist/types/inputs/emoji/emoji-data.d.ts +2 -0
- package/dist/types/inputs/emoji/emoji-index.d.ts +109 -0
- package/dist/types/inputs/emoji/emoji-messages.d.ts +30 -0
- package/dist/types/inputs/index.d.ts +10 -0
- package/dist/types/inputs/markdown/actions.d.ts +4 -0
- package/dist/types/inputs/markdown/code-zone.d.ts +7 -0
- package/dist/types/inputs/signature-messages.d.ts +11 -0
- package/dist/types/inputs/signature.d.ts +72 -0
- package/dist/types/internal/render-error.d.ts +13 -0
- package/dist/types/intl/messages.d.ts +54 -0
- package/dist/types/layout/AppWorkspace.d.ts +17 -0
- package/dist/types/layout/SidebarItemPreview.d.ts +2 -0
- package/dist/types/layout/index.d.ts +1 -1
- package/dist/types/surfaces/ResourceCard.d.ts +31 -0
- package/dist/types/surfaces/index.d.ts +2 -0
- package/package.json +5 -4
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { template as _$template } from "solid-js/web";
|
|
2
2
|
import { delegateEvents as _$delegateEvents } from "solid-js/web";
|
|
3
|
-
import {
|
|
3
|
+
import { className as _$className } from "solid-js/web";
|
|
4
4
|
import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
|
|
5
5
|
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
6
6
|
import { effect as _$effect } from "solid-js/web";
|
|
7
|
+
import { memo as _$memo } from "solid-js/web";
|
|
7
8
|
import { createComponent as _$createComponent } from "solid-js/web";
|
|
8
9
|
import { getNextElement as _$getNextElement } from "solid-js/web";
|
|
9
10
|
import { getNextMarker as _$getNextMarker } from "solid-js/web";
|
|
@@ -15,12 +16,16 @@ var _tmpl$ = /*#__PURE__*/_$template(`<span class=k2b-content-lightbox__counter
|
|
|
15
16
|
_tmpl$4 = /*#__PURE__*/_$template(`<button type=button class=k2b-content-lightbox__nav data-direction=previous><i class="ti ti-chevron-left"aria-hidden=true>`),
|
|
16
17
|
_tmpl$5 = /*#__PURE__*/_$template(`<button type=button class=k2b-content-lightbox__nav data-direction=next><i class="ti ti-chevron-right"aria-hidden=true>`),
|
|
17
18
|
_tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-content-lightbox__dots role=group>`),
|
|
18
|
-
_tmpl$7 = /*#__PURE__*/_$template(`<dialog class=k2b-content-lightbox><div class=k2b-content-lightbox__bar><div class=k2b-content-lightbox__meta><!$><!/><!$><!/></div><div class=k2b-content-lightbox__actions
|
|
19
|
-
_tmpl$8 = /*#__PURE__*/_$template(`<
|
|
20
|
-
_tmpl$9 = /*#__PURE__*/_$template(`<
|
|
19
|
+
_tmpl$7 = /*#__PURE__*/_$template(`<dialog class=k2b-content-lightbox><div class=k2b-content-lightbox__bar><div class=k2b-content-lightbox__meta><!$><!/><!$><!/></div><div class=k2b-content-lightbox__actions><!$><!/><!$><!/><button type=button class=k2b-content-lightbox__button><i class="ti ti-x"aria-hidden=true></i><span class=k2b-content-lightbox__button-label></span></button></div></div><div class=k2b-content-lightbox__stage></div><!$><!/><!$><!/>`),
|
|
20
|
+
_tmpl$8 = /*#__PURE__*/_$template(`<button type=button class=k2b-content-lightbox__button><i aria-hidden=true></i><span class=k2b-content-lightbox__button-label>`),
|
|
21
|
+
_tmpl$9 = /*#__PURE__*/_$template(`<img class=k2b-content-lightbox__image>`),
|
|
22
|
+
_tmpl$0 = /*#__PURE__*/_$template(`<button type=button class=k2b-content-lightbox__dot>`);
|
|
21
23
|
import { createEffect, createSignal, For, onCleanup, onMount, Show } from "solid-js";
|
|
22
24
|
import { returnFocus, ringOnReturn } from "../internal/focus-return";
|
|
23
25
|
import { useUiMessages } from "../intl/messages";
|
|
26
|
+
|
|
27
|
+
/** One more thing to do with the shown image, beside Download: a short label, its icon class, and what it does. */
|
|
28
|
+
|
|
24
29
|
/**
|
|
25
30
|
* Minimal, accessible lightbox using native <dialog>.
|
|
26
31
|
* Supports keyboard navigation, touch swipe gestures, and screen readers.
|
|
@@ -70,8 +75,13 @@ export default function Lightbox(props) {
|
|
|
70
75
|
props.onClose();
|
|
71
76
|
};
|
|
72
77
|
|
|
78
|
+
// A key belongs to the Lightbox while focus is inside it, or on the page with no other dialog open. A dialog opened
|
|
79
|
+
// from one of its actions keeps its own keys: Escape closes that dialog, and arrows stay in its fields.
|
|
80
|
+
const ownsKey = target => target instanceof Node && (dialogRef.contains(target) || target === document.body && Array.from(document.querySelectorAll("dialog[open]")).every(dialog => dialog === dialogRef));
|
|
81
|
+
|
|
73
82
|
// Keyboard navigation
|
|
74
83
|
const handleKeyDown = e => {
|
|
84
|
+
if (!ownsKey(e.target)) return;
|
|
75
85
|
switch (e.key) {
|
|
76
86
|
case "Escape":
|
|
77
87
|
// Handled here, so WebKit does not light the returned focus for this key.
|
|
@@ -147,14 +157,16 @@ export default function Lightbox(props) {
|
|
|
147
157
|
_el$14 = _el$3.nextSibling,
|
|
148
158
|
_el$21 = _el$14.firstChild,
|
|
149
159
|
[_el$22, _co$5] = _$getNextMarker(_el$21.nextSibling),
|
|
150
|
-
_el$
|
|
160
|
+
_el$23 = _el$22.nextSibling,
|
|
161
|
+
[_el$24, _co$6] = _$getNextMarker(_el$23.nextSibling),
|
|
162
|
+
_el$18 = _el$24.nextSibling,
|
|
151
163
|
_el$19 = _el$18.firstChild,
|
|
152
164
|
_el$20 = _el$19.nextSibling,
|
|
153
|
-
_el$
|
|
154
|
-
_el$
|
|
155
|
-
[_el$
|
|
156
|
-
_el$
|
|
157
|
-
[_el$
|
|
165
|
+
_el$25 = _el$2.nextSibling,
|
|
166
|
+
_el$29 = _el$25.nextSibling,
|
|
167
|
+
[_el$30, _co$7] = _$getNextMarker(_el$29.nextSibling),
|
|
168
|
+
_el$31 = _el$30.nextSibling,
|
|
169
|
+
[_el$32, _co$8] = _$getNextMarker(_el$31.nextSibling);
|
|
158
170
|
_el$.$$touchend = handleTouchEnd;
|
|
159
171
|
_el$.$$touchstart = handleTouchStart;
|
|
160
172
|
_el$.addEventListener("cancel", handleCancel);
|
|
@@ -188,6 +200,30 @@ export default function Lightbox(props) {
|
|
|
188
200
|
return _el$0;
|
|
189
201
|
}
|
|
190
202
|
}), _el$13, _co$4);
|
|
203
|
+
_$insert(_el$14, _$createComponent(For, {
|
|
204
|
+
get each() {
|
|
205
|
+
return current()?.actions ?? [];
|
|
206
|
+
},
|
|
207
|
+
children: action => (() => {
|
|
208
|
+
var _el$33 = _$getNextElement(_tmpl$8),
|
|
209
|
+
_el$34 = _el$33.firstChild,
|
|
210
|
+
_el$35 = _el$34.nextSibling;
|
|
211
|
+
_el$33.$$click = () => action.onClick();
|
|
212
|
+
_$insert(_el$35, () => action.label);
|
|
213
|
+
_$effect(_p$ => {
|
|
214
|
+
var _v$5 = action.label,
|
|
215
|
+
_v$6 = action.icon;
|
|
216
|
+
_v$5 !== _p$.e && _$setAttribute(_el$33, "aria-label", _p$.e = _v$5);
|
|
217
|
+
_v$6 !== _p$.t && _$className(_el$34, _p$.t = _v$6);
|
|
218
|
+
return _p$;
|
|
219
|
+
}, {
|
|
220
|
+
e: undefined,
|
|
221
|
+
t: undefined
|
|
222
|
+
});
|
|
223
|
+
_$runHydrationEvents();
|
|
224
|
+
return _el$33;
|
|
225
|
+
})()
|
|
226
|
+
}), _el$22, _co$5);
|
|
191
227
|
_$insert(_el$14, _$createComponent(Show, {
|
|
192
228
|
get when() {
|
|
193
229
|
return current()?.downloadUrl;
|
|
@@ -209,27 +245,27 @@ export default function Lightbox(props) {
|
|
|
209
245
|
});
|
|
210
246
|
return _el$15;
|
|
211
247
|
}
|
|
212
|
-
}), _el$
|
|
248
|
+
}), _el$24, _co$6);
|
|
213
249
|
_el$18.$$click = close;
|
|
214
250
|
_$insert(_el$20, () => messages().close);
|
|
215
|
-
_$insert(_el$
|
|
251
|
+
_$insert(_el$25, _$createComponent(Show, {
|
|
216
252
|
get when() {
|
|
217
253
|
return current();
|
|
218
254
|
},
|
|
219
255
|
children: image => (() => {
|
|
220
|
-
var _el$
|
|
221
|
-
_$setAttribute(_el$
|
|
256
|
+
var _el$36 = _$getNextElement(_tmpl$9);
|
|
257
|
+
_$setAttribute(_el$36, "draggable", false);
|
|
222
258
|
_$effect(_p$ => {
|
|
223
|
-
var _v$
|
|
224
|
-
_v$
|
|
225
|
-
_v$
|
|
226
|
-
_v$
|
|
259
|
+
var _v$7 = image().src,
|
|
260
|
+
_v$8 = image().alt ?? "";
|
|
261
|
+
_v$7 !== _p$.e && _$setAttribute(_el$36, "src", _p$.e = _v$7);
|
|
262
|
+
_v$8 !== _p$.t && _$setAttribute(_el$36, "alt", _p$.t = _v$8);
|
|
227
263
|
return _p$;
|
|
228
264
|
}, {
|
|
229
265
|
e: undefined,
|
|
230
266
|
t: undefined
|
|
231
267
|
});
|
|
232
|
-
return _el$
|
|
268
|
+
return _el$36;
|
|
233
269
|
})()
|
|
234
270
|
}));
|
|
235
271
|
_$insert(_el$, _$createComponent(Show, {
|
|
@@ -238,53 +274,53 @@ export default function Lightbox(props) {
|
|
|
238
274
|
},
|
|
239
275
|
get children() {
|
|
240
276
|
return [(() => {
|
|
241
|
-
var _el$
|
|
242
|
-
_el$
|
|
243
|
-
_$effect(() => _$setAttribute(_el$
|
|
277
|
+
var _el$26 = _$getNextElement(_tmpl$4);
|
|
278
|
+
_el$26.$$click = prev;
|
|
279
|
+
_$effect(() => _$setAttribute(_el$26, "aria-label", messages().previousImage));
|
|
244
280
|
_$runHydrationEvents();
|
|
245
|
-
return _el$
|
|
281
|
+
return _el$26;
|
|
246
282
|
})(), (() => {
|
|
247
|
-
var _el$
|
|
248
|
-
_el$
|
|
249
|
-
_$effect(() => _$setAttribute(_el$
|
|
283
|
+
var _el$27 = _$getNextElement(_tmpl$5);
|
|
284
|
+
_el$27.$$click = next;
|
|
285
|
+
_$effect(() => _$setAttribute(_el$27, "aria-label", messages().nextImage));
|
|
250
286
|
_$runHydrationEvents();
|
|
251
|
-
return _el$
|
|
287
|
+
return _el$27;
|
|
252
288
|
})()];
|
|
253
289
|
}
|
|
254
|
-
}), _el$
|
|
290
|
+
}), _el$30, _co$7);
|
|
255
291
|
_$insert(_el$, _$createComponent(Show, {
|
|
256
292
|
get when() {
|
|
257
293
|
return _$memo(() => !!isMultiple())() && props.images.length <= 10;
|
|
258
294
|
},
|
|
259
295
|
get children() {
|
|
260
|
-
var _el$
|
|
261
|
-
_$insert(_el$
|
|
296
|
+
var _el$28 = _$getNextElement(_tmpl$6);
|
|
297
|
+
_$insert(_el$28, _$createComponent(For, {
|
|
262
298
|
get each() {
|
|
263
299
|
return props.images;
|
|
264
300
|
},
|
|
265
301
|
children: (_, i) => (() => {
|
|
266
|
-
var _el$
|
|
267
|
-
_el$
|
|
302
|
+
var _el$37 = _$getNextElement(_tmpl$0);
|
|
303
|
+
_el$37.$$click = () => setIndex(i());
|
|
268
304
|
_$effect(_p$ => {
|
|
269
|
-
var _v$
|
|
270
|
-
_v$
|
|
305
|
+
var _v$9 = index() === i() ? "true" : undefined,
|
|
306
|
+
_v$0 = messages().goToImage({
|
|
271
307
|
index: i() + 1
|
|
272
308
|
});
|
|
273
|
-
_v$
|
|
274
|
-
_v$
|
|
309
|
+
_v$9 !== _p$.e && _$setAttribute(_el$37, "aria-current", _p$.e = _v$9);
|
|
310
|
+
_v$0 !== _p$.t && _$setAttribute(_el$37, "aria-label", _p$.t = _v$0);
|
|
275
311
|
return _p$;
|
|
276
312
|
}, {
|
|
277
313
|
e: undefined,
|
|
278
314
|
t: undefined
|
|
279
315
|
});
|
|
280
316
|
_$runHydrationEvents();
|
|
281
|
-
return _el$
|
|
317
|
+
return _el$37;
|
|
282
318
|
})()
|
|
283
319
|
}));
|
|
284
|
-
_$effect(() => _$setAttribute(_el$
|
|
285
|
-
return _el$
|
|
320
|
+
_$effect(() => _$setAttribute(_el$28, "aria-label", messages().imageNavigation));
|
|
321
|
+
return _el$28;
|
|
286
322
|
}
|
|
287
|
-
}), _el$
|
|
323
|
+
}), _el$32, _co$8);
|
|
288
324
|
_$effect(_p$ => {
|
|
289
325
|
var _v$3 = messages().imageLightbox,
|
|
290
326
|
_v$4 = messages().closeLightbox;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["content/Lightbox.tsx"],"sourcesContent":["import { createEffect, createSignal, For, onCleanup, onMount, Show } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type LightboxImage = {\n src: string;\n alt?: string;\n downloadUrl?: string;\n};\n\ntype LightboxProps = {\n images: LightboxImage[];\n initialIndex?: number;\n onClose: () => void;\n};\n\n/**\n * Minimal, accessible lightbox using native <dialog>.\n * Supports keyboard navigation, touch swipe gestures, and screen readers.\n */\nexport default function Lightbox(props: LightboxProps) {\n const messages = useUiMessages();\n const clampIndex = (value: number, images = props.images): number =>\n images.length === 0 ? 0 : Math.max(0, Math.min(value, images.length - 1));\n const [index, setIndex] = createSignal(clampIndex(props.initialIndex ?? 0));\n let dialogRef!: HTMLDialogElement;\n let opener: HTMLElement | null = null;\n let openerRing = true;\n\n createEffect(\n (previous: { images: LightboxImage[]; initialIndex: number | undefined }) => {\n const images = props.images;\n const initialIndex = props.initialIndex;\n setIndex((currentIndex) => {\n if (initialIndex !== previous.initialIndex) return clampIndex(initialIndex ?? 0, images);\n const previousImage = previous.images[currentIndex];\n const retained = previousImage ? images.findIndex((image) => image === previousImage || image.src === previousImage.src) : -1;\n return retained >= 0 ? retained : clampIndex(currentIndex, images);\n });\n return { images, initialIndex };\n },\n { images: props.images, initialIndex: props.initialIndex },\n );\n\n // Touch gesture tracking\n let touchStartX = 0;\n let touchStartY = 0;\n const SWIPE_THRESHOLD = 50;\n\n const current = () => props.images[index()];\n const isMultiple = () => props.images.length > 1;\n const prev = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i - 1 + props.images.length) % props.images.length);\n };\n const next = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i + 1) % props.images.length);\n };\n\n const close = () => {\n dialogRef.close();\n returnFocus(opener, openerRing);\n props.onClose();\n };\n\n // Keyboard navigation\n const handleKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case \"Escape\":\n // Handled here, so WebKit does not light the returned focus for this key.\n e.preventDefault();\n close();\n break;\n case \"ArrowLeft\":\n prev();\n break;\n case \"ArrowRight\":\n next();\n break;\n }\n };\n\n // Touch handlers for swipe gestures\n const handleTouchStart = (e: TouchEvent) => {\n const touch = e.touches[0];\n if (touch) {\n touchStartX = touch.clientX;\n touchStartY = touch.clientY;\n }\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n const touch = e.changedTouches[0];\n if (!touch) return;\n\n const deltaX = touch.clientX - touchStartX;\n const deltaY = touch.clientY - touchStartY;\n\n // Only trigger swipe if horizontal movement is dominant\n if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > SWIPE_THRESHOLD) {\n if (deltaX > 0) {\n prev();\n } else {\n next();\n }\n }\n };\n\n // Click on backdrop closes lightbox\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === dialogRef) {\n close();\n }\n };\n\n // The browser cancels the dialog itself, as on the Android back gesture;\n // closing here still returns focus and tells the owner.\n const handleCancel = (e: Event) => {\n e.preventDefault();\n close();\n };\n\n // Registration and teardown both live in onMount: onCleanup also runs when an\n // SSR render is disposed, where `document` does not exist.\n onMount(() => {\n opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n openerRing = ringOnReturn(opener);\n // The native dialog would return focus with a ring of the browser's choosing.\n opener?.blur();\n dialogRef.showModal();\n document.addEventListener(\"keydown\", handleKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", handleKeyDown));\n });\n\n return (\n <dialog\n ref={dialogRef}\n class=\"k2b-content-lightbox\"\n onMouseDown={handleBackdropClick}\n onCancel={handleCancel}\n onTouchStart={handleTouchStart}\n onTouchEnd={handleTouchEnd}\n aria-label={messages().imageLightbox}\n >\n {/* Top bar */}\n <div class=\"k2b-content-lightbox__bar\">\n <div class=\"k2b-content-lightbox__meta\">\n <Show when={isMultiple()}>\n <span class=\"k2b-content-lightbox__counter\" aria-live=\"polite\">\n {index() + 1} / {props.images.length}\n </span>\n </Show>\n <Show when={current()?.alt}>\n <div class=\"k2b-content-lightbox__caption\">\n <div class=\"k2b-content-lightbox__caption-text\">{current()?.alt}</div>\n </div>\n </Show>\n </div>\n\n <div class=\"k2b-content-lightbox__actions\">\n <Show when={current()?.downloadUrl}>\n <a href={current()!.downloadUrl} download=\"\" class=\"k2b-content-lightbox__button\" aria-label={messages().downloadImage}>\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().download}</span>\n </a>\n </Show>\n <button type=\"button\" onClick={close} class=\"k2b-content-lightbox__button\" aria-label={messages().closeLightbox}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().close}</span>\n </button>\n </div>\n </div>\n\n <div class=\"k2b-content-lightbox__stage\">\n <Show when={current()}>\n {(image) => <img src={image().src} alt={image().alt ?? \"\"} class=\"k2b-content-lightbox__image\" draggable={false} />}\n </Show>\n </div>\n\n <Show when={isMultiple()}>\n <button\n type=\"button\"\n onClick={prev}\n class=\"k2b-content-lightbox__nav\"\n data-direction=\"previous\"\n aria-label={messages().previousImage}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </button>\n <button type=\"button\" onClick={next} class=\"k2b-content-lightbox__nav\" data-direction=\"next\" aria-label={messages().nextImage}>\n <i class=\"ti ti-chevron-right\" aria-hidden=\"true\" />\n </button>\n </Show>\n\n <Show when={isMultiple() && props.images.length <= 10}>\n <div class=\"k2b-content-lightbox__dots\" role=\"group\" aria-label={messages().imageNavigation}>\n <For each={props.images}>\n {(_, i) => (\n <button\n type=\"button\"\n onClick={() => setIndex(i())}\n class=\"k2b-content-lightbox__dot\"\n aria-current={index() === i() ? \"true\" : undefined}\n aria-label={messages().goToImage({ index: i() + 1 })}\n />\n )}\n </For>\n </div>\n </Show>\n </dialog>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU;AACpF,SAAS,WAAW,EAAE,YAAY,QAAQ,0BAA0B;AACpE,SAAS,aAAa,QAAQ,kBAAkB;AAchD;AACA;AACA;AACA;AACA,eAAe,SAAS,QAAQ,CAAC,KAAoB,EAAE;EACrD,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,KACtD,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;EAC3E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;EAC3E,IAAI,SAA6B;EACjC,IAAI,MAA0B,GAAG,IAAI;EACrC,IAAI,UAAU,GAAG,IAAI;EAErB,YAAY,CACT,QAAuE,IAAK;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;IAC3B,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY;IACvC,QAAQ,CAAE,YAAY,IAAK;MACzB,IAAI,YAAY,KAAK,QAAQ,CAAC,YAAY,EAAE,OAAO,UAAU,CAAC,YAAY,IAAI,CAAC,EAAE,MAAM,CAAC;MACxF,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC;MACnD,MAAM,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAC,SAAS,CAAE,KAAK,IAAK,KAAK,KAAK,aAAa,IAAI,KAAK,CAAC,GAAG,KAAK,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;MAC7H,OAAO,QAAQ,IAAI,CAAC,GAAG,QAAQ,GAAG,UAAU,CAAC,YAAY,EAAE,MAAM,CAAC;IACpE,CAAC,CAAC;IACF,OAAO;MAAE,MAAM;MAAE;IAAa,CAAC;EACjC,CAAC,EACD;IAAE,MAAM,EAAE,KAAK,CAAC,MAAM;IAAE,YAAY,EAAE,KAAK,CAAC;EAAa,CAC3D,CAAC;;EAED;EACA,IAAI,WAAW,GAAG,CAAC;EACnB,IAAI,WAAW,GAAG,CAAC;EACnB,MAAM,eAAe,GAAG,EAAE;EAE1B,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;EAC3C,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;EAChD,MAAM,IAAI,GAAG,MAAM;IACjB,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE;IACnB,QAAQ,CAAE,CAAC,IAAK,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;EACtE,CAAC;EACD,MAAM,IAAI,GAAG,MAAM;IACjB,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE;IACnB,QAAQ,CAAE,CAAC,IAAK,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;EAChD,CAAC;EAED,MAAM,KAAK,GAAG,MAAM;IAClB,SAAS,CAAC,KAAK,CAAC,CAAC;IACjB,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC;IAC/B,KAAK,CAAC,OAAO,CAAC,CAAC;EACjB,CAAC;;EAED;EACA,MAAM,aAAa,GAAI,CAAgB,IAAK;IAC1C,QAAQ,CAAC,CAAC,GAAG;MACX,KAAK,QAAQ;QACX;QACA,CAAC,CAAC,cAAc,CAAC,CAAC;QAClB,KAAK,CAAC,CAAC;QACP;MACF,KAAK,WAAW;QACd,IAAI,CAAC,CAAC;QACN;MACF,KAAK,YAAY;QACf,IAAI,CAAC,CAAC;QACN;IACJ;EACF,CAAC;;EAED;EACA,MAAM,gBAAgB,GAAI,CAAa,IAAK;IAC1C,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1B,IAAI,KAAK,EAAE;MACT,WAAW,GAAG,KAAK,CAAC,OAAO;MAC3B,WAAW,GAAG,KAAK,CAAC,OAAO;IAC7B;EACF,CAAC;EAED,MAAM,cAAc,GAAI,CAAa,IAAK;IACxC,MAAM,KAAK,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK,EAAE;IAEZ,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,GAAG,WAAW;IAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,GAAG,WAAW;;IAE1C;IACA,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,eAAe,EAAE;MAC7E,IAAI,MAAM,GAAG,CAAC,EAAE;QACd,IAAI,CAAC,CAAC;MACR,CAAC,MAAM;QACL,IAAI,CAAC,CAAC;MACR;IACF;EACF,CAAC;;EAED;EACA,MAAM,mBAAmB,GAAI,CAAa,IAAK;IAC7C,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE;MAC1B,KAAK,CAAC,CAAC;IACT;EACF,CAAC;;EAED;EACA;EACA,MAAM,YAAY,GAAI,CAAQ,IAAK;IACjC,CAAC,CAAC,cAAc,CAAC,CAAC;IAClB,KAAK,CAAC,CAAC;EACT,CAAC;;EAED;EACA;EACA,OAAO,CAAC,MAAM;IACZ,MAAM,GAAG,QAAQ,CAAC,aAAa,YAAY,WAAW,GAAG,QAAQ,CAAC,aAAa,GAAG,IAAI;IACtF,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC;IACjC;IACA,MAAM,EAAE,IAAI,CAAC,CAAC;IACd,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC;IACnD,SAAS,CAAC,MAAM,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;EACzE,CAAC,CAAC;EAEF;IAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;IAAA,kBAOgB,cAAc;IAAA,oBADZ,gBAAgB;IAAA,gCADpB,YAAY;IAAA,mBADT,mBAAmB;IAAA,YAF3B,SAAS;IAAA,mDAAT,SAAS;IAAA,kCAWT,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,UAAU,CAAC,CAAC;MAAA;MAAA;QAAA;UAAA;UAAA;UAAA;UAAA;UAAA;QAAA,sBAEnB,KAAK,CAAC,CAAC,GAAG,CAAC;QAAA,sBAAK,KAAK,CAAC,MAAM,CAAC,MAAM;QAAA;MAAA;IAAA;IAAA,kCAGvC,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,OAAO,CAAC,CAAC,EAAE,GAAG;MAAA;MAAA;QAAA;UAAA;QAAA,sBAE2B,OAAO,CAAC,CAAC,EAAE,GAAG;QAAA;MAAA;IAAA;IAAA,mCAMlE,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,OAAO,CAAC,CAAC,EAAE,WAAW;MAAA;MAAA;QAAA;UAAA;UAAA;QAAA,uBAGoB,QAAQ,CAAC,CAAC,CAAC,QAAQ;QAAA;UAAA,UAF9D,OAAO,CAAC,CAAC,CAAE,WAAW;YAAA,OAA+D,QAAQ,CAAC,CAAC,CAAC,aAAa;UAAA;UAAA;UAAA;QAAA;UAAA;UAAA;QAAA;QAAA;MAAA;IAAA;IAAA,iBAKzF,KAAK;IAAA,uBAEgB,QAAQ,CAAC,CAAC,CAAC,KAAK;IAAA,mCAMrE,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,OAAO,CAAC,CAAC;MAAA;MAAA,UACjB,KAAK;QAAA;QAAA,oCAAmG,KAAK;QAAA;UAAA,WAAzF,KAAK,CAAC,CAAC,CAAC,GAAG;YAAA,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE;UAAA;UAAA;UAAA;QAAA;UAAA;UAAA;QAAA;QAAA;MAAA;IAA0D;IAAA,iCAItH,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,UAAU,CAAC,CAAC;MAAA;MAAA;QAAA;UAAA;UAAA,iBAGX,IAAI;UAAA,oDAGD,QAAQ,CAAC,CAAC,CAAC,aAAa;UAAA;UAAA;QAAA;UAAA;UAAA,iBAIP,IAAI;UAAA,oDAAsE,QAAQ,CAAC,CAAC,CAAC,SAAS;UAAA;UAAA;QAAA;MAAA;IAAA;IAAA,iCAK9H,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,yBAAU,CAAC,CAAC,OAAI,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE;MAAA;MAAA;QAAA;QAAA,mCAEhD,GAAG;UAAA,IAAC,IAAI;YAAA,OAAE,KAAK,CAAC,MAAM;UAAA;UAAA,UACpB,CAAC,CAAC,EAAE,CAAC;YAAA;YAAA,iBAGO,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YAAA;cAAA,WAEd,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,SAAS;gBAAA,OACtC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;kBAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG;gBAAE,CAAC,CAAC;cAAA;cAAA;cAAA;YAAA;cAAA;cAAA;YAAA;YAAA;YAAA;UAAA;QAEvD;QAAA,oDAV4D,QAAQ,CAAC,CAAC,CAAC,eAAe;QAAA;MAAA;IAAA;IAAA;MAAA,WArDjF,QAAQ,CAAC,CAAC,CAAC,aAAa;QAAA,OAwBuD,QAAQ,CAAC,CAAC,CAAC,aAAa;MAAA;MAAA;MAAA;IAAA;MAAA;MAAA;IAAA;IAAA;IAAA;EAAA;AA6CzH;AAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["content/Lightbox.tsx"],"sourcesContent":["import { createEffect, createSignal, For, onCleanup, onMount, Show } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\n\n/** One more thing to do with the shown image, beside Download: a short label, its icon class, and what it does. */\nexport type LightboxAction = {\n label: string;\n icon: string;\n onClick: () => void;\n};\n\nexport type LightboxImage = {\n src: string;\n alt?: string;\n downloadUrl?: string;\n /** Actions for this image, shown before Download in the same style. */\n actions?: readonly LightboxAction[];\n};\n\ntype LightboxProps = {\n images: LightboxImage[];\n initialIndex?: number;\n onClose: () => void;\n};\n\n/**\n * Minimal, accessible lightbox using native <dialog>.\n * Supports keyboard navigation, touch swipe gestures, and screen readers.\n */\nexport default function Lightbox(props: LightboxProps) {\n const messages = useUiMessages();\n const clampIndex = (value: number, images = props.images): number =>\n images.length === 0 ? 0 : Math.max(0, Math.min(value, images.length - 1));\n const [index, setIndex] = createSignal(clampIndex(props.initialIndex ?? 0));\n let dialogRef!: HTMLDialogElement;\n let opener: HTMLElement | null = null;\n let openerRing = true;\n\n createEffect(\n (previous: { images: LightboxImage[]; initialIndex: number | undefined }) => {\n const images = props.images;\n const initialIndex = props.initialIndex;\n setIndex((currentIndex) => {\n if (initialIndex !== previous.initialIndex) return clampIndex(initialIndex ?? 0, images);\n const previousImage = previous.images[currentIndex];\n const retained = previousImage ? images.findIndex((image) => image === previousImage || image.src === previousImage.src) : -1;\n return retained >= 0 ? retained : clampIndex(currentIndex, images);\n });\n return { images, initialIndex };\n },\n { images: props.images, initialIndex: props.initialIndex },\n );\n\n // Touch gesture tracking\n let touchStartX = 0;\n let touchStartY = 0;\n const SWIPE_THRESHOLD = 50;\n\n const current = () => props.images[index()];\n const isMultiple = () => props.images.length > 1;\n const prev = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i - 1 + props.images.length) % props.images.length);\n };\n const next = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i + 1) % props.images.length);\n };\n\n const close = () => {\n dialogRef.close();\n returnFocus(opener, openerRing);\n props.onClose();\n };\n\n // A key belongs to the Lightbox while focus is inside it, or on the page with no other dialog open. A dialog opened\n // from one of its actions keeps its own keys: Escape closes that dialog, and arrows stay in its fields.\n const ownsKey = (target: EventTarget | null) =>\n target instanceof Node &&\n (dialogRef.contains(target) ||\n (target === document.body && Array.from(document.querySelectorAll(\"dialog[open]\")).every((dialog) => dialog === dialogRef)));\n\n // Keyboard navigation\n const handleKeyDown = (e: KeyboardEvent) => {\n if (!ownsKey(e.target)) return;\n switch (e.key) {\n case \"Escape\":\n // Handled here, so WebKit does not light the returned focus for this key.\n e.preventDefault();\n close();\n break;\n case \"ArrowLeft\":\n prev();\n break;\n case \"ArrowRight\":\n next();\n break;\n }\n };\n\n // Touch handlers for swipe gestures\n const handleTouchStart = (e: TouchEvent) => {\n const touch = e.touches[0];\n if (touch) {\n touchStartX = touch.clientX;\n touchStartY = touch.clientY;\n }\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n const touch = e.changedTouches[0];\n if (!touch) return;\n\n const deltaX = touch.clientX - touchStartX;\n const deltaY = touch.clientY - touchStartY;\n\n // Only trigger swipe if horizontal movement is dominant\n if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > SWIPE_THRESHOLD) {\n if (deltaX > 0) {\n prev();\n } else {\n next();\n }\n }\n };\n\n // Click on backdrop closes lightbox\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === dialogRef) {\n close();\n }\n };\n\n // The browser cancels the dialog itself, as on the Android back gesture;\n // closing here still returns focus and tells the owner.\n const handleCancel = (e: Event) => {\n e.preventDefault();\n close();\n };\n\n // Registration and teardown both live in onMount: onCleanup also runs when an\n // SSR render is disposed, where `document` does not exist.\n onMount(() => {\n opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n openerRing = ringOnReturn(opener);\n // The native dialog would return focus with a ring of the browser's choosing.\n opener?.blur();\n dialogRef.showModal();\n document.addEventListener(\"keydown\", handleKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", handleKeyDown));\n });\n\n return (\n <dialog\n ref={dialogRef}\n class=\"k2b-content-lightbox\"\n onMouseDown={handleBackdropClick}\n onCancel={handleCancel}\n onTouchStart={handleTouchStart}\n onTouchEnd={handleTouchEnd}\n aria-label={messages().imageLightbox}\n >\n {/* Top bar */}\n <div class=\"k2b-content-lightbox__bar\">\n <div class=\"k2b-content-lightbox__meta\">\n <Show when={isMultiple()}>\n <span class=\"k2b-content-lightbox__counter\" aria-live=\"polite\">\n {index() + 1} / {props.images.length}\n </span>\n </Show>\n <Show when={current()?.alt}>\n <div class=\"k2b-content-lightbox__caption\">\n <div class=\"k2b-content-lightbox__caption-text\">{current()?.alt}</div>\n </div>\n </Show>\n </div>\n\n <div class=\"k2b-content-lightbox__actions\">\n <For each={current()?.actions ?? []}>\n {(action) => (\n <button type=\"button\" onClick={() => action.onClick()} class=\"k2b-content-lightbox__button\" aria-label={action.label}>\n <i class={action.icon} aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{action.label}</span>\n </button>\n )}\n </For>\n <Show when={current()?.downloadUrl}>\n <a href={current()!.downloadUrl} download=\"\" class=\"k2b-content-lightbox__button\" aria-label={messages().downloadImage}>\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().download}</span>\n </a>\n </Show>\n <button type=\"button\" onClick={close} class=\"k2b-content-lightbox__button\" aria-label={messages().closeLightbox}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().close}</span>\n </button>\n </div>\n </div>\n\n <div class=\"k2b-content-lightbox__stage\">\n <Show when={current()}>\n {(image) => <img src={image().src} alt={image().alt ?? \"\"} class=\"k2b-content-lightbox__image\" draggable={false} />}\n </Show>\n </div>\n\n <Show when={isMultiple()}>\n <button\n type=\"button\"\n onClick={prev}\n class=\"k2b-content-lightbox__nav\"\n data-direction=\"previous\"\n aria-label={messages().previousImage}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </button>\n <button type=\"button\" onClick={next} class=\"k2b-content-lightbox__nav\" data-direction=\"next\" aria-label={messages().nextImage}>\n <i class=\"ti ti-chevron-right\" aria-hidden=\"true\" />\n </button>\n </Show>\n\n <Show when={isMultiple() && props.images.length <= 10}>\n <div class=\"k2b-content-lightbox__dots\" role=\"group\" aria-label={messages().imageNavigation}>\n <For each={props.images}>\n {(_, i) => (\n <button\n type=\"button\"\n onClick={() => setIndex(i())}\n class=\"k2b-content-lightbox__dot\"\n aria-current={index() === i() ? \"true\" : undefined}\n aria-label={messages().goToImage({ index: i() + 1 })}\n />\n )}\n </For>\n </div>\n </Show>\n </dialog>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -16,11 +16,13 @@ var _tmpl$ = /*#__PURE__*/_$template(`<button type=button class=k2b-button data-
|
|
|
16
16
|
_tmpl$3 = /*#__PURE__*/_$template(`<span role=alert class=k2b-content-pdf-preview__notice>`),
|
|
17
17
|
_tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-content-pdf-preview__actions><!$><!/><!$><!/><!$><!/><!$><!/>`),
|
|
18
18
|
_tmpl$5 = /*#__PURE__*/_$template(`<a class=k2b-button data-variant=secondary data-size=sm target=_blank rel=noopener><i class="ti ti-external-link"aria-hidden=true></i><!$><!/>`),
|
|
19
|
-
_tmpl$6 = /*#__PURE__*/_$template(`<
|
|
20
|
-
_tmpl$7 = /*#__PURE__*/_$template(`<
|
|
21
|
-
_tmpl$8 = /*#__PURE__*/_$template(`<
|
|
22
|
-
_tmpl$9 = /*#__PURE__*/_$template(`<
|
|
19
|
+
_tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-content-pdf-preview__viewer><!$><!/><!$><!/>`),
|
|
20
|
+
_tmpl$7 = /*#__PURE__*/_$template(`<iframe class=k2b-content-pdf-preview__frame>`),
|
|
21
|
+
_tmpl$8 = /*#__PURE__*/_$template(`<button type=button class=k2b-button data-variant=secondary data-size=sm>`),
|
|
22
|
+
_tmpl$9 = /*#__PURE__*/_$template(`<h2 class=k2b-content-pdf-preview__title>`),
|
|
23
|
+
_tmpl$0 = /*#__PURE__*/_$template(`<section><div class=k2b-content-pdf-preview__toolbar><div class=k2b-content-pdf-preview__heading></div><!$><!/></div><!$><!/>`);
|
|
23
24
|
import { createSignal, onCleanup, onMount, Show } from "solid-js";
|
|
25
|
+
import { announce } from "../feedback/announce";
|
|
24
26
|
import { resolveUiMessages, useUiMessages } from "../intl/messages";
|
|
25
27
|
import Placeholder from "../surfaces/Placeholder";
|
|
26
28
|
const readErrorMessage = async response => {
|
|
@@ -44,15 +46,26 @@ export default function PdfPreview(props) {
|
|
|
44
46
|
const [error, setError] = createSignal(null);
|
|
45
47
|
const [failed, setFailed] = createSignal(false);
|
|
46
48
|
const [tabBlocked, setTabBlocked] = createSignal(false);
|
|
49
|
+
// The frame has its document only once it fires `load`; until then the loading state covers it.
|
|
50
|
+
const [drawn, setDrawn] = createSignal(false);
|
|
47
51
|
// An automatic preview shows one fixed document; the open action reuses it instead of requesting it again.
|
|
48
52
|
let shownBlob = null;
|
|
49
53
|
let openButton;
|
|
50
54
|
let frame;
|
|
55
|
+
let viewer;
|
|
51
56
|
let renderButton;
|
|
52
57
|
let errorRetryButton;
|
|
53
58
|
let disposed = false;
|
|
54
59
|
let loadGeneration = 0;
|
|
55
60
|
let openGeneration = 0;
|
|
61
|
+
|
|
62
|
+
// Without an inline PDF viewer (`navigator.pdfViewerEnabled === false`, as in Chrome on Android) a frame stays empty
|
|
63
|
+
// or downloads the file, so the viewer explains that instead and leaves the document to the open and download actions.
|
|
64
|
+
const inlineViewer = () => typeof navigator === "undefined" || navigator.pdfViewerEnabled !== false;
|
|
65
|
+
// There an automatic preview could show only that hint, so it requests nothing: the open action fetches the document
|
|
66
|
+
// when someone asks for it, and is also the retry after it fails. An on-demand preview still renders, because its
|
|
67
|
+
// request also checks the caller's input.
|
|
68
|
+
const openOnly = () => Boolean(props.autoLoad) && !inlineViewer();
|
|
56
69
|
const revokeCurrent = () => {
|
|
57
70
|
const current = url();
|
|
58
71
|
if (current) URL.revokeObjectURL(current);
|
|
@@ -88,12 +101,18 @@ export default function PdfPreview(props) {
|
|
|
88
101
|
const previousUrl = url();
|
|
89
102
|
shownBlob = blob;
|
|
90
103
|
setFailed(false);
|
|
104
|
+
setDrawn(false);
|
|
91
105
|
setUrl(nextUrl);
|
|
92
106
|
setLoading(false);
|
|
93
107
|
if (previousUrl) URL.revokeObjectURL(previousUrl);
|
|
94
|
-
// The
|
|
95
|
-
|
|
96
|
-
|
|
108
|
+
// The loading status turns into the missing-viewer hint in place and stops being a live region, so say it here.
|
|
109
|
+
if (!inlineViewer()) {
|
|
110
|
+
announce(messages().pdfPreviewNoViewer);
|
|
111
|
+
announce(messages().pdfPreviewNoViewerDescription);
|
|
112
|
+
}
|
|
113
|
+
// The shown document removes the retry action; keep keyboard focus in the actions instead of the page, or, when
|
|
114
|
+
// the host shows only the content, in the viewer, which hands it on to the document once the frame has loaded it.
|
|
115
|
+
if (retryFocused && document.activeElement === document.body) (openButton?.isConnected ? openButton : viewer)?.focus();
|
|
97
116
|
} catch (e) {
|
|
98
117
|
if (disposed || generation !== loadGeneration) return;
|
|
99
118
|
shownBlob = null;
|
|
@@ -105,9 +124,10 @@ export default function PdfPreview(props) {
|
|
|
105
124
|
}
|
|
106
125
|
};
|
|
107
126
|
onMount(() => {
|
|
108
|
-
// Hand the initial loading state to the request itself, which also covers a preview disabled by now
|
|
127
|
+
// Hand the initial loading state to the request itself, which also covers a preview disabled by now or one that
|
|
128
|
+
// leaves the document to the open action.
|
|
109
129
|
setLoading(false);
|
|
110
|
-
if (props.autoLoad) void load();
|
|
130
|
+
if (props.autoLoad && !openOnly()) void load();
|
|
111
131
|
});
|
|
112
132
|
const openInNewTab = async () => {
|
|
113
133
|
if (loading() || opening() || props.disabled?.()) return;
|
|
@@ -140,7 +160,7 @@ export default function PdfPreview(props) {
|
|
|
140
160
|
|
|
141
161
|
// With autoLoad, rendering again would show the same document: offer it only until one is shown. After a failure the
|
|
142
162
|
// default error state carries it as the retry; beside a caller's error content it stays in place while a retry loads.
|
|
143
|
-
const renderable = () => !props.autoLoad || (failed() ? Boolean(props.renderError) : !url() && !loading());
|
|
163
|
+
const renderable = () => !openOnly() && (!props.autoLoad || (failed() ? Boolean(props.renderError) : !url() && !loading()));
|
|
144
164
|
const actions = () => (() => {
|
|
145
165
|
var _el$ = _$getNextElement(_tmpl$4),
|
|
146
166
|
_el$1 = _el$.firstChild,
|
|
@@ -245,71 +265,118 @@ export default function PdfPreview(props) {
|
|
|
245
265
|
}), _el$16, _co$6);
|
|
246
266
|
return _el$;
|
|
247
267
|
})();
|
|
248
|
-
// Every state
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
268
|
+
// Every state uses one placeholder in the viewer's box, so loading changes no layout: idle and loading before a
|
|
269
|
+
// document arrives, loading over the frame until it has loaded the document, and the hint where no frame can.
|
|
270
|
+
const status = () => {
|
|
271
|
+
if (error()) return null;
|
|
272
|
+
if (!inlineViewer() && (url() || openOnly() && !loading())) return "no-viewer";
|
|
273
|
+
if (!url()) return loading() ? "loading" : "idle";
|
|
274
|
+
return drawn() ? null : "loading";
|
|
275
|
+
};
|
|
276
|
+
const viewerBox = () => // While it shows a placeholder, the viewer itself holds keyboard focus that has nowhere else to go.
|
|
277
|
+
(() => {
|
|
278
|
+
var _el$25 = _$getNextElement(_tmpl$6),
|
|
279
|
+
_el$26 = _el$25.firstChild,
|
|
280
|
+
[_el$27, _co$9] = _$getNextMarker(_el$26.nextSibling),
|
|
281
|
+
_el$28 = _el$27.nextSibling,
|
|
282
|
+
[_el$29, _co$0] = _$getNextMarker(_el$28.nextSibling);
|
|
283
|
+
_$use(element => viewer = element, _el$25);
|
|
284
|
+
_$insert(_el$25, _$createComponent(Show, {
|
|
285
|
+
get when() {
|
|
286
|
+
return _$memo(() => !!(!error() && inlineViewer()))() && url();
|
|
287
|
+
},
|
|
288
|
+
children: currentUrl => (() => {
|
|
289
|
+
var _el$30 = _$getNextElement(_tmpl$7);
|
|
290
|
+
_el$30.addEventListener("load", () => {
|
|
291
|
+
const waiting = document.activeElement === viewer;
|
|
292
|
+
setDrawn(true);
|
|
293
|
+
if (waiting) frame?.focus();
|
|
294
|
+
});
|
|
295
|
+
_$use(element => {
|
|
296
|
+
frame = element;
|
|
297
|
+
// A new frame loads its document again, also one that was shown before a failed reload.
|
|
298
|
+
setDrawn(false);
|
|
299
|
+
}, _el$30);
|
|
300
|
+
_$effect(_p$ => {
|
|
301
|
+
var _v$5 = drawn() ? "" : undefined,
|
|
302
|
+
_v$6 = !drawn(),
|
|
303
|
+
_v$7 = currentUrl(),
|
|
304
|
+
_v$8 = props.title ?? messages().pdfPreview;
|
|
305
|
+
_v$5 !== _p$.e && _$setAttribute(_el$30, "data-drawn", _p$.e = _v$5);
|
|
306
|
+
_v$6 !== _p$.t && _$setProperty(_el$30, "inert", _p$.t = _v$6);
|
|
307
|
+
_v$7 !== _p$.a && _$setAttribute(_el$30, "src", _p$.a = _v$7);
|
|
308
|
+
_v$8 !== _p$.o && _$setAttribute(_el$30, "title", _p$.o = _v$8);
|
|
309
|
+
return _p$;
|
|
310
|
+
}, {
|
|
311
|
+
e: undefined,
|
|
312
|
+
t: undefined,
|
|
313
|
+
a: undefined,
|
|
314
|
+
o: undefined
|
|
315
|
+
});
|
|
316
|
+
return _el$30;
|
|
317
|
+
})()
|
|
318
|
+
}), _el$27, _co$9);
|
|
319
|
+
_$insert(_el$25, _$createComponent(Show, {
|
|
320
|
+
get when() {
|
|
321
|
+
return error();
|
|
322
|
+
},
|
|
323
|
+
get fallback() {
|
|
324
|
+
return _$createComponent(Show, {
|
|
325
|
+
get when() {
|
|
326
|
+
return status();
|
|
327
|
+
},
|
|
328
|
+
children: state => _$createComponent(Placeholder, {
|
|
260
329
|
"class": "k2b-content-pdf-preview__placeholder",
|
|
261
330
|
get state() {
|
|
262
|
-
return
|
|
331
|
+
return state() === "loading" ? "loading" : "empty";
|
|
263
332
|
},
|
|
264
333
|
get icon() {
|
|
265
|
-
return
|
|
334
|
+
return state() === "loading" ? undefined : "ti ti-file-type-pdf";
|
|
266
335
|
},
|
|
267
336
|
get title() {
|
|
268
|
-
return _$memo(() =>
|
|
337
|
+
return _$memo(() => state() === "loading")() ? messages().loading : _$memo(() => state() === "no-viewer")() ? messages().pdfPreviewNoViewer : undefined;
|
|
269
338
|
},
|
|
270
339
|
get description() {
|
|
271
|
-
return _$memo(() =>
|
|
340
|
+
return _$memo(() => state() === "idle")() ? props.emptyText ?? messages().renderPdfPreview : _$memo(() => state() === "no-viewer")() ? messages().pdfPreviewNoViewerDescription : undefined;
|
|
272
341
|
}
|
|
273
|
-
})
|
|
342
|
+
})
|
|
343
|
+
});
|
|
344
|
+
},
|
|
345
|
+
children: message => _$createComponent(Placeholder, {
|
|
346
|
+
"class": "k2b-content-pdf-preview__placeholder",
|
|
347
|
+
state: "error",
|
|
348
|
+
get description() {
|
|
349
|
+
return message();
|
|
274
350
|
},
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
})
|
|
351
|
+
get action() {
|
|
352
|
+
return (
|
|
353
|
+
// One retry at a time: the render action moves here only where the toolbar no longer offers it, and the
|
|
354
|
+
// open action is the retry of a preview that leaves the document to it.
|
|
355
|
+
_$memo(() => !!(renderable() || openOnly()))() ? undefined : (() => {
|
|
356
|
+
var _el$31 = _$getNextElement(_tmpl$8);
|
|
357
|
+
_el$31.$$click = () => void load();
|
|
358
|
+
_$use(element => errorRetryButton = element, _el$31);
|
|
359
|
+
_$insert(_el$31, () => props.buttonLabel ?? messages().retry);
|
|
360
|
+
_$effect(() => _$setProperty(_el$31, "disabled", opening() || props.disabled?.()));
|
|
361
|
+
_$runHydrationEvents();
|
|
362
|
+
return _el$31;
|
|
363
|
+
})()
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
})
|
|
367
|
+
}), _el$29, _co$0);
|
|
368
|
+
_$effect(() => _$setAttribute(_el$25, "tabindex", status() ? -1 : undefined));
|
|
369
|
+
return _el$25;
|
|
370
|
+
})();
|
|
371
|
+
// A caller's error content replaces the whole viewer, as it brings its own layout.
|
|
372
|
+
const content = () => _$createComponent(Show, {
|
|
373
|
+
get when() {
|
|
374
|
+
return _$memo(() => !!props.renderError)() ? error() : null;
|
|
291
375
|
},
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return message();
|
|
297
|
-
},
|
|
298
|
-
get action() {
|
|
299
|
-
return (
|
|
300
|
-
// One retry at a time: the render action moves here only where the toolbar no longer offers it.
|
|
301
|
-
_$memo(() => !!renderable())() ? undefined : (() => {
|
|
302
|
-
var _el$26 = _$getNextElement(_tmpl$7);
|
|
303
|
-
_el$26.$$click = () => void load();
|
|
304
|
-
_$use(element => errorRetryButton = element, _el$26);
|
|
305
|
-
_$insert(_el$26, () => props.buttonLabel ?? messages().retry);
|
|
306
|
-
_$effect(() => _$setProperty(_el$26, "disabled", opening() || props.disabled?.()));
|
|
307
|
-
_$runHydrationEvents();
|
|
308
|
-
return _el$26;
|
|
309
|
-
})()
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
})
|
|
376
|
+
get fallback() {
|
|
377
|
+
return viewerBox();
|
|
378
|
+
},
|
|
379
|
+
children: message => props.renderError?.(message())
|
|
313
380
|
});
|
|
314
381
|
if (props.children) return props.children({
|
|
315
382
|
get actions() {
|
|
@@ -320,27 +387,27 @@ export default function PdfPreview(props) {
|
|
|
320
387
|
}
|
|
321
388
|
});
|
|
322
389
|
return (() => {
|
|
323
|
-
var _el$
|
|
324
|
-
_el$
|
|
325
|
-
_el$
|
|
326
|
-
_el$
|
|
327
|
-
[_el$
|
|
328
|
-
_el$
|
|
329
|
-
[_el$
|
|
330
|
-
_$insert(_el$
|
|
390
|
+
var _el$32 = _$getNextElement(_tmpl$0),
|
|
391
|
+
_el$33 = _el$32.firstChild,
|
|
392
|
+
_el$34 = _el$33.firstChild,
|
|
393
|
+
_el$36 = _el$34.nextSibling,
|
|
394
|
+
[_el$37, _co$1] = _$getNextMarker(_el$36.nextSibling),
|
|
395
|
+
_el$38 = _el$33.nextSibling,
|
|
396
|
+
[_el$39, _co$10] = _$getNextMarker(_el$38.nextSibling);
|
|
397
|
+
_$insert(_el$34, _$createComponent(Show, {
|
|
331
398
|
get when() {
|
|
332
399
|
return props.title;
|
|
333
400
|
},
|
|
334
401
|
get children() {
|
|
335
|
-
var _el$
|
|
336
|
-
_$insert(_el$
|
|
337
|
-
return _el$
|
|
402
|
+
var _el$35 = _$getNextElement(_tmpl$9);
|
|
403
|
+
_$insert(_el$35, () => props.title);
|
|
404
|
+
return _el$35;
|
|
338
405
|
}
|
|
339
406
|
}));
|
|
340
|
-
_$insert(_el$
|
|
341
|
-
_$insert(_el$
|
|
342
|
-
_$effect(() => _$className(_el$
|
|
343
|
-
return _el$
|
|
407
|
+
_$insert(_el$33, actions, _el$37, _co$1);
|
|
408
|
+
_$insert(_el$32, content, _el$39, _co$10);
|
|
409
|
+
_$effect(() => _$className(_el$32, `k2b-content-pdf-preview ${props.class ?? ""}`));
|
|
410
|
+
return _el$32;
|
|
344
411
|
})();
|
|
345
412
|
}
|
|
346
413
|
_$delegateEvents(["click"]);
|