|
2 | 2 | // Quote all tag names so that they're not mangled by minifier
|
3 | 3 | const { "button": button, "div": div, "header": header, "input": input, "label": label, "span": span, "style": style } = van.tags;
|
4 | 4 | const toStyleStr = (style) => Object.entries(style).map(([k, v]) => `${k}: ${v};`).join("");
|
| 5 | + const toStyleSheet = (styles) => { |
| 6 | + return Object.entries(styles) |
| 7 | + .map(([selector, properties]) => `${selector} { ${toStyleStr(properties)} }`) |
| 8 | + .join("\n"); |
| 9 | + }; |
5 | 10 | window.Modal = ({ closed, backgroundColor = "rgba(0,0,0,.5)", blurBackground = false, backgroundClass = "", backgroundStyleOverrides = {}, modalClass = "", modalStyleOverrides = {}, }, ...children) => {
|
6 | 11 | const backgroundStyle = {
|
7 | 12 | display: "flex",
|
|
239 | 244 | });
|
240 | 245 | return header({ class: bannerClass, style: bannerStyleStr }, children);
|
241 | 246 | };
|
| 247 | + let windowId = 0; |
242 | 248 | window.FloatingWindow = ({ title, closed, x = van.state(100), y = van.state(100), width = van.state(300), height = van.state(200), windowStyleOverrides = {}, headerStyleOverrides = {}, childrenContainerStyleOverrides = {}, closeCross = false }, ...children) => {
|
243 | 249 | let dragging = van.state(false);
|
244 | 250 | let resizingDirection = van.state(null);
|
|
286 | 292 | document.addEventListener('mousemove', onMouseMove);
|
287 | 293 | document.addEventListener('mouseup', onMouseUp);
|
288 | 294 | const grabAreaBgColor = 'transparent';
|
289 |
| - return () => closed.val ? null : van.add(div({ |
290 |
| - style: toStyleStr({ |
| 295 | + const crossId = `vanui-close-cross-${++windowId}`; |
| 296 | + if (document.getElementById('vanui-window-style') == null) { |
| 297 | + const static_styles = style({ type: "text/css", id: "vanui-window-style" }, toStyleSheet({ |
| 298 | + ".vanui-window-dragarea": { |
| 299 | + cursor: 'move', |
| 300 | + position: 'absolute', |
| 301 | + left: '0', |
| 302 | + top: '0', |
| 303 | + width: '100%', |
| 304 | + height: '1rem', |
| 305 | + }, |
| 306 | + ".vanui-window-resize-right": { |
| 307 | + cursor: 'e-resize', |
| 308 | + position: 'absolute', |
| 309 | + right: '0', |
| 310 | + top: '0', |
| 311 | + width: '10px', |
| 312 | + height: '100%', |
| 313 | + 'background-color': grabAreaBgColor, |
| 314 | + }, |
| 315 | + ".vanui-window-resize-bottom": { |
| 316 | + cursor: 's-resize', |
| 317 | + position: 'absolute', |
| 318 | + left: '0', |
| 319 | + bottom: '0', |
| 320 | + width: '100%', |
| 321 | + height: '10px', |
| 322 | + 'background-color': grabAreaBgColor, |
| 323 | + }, |
| 324 | + ".vanui-window-resize-rightbottom": { |
| 325 | + cursor: 'se-resize', |
| 326 | + position: 'absolute', |
| 327 | + right: '0', |
| 328 | + bottom: '0', |
| 329 | + width: '10px', |
| 330 | + height: '10px', |
| 331 | + 'background-color': grabAreaBgColor, |
| 332 | + }, |
| 333 | + })); |
| 334 | + document.head.appendChild(static_styles); |
| 335 | + } |
| 336 | + const dynamic_styles = style({ type: "text/css" }, toStyleSheet({ |
| 337 | + [`#${crossId}`]: { |
| 338 | + cursor: 'pointer', |
| 339 | + fontSize: '18px', |
| 340 | + transition: 'background-color 0.3s, color 0.3s', |
| 341 | + "border-radius": '50%', |
| 342 | + width: '24px', |
| 343 | + height: '24px', |
| 344 | + display: 'flex', |
| 345 | + "align-items": 'center', |
| 346 | + "justify-content": 'center', |
| 347 | + }, |
| 348 | + [`#${crossId}:hover`]: { |
| 349 | + "background-color": "red", |
| 350 | + color: "white", |
| 351 | + }, |
| 352 | + [`#vanui-window-${windowId}`]: { |
291 | 353 | position: 'fixed',
|
292 |
| - left: `${x.val}px`, |
293 |
| - top: `${y.val}px`, |
294 |
| - width: `${width.val}px`, |
295 |
| - height: `${height.val}px`, |
296 | 354 | 'background-color': 'white',
|
297 | 355 | border: '1px solid black',
|
298 | 356 | 'border-radius': '0.5rem',
|
299 | 357 | overflow: 'hidden',
|
300 |
| - ...windowStyleOverrides, |
301 |
| - }), |
302 |
| - }, div({ |
303 |
| - style: toStyleStr({ |
304 |
| - cursor: 'move', |
305 |
| - position: 'absolute', |
306 |
| - left: 0, |
307 |
| - top: 0, |
308 |
| - width: '100%', |
309 |
| - height: "1rem" |
310 |
| - }), |
311 |
| - onmousedown: onMouseDown, |
312 |
| - }), header({ |
313 |
| - style: toStyleStr({ |
| 358 | + }, |
| 359 | + [`#vanui-window-${windowId}-header`]: { |
314 | 360 | cursor: 'move',
|
315 | 361 | 'background-color': 'lightgray',
|
316 | 362 | "user-select": 'none',
|
317 | 363 | display: 'flex',
|
318 | 364 | "justify-content": 'space-between',
|
319 | 365 | "align-items": 'center',
|
320 | 366 | padding: '0.5rem',
|
321 |
| - ...headerStyleOverrides, |
| 367 | + } |
| 368 | + })); |
| 369 | + document.head.appendChild(dynamic_styles); |
| 370 | + return () => closed.val ? null : van.add(div({ |
| 371 | + id: `vanui-window-${windowId}`, |
| 372 | + style: toStyleStr({ |
| 373 | + left: `${x.val}px`, |
| 374 | + top: `${y.val}px`, |
| 375 | + width: `${width.val}px`, |
| 376 | + height: `${height.val}px`, |
| 377 | + ...windowStyleOverrides, |
322 | 378 | }),
|
| 379 | + }, title != null ? header({ |
| 380 | + id: `vanui-window-${windowId}-header`, |
| 381 | + style: toStyleStr(headerStyleOverrides), |
323 | 382 | onmousedown: onMouseDown,
|
324 | 383 | }, title, closeCross ? span({
|
325 |
| - style: toStyleStr({ |
326 |
| - cursor: 'pointer', |
327 |
| - fontSize: '18px', |
328 |
| - transition: 'background-color 0.3s, color 0.3s', |
329 |
| - "border-radius": '50%', |
330 |
| - width: '24px', |
331 |
| - height: '24px', |
332 |
| - display: 'flex', |
333 |
| - "align-items": 'center', |
334 |
| - "justify-content": 'center', |
335 |
| - }), |
336 |
| - class: "vanui-close-cross", |
| 384 | + id: crossId, |
337 | 385 | onclick: () => closed.val = true,
|
338 |
| - }, '×') : null), style({ type: "text/css" }, ` |
339 |
| - .vanui-close-cross:hover {${toStyleStr({ |
340 |
| - "background-color": "red", |
341 |
| - color: "white", |
342 |
| - })}} |
343 |
| - `), div({ |
344 |
| - style: toStyleStr({ |
345 |
| - cursor: 'e-resize', |
346 |
| - position: 'absolute', |
347 |
| - right: 0, |
348 |
| - top: 0, |
349 |
| - width: '10px', |
350 |
| - height: '100%', |
351 |
| - 'background-color': grabAreaBgColor, |
352 |
| - }), |
| 386 | + }, '×') : null) : div({ |
| 387 | + class: 'vanui-window-dragarea', |
| 388 | + onmousedown: onMouseDown, |
| 389 | + }), div({ |
| 390 | + class: 'vanui-window-resize-right', |
353 | 391 | onmousedown: onResizeMouseDown('right'),
|
354 | 392 | }), div({
|
355 |
| - style: toStyleStr({ |
356 |
| - cursor: 's-resize', |
357 |
| - position: 'absolute', |
358 |
| - left: 0, |
359 |
| - bottom: 0, |
360 |
| - width: '100%', |
361 |
| - height: '10px', |
362 |
| - 'background-color': grabAreaBgColor, |
363 |
| - }), |
| 393 | + class: 'vanui-window-resize-bottom', |
364 | 394 | onmousedown: onResizeMouseDown('bottom'),
|
365 | 395 | }), div({
|
366 |
| - style: toStyleStr({ |
367 |
| - cursor: 'se-resize', |
368 |
| - position: 'absolute', |
369 |
| - right: 0, |
370 |
| - bottom: 0, |
371 |
| - width: '10px', |
372 |
| - height: '10px', |
373 |
| - 'background-color': grabAreaBgColor, |
374 |
| - }), |
| 396 | + class: 'vanui-window-resize-rightbottom', |
375 | 397 | onmousedown: onResizeMouseDown('rightbottom'),
|
376 | 398 | }), div({ style: toStyleStr(childrenContainerStyleOverrides) }, children)));
|
377 | 399 | };
|
|
0 commit comments