@thunderclap-engine/engine 0.0.0-stage → 1.1.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/CHANGELOG.md +390 -0
- package/LICENSE +21 -0
- package/README.md +333 -2
- package/dist/analytics/analytics.d.ts +80 -0
- package/dist/analytics/analytics.js +129 -0
- package/dist/analytics/index.d.ts +1 -0
- package/dist/analytics/index.js +1 -0
- package/dist/anim/aim.d.ts +43 -0
- package/dist/anim/aim.js +157 -0
- package/dist/anim/clip.d.ts +98 -0
- package/dist/anim/clip.js +282 -0
- package/dist/anim/compress.d.ts +65 -0
- package/dist/anim/compress.js +339 -0
- package/dist/anim/foot-ik.d.ts +74 -0
- package/dist/anim/foot-ik.js +241 -0
- package/dist/anim/graph.d.ts +153 -0
- package/dist/anim/graph.js +532 -0
- package/dist/anim/ik.d.ts +105 -0
- package/dist/anim/ik.js +435 -0
- package/dist/anim/index.d.ts +36 -0
- package/dist/anim/index.js +21 -0
- package/dist/anim/match.d.ts +66 -0
- package/dist/anim/match.js +153 -0
- package/dist/anim/mixer.d.ts +113 -0
- package/dist/anim/mixer.js +314 -0
- package/dist/anim/morph.d.ts +41 -0
- package/dist/anim/morph.js +94 -0
- package/dist/anim/pose.d.ts +74 -0
- package/dist/anim/pose.js +254 -0
- package/dist/anim/quat.d.ts +44 -0
- package/dist/anim/quat.js +187 -0
- package/dist/anim/retarget.d.ts +97 -0
- package/dist/anim/retarget.js +366 -0
- package/dist/anim/root-motion.d.ts +44 -0
- package/dist/anim/root-motion.js +224 -0
- package/dist/anim/skin-pose.d.ts +39 -0
- package/dist/anim/skin-pose.js +53 -0
- package/dist/anim/socket.d.ts +47 -0
- package/dist/anim/socket.js +84 -0
- package/dist/anim/spring-chain.d.ts +73 -0
- package/dist/anim/spring-chain.js +294 -0
- package/dist/assets/atlas.d.ts +90 -0
- package/dist/assets/atlas.js +212 -0
- package/dist/assets/baked.d.ts +33 -0
- package/dist/assets/baked.js +38 -0
- package/dist/assets/bundle.d.ts +88 -0
- package/dist/assets/bundle.js +464 -0
- package/dist/assets/cache.d.ts +56 -0
- package/dist/assets/cache.js +123 -0
- package/dist/assets/gltf-load.d.ts +252 -0
- package/dist/assets/gltf-load.js +661 -0
- package/dist/assets/gltf-skin.d.ts +36 -0
- package/dist/assets/gltf-skin.js +109 -0
- package/dist/assets/gltf.d.ts +706 -0
- package/dist/assets/gltf.js +1376 -0
- package/dist/assets/index.d.ts +20 -0
- package/dist/assets/index.js +10 -0
- package/dist/assets/ktx2.d.ts +71 -0
- package/dist/assets/ktx2.js +213 -0
- package/dist/assets/manifest.d.ts +79 -0
- package/dist/assets/manifest.js +7 -0
- package/dist/assets/meshopt.d.ts +23 -0
- package/dist/assets/meshopt.js +403 -0
- package/dist/audio/audio.d.ts +733 -0
- package/dist/audio/audio.js +2013 -0
- package/dist/audio/dsp.d.ts +61 -0
- package/dist/audio/dsp.js +159 -0
- package/dist/audio/duck.d.ts +44 -0
- package/dist/audio/duck.js +101 -0
- package/dist/audio/envelope.d.ts +53 -0
- package/dist/audio/envelope.js +106 -0
- package/dist/audio/index.d.ts +13 -0
- package/dist/audio/index.js +14 -0
- package/dist/audio/music.d.ts +113 -0
- package/dist/audio/music.js +548 -0
- package/dist/audio/occlusion.d.ts +55 -0
- package/dist/audio/occlusion.js +61 -0
- package/dist/audio/persist.d.ts +23 -0
- package/dist/audio/persist.js +27 -0
- package/dist/audio/recipes.d.ts +55 -0
- package/dist/audio/recipes.js +227 -0
- package/dist/audio/send.d.ts +41 -0
- package/dist/audio/send.js +118 -0
- package/dist/audio/sprites.d.ts +59 -0
- package/dist/audio/sprites.js +43 -0
- package/dist/audio/synth.d.ts +103 -0
- package/dist/audio/synth.js +197 -0
- package/dist/audio/variations.d.ts +25 -0
- package/dist/audio/variations.js +55 -0
- package/dist/audio/zones.d.ts +100 -0
- package/dist/audio/zones.js +167 -0
- package/dist/core/detached-surface.d.ts +44 -0
- package/dist/core/detached-surface.js +104 -0
- package/dist/core/events.d.ts +24 -0
- package/dist/core/events.js +43 -0
- package/dist/core/game.d.ts +409 -0
- package/dist/core/game.js +530 -0
- package/dist/core/hash.d.ts +24 -0
- package/dist/core/hash.js +49 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.js +9 -0
- package/dist/core/loop.d.ts +113 -0
- package/dist/core/loop.js +185 -0
- package/dist/core/math.d.ts +58 -0
- package/dist/core/math.js +210 -0
- package/dist/core/noise.d.ts +40 -0
- package/dist/core/noise.js +247 -0
- package/dist/core/pool.d.ts +42 -0
- package/dist/core/pool.js +85 -0
- package/dist/core/random.d.ts +61 -0
- package/dist/core/random.js +199 -0
- package/dist/core/scene.d.ts +79 -0
- package/dist/core/scene.js +195 -0
- package/dist/core/timer.d.ts +66 -0
- package/dist/core/timer.js +286 -0
- package/dist/fx/billboard-wgsl.d.ts +29 -0
- package/dist/fx/billboard-wgsl.js +158 -0
- package/dist/fx/billboard.d.ts +249 -0
- package/dist/fx/billboard.js +702 -0
- package/dist/fx/debug-draw.d.ts +127 -0
- package/dist/fx/debug-draw.js +523 -0
- package/dist/fx/debug-wgsl.d.ts +7 -0
- package/dist/fx/debug-wgsl.js +32 -0
- package/dist/fx/decals-wgsl.d.ts +15 -0
- package/dist/fx/decals-wgsl.js +173 -0
- package/dist/fx/decals.d.ts +216 -0
- package/dist/fx/decals.js +607 -0
- package/dist/fx/effect.d.ts +129 -0
- package/dist/fx/effect.js +349 -0
- package/dist/fx/effects/hit-spark.json +48 -0
- package/dist/fx/effects/index.d.ts +8 -0
- package/dist/fx/effects/index.js +9 -0
- package/dist/fx/effects/magic-aura.json +47 -0
- package/dist/fx/effects/smoke-puff.json +34 -0
- package/dist/fx/emit-surface.d.ts +40 -0
- package/dist/fx/emit-surface.js +124 -0
- package/dist/fx/flicker.d.ts +30 -0
- package/dist/fx/flicker.js +42 -0
- package/dist/fx/index.d.ts +31 -0
- package/dist/fx/index.js +20 -0
- package/dist/fx/particles-wgsl.d.ts +57 -0
- package/dist/fx/particles-wgsl.js +828 -0
- package/dist/fx/particles.d.ts +566 -0
- package/dist/fx/particles.js +1533 -0
- package/dist/fx/random.d.ts +15 -0
- package/dist/fx/random.js +20 -0
- package/dist/fx/sky-wgsl.d.ts +23 -0
- package/dist/fx/sky-wgsl.js +127 -0
- package/dist/fx/sky.d.ts +96 -0
- package/dist/fx/sky.js +175 -0
- package/dist/fx/text-atlas.d.ts +143 -0
- package/dist/fx/text-atlas.js +327 -0
- package/dist/fx/trail-wgsl.d.ts +11 -0
- package/dist/fx/trail-wgsl.js +42 -0
- package/dist/fx/trail.d.ts +194 -0
- package/dist/fx/trail.js +555 -0
- package/dist/fx/water-wgsl.d.ts +34 -0
- package/dist/fx/water-wgsl.js +197 -0
- package/dist/fx/water.d.ts +176 -0
- package/dist/fx/water.js +371 -0
- package/dist/geom/collide/bvh.d.ts +151 -0
- package/dist/geom/collide/bvh.js +493 -0
- package/dist/geom/collide/debug.d.ts +14 -0
- package/dist/geom/collide/debug.js +74 -0
- package/dist/geom/collide/grid.d.ts +26 -0
- package/dist/geom/collide/grid.js +91 -0
- package/dist/geom/collide/index.d.ts +8 -0
- package/dist/geom/collide/index.js +8 -0
- package/dist/geom/collide/queries.d.ts +70 -0
- package/dist/geom/collide/queries.js +583 -0
- package/dist/geom/collide/serialize.d.ts +14 -0
- package/dist/geom/collide/serialize.js +145 -0
- package/dist/geom/collide/shapes.d.ts +161 -0
- package/dist/geom/collide/shapes.js +686 -0
- package/dist/geom/collide/slide.d.ts +66 -0
- package/dist/geom/collide/slide.js +375 -0
- package/dist/geom/collide/tile-slide.d.ts +88 -0
- package/dist/geom/collide/tile-slide.js +255 -0
- package/dist/geom/geometry.d.ts +95 -0
- package/dist/geom/geometry.js +322 -0
- package/dist/geom/heightfield.d.ts +72 -0
- package/dist/geom/heightfield.js +295 -0
- package/dist/geom/hull.d.ts +27 -0
- package/dist/geom/hull.js +279 -0
- package/dist/geom/index.d.ts +35 -0
- package/dist/geom/index.js +23 -0
- package/dist/geom/iso.d.ts +74 -0
- package/dist/geom/iso.js +89 -0
- package/dist/geom/lod.d.ts +29 -0
- package/dist/geom/lod.js +27 -0
- package/dist/geom/ops.d.ts +47 -0
- package/dist/geom/ops.js +285 -0
- package/dist/geom/primitives.d.ts +97 -0
- package/dist/geom/primitives.js +359 -0
- package/dist/geom/shapes.d.ts +43 -0
- package/dist/geom/shapes.js +88 -0
- package/dist/geom/simplify.d.ts +38 -0
- package/dist/geom/simplify.js +519 -0
- package/dist/geom/split.d.ts +37 -0
- package/dist/geom/split.js +413 -0
- package/dist/geom/sweep.d.ts +83 -0
- package/dist/geom/sweep.js +534 -0
- package/dist/geom/tangents.d.ts +16 -0
- package/dist/geom/tangents.js +124 -0
- package/dist/geom/triangulate.d.ts +19 -0
- package/dist/geom/triangulate.js +147 -0
- package/dist/host/default.d.ts +10 -0
- package/dist/host/default.js +10 -0
- package/dist/host/index.d.ts +4 -0
- package/dist/host/index.js +3 -0
- package/dist/host/types.d.ts +144 -0
- package/dist/host/types.js +1 -0
- package/dist/host/web-links.d.ts +38 -0
- package/dist/host/web-links.js +110 -0
- package/dist/host/web.d.ts +30 -0
- package/dist/host/web.js +216 -0
- package/dist/host/xr.d.ts +24 -0
- package/dist/host/xr.js +59 -0
- package/dist/i18n/i18n.d.ts +59 -0
- package/dist/i18n/i18n.js +241 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.js +3 -0
- package/dist/i18n/message.d.ts +72 -0
- package/dist/i18n/message.js +369 -0
- package/dist/i18n/negotiate.d.ts +17 -0
- package/dist/i18n/negotiate.js +58 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -0
- package/dist/input/bindings.d.ts +31 -0
- package/dist/input/bindings.js +141 -0
- package/dist/input/clock.d.ts +44 -0
- package/dist/input/clock.js +49 -0
- package/dist/input/follow.d.ts +133 -0
- package/dist/input/follow.js +218 -0
- package/dist/input/gestures.d.ts +281 -0
- package/dist/input/gestures.js +662 -0
- package/dist/input/glyphs.d.ts +35 -0
- package/dist/input/glyphs.js +216 -0
- package/dist/input/gyro.d.ts +85 -0
- package/dist/input/gyro.js +140 -0
- package/dist/input/index.d.ts +19 -0
- package/dist/input/index.js +16 -0
- package/dist/input/input.d.ts +543 -0
- package/dist/input/input.js +1492 -0
- package/dist/input/look.d.ts +327 -0
- package/dist/input/look.js +681 -0
- package/dist/input/magnify.d.ts +177 -0
- package/dist/input/magnify.js +131 -0
- package/dist/input/pointer-dispatch.d.ts +138 -0
- package/dist/input/pointer-dispatch.js +180 -0
- package/dist/input/pointer-router.d.ts +204 -0
- package/dist/input/pointer-router.js +533 -0
- package/dist/input/pointer-sources.d.ts +164 -0
- package/dist/input/pointer-sources.js +306 -0
- package/dist/input/rays.d.ts +138 -0
- package/dist/input/rays.js +615 -0
- package/dist/input/record.d.ts +209 -0
- package/dist/input/record.js +601 -0
- package/dist/input/touch-zones.d.ts +147 -0
- package/dist/input/touch-zones.js +300 -0
- package/dist/input/types.d.ts +158 -0
- package/dist/input/types.js +1 -0
- package/dist/input/xr-source.d.ts +53 -0
- package/dist/input/xr-source.js +164 -0
- package/dist/nav/astar.d.ts +45 -0
- package/dist/nav/astar.js +182 -0
- package/dist/nav/corridor.d.ts +40 -0
- package/dist/nav/corridor.js +95 -0
- package/dist/nav/crowd.d.ts +94 -0
- package/dist/nav/crowd.js +624 -0
- package/dist/nav/flow.d.ts +61 -0
- package/dist/nav/flow.js +193 -0
- package/dist/nav/grid.d.ts +108 -0
- package/dist/nav/grid.js +210 -0
- package/dist/nav/heap.d.ts +22 -0
- package/dist/nav/heap.js +92 -0
- package/dist/nav/index.d.ts +37 -0
- package/dist/nav/index.js +19 -0
- package/dist/nav/mesh/areas.d.ts +44 -0
- package/dist/nav/mesh/areas.js +98 -0
- package/dist/nav/mesh/bake-options.d.ts +33 -0
- package/dist/nav/mesh/bake-options.js +76 -0
- package/dist/nav/mesh/contour.d.ts +22 -0
- package/dist/nav/mesh/contour.js +323 -0
- package/dist/nav/mesh/flow3.d.ts +35 -0
- package/dist/nav/mesh/flow3.js +229 -0
- package/dist/nav/mesh/links.d.ts +38 -0
- package/dist/nav/mesh/links.js +72 -0
- package/dist/nav/mesh/mesh-path.d.ts +152 -0
- package/dist/nav/mesh/mesh-path.js +643 -0
- package/dist/nav/mesh/mesh-reach.d.ts +78 -0
- package/dist/nav/mesh/mesh-reach.js +450 -0
- package/dist/nav/mesh/navmesh.d.ts +117 -0
- package/dist/nav/mesh/navmesh.js +647 -0
- package/dist/nav/mesh/polymesh.d.ts +24 -0
- package/dist/nav/mesh/polymesh.js +384 -0
- package/dist/nav/mesh/regions.d.ts +12 -0
- package/dist/nav/mesh/regions.js +367 -0
- package/dist/nav/mesh/serialize.d.ts +13 -0
- package/dist/nav/mesh/serialize.js +197 -0
- package/dist/nav/mesh/voxelize.d.ts +111 -0
- package/dist/nav/mesh/voxelize.js +552 -0
- package/dist/nav/obstacles.d.ts +75 -0
- package/dist/nav/obstacles.js +294 -0
- package/dist/nav/path.d.ts +59 -0
- package/dist/nav/path.js +177 -0
- package/dist/nav/query-queue.d.ts +46 -0
- package/dist/nav/query-queue.js +308 -0
- package/dist/nav/reach.d.ts +53 -0
- package/dist/nav/reach.js +148 -0
- package/dist/nav/steer.d.ts +36 -0
- package/dist/nav/steer.js +78 -0
- package/dist/platform/boot.d.ts +28 -0
- package/dist/platform/boot.js +43 -0
- package/dist/platform/device-mode.d.ts +40 -0
- package/dist/platform/device-mode.js +104 -0
- package/dist/platform/device.d.ts +31 -0
- package/dist/platform/device.js +91 -0
- package/dist/platform/environment.d.ts +42 -0
- package/dist/platform/environment.js +82 -0
- package/dist/platform/gpu.d.ts +40 -0
- package/dist/platform/gpu.js +57 -0
- package/dist/platform/index.d.ts +18 -0
- package/dist/platform/index.js +10 -0
- package/dist/platform/letterbox.d.ts +43 -0
- package/dist/platform/letterbox.js +57 -0
- package/dist/platform/links.d.ts +20 -0
- package/dist/platform/links.js +43 -0
- package/dist/platform/screens.d.ts +36 -0
- package/dist/platform/screens.js +138 -0
- package/dist/platform/surface.d.ts +72 -0
- package/dist/platform/surface.js +157 -0
- package/dist/platform/xr-fake.d.ts +168 -0
- package/dist/platform/xr-fake.js +434 -0
- package/dist/platform/xr-surface.d.ts +120 -0
- package/dist/platform/xr-surface.js +214 -0
- package/dist/platform/xr-types.d.ts +262 -0
- package/dist/post/ao.d.ts +12 -0
- package/dist/post/ao.js +136 -0
- package/dist/post/blend.d.ts +27 -0
- package/dist/post/blend.js +129 -0
- package/dist/post/depth-pass.d.ts +43 -0
- package/dist/post/depth-pass.js +118 -0
- package/dist/post/dof.d.ts +1 -0
- package/dist/post/dof.js +66 -0
- package/dist/post/exposure.d.ts +80 -0
- package/dist/post/exposure.js +322 -0
- package/dist/post/index.d.ts +12 -0
- package/dist/post/index.js +11 -0
- package/dist/post/lens-dirt.d.ts +13 -0
- package/dist/post/lens-dirt.js +91 -0
- package/dist/post/lut.d.ts +19 -0
- package/dist/post/lut.js +50 -0
- package/dist/post/motion-blur.d.ts +9 -0
- package/dist/post/motion-blur.js +78 -0
- package/dist/post/post-stack.d.ts +302 -0
- package/dist/post/post-stack.js +1137 -0
- package/dist/post/settings.d.ts +485 -0
- package/dist/post/settings.js +416 -0
- package/dist/post/shaders.d.ts +25 -0
- package/dist/post/shaders.js +410 -0
- package/dist/post/ssr.d.ts +16 -0
- package/dist/post/ssr.js +155 -0
- package/dist/post/taa.d.ts +74 -0
- package/dist/post/taa.js +235 -0
- package/dist/post/white-balance.d.ts +25 -0
- package/dist/post/white-balance.js +98 -0
- package/dist/render/bindings.d.ts +98 -0
- package/dist/render/bindings.js +281 -0
- package/dist/render/blend.d.ts +13 -0
- package/dist/render/blend.js +26 -0
- package/dist/render/camera-2d.d.ts +72 -0
- package/dist/render/camera-2d.js +92 -0
- package/dist/render/camera.d.ts +302 -0
- package/dist/render/camera.js +671 -0
- package/dist/render/color.d.ts +16 -0
- package/dist/render/color.js +41 -0
- package/dist/render/compressed.d.ts +104 -0
- package/dist/render/compressed.js +248 -0
- package/dist/render/diagnostics.d.ts +15 -0
- package/dist/render/diagnostics.js +43 -0
- package/dist/render/dynamic-resolution.d.ts +70 -0
- package/dist/render/dynamic-resolution.js +126 -0
- package/dist/render/fake-gpu.d.ts +204 -0
- package/dist/render/fake-gpu.js +426 -0
- package/dist/render/flipbook.d.ts +56 -0
- package/dist/render/flipbook.js +87 -0
- package/dist/render/frame.d.ts +278 -0
- package/dist/render/frame.js +174 -0
- package/dist/render/fullscreen.d.ts +54 -0
- package/dist/render/fullscreen.js +91 -0
- package/dist/render/gpu-timer.d.ts +73 -0
- package/dist/render/gpu-timer.js +186 -0
- package/dist/render/index.d.ts +53 -0
- package/dist/render/index.js +29 -0
- package/dist/render/instance-list.d.ts +185 -0
- package/dist/render/instance-list.js +547 -0
- package/dist/render/lights.d.ts +181 -0
- package/dist/render/lights.js +233 -0
- package/dist/render/lod.d.ts +54 -0
- package/dist/render/lod.js +52 -0
- package/dist/render/material.d.ts +165 -0
- package/dist/render/material.js +292 -0
- package/dist/render/mesh.d.ts +284 -0
- package/dist/render/mesh.js +472 -0
- package/dist/render/mipmap.d.ts +16 -0
- package/dist/render/mipmap.js +121 -0
- package/dist/render/parallax.d.ts +50 -0
- package/dist/render/parallax.js +47 -0
- package/dist/render/pbr-wgsl.d.ts +31 -0
- package/dist/render/pbr-wgsl.js +119 -0
- package/dist/render/ping-pong.d.ts +42 -0
- package/dist/render/ping-pong.js +74 -0
- package/dist/render/renderer.d.ts +741 -0
- package/dist/render/renderer.js +2486 -0
- package/dist/render/scene-pipelines.d.ts +44 -0
- package/dist/render/scene-pipelines.js +92 -0
- package/dist/render/scene-target.d.ts +170 -0
- package/dist/render/scene-target.js +450 -0
- package/dist/render/shadow.d.ts +74 -0
- package/dist/render/shadow.js +208 -0
- package/dist/render/skin.d.ts +112 -0
- package/dist/render/skin.js +240 -0
- package/dist/render/snapshot.d.ts +36 -0
- package/dist/render/snapshot.js +34 -0
- package/dist/render/standard.d.ts +162 -0
- package/dist/render/standard.js +263 -0
- package/dist/render/texture.d.ts +142 -0
- package/dist/render/texture.js +228 -0
- package/dist/render/tile-layer.d.ts +110 -0
- package/dist/render/tile-layer.js +304 -0
- package/dist/render/transform.d.ts +115 -0
- package/dist/render/transform.js +318 -0
- package/dist/render/wgsl.d.ts +131 -0
- package/dist/render/wgsl.js +528 -0
- package/dist/save/codec.d.ts +49 -0
- package/dist/save/codec.js +169 -0
- package/dist/save/index.d.ts +8 -0
- package/dist/save/index.js +8 -0
- package/dist/save/journal.d.ts +24 -0
- package/dist/save/journal.js +102 -0
- package/dist/save/migrate.d.ts +15 -0
- package/dist/save/migrate.js +37 -0
- package/dist/save/schema.d.ts +72 -0
- package/dist/save/schema.js +154 -0
- package/dist/save/settings.d.ts +28 -0
- package/dist/save/settings.js +59 -0
- package/dist/save/slots.d.ts +56 -0
- package/dist/save/slots.js +200 -0
- package/dist/save/storage.d.ts +35 -0
- package/dist/save/storage.js +62 -0
- package/dist/save/store.d.ts +114 -0
- package/dist/save/store.js +269 -0
- package/dist/testing/fake-host.d.ts +103 -0
- package/dist/testing/fake-host.js +163 -0
- package/dist/testing/fixed-clock.d.ts +25 -0
- package/dist/testing/fixed-clock.js +30 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/test-game.d.ts +76 -0
- package/dist/testing/test-game.js +92 -0
- package/dist/tween/ease.d.ts +77 -0
- package/dist/tween/ease.js +192 -0
- package/dist/tween/index.d.ts +8 -0
- package/dist/tween/index.js +7 -0
- package/dist/tween/timeline.d.ts +78 -0
- package/dist/tween/timeline.js +269 -0
- package/dist/tween/tween.d.ts +168 -0
- package/dist/tween/tween.js +320 -0
- package/dist/ui/anchor.d.ts +206 -0
- package/dist/ui/anchor.js +307 -0
- package/dist/ui/caption.d.ts +122 -0
- package/dist/ui/caption.js +286 -0
- package/dist/ui/cursor.d.ts +105 -0
- package/dist/ui/cursor.js +261 -0
- package/dist/ui/dom.d.ts +30 -0
- package/dist/ui/dom.js +92 -0
- package/dist/ui/floats.d.ts +86 -0
- package/dist/ui/floats.js +260 -0
- package/dist/ui/hud.d.ts +198 -0
- package/dist/ui/hud.js +431 -0
- package/dist/ui/index.d.ts +37 -0
- package/dist/ui/index.js +34 -0
- package/dist/ui/inventory-card.d.ts +52 -0
- package/dist/ui/inventory-card.js +173 -0
- package/dist/ui/inventory-context.d.ts +29 -0
- package/dist/ui/inventory-context.js +125 -0
- package/dist/ui/inventory-drag.d.ts +63 -0
- package/dist/ui/inventory-drag.js +394 -0
- package/dist/ui/inventory-grid.d.ts +66 -0
- package/dist/ui/inventory-grid.js +625 -0
- package/dist/ui/inventory-radial.d.ts +39 -0
- package/dist/ui/inventory-radial.js +168 -0
- package/dist/ui/inventory.d.ts +128 -0
- package/dist/ui/inventory.js +154 -0
- package/dist/ui/layout.d.ts +356 -0
- package/dist/ui/layout.js +856 -0
- package/dist/ui/link.d.ts +64 -0
- package/dist/ui/link.js +155 -0
- package/dist/ui/loading.d.ts +40 -0
- package/dist/ui/loading.js +157 -0
- package/dist/ui/loupe.d.ts +74 -0
- package/dist/ui/loupe.js +164 -0
- package/dist/ui/menu-nav.d.ts +33 -0
- package/dist/ui/menu-nav.js +28 -0
- package/dist/ui/minimap-canvas.d.ts +145 -0
- package/dist/ui/minimap-canvas.js +460 -0
- package/dist/ui/notify.d.ts +40 -0
- package/dist/ui/notify.js +141 -0
- package/dist/ui/orb.d.ts +53 -0
- package/dist/ui/orb.js +304 -0
- package/dist/ui/overlay.d.ts +213 -0
- package/dist/ui/overlay.js +394 -0
- package/dist/ui/padnav.d.ts +53 -0
- package/dist/ui/padnav.js +146 -0
- package/dist/ui/perf.d.ts +130 -0
- package/dist/ui/perf.js +329 -0
- package/dist/ui/rotate-card.d.ts +54 -0
- package/dist/ui/rotate-card.js +97 -0
- package/dist/ui/stack.d.ts +128 -0
- package/dist/ui/stack.js +312 -0
- package/dist/ui/styles.d.ts +13 -0
- package/dist/ui/styles.js +200 -0
- package/dist/ui/text-scale.d.ts +67 -0
- package/dist/ui/text-scale.js +102 -0
- package/dist/ui/theme.d.ts +70 -0
- package/dist/ui/theme.js +98 -0
- package/dist/ui/toast.d.ts +23 -0
- package/dist/ui/toast.js +46 -0
- package/dist/ui/tooltip.d.ts +89 -0
- package/dist/ui/tooltip.js +333 -0
- package/dist/ui/widgets-2.d.ts +134 -0
- package/dist/ui/widgets-2.js +399 -0
- package/dist/ui/widgets-3.d.ts +91 -0
- package/dist/ui/widgets-3.js +212 -0
- package/dist/ui/widgets.d.ts +34 -0
- package/dist/ui/widgets.js +50 -0
- package/dist/ui/world-panel/index.d.ts +5 -0
- package/dist/ui/world-panel/index.js +5 -0
- package/dist/ui/world-panel/layout.d.ts +38 -0
- package/dist/ui/world-panel/layout.js +68 -0
- package/dist/ui/world-panel/paint.d.ts +96 -0
- package/dist/ui/world-panel/paint.js +136 -0
- package/dist/ui/world-panel/panel.d.ts +235 -0
- package/dist/ui/world-panel/panel.js +762 -0
- package/dist/ui/world-panel/wgsl.d.ts +10 -0
- package/dist/ui/world-panel/wgsl.js +52 -0
- package/dist/ui/world-panel/widgets.d.ts +207 -0
- package/dist/ui/world-panel/widgets.js +569 -0
- package/dist/voxel/chunks.d.ts +77 -0
- package/dist/voxel/chunks.js +149 -0
- package/dist/voxel/grid.d.ts +84 -0
- package/dist/voxel/grid.js +223 -0
- package/dist/voxel/index.d.ts +22 -0
- package/dist/voxel/index.js +7 -0
- package/dist/voxel/mesher-worker.d.ts +14 -0
- package/dist/voxel/mesher-worker.js +47 -0
- package/dist/voxel/mesher.d.ts +73 -0
- package/dist/voxel/mesher.js +306 -0
- package/dist/voxel/ray.d.ts +32 -0
- package/dist/voxel/ray.js +73 -0
- package/dist/voxel/wgsl.d.ts +16 -0
- package/dist/voxel/wgsl.js +28 -0
- package/dist/voxel/worker-client.d.ts +79 -0
- package/dist/voxel/worker-client.js +122 -0
- package/package.json +177 -3
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { toFrameUnits } from './text-scale.js';
|
|
2
|
+
/**
|
|
3
|
+
* The overlay's root and layers (ui/overlay.ts), in CSS px. `--tc-unit` is what one px of a
|
|
4
|
+
* design-px stylesheet (`toFrameUnits`) draws as on each layer: one design px of the frame
|
|
5
|
+
* (`--tc-dpx`) on the frame's layers, one CSS px in the layout's regions and, in `css` units,
|
|
6
|
+
* in the panels and toasts.
|
|
7
|
+
*/
|
|
8
|
+
const ROOT_CSS = `
|
|
9
|
+
.tc-overlay {
|
|
10
|
+
position: absolute; inset: 0; --tc-unit: var(--tc-dpx, 1px);
|
|
11
|
+
pointer-events: none; overflow: hidden; contain: layout style;
|
|
12
|
+
font-family: var(--tc-font-body); font-size: var(--tc-font-size-m);
|
|
13
|
+
line-height: var(--tc-line-height); color: var(--tc-color-text);
|
|
14
|
+
-webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
|
|
15
|
+
user-select: none; -webkit-user-select: none;
|
|
16
|
+
}
|
|
17
|
+
.tc-overlay *, .tc-overlay *::before, .tc-overlay *::after { box-sizing: border-box; }
|
|
18
|
+
/* Each layer is its own stacking context: a z-index inside one never lifts it over a later layer. */
|
|
19
|
+
.tc-layer { position: absolute; inset: 0; pointer-events: none; isolation: isolate; }
|
|
20
|
+
.tc-layer[data-layer="hud"], .tc-layer[data-layer="captions"],
|
|
21
|
+
.tc-overlay[data-units="frame"] > .tc-layer:is([data-layer="panels"], [data-layer="toasts"]) {
|
|
22
|
+
inset: auto; left: var(--tc-frame-x, 0px); top: var(--tc-frame-y, 0px);
|
|
23
|
+
width: var(--tc-frame-w, 100%); height: var(--tc-frame-h, 100%); overflow: hidden; }
|
|
24
|
+
.tc-layer[data-layer="layout"],
|
|
25
|
+
.tc-overlay[data-units="css"] > .tc-layer:is([data-layer="panels"], [data-layer="toasts"]) { --tc-unit: 1px; }
|
|
26
|
+
/* Native controls draw their thumb, track and arrow in CSS px whatever their box: on the frame's
|
|
27
|
+
layers they are zoomed by the frame's scale instead, their own px read as design px. */
|
|
28
|
+
.tc-layer:is([data-layer="hud"], [data-layer="captions"]) :is(input[type="range"], select),
|
|
29
|
+
.tc-overlay[data-units="frame"] > .tc-layer:is([data-layer="panels"], [data-layer="toasts"]) :is(input[type="range"], select) {
|
|
30
|
+
zoom: var(--tc-zoom, 1); --tc-unit: 1px; }
|
|
31
|
+
/* Theme tokens are resolved on the root, so they are frame px already: a zoomed select would
|
|
32
|
+
draw them at --tc-dpx² (ws/ui-widgets wish). Divide the ones it reads back out. */
|
|
33
|
+
.tc-layer:is([data-layer="hud"], [data-layer="captions"]) select,
|
|
34
|
+
.tc-overlay[data-units="frame"] > .tc-layer:is([data-layer="panels"], [data-layer="toasts"]) select {
|
|
35
|
+
font-size: calc(var(--tc-font-size-s) / var(--tc-zoom, 1));
|
|
36
|
+
padding: calc(var(--tc-space-2) / var(--tc-zoom, 1)) calc(var(--tc-space-3) / var(--tc-zoom, 1));
|
|
37
|
+
border-width: calc(var(--tc-border-width) / var(--tc-zoom, 1));
|
|
38
|
+
border-radius: calc(var(--tc-radius-m) / var(--tc-zoom, 1)); }
|
|
39
|
+
/* Theme lengths are already frame px there: undo the zoom for them (a hair over, so the
|
|
40
|
+
whole-pixel ring the token rounds to does not snap down a pixel). */
|
|
41
|
+
.tc-layer:is([data-layer="hud"], [data-layer="captions"]) :is(input[type="range"], select):focus-visible,
|
|
42
|
+
.tc-overlay[data-units="frame"] > .tc-layer:is([data-layer="panels"], [data-layer="toasts"]) :is(input[type="range"], select):focus-visible {
|
|
43
|
+
outline-width: calc(var(--tc-focus-ring) / var(--tc-zoom, 1) + 0.1px); }
|
|
44
|
+
`;
|
|
45
|
+
/** Base widgets, in design px (`toFrameUnits`: one px is `--tc-unit`). */
|
|
46
|
+
const WIDGET_CSS = `
|
|
47
|
+
.tc-interactive { pointer-events: auto; }
|
|
48
|
+
|
|
49
|
+
.tc-panel-host { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; }
|
|
50
|
+
.tc-panel-host[data-modal="true"] { pointer-events: auto; }
|
|
51
|
+
.tc-backdrop { position: absolute; inset: 0; background: var(--tc-color-backdrop); animation: tc-fade var(--tc-duration-normal) var(--tc-easing); }
|
|
52
|
+
.tc-panel { position: relative; pointer-events: auto; max-width: 90%; max-height: 90%; overflow: auto; outline: none;
|
|
53
|
+
animation: tc-rise var(--tc-duration-normal) var(--tc-easing); }
|
|
54
|
+
.tc-card { background: var(--tc-color-surface); color: var(--tc-color-text);
|
|
55
|
+
border: var(--tc-border-width) solid var(--tc-color-border); border-radius: var(--tc-radius-l);
|
|
56
|
+
box-shadow: var(--tc-shadow); padding: var(--tc-space-5); }
|
|
57
|
+
.tc-panel-title { font-family: var(--tc-font-display); font-size: var(--tc-font-size-l); margin: 0 0 var(--tc-space-3); font-weight: 600; }
|
|
58
|
+
|
|
59
|
+
.tc-button { pointer-events: auto; font: inherit; font-family: var(--tc-font-display); font-size: var(--tc-font-size-m);
|
|
60
|
+
color: var(--tc-color-text); background: var(--tc-color-surface-alt);
|
|
61
|
+
border: var(--tc-border-width) solid var(--tc-color-border); border-radius: var(--tc-radius-m);
|
|
62
|
+
padding: var(--tc-space-2) var(--tc-space-4); min-height: 64px; cursor: pointer;
|
|
63
|
+
transition: background var(--tc-duration-fast), border-color var(--tc-duration-fast), transform var(--tc-duration-fast); }
|
|
64
|
+
.tc-button:hover:not(:disabled) { border-color: var(--tc-color-accent); }
|
|
65
|
+
.tc-button:active:not(:disabled) { transform: translateY(1px); }
|
|
66
|
+
.tc-button:disabled { opacity: 0.45; cursor: default; }
|
|
67
|
+
.tc-button[data-variant="primary"] { background: var(--tc-color-accent); color: var(--tc-color-accent-text); border-color: var(--tc-color-accent); }
|
|
68
|
+
.tc-button[data-variant="ghost"] { background: transparent; border-color: transparent; }
|
|
69
|
+
.tc-overlay :focus-visible { outline: var(--tc-focus-ring) solid var(--tc-color-focus); outline-offset: 4px; }
|
|
70
|
+
|
|
71
|
+
.tc-field { display: flex; align-items: center; gap: var(--tc-space-3); pointer-events: auto; font-family: var(--tc-font-ui); font-size: var(--tc-font-size-s); }
|
|
72
|
+
.tc-field input[type="range"] { flex: 1; accent-color: var(--tc-color-accent); min-height: 48px; }
|
|
73
|
+
.tc-field input[type="checkbox"] { width: 32px; height: 32px; accent-color: var(--tc-color-accent); }
|
|
74
|
+
|
|
75
|
+
.tc-toasts { position: absolute; left: 50%; top: var(--tc-space-5); transform: translateX(-50%);
|
|
76
|
+
display: flex; flex-direction: column; align-items: center; gap: var(--tc-space-2); }
|
|
77
|
+
.tc-toast { pointer-events: auto; cursor: pointer; background: var(--tc-color-surface); color: var(--tc-color-text);
|
|
78
|
+
border-left: 6px solid var(--tc-color-info); border-radius: var(--tc-radius-m); box-shadow: var(--tc-shadow);
|
|
79
|
+
padding: var(--tc-space-3) var(--tc-space-4); font-family: var(--tc-font-ui); font-size: var(--tc-font-size-s);
|
|
80
|
+
max-width: 1100px; animation: tc-drop var(--tc-duration-normal) var(--tc-easing); }
|
|
81
|
+
.tc-toast[data-tone="success"] { border-left-color: var(--tc-color-success); }
|
|
82
|
+
.tc-toast[data-tone="warn"] { border-left-color: var(--tc-color-warn); }
|
|
83
|
+
.tc-toast[data-tone="danger"] { border-left-color: var(--tc-color-danger); }
|
|
84
|
+
|
|
85
|
+
.tc-caption { position: absolute; pointer-events: auto; cursor: pointer; display: flex; gap: var(--tc-space-3); align-items: flex-start;
|
|
86
|
+
width: max-content; max-width: min(var(--tc-caption-max-width, 720px), calc(100% - 2 * var(--tc-caption-margin, var(--tc-space-5))));
|
|
87
|
+
background: var(--tc-color-surface); border: var(--tc-border-width) solid var(--tc-color-border);
|
|
88
|
+
border-radius: var(--tc-radius-m); box-shadow: var(--tc-shadow); padding: var(--tc-space-3) var(--tc-space-4);
|
|
89
|
+
transition: opacity var(--tc-duration-normal) var(--tc-easing), transform var(--tc-duration-normal) var(--tc-easing); }
|
|
90
|
+
.tc-caption[hidden], .tc-caption[data-suspended] { display: none; }
|
|
91
|
+
.tc-caption[data-corner$="right"] { right: var(--tc-caption-margin, var(--tc-space-5)); }
|
|
92
|
+
.tc-caption[data-corner$="left"] { left: var(--tc-caption-margin, var(--tc-space-5)); }
|
|
93
|
+
.tc-caption[data-corner^="bottom"] { bottom: var(--tc-caption-margin, var(--tc-space-5)); }
|
|
94
|
+
.tc-caption[data-corner^="top"] { top: var(--tc-caption-margin, var(--tc-space-5)); }
|
|
95
|
+
.tc-caption-side { flex: none; display: flex; flex-direction: column; align-items: center; gap: var(--tc-space-1); }
|
|
96
|
+
.tc-caption-side[hidden], .tc-caption-portrait:empty { display: none; }
|
|
97
|
+
.tc-caption-body { flex: 1 1 auto; min-width: 0; }
|
|
98
|
+
.tc-caption-speaker { font-family: var(--tc-font-ui); font-size: var(--tc-font-size-s); color: var(--tc-color-accent);
|
|
99
|
+
letter-spacing: 0.08em; text-transform: uppercase; line-height: 1.2; }
|
|
100
|
+
.tc-caption-body > .tc-caption-speaker { margin-bottom: var(--tc-space-1); }
|
|
101
|
+
.tc-caption-speaker:empty { display: none; }
|
|
102
|
+
.tc-caption-text { font-size: var(--tc-font-size-m); white-space: pre-wrap; overflow-wrap: break-word; }
|
|
103
|
+
.tc-caption-text .tc-caption-pending { visibility: hidden; }
|
|
104
|
+
|
|
105
|
+
.tc-link { position: relative; display: flex; flex-direction: column; align-items: center; pointer-events: auto; }
|
|
106
|
+
.tc-link-row { display: flex; align-items: center; gap: var(--tc-space-2); }
|
|
107
|
+
.tc-link-copy { pointer-events: auto; display: inline-flex; align-items: center; gap: var(--tc-space-2); padding: 6px 14px;
|
|
108
|
+
border-radius: 999px; cursor: pointer; white-space: nowrap; font-family: var(--tc-font-ui); font-size: calc(var(--tc-font-size-s) * 0.75);
|
|
109
|
+
line-height: 1.2; color: var(--tc-color-text); background: var(--tc-color-surface); border: 1px solid var(--tc-color-border); }
|
|
110
|
+
.tc-link-copy:hover { border-color: var(--tc-color-accent); }
|
|
111
|
+
.tc-link-copy[data-copied] { color: var(--tc-color-success); border-color: var(--tc-color-success); }
|
|
112
|
+
.tc-link-copy-icon { width: 1.1em; height: 1.1em; flex: none; }
|
|
113
|
+
.tc-link-fallback { position: absolute; z-index: 5; display: flex; flex-direction: column; gap: var(--tc-space-2);
|
|
114
|
+
width: max-content; min-width: 560px; max-width: 1000px;
|
|
115
|
+
box-sizing: border-box; padding: 12px var(--tc-space-3) 14px; text-align: left; pointer-events: auto;
|
|
116
|
+
background: var(--tc-color-surface); border: 1px solid var(--tc-color-border); border-radius: var(--tc-radius-m); box-shadow: var(--tc-shadow); }
|
|
117
|
+
.tc-link-fallback[hidden] { display: none; }
|
|
118
|
+
.tc-link-fallback[data-place="below"] { top: calc(100% + 10px); }
|
|
119
|
+
.tc-link-fallback[data-place="above"] { bottom: calc(100% + 10px); }
|
|
120
|
+
.tc-link-fallback[data-align="center"] { left: 50%; transform: translateX(-50%); }
|
|
121
|
+
.tc-link-fallback[data-align="start"] { left: 0; }
|
|
122
|
+
.tc-link-fallback[data-align="end"] { right: 0; }
|
|
123
|
+
.tc-link-fallback-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--tc-space-3); }
|
|
124
|
+
.tc-link-message { font-family: var(--tc-font-ui); font-size: calc(var(--tc-font-size-s) * 0.75); line-height: 1.3; color: var(--tc-color-text); }
|
|
125
|
+
.tc-link-close { flex: none; padding: 3px 12px; border-radius: 999px; cursor: pointer; font-family: var(--tc-font-ui);
|
|
126
|
+
font-size: calc(var(--tc-font-size-s) * 0.67); color: var(--tc-color-text); background: transparent; border: 1px solid var(--tc-color-border); }
|
|
127
|
+
.tc-link-close:hover { border-color: var(--tc-color-accent); }
|
|
128
|
+
.tc-link-field { width: 100%; box-sizing: border-box; padding: 6px 10px; border-radius: var(--tc-radius-s); font-family: var(--tc-font-mono);
|
|
129
|
+
font-size: calc(var(--tc-font-size-s) * 0.83); color: var(--tc-color-text); background: var(--tc-color-bg); border: 1px solid var(--tc-color-border); }
|
|
130
|
+
|
|
131
|
+
`;
|
|
132
|
+
/** The layers that follow the form's units (regions, and panels and toasts in `css` units). */
|
|
133
|
+
const CSSU = '.tc-overlay[data-units="css"] :is(.tc-layer[data-layer="layout"], .tc-layer[data-layer="panels"], .tc-layer[data-layer="toasts"])';
|
|
134
|
+
/** `css` units: base widgets in regions, panels and toasts honour the density tokens (CSS px). */
|
|
135
|
+
const CSS_UNITS_CSS = `
|
|
136
|
+
${CSSU} .tc-button { min-height: var(--tc-tap-min, 32px); min-width: var(--tc-tap-min, 32px);
|
|
137
|
+
padding: var(--tc-space-2) var(--tc-space-4); }
|
|
138
|
+
${CSSU} .tc-field { min-height: var(--tc-tap-min, 32px); }
|
|
139
|
+
${CSSU} .tc-field input[type="range"] { min-height: var(--tc-tap-min, 32px); margin: 0; }
|
|
140
|
+
${CSSU} .tc-field input[type="checkbox"] { width: 20px; height: 20px; }
|
|
141
|
+
${CSSU} .tc-panel-host { padding: var(--tc-modal-top, 8px) var(--tc-modal-right, 8px) var(--tc-modal-bottom, 8px) var(--tc-modal-left, 8px); }
|
|
142
|
+
${CSSU} .tc-panel { max-width: 100%; max-height: 100%; }
|
|
143
|
+
${CSSU} .tc-toasts { top: calc(var(--tc-safe-top-px, 0px) + var(--tc-space-4)); width: max-content; max-width: calc(100% - 32px); }
|
|
144
|
+
${CSSU} .tc-toast { max-width: 560px; }
|
|
145
|
+
${CSSU} .tc-caption { --tc-caption-max-width: 480px; --tc-caption-margin: var(--tc-space-4); }
|
|
146
|
+
${CSSU} .tc-link-fallback { min-width: 0; width: min(480px, 90vw); }
|
|
147
|
+
|
|
148
|
+
/* Layout regions (ui/layout.ts). The grid is laid out in the safe area; regions scroll rather than spill. */
|
|
149
|
+
.tc-layout { position: absolute; inset: 0; display: grid; pointer-events: none; }
|
|
150
|
+
.tc-region { position: relative; min-width: 0; min-height: 0; overflow: auto; overscroll-behavior: contain;
|
|
151
|
+
display: flex; gap: var(--tc-region-pad, 8px); padding: var(--tc-region-pad, 8px); pointer-events: none; }
|
|
152
|
+
.tc-region[hidden] { display: none; }
|
|
153
|
+
.tc-region > * { flex: none; }
|
|
154
|
+
.tc-region[data-region="top"], .tc-region[data-region="bottom"] { flex-direction: row; align-items: center; }
|
|
155
|
+
.tc-region[data-region="left"], .tc-region[data-region="right"], .tc-region[data-region="cardLane"] { flex-direction: column; align-items: stretch; }
|
|
156
|
+
.tc-region[data-region="captionLane"] { flex-direction: row; align-items: stretch; }
|
|
157
|
+
.tc-region[data-region="fill"], .tc-region[data-region="modal"] { flex-direction: column; align-items: center; justify-content: center; }
|
|
158
|
+
.tc-region[data-region="modal"] { position: absolute; }
|
|
159
|
+
.tc-layout-free { position: absolute; inset: 0; pointer-events: none; }
|
|
160
|
+
.tc-overlay [data-tc-layout-hidden] { display: none !important; }
|
|
161
|
+
.tc-caption[data-docked] { position: relative; inset: auto; width: 100%; max-width: none; max-height: 100%; overflow: auto; flex: 1 1 auto; }
|
|
162
|
+
|
|
163
|
+
.tc-sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
|
|
164
|
+
clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
|
|
165
|
+
|
|
166
|
+
@keyframes tc-fade { from { opacity: 0; } }
|
|
167
|
+
@keyframes tc-rise { from { opacity: 0; transform: translateY(16px) scale(0.98); } }
|
|
168
|
+
@keyframes tc-drop { from { opacity: 0; transform: translateY(-12px); } }
|
|
169
|
+
@media (prefers-reduced-motion: reduce) {
|
|
170
|
+
.tc-overlay *, .tc-overlay *::before, .tc-overlay *::after { animation: none !important; transition: none !important; }
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
/**
|
|
174
|
+
* The overlay's base stylesheet: tokens, layers, panels, widgets and units. Injected once
|
|
175
|
+
* per document by `ensureStyles`; the HUD, cursor, tooltip and other widget sheets add
|
|
176
|
+
* their own `<style>` beside it. Everything is under `.tc-overlay`.
|
|
177
|
+
*/
|
|
178
|
+
export const BASE_CSS = ROOT_CSS + toFrameUnits(WIDGET_CSS) + CSS_UNITS_CSS;
|
|
179
|
+
const STYLE_ID = 'tc-ui-base';
|
|
180
|
+
/** Add the base stylesheet to `doc` once. */
|
|
181
|
+
export function ensureStyles(doc = document) {
|
|
182
|
+
if (doc.getElementById(STYLE_ID))
|
|
183
|
+
return;
|
|
184
|
+
const style = doc.createElement('style');
|
|
185
|
+
style.id = STYLE_ID;
|
|
186
|
+
style.textContent = BASE_CSS;
|
|
187
|
+
doc.head.appendChild(style);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* True if the user prefers reduced motion in `win` (default the global window; false where
|
|
191
|
+
* `matchMedia` is unavailable). `platform`'s `prefersReducedMotion()` reads the global window only.
|
|
192
|
+
*/
|
|
193
|
+
export function prefersReducedMotionIn(win = globalThis.window) {
|
|
194
|
+
try {
|
|
195
|
+
return !!win?.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text size: the density tokens `--tc-text-scale` and `--tc-text-min` on the overlay root.
|
|
3
|
+
*
|
|
4
|
+
* - `--tc-text-scale` is the player's text size as a factor (1, 1.25, 1.5 …). A game passes each
|
|
5
|
+
* stylesheet through `scaleFontSizes()` when it injects it, so all overlay text follows the
|
|
6
|
+
* token live. `applyTextScale()` sets it, plus the engine's own font tokens to match.
|
|
7
|
+
* - `--tc-text-min` is a floor for every scaled font size, CSS px. The layout sets it from its
|
|
8
|
+
* form spec (`FormSpec.textMin`; 0 = no floor).
|
|
9
|
+
*
|
|
10
|
+
* A stylesheet written in design px (sizes that scale with the canvas frame) also passes
|
|
11
|
+
* through `toFrameUnits()`, after `scaleFontSizes()`: every `Npx` becomes N design px.
|
|
12
|
+
*
|
|
13
|
+
* Small text scales fully. Large display text is already big, so it only grows as far as needed
|
|
14
|
+
* to stay at least as large as scaled body text: a size N becomes max(N, min(N, 30) × scale).
|
|
15
|
+
* At 150%, 24 px → 36, 30 → 45, 40 → 45, 56 → 56.
|
|
16
|
+
*/
|
|
17
|
+
export declare const TEXT_SCALE_VAR = "--tc-text-scale";
|
|
18
|
+
/** Smallest font size in design px; every scaled size floors at it. */
|
|
19
|
+
export declare const TEXT_MIN_VAR = "--tc-text-min";
|
|
20
|
+
/** The scaled value of `px` at `scale` (1 = 100%). */
|
|
21
|
+
export declare function scaledPx(px: number, scale: number): number;
|
|
22
|
+
/** A CSS length for `px` that follows `--tc-text-scale` and floors at `--tc-text-min`. */
|
|
23
|
+
export declare function scalePxCss(px: number): string;
|
|
24
|
+
/**
|
|
25
|
+
* What one px of a `toFrameUnits` stylesheet draws as, CSS px: one design px of the frame
|
|
26
|
+
* (`--tc-dpx`, `Overlay.scale`) on the frame's layers; 1px in the layout's regions and, in `css`
|
|
27
|
+
* units, in the panels and toasts.
|
|
28
|
+
*/
|
|
29
|
+
export declare const UNIT_VAR = "--tc-unit";
|
|
30
|
+
/**
|
|
31
|
+
* Rewrites every `Npx` length in `css` (a stylesheet, a declaration or one value) as N design
|
|
32
|
+
* px: `calc(N * var(--tc-unit, 1px))`, so it scales with the canvas frame. Media and container
|
|
33
|
+
* queries and `url()`s are left alone (custom properties can't be used there).
|
|
34
|
+
*/
|
|
35
|
+
export declare function toFrameUnits(css: string): string;
|
|
36
|
+
/** Rewrites every `font-size: Npx` (and `font: … Npx/…` shorthand) in a stylesheet. */
|
|
37
|
+
export declare function scaleFontSizes(css: string): string;
|
|
38
|
+
/** The engine's font sizes at 100% on a scaled design-px overlay. */
|
|
39
|
+
export declare const DESIGN_FONT_PX: {
|
|
40
|
+
fontSizeS: number;
|
|
41
|
+
fontSizeM: number;
|
|
42
|
+
fontSizeL: number;
|
|
43
|
+
fontSizeXl: number;
|
|
44
|
+
fontSizeXxl: number;
|
|
45
|
+
};
|
|
46
|
+
/** The engine's font sizes at 100% on a CSS-px overlay (`cssPxTheme`). */
|
|
47
|
+
export declare const CSS_FONT_PX: {
|
|
48
|
+
fontSizeS: number;
|
|
49
|
+
fontSizeM: number;
|
|
50
|
+
fontSizeL: number;
|
|
51
|
+
fontSizeXl: number;
|
|
52
|
+
fontSizeXxl: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Engine theme font tokens at a text scale (the engine's own captions, panels and buttons).
|
|
56
|
+
* `base` is `DESIGN_FONT_PX` (default) or `CSS_FONT_PX` for a CSS-px overlay. Body sizes scale
|
|
57
|
+
* as `scaledPx` does relative to the design body size, so both bases grow the same way.
|
|
58
|
+
*/
|
|
59
|
+
export declare function textScaleTokens(scale: number, base?: Record<string, number>): Record<string, string>;
|
|
60
|
+
/**
|
|
61
|
+
* Sets the text scale (1 = 100%) on the overlay root: `--tc-text-scale`, and
|
|
62
|
+
* `data-text-scale="<percent>"` when it is not 100% so stylesheets can make room for larger
|
|
63
|
+
* text. `setTheme` (usually `overlay.setTheme`) gets the engine font tokens to match: CSS-px
|
|
64
|
+
* sizes while the overlay is in `css` units (`data-units="css"`), design px otherwise (the
|
|
65
|
+
* overlay scales those with the frame, and re-derives them when its units change).
|
|
66
|
+
*/
|
|
67
|
+
export declare function applyTextScale(root: HTMLElement, scale: number, setTheme?: (t: Record<string, string>) => void): void;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text size: the density tokens `--tc-text-scale` and `--tc-text-min` on the overlay root.
|
|
3
|
+
*
|
|
4
|
+
* - `--tc-text-scale` is the player's text size as a factor (1, 1.25, 1.5 …). A game passes each
|
|
5
|
+
* stylesheet through `scaleFontSizes()` when it injects it, so all overlay text follows the
|
|
6
|
+
* token live. `applyTextScale()` sets it, plus the engine's own font tokens to match.
|
|
7
|
+
* - `--tc-text-min` is a floor for every scaled font size, CSS px. The layout sets it from its
|
|
8
|
+
* form spec (`FormSpec.textMin`; 0 = no floor).
|
|
9
|
+
*
|
|
10
|
+
* A stylesheet written in design px (sizes that scale with the canvas frame) also passes
|
|
11
|
+
* through `toFrameUnits()`, after `scaleFontSizes()`: every `Npx` becomes N design px.
|
|
12
|
+
*
|
|
13
|
+
* Small text scales fully. Large display text is already big, so it only grows as far as needed
|
|
14
|
+
* to stay at least as large as scaled body text: a size N becomes max(N, min(N, 30) × scale).
|
|
15
|
+
* At 150%, 24 px → 36, 30 → 45, 40 → 45, 56 → 56.
|
|
16
|
+
*/
|
|
17
|
+
export const TEXT_SCALE_VAR = '--tc-text-scale';
|
|
18
|
+
/** Smallest font size in design px; every scaled size floors at it. */
|
|
19
|
+
export const TEXT_MIN_VAR = '--tc-text-min';
|
|
20
|
+
const MIN = `var(${TEXT_MIN_VAR}, 0px)`;
|
|
21
|
+
/** Sizes up to this scale fully; above it, text is only kept from falling behind. */
|
|
22
|
+
const BODY_PX = 30;
|
|
23
|
+
/** The scaled value of `px` at `scale` (1 = 100%). */
|
|
24
|
+
export function scaledPx(px, scale) {
|
|
25
|
+
return Math.max(px, Math.min(px, BODY_PX) * scale);
|
|
26
|
+
}
|
|
27
|
+
/** A CSS length for `px` that follows `--tc-text-scale` and floors at `--tc-text-min`. */
|
|
28
|
+
export function scalePxCss(px) {
|
|
29
|
+
const v = `var(${TEXT_SCALE_VAR}, 1)`;
|
|
30
|
+
if (px <= BODY_PX)
|
|
31
|
+
return `max(calc(${px}px * ${v}), ${MIN})`;
|
|
32
|
+
if (px < BODY_PX * 1.5)
|
|
33
|
+
return `max(${px}px, calc(${BODY_PX}px * ${v}), ${MIN})`;
|
|
34
|
+
return `${px}px`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* What one px of a `toFrameUnits` stylesheet draws as, CSS px: one design px of the frame
|
|
38
|
+
* (`--tc-dpx`, `Overlay.scale`) on the frame's layers; 1px in the layout's regions and, in `css`
|
|
39
|
+
* units, in the panels and toasts.
|
|
40
|
+
*/
|
|
41
|
+
export const UNIT_VAR = '--tc-unit';
|
|
42
|
+
/**
|
|
43
|
+
* Rewrites every `Npx` length in `css` (a stylesheet, a declaration or one value) as N design
|
|
44
|
+
* px: `calc(N * var(--tc-unit, 1px))`, so it scales with the canvas frame. Media and container
|
|
45
|
+
* queries and `url()`s are left alone (custom properties can't be used there).
|
|
46
|
+
*/
|
|
47
|
+
export function toFrameUnits(css) {
|
|
48
|
+
return css.replace(/(@(?:media|container|supports)[^{]*)|(url\([^)]*\))|(?<![\w.-])(-?(?:\d+\.?\d*|\.\d+))px\b/g, (m, at, url, n) => at || url || n === undefined ? m : `calc(${n} * var(${UNIT_VAR}, 1px))`);
|
|
49
|
+
}
|
|
50
|
+
/** Rewrites every `font-size: Npx` (and `font: … Npx/…` shorthand) in a stylesheet. */
|
|
51
|
+
export function scaleFontSizes(css) {
|
|
52
|
+
return css
|
|
53
|
+
.replace(/font-size:\s*(\d+(?:\.\d+)?)px/g, (_, n) => `font-size: ${scalePxCss(+n)}`)
|
|
54
|
+
.replace(/(\bfont:\s*(?:\d{3}\s+)?)(\d+(?:\.\d+)?)px(?=\s*\/|\s)/g, (_, pre, n) => `${pre}${scalePxCss(+n)}`);
|
|
55
|
+
}
|
|
56
|
+
/** The engine's font sizes at 100% on a scaled design-px overlay. */
|
|
57
|
+
export const DESIGN_FONT_PX = {
|
|
58
|
+
fontSizeS: 24,
|
|
59
|
+
fontSizeM: 30,
|
|
60
|
+
fontSizeL: 40,
|
|
61
|
+
fontSizeXl: 56,
|
|
62
|
+
fontSizeXxl: 84,
|
|
63
|
+
};
|
|
64
|
+
/** The engine's font sizes at 100% on a CSS-px overlay (`cssPxTheme`). */
|
|
65
|
+
export const CSS_FONT_PX = {
|
|
66
|
+
fontSizeS: 14,
|
|
67
|
+
fontSizeM: 16,
|
|
68
|
+
fontSizeL: 20,
|
|
69
|
+
fontSizeXl: 28,
|
|
70
|
+
fontSizeXxl: 40,
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Engine theme font tokens at a text scale (the engine's own captions, panels and buttons).
|
|
74
|
+
* `base` is `DESIGN_FONT_PX` (default) or `CSS_FONT_PX` for a CSS-px overlay. Body sizes scale
|
|
75
|
+
* as `scaledPx` does relative to the design body size, so both bases grow the same way.
|
|
76
|
+
*/
|
|
77
|
+
export function textScaleTokens(scale, base = DESIGN_FONT_PX) {
|
|
78
|
+
// scaledPx's body/display split is in design px; map CSS sizes onto it by the M ratio.
|
|
79
|
+
const k = (base.fontSizeM ?? 30) / 30;
|
|
80
|
+
const out = {};
|
|
81
|
+
for (const [name, px] of Object.entries(base)) {
|
|
82
|
+
const v = Math.round(scaledPx(px / k, scale) * k);
|
|
83
|
+
out[name] = v < 50 * k ? `max(${v}px, ${MIN})` : `${v}px`;
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Sets the text scale (1 = 100%) on the overlay root: `--tc-text-scale`, and
|
|
89
|
+
* `data-text-scale="<percent>"` when it is not 100% so stylesheets can make room for larger
|
|
90
|
+
* text. `setTheme` (usually `overlay.setTheme`) gets the engine font tokens to match: CSS-px
|
|
91
|
+
* sizes while the overlay is in `css` units (`data-units="css"`), design px otherwise (the
|
|
92
|
+
* overlay scales those with the frame, and re-derives them when its units change).
|
|
93
|
+
*/
|
|
94
|
+
export function applyTextScale(root, scale, setTheme) {
|
|
95
|
+
root.style.setProperty(TEXT_SCALE_VAR, String(scale));
|
|
96
|
+
const pct = Math.round(scale * 100);
|
|
97
|
+
if (pct === 100)
|
|
98
|
+
delete root.dataset.textScale;
|
|
99
|
+
else
|
|
100
|
+
root.dataset.textScale = String(pct);
|
|
101
|
+
setTheme?.(textScaleTokens(scale, root.dataset.units === 'css' ? CSS_FONT_PX : DESIGN_FONT_PX));
|
|
102
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme tokens, exposed as CSS custom properties on the overlay root: `colorAccent` becomes
|
|
3
|
+
* `--tc-color-accent`. Sizes are in **design pixels** of the frame (1920×1080 by default): in
|
|
4
|
+
* `frame` units each is `--tc-dpx` CSS px, so 30px reads as ~15px in a 960×540 embed.
|
|
5
|
+
*
|
|
6
|
+
* Fonts are system stacks only: nothing is fetched at runtime. A game may add a self-hosted
|
|
7
|
+
* font with `@font-face` (committed with its licence) and put it first in a stack.
|
|
8
|
+
*/
|
|
9
|
+
export declare const defaultTheme: {
|
|
10
|
+
fontBody: string;
|
|
11
|
+
fontDisplay: string;
|
|
12
|
+
fontMono: string;
|
|
13
|
+
fontUi: string;
|
|
14
|
+
fontSizeS: string;
|
|
15
|
+
fontSizeM: string;
|
|
16
|
+
fontSizeL: string;
|
|
17
|
+
fontSizeXl: string;
|
|
18
|
+
fontSizeXxl: string;
|
|
19
|
+
lineHeight: string;
|
|
20
|
+
colorBg: string;
|
|
21
|
+
colorSurface: string;
|
|
22
|
+
colorSurfaceAlt: string;
|
|
23
|
+
colorBorder: string;
|
|
24
|
+
colorText: string;
|
|
25
|
+
colorTextMuted: string;
|
|
26
|
+
colorAccent: string;
|
|
27
|
+
colorAccentText: string;
|
|
28
|
+
colorFocus: string;
|
|
29
|
+
colorBackdrop: string;
|
|
30
|
+
colorInfo: string;
|
|
31
|
+
colorSuccess: string;
|
|
32
|
+
colorWarn: string;
|
|
33
|
+
colorDanger: string;
|
|
34
|
+
/** The damage trail behind a meter's fill (ws/ui-5). */
|
|
35
|
+
colorMeterTrail: string;
|
|
36
|
+
space1: string;
|
|
37
|
+
space2: string;
|
|
38
|
+
space3: string;
|
|
39
|
+
space4: string;
|
|
40
|
+
space5: string;
|
|
41
|
+
space6: string;
|
|
42
|
+
radiusS: string;
|
|
43
|
+
radiusM: string;
|
|
44
|
+
radiusL: string;
|
|
45
|
+
borderWidth: string;
|
|
46
|
+
shadow: string;
|
|
47
|
+
focusRing: string;
|
|
48
|
+
durationFast: string;
|
|
49
|
+
durationNormal: string;
|
|
50
|
+
easing: string;
|
|
51
|
+
};
|
|
52
|
+
export type ThemeTokens = {
|
|
53
|
+
[K in keyof typeof defaultTheme]: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Size tokens for the overlay's `css` units (phones; `FormSpec.units`), applied over
|
|
57
|
+
* `defaultTheme`: the same scale at screen size (about half the design-px values), so 16 px body
|
|
58
|
+
* text reads as 16 px on every screen. Colours, fonts and timings are shared.
|
|
59
|
+
*/
|
|
60
|
+
export declare const cssPxTheme: Partial<ThemeTokens>;
|
|
61
|
+
/** Games may add their own tokens too; they become `--tc-<kebab-name>` the same way. */
|
|
62
|
+
export type ThemeOverrides = Partial<ThemeTokens> & Record<string, string>;
|
|
63
|
+
/** `colorAccent` → `--tc-color-accent`, `fontSizeXl` → `--tc-font-size-xl`, `space1` → `--tc-space-1`. */
|
|
64
|
+
export declare function tokenVar(name: string): string;
|
|
65
|
+
/** `var(--tc-…)` for use in inline styles. */
|
|
66
|
+
export declare function cssVar(name: keyof ThemeTokens | (string & {})): string;
|
|
67
|
+
/** CSS declarations for a set of tokens, e.g. for a `:root` or class rule. */
|
|
68
|
+
export declare function themeToCss(tokens: Record<string, string>): string;
|
|
69
|
+
/** Set tokens as custom properties on an element (inherits to children). */
|
|
70
|
+
export declare function applyTheme(el: HTMLElement, tokens: Record<string, string>): void;
|
package/dist/ui/theme.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme tokens, exposed as CSS custom properties on the overlay root: `colorAccent` becomes
|
|
3
|
+
* `--tc-color-accent`. Sizes are in **design pixels** of the frame (1920×1080 by default): in
|
|
4
|
+
* `frame` units each is `--tc-dpx` CSS px, so 30px reads as ~15px in a 960×540 embed.
|
|
5
|
+
*
|
|
6
|
+
* Fonts are system stacks only: nothing is fetched at runtime. A game may add a self-hosted
|
|
7
|
+
* font with `@font-face` (committed with its licence) and put it first in a stack.
|
|
8
|
+
*/
|
|
9
|
+
export const defaultTheme = {
|
|
10
|
+
fontBody: "'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, serif",
|
|
11
|
+
fontDisplay: "'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, serif",
|
|
12
|
+
fontMono: "ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace",
|
|
13
|
+
fontUi: "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
|
|
14
|
+
fontSizeS: '24px',
|
|
15
|
+
fontSizeM: '30px',
|
|
16
|
+
fontSizeL: '40px',
|
|
17
|
+
fontSizeXl: '56px',
|
|
18
|
+
fontSizeXxl: '84px',
|
|
19
|
+
lineHeight: '1.4',
|
|
20
|
+
colorBg: '#0b0d14',
|
|
21
|
+
colorSurface: 'rgba(18, 21, 30, 0.94)',
|
|
22
|
+
colorSurfaceAlt: 'rgba(32, 36, 48, 0.96)',
|
|
23
|
+
colorBorder: 'rgba(224, 180, 90, 0.35)',
|
|
24
|
+
colorText: '#ece6d8',
|
|
25
|
+
colorTextMuted: '#a7a091',
|
|
26
|
+
colorAccent: '#e0b45a',
|
|
27
|
+
colorAccentText: '#1a1408',
|
|
28
|
+
colorFocus: '#ffd27a',
|
|
29
|
+
colorBackdrop: 'rgba(5, 6, 10, 0.6)',
|
|
30
|
+
colorInfo: '#7cc4e8',
|
|
31
|
+
colorSuccess: '#8fd18a',
|
|
32
|
+
colorWarn: '#f0b45a',
|
|
33
|
+
colorDanger: '#e8766a',
|
|
34
|
+
/** The damage trail behind a meter's fill (ws/ui-5). */
|
|
35
|
+
colorMeterTrail: 'rgba(255, 236, 200, 0.75)',
|
|
36
|
+
space1: '4px',
|
|
37
|
+
space2: '8px',
|
|
38
|
+
space3: '16px',
|
|
39
|
+
space4: '24px',
|
|
40
|
+
space5: '40px',
|
|
41
|
+
space6: '64px',
|
|
42
|
+
radiusS: '6px',
|
|
43
|
+
radiusM: '12px',
|
|
44
|
+
radiusL: '20px',
|
|
45
|
+
borderWidth: '2px',
|
|
46
|
+
shadow: '0 12px 48px rgba(0, 0, 0, 0.55)',
|
|
47
|
+
focusRing: '3px',
|
|
48
|
+
durationFast: '120ms',
|
|
49
|
+
durationNormal: '240ms',
|
|
50
|
+
easing: 'cubic-bezier(0.2, 0.7, 0.2, 1)',
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Size tokens for the overlay's `css` units (phones; `FormSpec.units`), applied over
|
|
54
|
+
* `defaultTheme`: the same scale at screen size (about half the design-px values), so 16 px body
|
|
55
|
+
* text reads as 16 px on every screen. Colours, fonts and timings are shared.
|
|
56
|
+
*/
|
|
57
|
+
export const cssPxTheme = {
|
|
58
|
+
fontSizeS: '14px',
|
|
59
|
+
fontSizeM: '16px',
|
|
60
|
+
fontSizeL: '20px',
|
|
61
|
+
fontSizeXl: '28px',
|
|
62
|
+
fontSizeXxl: '40px',
|
|
63
|
+
space1: '2px',
|
|
64
|
+
space2: '4px',
|
|
65
|
+
space3: '8px',
|
|
66
|
+
space4: '12px',
|
|
67
|
+
space5: '20px',
|
|
68
|
+
space6: '32px',
|
|
69
|
+
radiusS: '4px',
|
|
70
|
+
radiusM: '8px',
|
|
71
|
+
radiusL: '12px',
|
|
72
|
+
borderWidth: '1px',
|
|
73
|
+
shadow: '0 6px 24px rgba(0, 0, 0, 0.55)',
|
|
74
|
+
focusRing: '2px',
|
|
75
|
+
};
|
|
76
|
+
/** `colorAccent` → `--tc-color-accent`, `fontSizeXl` → `--tc-font-size-xl`, `space1` → `--tc-space-1`. */
|
|
77
|
+
export function tokenVar(name) {
|
|
78
|
+
const kebab = name
|
|
79
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
80
|
+
.replace(/([a-zA-Z])(\d)/g, '$1-$2')
|
|
81
|
+
.toLowerCase();
|
|
82
|
+
return `--tc-${kebab}`;
|
|
83
|
+
}
|
|
84
|
+
/** `var(--tc-…)` for use in inline styles. */
|
|
85
|
+
export function cssVar(name) {
|
|
86
|
+
return `var(${tokenVar(name)})`;
|
|
87
|
+
}
|
|
88
|
+
/** CSS declarations for a set of tokens, e.g. for a `:root` or class rule. */
|
|
89
|
+
export function themeToCss(tokens) {
|
|
90
|
+
return Object.entries(tokens)
|
|
91
|
+
.map(([k, v]) => `${tokenVar(k)}: ${v};`)
|
|
92
|
+
.join('\n');
|
|
93
|
+
}
|
|
94
|
+
/** Set tokens as custom properties on an element (inherits to children). */
|
|
95
|
+
export function applyTheme(el, tokens) {
|
|
96
|
+
for (const [k, v] of Object.entries(tokens))
|
|
97
|
+
el.style.setProperty(tokenVar(k), v);
|
|
98
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ToastTone = 'info' | 'success' | 'warn' | 'danger';
|
|
2
|
+
export interface ToastOptions {
|
|
3
|
+
/** ms before it disappears. `0` = until dismissed. Default 3500. */
|
|
4
|
+
duration?: number;
|
|
5
|
+
tone?: ToastTone;
|
|
6
|
+
}
|
|
7
|
+
export interface ToastHandle {
|
|
8
|
+
readonly element: HTMLElement;
|
|
9
|
+
dismiss(): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Transient notices in a polite live region. Click to dismiss. At most `max` are shown;
|
|
13
|
+
* the oldest goes first.
|
|
14
|
+
*/
|
|
15
|
+
export declare class Toaster {
|
|
16
|
+
private readonly max;
|
|
17
|
+
readonly element: HTMLElement;
|
|
18
|
+
private readonly live;
|
|
19
|
+
constructor(container: HTMLElement, max?: number);
|
|
20
|
+
get count(): number;
|
|
21
|
+
show(message: string | Node, opts?: ToastOptions): ToastHandle;
|
|
22
|
+
clear(): void;
|
|
23
|
+
}
|
package/dist/ui/toast.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { h } from './dom.js';
|
|
2
|
+
/**
|
|
3
|
+
* Transient notices in a polite live region. Click to dismiss. At most `max` are shown;
|
|
4
|
+
* the oldest goes first.
|
|
5
|
+
*/
|
|
6
|
+
export class Toaster {
|
|
7
|
+
max;
|
|
8
|
+
element;
|
|
9
|
+
live = [];
|
|
10
|
+
constructor(container, max = 3) {
|
|
11
|
+
this.max = max;
|
|
12
|
+
this.element = h('div', { class: 'tc-toasts', role: 'status', 'aria-live': 'polite' });
|
|
13
|
+
container.append(this.element);
|
|
14
|
+
}
|
|
15
|
+
get count() {
|
|
16
|
+
return this.live.length;
|
|
17
|
+
}
|
|
18
|
+
show(message, opts = {}) {
|
|
19
|
+
const el = h('div', { class: 'tc-toast', dataset: { tone: opts.tone ?? 'info' } }, message);
|
|
20
|
+
let timer = null;
|
|
21
|
+
const handle = {
|
|
22
|
+
element: el,
|
|
23
|
+
dismiss: () => {
|
|
24
|
+
if (timer)
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
const i = this.live.indexOf(handle);
|
|
27
|
+
if (i >= 0)
|
|
28
|
+
this.live.splice(i, 1);
|
|
29
|
+
el.remove();
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
el.addEventListener('click', () => handle.dismiss());
|
|
33
|
+
this.element.append(el);
|
|
34
|
+
this.live.push(handle);
|
|
35
|
+
while (this.live.length > this.max)
|
|
36
|
+
this.live[0].dismiss();
|
|
37
|
+
const duration = opts.duration ?? 3500;
|
|
38
|
+
if (duration > 0)
|
|
39
|
+
timer = setTimeout(handle.dismiss, duration);
|
|
40
|
+
return handle;
|
|
41
|
+
}
|
|
42
|
+
clear() {
|
|
43
|
+
for (const t of [...this.live])
|
|
44
|
+
t.dismiss();
|
|
45
|
+
}
|
|
46
|
+
}
|