@joewinke/jatui 0.2.12 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/attention.js +21 -13
- package/dist/actions/collapse.js +15 -29
- package/dist/actions/floating.js +29 -37
- package/dist/actions/listNav.js +108 -137
- package/dist/actions/railNav.js +72 -89
- package/dist/actions/staggerEntrance.js +19 -23
- package/dist/actions/tooltip.js +63 -51
- package/dist/assets/sounds/error.js +1 -1
- package/dist/assets/sounds/notify.js +1 -1
- package/dist/assets/sounds/pop.js +1 -1
- package/dist/assets/sounds/send.js +1 -1
- package/dist/assets/sounds/success.js +1 -1
- package/dist/assets/sounds/toggle.js +1 -1
- package/dist/components/graph/theme.js +26 -36
- package/dist/components/markup.js +59 -62
- package/dist/components/session-nav/transcriptModel.js +49 -66
- package/dist/components/shell/shell.js +14 -15
- package/dist/components/table/flexRender.js +2 -2
- package/dist/data/emojis.js +4 -4
- package/dist/dnd/autoScroll.js +10 -12
- package/dist/dnd/createDndBoard.js +94 -185
- package/dist/dnd/draggable.js +15 -23
- package/dist/dnd/dropTarget.js +15 -29
- package/dist/dnd/types.d.ts +9 -0
- package/dist/dnd/types.js +2 -14
- package/dist/showcase/generative/intent.js +19 -21
- package/dist/showcase/generative/manifest.js +27 -80
- package/dist/showcase/scroll/scrollProgress.js +20 -22
- package/dist/showcase/scroll/scrollReveal.js +17 -20
- package/dist/stores/commandPalette.js +18 -46
- package/dist/stores/confirmDialog.js +9 -9
- package/dist/stores/inputDialog.js +9 -9
- package/dist/stores/toast.js +10 -33
- package/dist/transitions/glide.js +29 -25
- package/dist/types/booking.js +4 -4
- package/dist/types/comments.js +2 -2
- package/dist/types/messaging.js +3 -3
- package/dist/types/pipeline.js +2 -2
- package/dist/utils/currency.js +2 -4
- package/dist/utils/daisyuiColors.js +25 -27
- package/dist/utils/dateFormatters.js +44 -44
- package/dist/utils/googleMapsLoader.js +46 -100
- package/dist/utils/mentionParser.js +30 -30
- package/dist/utils/phone.js +21 -27
- package/dist/utils/phoneFormat.js +9 -9
- package/dist/utils/sound.js +27 -78
- package/dist/utils/splitText.js +15 -26
- package/dist/utils/taskUtils.js +1 -1
- package/dist/utils/themeWipe.js +27 -72
- package/dist/utils/viewTransition.js +6 -51
- package/package.json +7 -3
- package/dist/dnd/createDndBoard.test.d.ts +0 -1
- package/dist/dnd/createDndBoard.test.js +0 -261
package/dist/utils/phone.js
CHANGED
|
@@ -1,34 +1,31 @@
|
|
|
1
1
|
import { parsePhoneNumberFromString, getCountries, getCountryCallingCode, } from "libphonenumber-js";
|
|
2
|
-
export
|
|
3
|
-
export function toE164(raw, defaultCountry) {
|
|
4
|
-
if (defaultCountry === void 0) { defaultCountry = DEFAULT_COUNTRY; }
|
|
2
|
+
export const DEFAULT_COUNTRY = "US";
|
|
3
|
+
export function toE164(raw, defaultCountry = DEFAULT_COUNTRY) {
|
|
5
4
|
if (!raw)
|
|
6
5
|
return null;
|
|
7
|
-
|
|
6
|
+
const trimmed = raw.trim();
|
|
8
7
|
if (!trimmed)
|
|
9
8
|
return null;
|
|
10
|
-
|
|
11
|
-
if (parsed
|
|
9
|
+
const parsed = parsePhoneNumberFromString(trimmed, defaultCountry);
|
|
10
|
+
if (parsed?.isValid())
|
|
12
11
|
return parsed.number;
|
|
13
12
|
return null;
|
|
14
13
|
}
|
|
15
14
|
export function formatPhoneForDisplay(e164) {
|
|
16
15
|
if (!e164)
|
|
17
16
|
return "";
|
|
18
|
-
|
|
17
|
+
const parsed = parsePhoneNumberFromString(e164);
|
|
19
18
|
if (!parsed)
|
|
20
19
|
return e164;
|
|
21
20
|
return parsed.country === DEFAULT_COUNTRY ? parsed.formatNational() : parsed.formatInternational();
|
|
22
21
|
}
|
|
23
|
-
export function isValidPhone(raw, defaultCountry) {
|
|
24
|
-
var _a;
|
|
25
|
-
if (defaultCountry === void 0) { defaultCountry = DEFAULT_COUNTRY; }
|
|
22
|
+
export function isValidPhone(raw, defaultCountry = DEFAULT_COUNTRY) {
|
|
26
23
|
if (!raw)
|
|
27
24
|
return false;
|
|
28
|
-
|
|
29
|
-
return
|
|
25
|
+
const parsed = parsePhoneNumberFromString(raw.trim(), defaultCountry);
|
|
26
|
+
return parsed?.isValid() ?? false;
|
|
30
27
|
}
|
|
31
|
-
|
|
28
|
+
const COUNTRY_NAMES = {
|
|
32
29
|
US: "United States", CA: "Canada", GB: "United Kingdom", AU: "Australia", NZ: "New Zealand",
|
|
33
30
|
IE: "Ireland", DE: "Germany", FR: "France", ES: "Spain", IT: "Italy", NL: "Netherlands",
|
|
34
31
|
BE: "Belgium", CH: "Switzerland", AT: "Austria", SE: "Sweden", NO: "Norway", DK: "Denmark",
|
|
@@ -43,25 +40,22 @@ function flagEmoji(code) {
|
|
|
43
40
|
return code
|
|
44
41
|
.toUpperCase()
|
|
45
42
|
.split("")
|
|
46
|
-
.map(
|
|
43
|
+
.map((c) => String.fromCodePoint(127397 + c.charCodeAt(0)))
|
|
47
44
|
.join("");
|
|
48
45
|
}
|
|
49
|
-
|
|
46
|
+
let countriesCache = null;
|
|
50
47
|
export function listCountries() {
|
|
51
48
|
if (countriesCache)
|
|
52
49
|
return countriesCache;
|
|
53
|
-
|
|
54
|
-
.map(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
});
|
|
62
|
-
})
|
|
63
|
-
.sort(function (a, b) { return a.name.localeCompare(b.name); });
|
|
50
|
+
const all = getCountries()
|
|
51
|
+
.map((code) => ({
|
|
52
|
+
code,
|
|
53
|
+
name: COUNTRY_NAMES[code] ?? code,
|
|
54
|
+
dialCode: `+${getCountryCallingCode(code)}`,
|
|
55
|
+
flag: flagEmoji(code),
|
|
56
|
+
}))
|
|
57
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
64
58
|
countriesCache = all;
|
|
65
59
|
return all;
|
|
66
60
|
}
|
|
67
|
-
export
|
|
61
|
+
export const PRIORITY_COUNTRIES = ["US", "CA", "GB", "AU", "MX"];
|
|
@@ -14,19 +14,19 @@ export function stripPhoneNumber(value) {
|
|
|
14
14
|
* Formats a phone number to (xxx) xxx-xxxx format
|
|
15
15
|
*/
|
|
16
16
|
export function formatPhoneNumber(value) {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const digits = stripPhoneNumber(value);
|
|
18
|
+
const limitedDigits = digits.slice(0, 10);
|
|
19
19
|
if (limitedDigits.length === 0) {
|
|
20
20
|
return '';
|
|
21
21
|
}
|
|
22
22
|
else if (limitedDigits.length <= 3) {
|
|
23
|
-
return
|
|
23
|
+
return `(${limitedDigits}`;
|
|
24
24
|
}
|
|
25
25
|
else if (limitedDigits.length <= 6) {
|
|
26
|
-
return
|
|
26
|
+
return `(${limitedDigits.slice(0, 3)}) ${limitedDigits.slice(3)}`;
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
|
-
return
|
|
29
|
+
return `(${limitedDigits.slice(0, 3)}) ${limitedDigits.slice(3, 6)}-${limitedDigits.slice(6)}`;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
@@ -45,11 +45,11 @@ export function isValidPhoneNumber(value) {
|
|
|
45
45
|
* Handles input formatting with cursor position preservation
|
|
46
46
|
*/
|
|
47
47
|
export function updatePhoneInput(input, newValue, oldValue) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
const cursorPosition = input.selectionStart || 0;
|
|
49
|
+
const oldLength = oldValue.length;
|
|
50
|
+
const newLength = newValue.length;
|
|
51
51
|
input.value = newValue;
|
|
52
|
-
|
|
52
|
+
let newCursorPosition = cursorPosition;
|
|
53
53
|
if (newLength > oldLength) {
|
|
54
54
|
newCursorPosition = cursorPosition + (newLength - oldLength);
|
|
55
55
|
}
|
package/dist/utils/sound.js
CHANGED
|
@@ -1,42 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
-
function step(op) {
|
|
15
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
-
switch (op[0]) {
|
|
20
|
-
case 0: case 1: t = op; break;
|
|
21
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
-
default:
|
|
25
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
-
if (t[2]) _.ops.pop();
|
|
30
|
-
_.trys.pop(); continue;
|
|
31
|
-
}
|
|
32
|
-
op = body.call(thisArg, _);
|
|
33
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
var ctx = null;
|
|
38
|
-
var buffers = new Map();
|
|
39
|
-
var STORAGE_KEY = 'jatui-sound-enabled';
|
|
1
|
+
let ctx = null;
|
|
2
|
+
const buffers = new Map();
|
|
3
|
+
const STORAGE_KEY = 'jatui-sound-enabled';
|
|
40
4
|
function getContext() {
|
|
41
5
|
if (ctx)
|
|
42
6
|
return ctx;
|
|
@@ -44,7 +8,7 @@ function getContext() {
|
|
|
44
8
|
ctx = new AudioContext();
|
|
45
9
|
return ctx;
|
|
46
10
|
}
|
|
47
|
-
catch
|
|
11
|
+
catch {
|
|
48
12
|
return null;
|
|
49
13
|
}
|
|
50
14
|
}
|
|
@@ -58,54 +22,39 @@ export function setSoundEnabled(enabled) {
|
|
|
58
22
|
return;
|
|
59
23
|
localStorage.setItem(STORAGE_KEY, String(enabled));
|
|
60
24
|
}
|
|
61
|
-
export function registerSound(name, dataUri) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
bytes[i] = binary.charCodeAt(i);
|
|
78
|
-
return [4 /*yield*/, audioCtx.decodeAudioData(bytes.buffer)];
|
|
79
|
-
case 2:
|
|
80
|
-
buffer = _b.sent();
|
|
81
|
-
buffers.set(name, buffer);
|
|
82
|
-
return [3 /*break*/, 4];
|
|
83
|
-
case 3:
|
|
84
|
-
_a = _b.sent();
|
|
85
|
-
return [3 /*break*/, 4];
|
|
86
|
-
case 4: return [2 /*return*/];
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
});
|
|
25
|
+
export async function registerSound(name, dataUri) {
|
|
26
|
+
const audioCtx = getContext();
|
|
27
|
+
if (!audioCtx)
|
|
28
|
+
return;
|
|
29
|
+
try {
|
|
30
|
+
const base64 = dataUri.split(',')[1];
|
|
31
|
+
const binary = atob(base64);
|
|
32
|
+
const bytes = new Uint8Array(binary.length);
|
|
33
|
+
for (let i = 0; i < binary.length; i++)
|
|
34
|
+
bytes[i] = binary.charCodeAt(i);
|
|
35
|
+
const buffer = await audioCtx.decodeAudioData(bytes.buffer);
|
|
36
|
+
buffers.set(name, buffer);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Silently ignore decode failures — clip may not be supported in this browser
|
|
40
|
+
}
|
|
90
41
|
}
|
|
91
|
-
export function play(name, options) {
|
|
92
|
-
var _a;
|
|
93
|
-
if (options === void 0) { options = {}; }
|
|
42
|
+
export function play(name, options = {}) {
|
|
94
43
|
if (!isSoundEnabled())
|
|
95
44
|
return;
|
|
96
|
-
|
|
45
|
+
const audioCtx = getContext();
|
|
97
46
|
if (!audioCtx)
|
|
98
47
|
return;
|
|
99
|
-
|
|
48
|
+
const buffer = buffers.get(name);
|
|
100
49
|
if (!buffer)
|
|
101
50
|
return;
|
|
102
51
|
// Resume suspended context (browser autoplay policy requires user gesture first)
|
|
103
52
|
if (audioCtx.state === 'suspended') {
|
|
104
|
-
audioCtx.resume().catch(
|
|
53
|
+
audioCtx.resume().catch(() => { });
|
|
105
54
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
gain.gain.value =
|
|
55
|
+
const source = audioCtx.createBufferSource();
|
|
56
|
+
const gain = audioCtx.createGain();
|
|
57
|
+
gain.gain.value = options.volume ?? 0.15;
|
|
109
58
|
source.buffer = buffer;
|
|
110
59
|
source.connect(gain);
|
|
111
60
|
gain.connect(audioCtx.destination);
|
package/dist/utils/splitText.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
// Pattern after Splitting.js (MIT) — https://github.com/shshaw/Splitting
|
|
2
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
3
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
4
|
-
if (ar || !(i in from)) {
|
|
5
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
6
|
-
ar[i] = from[i];
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
-
};
|
|
11
2
|
/**
|
|
12
3
|
* Wraps text content of `node` into `<span>` elements and stamps CSS custom
|
|
13
4
|
* properties so pure-CSS animations can stagger by index.
|
|
@@ -23,35 +14,33 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
23
14
|
* are flattened back to text before the new split.
|
|
24
15
|
*/
|
|
25
16
|
export function splitText(node, options) {
|
|
26
|
-
|
|
27
|
-
var by = options.by;
|
|
17
|
+
const { by } = options;
|
|
28
18
|
// Capture original text and restore any previous split.
|
|
29
|
-
|
|
19
|
+
const originalText = node.getAttribute('data-split-original') ?? node.textContent ?? '';
|
|
30
20
|
restoreNode(node, originalText);
|
|
31
21
|
// Set accessibility label so the unsplit text is announced.
|
|
32
22
|
node.setAttribute('aria-label', originalText);
|
|
33
23
|
node.setAttribute('data-split-original', originalText);
|
|
34
24
|
node.setAttribute('data-split-by', by);
|
|
35
|
-
|
|
25
|
+
let count = 0;
|
|
36
26
|
if (by === 'char') {
|
|
37
|
-
|
|
27
|
+
const chars = [...originalText]; // Unicode-aware
|
|
38
28
|
count = chars.length;
|
|
39
29
|
node.innerHTML = '';
|
|
40
|
-
for (
|
|
30
|
+
for (let i = 0; i < chars.length; i++) {
|
|
41
31
|
node.appendChild(makeSpan(chars[i], '--char-index', i, '--char-total', count));
|
|
42
32
|
}
|
|
43
33
|
}
|
|
44
34
|
else if (by === 'word') {
|
|
45
35
|
// Split preserving whitespace tokens so spaces render correctly.
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
const tokens = originalText.split(/(\s+)/);
|
|
37
|
+
const words = tokens.filter((t) => !/^\s+$/.test(t));
|
|
48
38
|
count = words.length;
|
|
49
39
|
node.innerHTML = '';
|
|
50
|
-
|
|
51
|
-
for (
|
|
52
|
-
var token = tokens_1[_i];
|
|
40
|
+
let wordIdx = 0;
|
|
41
|
+
for (const token of tokens) {
|
|
53
42
|
if (/^\s+$/.test(token)) {
|
|
54
|
-
|
|
43
|
+
const space = document.createElement('span');
|
|
55
44
|
space.setAttribute('aria-hidden', 'true');
|
|
56
45
|
space.style.whiteSpace = 'pre';
|
|
57
46
|
space.textContent = token;
|
|
@@ -64,22 +53,22 @@ export function splitText(node, options) {
|
|
|
64
53
|
}
|
|
65
54
|
else {
|
|
66
55
|
// 'line' — split by newline characters in the original text.
|
|
67
|
-
|
|
56
|
+
const lines = originalText.split('\n');
|
|
68
57
|
count = lines.length;
|
|
69
58
|
node.innerHTML = '';
|
|
70
|
-
for (
|
|
59
|
+
for (let i = 0; i < lines.length; i++) {
|
|
71
60
|
if (i > 0)
|
|
72
61
|
node.appendChild(document.createTextNode('\n'));
|
|
73
62
|
node.appendChild(makeSpan(lines[i], '--line-index', i, '--line-total', count));
|
|
74
63
|
}
|
|
75
64
|
}
|
|
76
65
|
return {
|
|
77
|
-
count
|
|
78
|
-
cleanup:
|
|
66
|
+
count,
|
|
67
|
+
cleanup: () => restoreNode(node, originalText)
|
|
79
68
|
};
|
|
80
69
|
}
|
|
81
70
|
function makeSpan(text, indexVar, index, totalVar, total) {
|
|
82
|
-
|
|
71
|
+
const span = document.createElement('span');
|
|
83
72
|
span.setAttribute('aria-hidden', 'true');
|
|
84
73
|
span.style.setProperty(indexVar, String(index));
|
|
85
74
|
span.style.setProperty(totalVar, String(total));
|
package/dist/utils/taskUtils.js
CHANGED
|
@@ -67,5 +67,5 @@ export function typeIcon(type) {
|
|
|
67
67
|
* "in_progress" → "In Progress"
|
|
68
68
|
*/
|
|
69
69
|
export function statusLabel(status) {
|
|
70
|
-
return status.replace(/_/g, ' ').replace(/\b\w/g,
|
|
70
|
+
return status.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
71
71
|
}
|
package/dist/utils/themeWipe.js
CHANGED
|
@@ -9,44 +9,8 @@
|
|
|
9
9
|
* prefers-reduced-motion is set, applyTheme() runs synchronously with no
|
|
10
10
|
* animation.
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
23
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
-
function step(op) {
|
|
26
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
29
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
-
switch (op[0]) {
|
|
31
|
-
case 0: case 1: t = op; break;
|
|
32
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
-
default:
|
|
36
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
-
if (t[2]) _.ops.pop();
|
|
41
|
-
_.trys.pop(); continue;
|
|
42
|
-
}
|
|
43
|
-
op = body.call(thisArg, _);
|
|
44
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var DURATION = 500;
|
|
49
|
-
var EASING = 'cubic-bezier(0.16, 1, 0.3, 1)'; // --motion-glide fallback
|
|
12
|
+
const DURATION = 500;
|
|
13
|
+
const EASING = 'cubic-bezier(0.16, 1, 0.3, 1)'; // --motion-glide fallback
|
|
50
14
|
/**
|
|
51
15
|
* @param event - The click (or pointer) event that triggered the theme toggle.
|
|
52
16
|
* Used to anchor the reveal circle. Pass null to default to
|
|
@@ -56,39 +20,30 @@ var EASING = 'cubic-bezier(0.16, 1, 0.3, 1)'; // --motion-glide fallback
|
|
|
56
20
|
* inside the startViewTransition callback so the snapshot
|
|
57
21
|
* captures the old state and the new DOM is recorded after.
|
|
58
22
|
*/
|
|
59
|
-
export function themeWipe(event, applyTheme) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
{ clipPath: "circle(".concat(endRadius, "px at ").concat(x, "px ").concat(y, "px)") }
|
|
85
|
-
], {
|
|
86
|
-
duration: DURATION,
|
|
87
|
-
easing: resolvedEasing,
|
|
88
|
-
pseudoElement: '::view-transition-new(root)'
|
|
89
|
-
});
|
|
90
|
-
return [2 /*return*/];
|
|
91
|
-
}
|
|
92
|
-
});
|
|
23
|
+
export async function themeWipe(event, applyTheme) {
|
|
24
|
+
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
25
|
+
if (prefersReduced || !document.startViewTransition) {
|
|
26
|
+
applyTheme();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Origin: click point or viewport center
|
|
30
|
+
const x = event ? event.clientX : window.innerWidth / 2;
|
|
31
|
+
const y = event ? event.clientY : window.innerHeight / 2;
|
|
32
|
+
// Radius that covers the entire viewport from the click origin
|
|
33
|
+
const endRadius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y));
|
|
34
|
+
const transition = document.startViewTransition(applyTheme);
|
|
35
|
+
// Wait until both snapshots are captured before animating
|
|
36
|
+
await transition.ready;
|
|
37
|
+
// Read the resolved --motion-glide easing from CSS custom properties
|
|
38
|
+
const resolvedEasing = getComputedStyle(document.documentElement)
|
|
39
|
+
.getPropertyValue('--motion-glide')
|
|
40
|
+
.trim() || EASING;
|
|
41
|
+
document.documentElement.animate([
|
|
42
|
+
{ clipPath: `circle(0px at ${x}px ${y}px)` },
|
|
43
|
+
{ clipPath: `circle(${endRadius}px at ${x}px ${y}px)` }
|
|
44
|
+
], {
|
|
45
|
+
duration: DURATION,
|
|
46
|
+
easing: resolvedEasing,
|
|
47
|
+
pseudoElement: '::view-transition-new(root)'
|
|
93
48
|
});
|
|
94
49
|
}
|
|
@@ -16,60 +16,15 @@
|
|
|
16
16
|
* proceeds normally. prefers-reduced-motion is honoured automatically by the
|
|
17
17
|
* browser's View Transitions implementation; no extra guard is needed here.
|
|
18
18
|
*/
|
|
19
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
20
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
21
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
22
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
23
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
24
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
25
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
29
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
30
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
31
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
32
|
-
function step(op) {
|
|
33
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
34
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
35
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
36
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
37
|
-
switch (op[0]) {
|
|
38
|
-
case 0: case 1: t = op; break;
|
|
39
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
40
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
41
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
42
|
-
default:
|
|
43
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
44
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
45
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
46
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
47
|
-
if (t[2]) _.ops.pop();
|
|
48
|
-
_.trys.pop(); continue;
|
|
49
|
-
}
|
|
50
|
-
op = body.call(thisArg, _);
|
|
51
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
52
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
19
|
export function viewTransition(onNavigate) {
|
|
56
|
-
|
|
57
|
-
onNavigate(function (navigation) {
|
|
20
|
+
onNavigate((navigation) => {
|
|
58
21
|
if (!document.startViewTransition)
|
|
59
22
|
return;
|
|
60
|
-
return new Promise(
|
|
61
|
-
document.startViewTransition(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
resolve();
|
|
66
|
-
return [4 /*yield*/, navigation.complete];
|
|
67
|
-
case 1:
|
|
68
|
-
_a.sent();
|
|
69
|
-
return [2 /*return*/];
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}); });
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
document.startViewTransition(async () => {
|
|
25
|
+
resolve();
|
|
26
|
+
await navigation.complete;
|
|
27
|
+
});
|
|
73
28
|
});
|
|
74
29
|
});
|
|
75
30
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joewinke/jatui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared Svelte 5 component library for JAT projects",
|
|
6
6
|
"type": "module",
|
|
@@ -67,7 +67,8 @@
|
|
|
67
67
|
"build": "vite build",
|
|
68
68
|
"build:site": "npm run package && vite build",
|
|
69
69
|
"preview": "vite preview",
|
|
70
|
-
"package": "svelte-package --input src/lib --output dist && node scripts/compile-rune-modules.mjs",
|
|
70
|
+
"package": "svelte-kit sync && svelte-package --input src/lib --output dist && node scripts/compile-rune-modules.mjs && node scripts/verify-dist.mjs",
|
|
71
|
+
"test:dist": "vitest run --config vitest.dist.config.ts",
|
|
71
72
|
"check:demos": "node scripts/check-demo-coverage.mjs",
|
|
72
73
|
"guard": "node scripts/check-demo-coverage.mjs",
|
|
73
74
|
"prepublishOnly": "node scripts/guard-ci-publish.mjs && npm run package"
|
|
@@ -158,7 +159,10 @@
|
|
|
158
159
|
"svelte": "^5.0.0",
|
|
159
160
|
"tailwindcss": "^4.0.0",
|
|
160
161
|
"typescript": "^5.0.0",
|
|
161
|
-
"vite": "^6.0.0"
|
|
162
|
+
"vite": "^6.0.0",
|
|
163
|
+
"@vitest/browser": "^3.2.0",
|
|
164
|
+
"playwright": "^1.53.0",
|
|
165
|
+
"vitest": "^3.2.0"
|
|
162
166
|
},
|
|
163
167
|
"dependencies": {
|
|
164
168
|
"diff": "^9.0.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|