@warmio/ui 1.2.0 → 1.4.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 +11 -9
- package/dist/button.js +1 -3
- package/dist/chunks/{chunk-D25QMXJR.js → chunk-4RQCHKAW.js} +28 -8
- package/dist/chunks/{chunk-UB25BRXT.js → chunk-FW2EHGRK.js} +129 -72
- package/dist/chunks/chunk-GKEYV2XW.js +10 -0
- package/dist/chunks/chunk-HDCV4ACN.js +469 -0
- package/dist/chunks/{chunk-SK7IZUFC.js → chunk-KN6WVLCR.js} +6 -78
- package/dist/chunks/{chunk-ZEDHNFX6.js → chunk-MIMC4M6W.js} +5 -11
- package/dist/chunks/{chunk-4UZNCKKG.js → chunk-PBWF6BDE.js} +11 -4
- package/dist/chunks/chunk-YTDMREDR.js +201 -0
- package/dist/dropdown-menu.js +1 -1
- package/dist/index.js +16 -9
- package/dist/logo.js +7 -1
- package/dist/product-header.js +1 -1
- package/dist/product-header.types.d.ts +9 -8
- package/dist/sheet.js +2 -3
- package/dist/sidebar.js +4 -3
- package/dist/text.js +1 -1
- package/package.json +2 -2
- package/types/badge.d.ts +1 -0
- package/types/button.d.ts +9 -48
- package/types/dropdown-menu.d.ts +2 -2
- package/types/index.d.ts +113 -8
- package/types/logo.d.ts +8 -25
- package/types/sheet.d.ts +1 -4
- package/types/sidebar.d.ts +2 -1
- package/types/text.d.ts +3 -1
- package/dist/chunks/chunk-KCEDMF2I.js +0 -124
- package/dist/chunks/chunk-OWDC2VC6.js +0 -135
- package/dist/chunks/chunk-T2TXMN3G.js +0 -74
- package/dist/chunks/chunk-VNQVIATP.js +0 -91
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-VIB7OX7D.js";
|
|
4
|
+
|
|
5
|
+
// ../ui/src/warmio/flame-expression-video.tsx
|
|
6
|
+
import { useRef } from "react";
|
|
7
|
+
|
|
8
|
+
// ../ui/src/warmio/flame-expression-videos.ts
|
|
9
|
+
var FLAME_EXPRESSION_VIDEO_PACK = "v4";
|
|
10
|
+
var FLAME_EXPRESSION_VIDEO_IDS = ["NORMAL", "LUL", "POG", "CRY", "LOVE", "HYPE"];
|
|
11
|
+
var LEGACY_MASCOT_MOOD_TO_EXPRESSION = {
|
|
12
|
+
calm: "NORMAL",
|
|
13
|
+
happy: "LUL",
|
|
14
|
+
focused: "NORMAL",
|
|
15
|
+
relieved: "LOVE",
|
|
16
|
+
/** @deprecated Use peekEyes="closed" on auth peek instead. */
|
|
17
|
+
"password-retry": "NORMAL",
|
|
18
|
+
frustrated: "CRY"
|
|
19
|
+
};
|
|
20
|
+
function isLegacyMascotMood(expression) {
|
|
21
|
+
return Object.hasOwn(LEGACY_MASCOT_MOOD_TO_EXPRESSION, expression);
|
|
22
|
+
}
|
|
23
|
+
function isFlameExpressionVideoId(expression) {
|
|
24
|
+
for (const id of FLAME_EXPRESSION_VIDEO_IDS) {
|
|
25
|
+
if (id === expression) return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
function getFlameExpressionVideoSrc(expression, theme) {
|
|
30
|
+
return `/flame-expressions/${FLAME_EXPRESSION_VIDEO_PACK}/${expression}/open_${theme}.mp4`;
|
|
31
|
+
}
|
|
32
|
+
function getFlameMascotPeekVideoSrc(eyes, theme) {
|
|
33
|
+
return `/mascot/${eyes}_${theme}.mp4`;
|
|
34
|
+
}
|
|
35
|
+
function resolveFlameExpressionVideoId(expression) {
|
|
36
|
+
if (!expression) return "NORMAL";
|
|
37
|
+
if (isLegacyMascotMood(expression)) {
|
|
38
|
+
return LEGACY_MASCOT_MOOD_TO_EXPRESSION[expression];
|
|
39
|
+
}
|
|
40
|
+
if (isFlameExpressionVideoId(expression)) {
|
|
41
|
+
return expression;
|
|
42
|
+
}
|
|
43
|
+
return "NORMAL";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ../ui/src/warmio/flame-expression-video.tsx
|
|
47
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
48
|
+
var LIGHT_KEY = 247;
|
|
49
|
+
var DARK_KEY = 17;
|
|
50
|
+
var HARD_KEY = 16;
|
|
51
|
+
var SOFT_KEY = 42;
|
|
52
|
+
function prefersReducedMotion() {
|
|
53
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
54
|
+
}
|
|
55
|
+
function isDarkDocument() {
|
|
56
|
+
return document.documentElement.classList.contains("dark");
|
|
57
|
+
}
|
|
58
|
+
function pixelChannel(pixels, index) {
|
|
59
|
+
const value = pixels[index];
|
|
60
|
+
if (value === void 0) throw new Error("Canvas pixel data is unexpectedly sparse");
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
function isDarkForRoot(root) {
|
|
64
|
+
const theme = root.dataset["flameTheme"];
|
|
65
|
+
if (theme === "dark") return true;
|
|
66
|
+
if (theme === "light") return false;
|
|
67
|
+
return isDarkDocument();
|
|
68
|
+
}
|
|
69
|
+
function punchKeyedBackground(context, width, height, dark) {
|
|
70
|
+
const frame = context.getImageData(0, 0, width, height);
|
|
71
|
+
const pixels = frame.data;
|
|
72
|
+
const key = dark ? DARK_KEY : LIGHT_KEY;
|
|
73
|
+
for (let index = 0; index < pixels.length; index += 4) {
|
|
74
|
+
const red = pixelChannel(pixels, index);
|
|
75
|
+
const green = pixelChannel(pixels, index + 1);
|
|
76
|
+
const blue = pixelChannel(pixels, index + 2);
|
|
77
|
+
if (!dark) {
|
|
78
|
+
const minChannel = Math.min(red, green, blue);
|
|
79
|
+
if (minChannel > LIGHT_KEY) {
|
|
80
|
+
pixels[index] = 255;
|
|
81
|
+
pixels[index + 1] = 255;
|
|
82
|
+
pixels[index + 2] = 255;
|
|
83
|
+
pixels[index + 3] = 255;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const distance = Math.max(Math.abs(red - key), Math.abs(green - key), Math.abs(blue - key));
|
|
88
|
+
if (distance <= HARD_KEY) {
|
|
89
|
+
pixels[index + 3] = 0;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (distance < SOFT_KEY) {
|
|
93
|
+
const alpha = pixelChannel(pixels, index + 3);
|
|
94
|
+
pixels[index + 3] = Math.round(alpha * ((distance - HARD_KEY) / (SOFT_KEY - HARD_KEY)));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
context.putImageData(frame, 0, 0);
|
|
98
|
+
}
|
|
99
|
+
function syncCanvasSize(canvas, context) {
|
|
100
|
+
const cssSize = canvas.clientWidth;
|
|
101
|
+
if (cssSize === 0) return false;
|
|
102
|
+
const pixelRatio = Math.min(Math.max(window.devicePixelRatio || 1, 2), 3);
|
|
103
|
+
const nextSize = Math.max(1, Math.round(cssSize * pixelRatio));
|
|
104
|
+
if (canvas.width !== nextSize || canvas.height !== nextSize) {
|
|
105
|
+
canvas.width = nextSize;
|
|
106
|
+
canvas.height = nextSize;
|
|
107
|
+
}
|
|
108
|
+
context.imageSmoothingEnabled = true;
|
|
109
|
+
context.imageSmoothingQuality = "high";
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
function drawKeyedFrame(video, canvas, context, dark) {
|
|
113
|
+
if (!syncCanvasSize(canvas, context) || video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
117
|
+
punchKeyedBackground(context, canvas.width, canvas.height, dark);
|
|
118
|
+
}
|
|
119
|
+
function sourceForTheme(video, dark) {
|
|
120
|
+
return dark ? video.dataset["darkSrc"] : video.dataset["lightSrc"];
|
|
121
|
+
}
|
|
122
|
+
function bindKeyedExpressionVideo(root) {
|
|
123
|
+
if (root.dataset["bound"] === "true") return () => void 0;
|
|
124
|
+
root.dataset["bound"] = "true";
|
|
125
|
+
const video = root.querySelector("[data-flame-expression-video-source]");
|
|
126
|
+
const canvas = root.querySelector("[data-flame-expression-video-frame]");
|
|
127
|
+
if (!video || !canvas) {
|
|
128
|
+
delete root.dataset["bound"];
|
|
129
|
+
return () => void 0;
|
|
130
|
+
}
|
|
131
|
+
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
132
|
+
if (!context) {
|
|
133
|
+
root.hidden = true;
|
|
134
|
+
delete root.dataset["bound"];
|
|
135
|
+
return () => void 0;
|
|
136
|
+
}
|
|
137
|
+
let dark = isDarkForRoot(root);
|
|
138
|
+
let playing = false;
|
|
139
|
+
let visible = true;
|
|
140
|
+
let frameHandle = 0;
|
|
141
|
+
let lastVideoTime = -1;
|
|
142
|
+
const reducedMotion = prefersReducedMotion();
|
|
143
|
+
let loadedDataListener = null;
|
|
144
|
+
const drawFrame = () => {
|
|
145
|
+
const nextDark = isDarkForRoot(root);
|
|
146
|
+
if (nextDark !== dark) {
|
|
147
|
+
applyTheme(nextDark);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
drawKeyedFrame(video, canvas, context, dark);
|
|
151
|
+
};
|
|
152
|
+
const stopLoop = () => {
|
|
153
|
+
cancelAnimationFrame(frameHandle);
|
|
154
|
+
frameHandle = 0;
|
|
155
|
+
lastVideoTime = -1;
|
|
156
|
+
};
|
|
157
|
+
const loop = () => {
|
|
158
|
+
if (!playing || reducedMotion) return;
|
|
159
|
+
if (video.currentTime !== lastVideoTime) {
|
|
160
|
+
lastVideoTime = video.currentTime;
|
|
161
|
+
drawFrame();
|
|
162
|
+
}
|
|
163
|
+
frameHandle = requestAnimationFrame(loop);
|
|
164
|
+
};
|
|
165
|
+
const startLoop = () => {
|
|
166
|
+
if (playing || reducedMotion) {
|
|
167
|
+
drawFrame();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
playing = true;
|
|
171
|
+
void video.play().catch(() => void 0);
|
|
172
|
+
loop();
|
|
173
|
+
};
|
|
174
|
+
const pauseLoop = () => {
|
|
175
|
+
playing = false;
|
|
176
|
+
video.pause();
|
|
177
|
+
stopLoop();
|
|
178
|
+
};
|
|
179
|
+
const playWhenSized = () => {
|
|
180
|
+
if (root.clientWidth === 0) return;
|
|
181
|
+
drawFrame();
|
|
182
|
+
if (!visible || reducedMotion || playing) return;
|
|
183
|
+
startLoop();
|
|
184
|
+
};
|
|
185
|
+
const continueFrom = (resumeAt) => {
|
|
186
|
+
if (Number.isFinite(resumeAt) && resumeAt > 0) {
|
|
187
|
+
try {
|
|
188
|
+
video.currentTime = resumeAt;
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
drawFrame();
|
|
193
|
+
if (visible && !reducedMotion) {
|
|
194
|
+
startLoop();
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const waitForData = (resumeAt) => {
|
|
198
|
+
if (loadedDataListener) {
|
|
199
|
+
video.removeEventListener("loadeddata", loadedDataListener);
|
|
200
|
+
}
|
|
201
|
+
loadedDataListener = () => continueFrom(resumeAt);
|
|
202
|
+
if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
203
|
+
loadedDataListener();
|
|
204
|
+
loadedDataListener = null;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
video.addEventListener("loadeddata", loadedDataListener, { once: true });
|
|
208
|
+
void video.play().catch(() => void 0);
|
|
209
|
+
};
|
|
210
|
+
const applyTheme = (nextDark) => {
|
|
211
|
+
const nextSrc = sourceForTheme(video, nextDark);
|
|
212
|
+
if (!nextSrc) return;
|
|
213
|
+
const resumeAt = video.currentTime;
|
|
214
|
+
dark = nextDark;
|
|
215
|
+
const assignedSrc = video.getAttribute("src");
|
|
216
|
+
const alreadyOnSource = video.networkState !== HTMLMediaElement.NETWORK_EMPTY && (video.dataset["activeSrc"] === nextSrc || assignedSrc === nextSrc);
|
|
217
|
+
if (alreadyOnSource) {
|
|
218
|
+
video.dataset["activeSrc"] = nextSrc;
|
|
219
|
+
waitForData(resumeAt);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
pauseLoop();
|
|
223
|
+
video.dataset["activeSrc"] = nextSrc;
|
|
224
|
+
video.src = nextSrc;
|
|
225
|
+
waitForData(resumeAt);
|
|
226
|
+
};
|
|
227
|
+
syncCanvasSize(canvas, context);
|
|
228
|
+
applyTheme(dark);
|
|
229
|
+
const visibility = new IntersectionObserver(
|
|
230
|
+
(entries) => {
|
|
231
|
+
visible = entries.some((entry) => entry.isIntersecting);
|
|
232
|
+
if (!visible) {
|
|
233
|
+
pauseLoop();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (reducedMotion) {
|
|
237
|
+
drawFrame();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
startLoop();
|
|
241
|
+
},
|
|
242
|
+
{ threshold: 0 }
|
|
243
|
+
);
|
|
244
|
+
visibility.observe(root);
|
|
245
|
+
const resize = new ResizeObserver(playWhenSized);
|
|
246
|
+
resize.observe(root);
|
|
247
|
+
const themeObserver = new MutationObserver(() => {
|
|
248
|
+
const nextDark = isDarkForRoot(root);
|
|
249
|
+
if (nextDark === dark) return;
|
|
250
|
+
applyTheme(nextDark);
|
|
251
|
+
});
|
|
252
|
+
themeObserver.observe(document.documentElement, {
|
|
253
|
+
attributes: true,
|
|
254
|
+
attributeFilter: ["class"]
|
|
255
|
+
});
|
|
256
|
+
const themeOverrideObserver = new MutationObserver(() => {
|
|
257
|
+
const nextDark = isDarkForRoot(root);
|
|
258
|
+
if (nextDark === dark) return;
|
|
259
|
+
applyTheme(nextDark);
|
|
260
|
+
});
|
|
261
|
+
themeOverrideObserver.observe(root, {
|
|
262
|
+
attributes: true,
|
|
263
|
+
attributeFilter: ["data-flame-theme"]
|
|
264
|
+
});
|
|
265
|
+
return () => {
|
|
266
|
+
visibility.disconnect();
|
|
267
|
+
resize.disconnect();
|
|
268
|
+
themeObserver.disconnect();
|
|
269
|
+
themeOverrideObserver.disconnect();
|
|
270
|
+
pauseLoop();
|
|
271
|
+
if (loadedDataListener) {
|
|
272
|
+
video.removeEventListener("loadeddata", loadedDataListener);
|
|
273
|
+
}
|
|
274
|
+
video.removeAttribute("src");
|
|
275
|
+
video.load();
|
|
276
|
+
delete video.dataset["activeSrc"];
|
|
277
|
+
delete root.dataset["bound"];
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function readDomVideoTheme() {
|
|
281
|
+
if (typeof document === "undefined") return "light";
|
|
282
|
+
const mode = document.documentElement.getAttribute("data-theme-mode");
|
|
283
|
+
if (mode === "dark") return "dark";
|
|
284
|
+
if (mode === "light") return "light";
|
|
285
|
+
if (globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches) return "dark";
|
|
286
|
+
return "light";
|
|
287
|
+
}
|
|
288
|
+
function WarmFlameExpressionVideo({
|
|
289
|
+
expression: expressionProp = "NORMAL",
|
|
290
|
+
size = "default",
|
|
291
|
+
label = null,
|
|
292
|
+
theme: themeProp,
|
|
293
|
+
peekEyes
|
|
294
|
+
}) {
|
|
295
|
+
const cleanupRef = useRef(void 0);
|
|
296
|
+
const expression = resolveFlameExpressionVideoId(expressionProp);
|
|
297
|
+
const videoTheme = themeProp ?? readDomVideoTheme();
|
|
298
|
+
const lightSrc = peekEyes ? getFlameMascotPeekVideoSrc(peekEyes, "light") : getFlameExpressionVideoSrc(expression, "light");
|
|
299
|
+
const darkSrc = peekEyes ? getFlameMascotPeekVideoSrc(peekEyes, "dark") : getFlameExpressionVideoSrc(expression, "dark");
|
|
300
|
+
const source = videoTheme === "dark" ? darkSrc : lightSrc;
|
|
301
|
+
const setRootRef = useRef(null);
|
|
302
|
+
if (setRootRef.current === null) {
|
|
303
|
+
setRootRef.current = (node) => {
|
|
304
|
+
cleanupRef.current?.();
|
|
305
|
+
cleanupRef.current = void 0;
|
|
306
|
+
if (!node) return;
|
|
307
|
+
cleanupRef.current = bindKeyedExpressionVideo(node);
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
return /* @__PURE__ */ jsxs(
|
|
311
|
+
"div",
|
|
312
|
+
{
|
|
313
|
+
ref: setRootRef.current,
|
|
314
|
+
className: cn(
|
|
315
|
+
"warm-flame-expression-video",
|
|
316
|
+
"pointer-events-none inline-flex shrink-0 select-none"
|
|
317
|
+
),
|
|
318
|
+
"data-slot": "warm-flame-expression-video",
|
|
319
|
+
"data-size": size,
|
|
320
|
+
"data-expression": expression,
|
|
321
|
+
"data-flame-peek-eyes": peekEyes,
|
|
322
|
+
"data-flame-theme": videoTheme,
|
|
323
|
+
role: label ? "img" : void 0,
|
|
324
|
+
"aria-label": label ?? void 0,
|
|
325
|
+
"aria-hidden": label ? void 0 : true,
|
|
326
|
+
children: [
|
|
327
|
+
/* @__PURE__ */ jsx(
|
|
328
|
+
"video",
|
|
329
|
+
{
|
|
330
|
+
className: "warm-flame-expression-video__source",
|
|
331
|
+
"data-flame-expression-video-source": "",
|
|
332
|
+
"data-light-src": lightSrc,
|
|
333
|
+
"data-dark-src": darkSrc,
|
|
334
|
+
src: source,
|
|
335
|
+
muted: true,
|
|
336
|
+
loop: true,
|
|
337
|
+
playsInline: true,
|
|
338
|
+
preload: "auto",
|
|
339
|
+
disablePictureInPicture: true,
|
|
340
|
+
"aria-hidden": "true"
|
|
341
|
+
}
|
|
342
|
+
),
|
|
343
|
+
/* @__PURE__ */ jsx("canvas", { className: "warm-flame-expression-video__frame", "data-flame-expression-video-frame": "" })
|
|
344
|
+
]
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ../ui/src/warmio/logo.tsx
|
|
350
|
+
import {
|
|
351
|
+
Logo,
|
|
352
|
+
WarmLogoIcon
|
|
353
|
+
} from "@warmio/design/logo";
|
|
354
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
355
|
+
var brandedLogoShellClassNameBySize = {
|
|
356
|
+
sm: "size-8",
|
|
357
|
+
md: "size-10",
|
|
358
|
+
lg: "size-14"
|
|
359
|
+
};
|
|
360
|
+
var brandedLogoIconClassNameBySize = {
|
|
361
|
+
sm: "size-5",
|
|
362
|
+
md: "size-6",
|
|
363
|
+
lg: "size-8"
|
|
364
|
+
};
|
|
365
|
+
var _WarmLogoGlyph = /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
366
|
+
/* @__PURE__ */ jsx2(
|
|
367
|
+
"path",
|
|
368
|
+
{
|
|
369
|
+
d: "M 33.500 40.660 C 20.206 42.744, 0 48.560, -0 50.302 C -0 51.759, 123.955 348.889, 127.738 356.500 C 142.182 385.561, 169.450 410.275, 198.946 421.040 C 218.922 428.330, 243.683 430.825, 264.526 427.648 C 277.151 425.724, 294.628 420.011, 294.194 417.952 C 293.790 416.040, 172.732 124.599, 168.522 115.405 C 161.779 100.679, 149.168 84.171, 135.093 71.646 C 119.358 57.644, 98.880 47.362, 77 42.478 C 69.645 40.836, 40.220 39.606, 33.500 40.660",
|
|
370
|
+
fill: "currentColor"
|
|
371
|
+
}
|
|
372
|
+
),
|
|
373
|
+
/* @__PURE__ */ jsx2(
|
|
374
|
+
"path",
|
|
375
|
+
{
|
|
376
|
+
d: "M 229.651 41.597 C 217.916 43.718, 202.443 49.144, 202.744 51.035 C 203.418 55.268, 329.689 356.584, 333.687 363.500 C 340.525 375.327, 345.293 381.483, 355.408 391.538 C 374.603 410.619, 398.878 423.014, 425.907 427.533 C 439.649 429.831, 463.594 429.132, 476 426.072 C 489.892 422.645, 497.188 419.815, 496.703 418.043 C 495.416 413.331, 371.058 116.094, 367.406 109 C 349.467 74.149, 313.008 47.875, 273.752 41.509 C 262.281 39.648, 240.195 39.693, 229.651 41.597",
|
|
377
|
+
fill: "currentColor"
|
|
378
|
+
}
|
|
379
|
+
),
|
|
380
|
+
/* @__PURE__ */ jsx2(
|
|
381
|
+
"path",
|
|
382
|
+
{
|
|
383
|
+
d: "M 463 40.593 C 451.670 42.545, 447.288 43.569, 439 46.203 C 433.775 47.864, 429.338 49.372, 429.140 49.555 C 428.942 49.737, 434.670 64.021, 441.868 81.297 C 455.574 114.190, 462.215 131.660, 468.447 151.208 C 475.360 172.892, 486.124 186.213, 503.834 194.997 C 530.956 208.450, 564.982 201.679, 583.654 179.112 C 604.399 154.041, 605.407 121.944, 586.291 95.155 C 567.827 69.280, 539.107 50.114, 508 42.907 C 500.680 41.212, 494.713 40.644, 482 40.434 C 472.925 40.284, 464.375 40.356, 463 40.593",
|
|
384
|
+
fill: "currentColor"
|
|
385
|
+
}
|
|
386
|
+
)
|
|
387
|
+
] });
|
|
388
|
+
function WarmBrandedLogoMark({
|
|
389
|
+
size = "md",
|
|
390
|
+
className,
|
|
391
|
+
logoClassName
|
|
392
|
+
}) {
|
|
393
|
+
return /* @__PURE__ */ jsxs2(
|
|
394
|
+
"span",
|
|
395
|
+
{
|
|
396
|
+
className: cn(
|
|
397
|
+
"relative inline-flex shrink-0 items-center justify-center",
|
|
398
|
+
brandedLogoShellClassNameBySize[size],
|
|
399
|
+
className
|
|
400
|
+
),
|
|
401
|
+
"aria-hidden": "true",
|
|
402
|
+
children: [
|
|
403
|
+
/* @__PURE__ */ jsx2("span", { className: "pointer-events-none absolute inset-0 scale-[1.35] opacity-90", children: /* @__PURE__ */ jsx2(WarmFlameExpressionVideo, { expression: "calm", label: null }) }),
|
|
404
|
+
/* @__PURE__ */ jsx2(
|
|
405
|
+
"svg",
|
|
406
|
+
{
|
|
407
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
408
|
+
viewBox: "0 0 600 600",
|
|
409
|
+
className: cn(
|
|
410
|
+
"relative z-10 drop-shadow-sm",
|
|
411
|
+
brandedLogoIconClassNameBySize[size],
|
|
412
|
+
logoClassName
|
|
413
|
+
),
|
|
414
|
+
"aria-hidden": "true",
|
|
415
|
+
children: /* @__PURE__ */ jsx2("g", { transform: "translate(0 108)", children: _WarmLogoGlyph })
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
]
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
function WarmBrandedLogoLink({
|
|
423
|
+
href,
|
|
424
|
+
ariaLabel = "Warm home",
|
|
425
|
+
size = "md",
|
|
426
|
+
className,
|
|
427
|
+
logoClassName
|
|
428
|
+
}) {
|
|
429
|
+
return /* @__PURE__ */ jsx2("a", { href, "aria-label": ariaLabel, className: "inline-flex shrink-0 items-center", children: /* @__PURE__ */ jsx2(
|
|
430
|
+
WarmBrandedLogoMark,
|
|
431
|
+
{
|
|
432
|
+
size,
|
|
433
|
+
...className !== void 0 ? { className } : {},
|
|
434
|
+
...logoClassName !== void 0 ? { logoClassName } : {}
|
|
435
|
+
}
|
|
436
|
+
) });
|
|
437
|
+
}
|
|
438
|
+
function WarmBrandedLogoMarkStatic({
|
|
439
|
+
className,
|
|
440
|
+
logoClassName
|
|
441
|
+
}) {
|
|
442
|
+
return /* @__PURE__ */ jsxs2("span", { className: cn("relative inline-flex size-8 items-center justify-center", className), children: [
|
|
443
|
+
/* @__PURE__ */ jsx2(
|
|
444
|
+
"span",
|
|
445
|
+
{
|
|
446
|
+
"aria-hidden": "true",
|
|
447
|
+
className: "absolute inset-0 rounded-full bg-gradient-to-br from-primary/90 via-warning/80 to-primary/70"
|
|
448
|
+
}
|
|
449
|
+
),
|
|
450
|
+
/* @__PURE__ */ jsx2(
|
|
451
|
+
"svg",
|
|
452
|
+
{
|
|
453
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
454
|
+
viewBox: "0 0 600 600",
|
|
455
|
+
className: cn("relative z-10 size-5 drop-shadow-sm", logoClassName),
|
|
456
|
+
"aria-hidden": "true",
|
|
457
|
+
children: /* @__PURE__ */ jsx2("g", { transform: "translate(0 108)", children: _WarmLogoGlyph })
|
|
458
|
+
}
|
|
459
|
+
)
|
|
460
|
+
] });
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export {
|
|
464
|
+
WarmBrandedLogoMark,
|
|
465
|
+
WarmBrandedLogoLink,
|
|
466
|
+
WarmBrandedLogoMarkStatic,
|
|
467
|
+
Logo,
|
|
468
|
+
WarmLogoIcon
|
|
469
|
+
};
|
|
@@ -6,76 +6,6 @@ import {
|
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
|
8
8
|
import { CheckIcon } from "lucide-react";
|
|
9
|
-
|
|
10
|
-
// ../ui/src/lib/interaction-feedback.ts
|
|
11
|
-
import { play, setEnabled } from "cuelume";
|
|
12
|
-
|
|
13
|
-
// ../ui/src/lib/haptic.ts
|
|
14
|
-
var supportsHaptic = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(pointer: coarse)").matches : false;
|
|
15
|
-
function getWarmCapacitor(win) {
|
|
16
|
-
return win?.Capacitor;
|
|
17
|
-
}
|
|
18
|
-
function isIosCapacitorApp(win = typeof window === "undefined" ? void 0 : window) {
|
|
19
|
-
const capacitor = getWarmCapacitor(win);
|
|
20
|
-
return capacitor?.getPlatform?.() === "ios" && capacitor?.isNativePlatform?.() === true;
|
|
21
|
-
}
|
|
22
|
-
function hasVibrate(nav) {
|
|
23
|
-
return "vibrate" in nav && typeof nav.vibrate === "function";
|
|
24
|
-
}
|
|
25
|
-
function triggerIosCapacitorHaptic() {
|
|
26
|
-
const haptics = getWarmCapacitor(typeof window === "undefined" ? void 0 : window)?.Plugins?.Haptics;
|
|
27
|
-
void haptics?.impact?.({ style: "LIGHT" }).catch(() => {
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
function haptic(pattern = 50) {
|
|
31
|
-
try {
|
|
32
|
-
if (isIosCapacitorApp()) {
|
|
33
|
-
triggerIosCapacitorHaptic();
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (!supportsHaptic) return;
|
|
37
|
-
if (hasVibrate(navigator)) {
|
|
38
|
-
navigator.vibrate(pattern);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const label = document.createElement("label");
|
|
42
|
-
label.ariaHidden = "true";
|
|
43
|
-
label.style.display = "none";
|
|
44
|
-
const input = document.createElement("input");
|
|
45
|
-
input.type = "checkbox";
|
|
46
|
-
input.setAttribute("switch", "");
|
|
47
|
-
label.appendChild(input);
|
|
48
|
-
try {
|
|
49
|
-
document.head.appendChild(label);
|
|
50
|
-
label.click();
|
|
51
|
-
} finally {
|
|
52
|
-
document.head.removeChild(label);
|
|
53
|
-
}
|
|
54
|
-
} catch {
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ../ui/src/lib/interaction-feedback.ts
|
|
59
|
-
var soundByIntent = {
|
|
60
|
-
press: "press",
|
|
61
|
-
selection: "tick",
|
|
62
|
-
toggle: "toggle"
|
|
63
|
-
};
|
|
64
|
-
var soundsEnabled = false;
|
|
65
|
-
setEnabled(false);
|
|
66
|
-
function triggerInteractionFeedback(intent, options = {}) {
|
|
67
|
-
if (options.haptic) {
|
|
68
|
-
haptic();
|
|
69
|
-
}
|
|
70
|
-
if (!soundsEnabled) return;
|
|
71
|
-
if (typeof document !== "undefined" && document.hidden) return;
|
|
72
|
-
try {
|
|
73
|
-
play(soundByIntent[intent]);
|
|
74
|
-
} catch {
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ../ui/src/warmio/dropdown-menu.tsx
|
|
79
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
80
10
|
function DropdownMenu(props) {
|
|
81
11
|
return /* @__PURE__ */ jsx(MenuPrimitive.Root, { ...props });
|
|
@@ -132,7 +62,7 @@ function DropdownMenuContent({
|
|
|
132
62
|
dropdownMenuContentSizeClasses[size],
|
|
133
63
|
dropdownMenuContentSpacingClasses[spacing],
|
|
134
64
|
"data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
135
|
-
"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-
|
|
65
|
+
"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-90 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95 motion-reduce:animate-none"
|
|
136
66
|
),
|
|
137
67
|
...props,
|
|
138
68
|
children
|
|
@@ -164,7 +94,7 @@ function DropdownMenuItem({
|
|
|
164
94
|
"data-slot": "dropdown-menu-item",
|
|
165
95
|
"data-inset": inset,
|
|
166
96
|
"data-variant": variant,
|
|
167
|
-
className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 text-sm outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-
|
|
97
|
+
className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 text-sm outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
|
|
168
98
|
...props
|
|
169
99
|
}
|
|
170
100
|
);
|
|
@@ -186,7 +116,7 @@ function DropdownMenuLinkItem({
|
|
|
186
116
|
"data-slot": "dropdown-menu-item",
|
|
187
117
|
"data-inset": inset,
|
|
188
118
|
"data-variant": variant,
|
|
189
|
-
className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 text-sm outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-
|
|
119
|
+
className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 text-sm outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
|
|
190
120
|
render: /* @__PURE__ */ jsx("a", { href, children }),
|
|
191
121
|
...props
|
|
192
122
|
}
|
|
@@ -203,7 +133,6 @@ function DropdownMenuCheckboxItem({
|
|
|
203
133
|
...props
|
|
204
134
|
}) {
|
|
205
135
|
const handleCheckedChange = (nextChecked, eventDetails) => {
|
|
206
|
-
triggerInteractionFeedback("toggle");
|
|
207
136
|
onCheckedChange?.(nextChecked, eventDetails);
|
|
208
137
|
};
|
|
209
138
|
return /* @__PURE__ */ jsxs(
|
|
@@ -212,7 +141,7 @@ function DropdownMenuCheckboxItem({
|
|
|
212
141
|
ref,
|
|
213
142
|
"data-slot": "dropdown-menu-checkbox-item",
|
|
214
143
|
"data-inset": inset,
|
|
215
|
-
className: "relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-
|
|
144
|
+
className: "relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-4 pl-2 text-sm outline-hidden select-none focus:bg-sidebar-accent focus:text-sidebar-accent-foreground focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
216
145
|
checked,
|
|
217
146
|
onCheckedChange: handleCheckedChange,
|
|
218
147
|
...props,
|
|
@@ -237,7 +166,6 @@ function DropdownMenuRadioGroup({
|
|
|
237
166
|
...props
|
|
238
167
|
}) {
|
|
239
168
|
const handleValueChange = (value, eventDetails) => {
|
|
240
|
-
triggerInteractionFeedback("selection");
|
|
241
169
|
onValueChange?.(value, eventDetails);
|
|
242
170
|
};
|
|
243
171
|
return /* @__PURE__ */ jsx(
|
|
@@ -265,7 +193,7 @@ function DropdownMenuRadioItem({
|
|
|
265
193
|
"data-slot": "dropdown-menu-radio-item",
|
|
266
194
|
"data-inset": inset,
|
|
267
195
|
className: cn(
|
|
268
|
-
"relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-
|
|
196
|
+
"relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-4 pl-2 text-sm outline-hidden select-none focus:bg-sidebar-accent focus:text-sidebar-accent-foreground focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
269
197
|
presentation === "selectMenu" && "min-h-12 text-base"
|
|
270
198
|
),
|
|
271
199
|
...props,
|
|
@@ -296,7 +224,7 @@ function DropdownMenuLabel({
|
|
|
296
224
|
ref,
|
|
297
225
|
"data-slot": "dropdown-menu-label",
|
|
298
226
|
"data-inset": inset,
|
|
299
|
-
className: "px-2 py-2 text-xs font-bold text-muted-foreground data-inset:pl-
|
|
227
|
+
className: "px-2 py-2 text-xs font-bold text-muted-foreground data-inset:pl-4",
|
|
300
228
|
...props
|
|
301
229
|
}
|
|
302
230
|
);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
SheetHeader,
|
|
7
7
|
SheetTitle,
|
|
8
8
|
SheetTrigger
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-YTDMREDR.js";
|
|
10
10
|
|
|
11
11
|
// ../ui/src/warmio/sheet.tsx
|
|
12
12
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -37,26 +37,20 @@ function SheetContent2({
|
|
|
37
37
|
{
|
|
38
38
|
...props,
|
|
39
39
|
className: contentClassName,
|
|
40
|
-
|
|
40
|
+
...presentation === "navigation" ? { overlayClassName: "duration-200 ease-in-out" } : {}
|
|
41
41
|
}
|
|
42
42
|
);
|
|
43
43
|
}
|
|
44
|
-
function SheetFooter2({
|
|
45
|
-
|
|
46
|
-
spacing = "default",
|
|
47
|
-
style: _style,
|
|
48
|
-
...props
|
|
49
|
-
}) {
|
|
50
|
-
return /* @__PURE__ */ jsx(SheetFooter, { ...props, className: spacing === "roomy" ? "gap-4 p-6" : void 0 });
|
|
44
|
+
function SheetFooter2({ className: _className, style: _style, ...props }) {
|
|
45
|
+
return /* @__PURE__ */ jsx(SheetFooter, { ...props });
|
|
51
46
|
}
|
|
52
47
|
function SheetHeader2({
|
|
53
48
|
className: _className,
|
|
54
49
|
presentation,
|
|
55
|
-
spacing = "default",
|
|
56
50
|
style: _style,
|
|
57
51
|
...props
|
|
58
52
|
}) {
|
|
59
|
-
const className = presentation === "navigation" ? "border-b border-border bg-background p-0" :
|
|
53
|
+
const className = presentation === "navigation" ? "border-b border-border bg-background p-0" : void 0;
|
|
60
54
|
return /* @__PURE__ */ jsx(SheetHeader, { ...props, className });
|
|
61
55
|
}
|
|
62
56
|
function SheetTitle2({
|