Skip to content

Commit

Permalink
feat: combine focus and blur, default props, vanilla demo wip
Browse files Browse the repository at this point in the history
  • Loading branch information
verekia committed Apr 3, 2024
1 parent 94eb5e6 commit 46152c7
Show file tree
Hide file tree
Showing 31 changed files with 467 additions and 101 deletions.
6 changes: 2 additions & 4 deletions examples/react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,7 @@ const UI = ({
<h2 className="section-heading">🍃 Tailwind</h2>
<div>
<div>
Current width range:
<span className="hidden max-5xs:inline">5xs and below</span>
Current width range: <span className="hidden max-5xs:inline">5xs and below</span>
<span className="hidden 5xs:max-4xs:inline">5xs to 4xs</span>
<span className="hidden 4xs:max-3xs:inline">4xs to 3xs</span>
<span className="hidden 3xs:max-2xs:inline">3xs to 2xs</span>
Expand All @@ -308,8 +307,7 @@ const UI = ({
<span className="hidden 5xl:inline">5xl and up</span>
</div>
<div>
Current height range:
<span className="hidden max-5xs-h:inline">5xs and below</span>
Current height range: <span className="hidden max-5xs-h:inline">5xs and below</span>
<span className="hidden 5xs-h:max-4xs-h:inline">5xs to 4xs</span>
<span className="hidden 4xs-h:max-3xs-h:inline">4xs to 3xs</span>
<span className="hidden 3xs-h:max-2xs-h:inline">3xs to 2xs</span>
Expand Down
16 changes: 11 additions & 5 deletions examples/vanilla/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
<!doctype html>
<html lang="en">
<html lang="en" class="h-dvh">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vanilla</title>
<title>Mana Potion – Vanilla</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link rel="apple-touch-icon" href="/icon-180.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="icon" sizes="any" href="/favicon.ico" />
<meta name="theme-color" content="#333" />
</head>
<body>
<body class="h-full bg-[#4c420b] text-white">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
Expand Down
Binary file added examples/vanilla/public/favicon.ico
Binary file not shown.
Binary file added examples/vanilla/public/icon-180.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/vanilla/public/icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/vanilla/public/icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/vanilla/public/mana-potion.webp
Binary file not shown.
12 changes: 12 additions & 0 deletions examples/vanilla/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"short_name": "Mana Potion Svelte",
"name": "Mana Potion Svelte",
"start_url": "/",
"background_color": "#333",
"theme_color": "#333",
"display": "standalone",
"icons": [
{ "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }
]
}
305 changes: 305 additions & 0 deletions examples/vanilla/src/App.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
import {
DeviceTypeChangePayload,
enterFullscreen,
exitFullscreen,
FullscreenChangePayload,
getBrowser,
getMouse,
LeftMouseButtonDownPayload,
LeftMouseButtonUpPayload,
listeners,
lockKeys,
lockOrientation,
lockPointer,
MiddleMouseButtonDownPayload,
MiddleMouseButtonUpPayload,
MouseMovePayload,
MouseScrollPayload,
PageFocusChangePayload,
PageVisibilityPayload,
PointerLockChangePayload,
ResizePayload,
RightMouseButtonDownPayload,
RightMouseButtonUpPayload,
ScreenOrientationChangePayload,
unlockKeys,
unlockOrientation,
unlockPointer,
} from '@manapotion/vanilla'

import { DiscordIcon, GitHubIcon, TwitterIcon } from './components/icons'
import Item from './components/Item'
import html from './html'

const getLabelValue = (value: boolean) =>
value === true ? 'Yes' : value === false ? 'No' : 'Unknown'

const getLabelClass = (value: boolean) =>
`label ${value === true ? 'label--positive' : value === false ? 'label--negative' : 'label--unknown'}`

document.addEventListener('DOMContentLoaded', () => {
const mouseLeft = document.getElementById('mouse-left')!
mouseLeft.textContent = getLabelValue(false)
mouseLeft.className = getLabelClass(false)

const mouseMiddle = document.getElementById('mouse-middle')!
mouseMiddle.textContent = getLabelValue(false)
mouseMiddle.className = getLabelClass(false)

const mouseRight = document.getElementById('mouse-right')!
mouseRight.textContent = getLabelValue(false)
mouseRight.className = getLabelClass(false)

listeners({
onFullscreenChange: ({ isFullscreen }: FullscreenChangePayload) => {
const el = document.getElementById('isFullscreen')!
const btn = document.getElementById('fullscreenButton')!
el.textContent = getLabelValue(isFullscreen)
el.className = getLabelClass(isFullscreen)
btn.textContent = isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'
},
onPageVisibilityChange: ({ isPageVisible }: PageVisibilityPayload) => {
const el = document.getElementById('isPageVisible')!
el.textContent = getLabelValue(isPageVisible)
el.className = getLabelClass(isPageVisible)
},
onPageFocusChange: ({ isPageFocused }: PageFocusChangePayload) => {
const el = document.getElementById('isPageFocused')!
el.textContent = getLabelValue(isPageFocused)
el.className = getLabelClass(isPageFocused)
},
onDeviceTypeChange: ({ isDesktop, isMobile }: DeviceTypeChangePayload) => {
const elDesktop = document.getElementById('isDesktop')!
elDesktop.textContent = getLabelValue(isDesktop)
elDesktop.className = getLabelClass(isDesktop)

const elMobile = document.getElementById('isMobile')!
elMobile.textContent = getLabelValue(isMobile)
elMobile.className = getLabelClass(isMobile)
},
onScreenOrientationChange: ({ isPortrait, isLandscape }: ScreenOrientationChangePayload) => {
const elPortrait = document.getElementById('isPortrait')!
elPortrait.textContent = getLabelValue(isPortrait)
elPortrait.className = getLabelClass(isPortrait)

const elLandscape = document.getElementById('isLandscape')!
elLandscape.textContent = getLabelValue(isLandscape)
elLandscape.className = getLabelClass(isLandscape)
},
onResize: ({ width, height }: ResizePayload) => {
const el = document.getElementById('windowSize')!
el.textContent = `${width}x${height}`
},
onPointerLockChange: ({ isPointerLocked }: PointerLockChangePayload) => {
const el = document.getElementById('isMouseLocked')!
el.textContent = getLabelValue(isPointerLocked)
el.className = getLabelClass(isPointerLocked)
const btn = document.getElementById('mouseLockButton')!
btn.textContent = isPointerLocked ? 'Unlock' : 'Lock'
},
onLeftMouseButtonDown: (_: LeftMouseButtonDownPayload) => {
const el = document.getElementById('mouse-left')!
el.textContent = getLabelValue(true)
el.className = getLabelClass(true)
},
onMiddleMouseButtonDown: (_: MiddleMouseButtonDownPayload) => {
const el = document.getElementById('mouse-middle')!
el.textContent = getLabelValue(true)
el.className = getLabelClass(true)
},
onRightMouseButtonDown: (_: RightMouseButtonDownPayload) => {
const el = document.getElementById('mouse-right')!
el.textContent = getLabelValue(true)
el.className = getLabelClass(true)
},
onLeftMouseButtonUp: (_: LeftMouseButtonUpPayload) => {
const el = document.getElementById('mouse-left')!
el.textContent = getLabelValue(false)
el.className = getLabelClass(false)
},
onMiddleMouseButtonUp: (_: MiddleMouseButtonUpPayload) => {
const el = document.getElementById('mouse-middle')!
el.textContent = getLabelValue(false)
el.className = getLabelClass(false)
},
onRightMouseButtonUp: (_: RightMouseButtonUpPayload) => {
const el = document.getElementById('mouse-right')!
el.textContent = getLabelValue(false)
el.className = getLabelClass(false)
},
onMouseMove: ({ position, movement }: MouseMovePayload) => {
const elPos = document.getElementById('mouse-position')!
elPos.textContent = `${position.x}, ${position.y}`

const elMove = document.getElementById('mouse-movement')!
elMove.textContent = `${movement.x}, ${movement.y}`
},
onScroll: ({ y }: MouseScrollPayload) => {
const el = document.getElementById('mouse-scroll-y')!
el.textContent = String(Math.round(y))
},
})
})

// @ts-expect-error should define this function in the global scope
window.handleToggleFullscreen = () =>
getBrowser().isFullscreen ? exitFullscreen() : enterFullscreen()
// @ts-expect-error should define this function in the global scope
window.handleTogglePointerLock = () => (getMouse().locked ? unlockPointer() : lockPointer())
// @ts-expect-error should define this function in the global scope
window.lockOrientation = lockOrientation
// @ts-expect-error should define this function in the global scope
window.unlockOrientation = unlockOrientation
// @ts-expect-error should define this function in the global scope
window.lockKeys = lockKeys
// @ts-expect-error should define this function in the global scope
window.unlockKeys = unlockKeys

export const App = html`
<main class="mx-auto max-w-7xl px-5 pb-16 pt-5" oncontextmenu="event.preventDefault()">
<div class="mb-5 flex flex-col items-center justify-center gap-6 sm:flex-row">
<img src="/mana-potion.webp" class="w-28" alt="Logo" />
<div class="flex flex-col gap-3">
<h1 class="text-center text-5xl font-medium sm:text-left">Mana Potion</h1>
<h2 class="max-w-lg text-pretty text-center text-lg text-gray-200 sm:text-left">
Toolkit for JavaScript game development and interactive experiences with
<a class="underline" href="https://manapotion.org">React</a>,
<a class="underline" href="https://vue.manapotion.org">Vue</a>,
<a class="underline" href="https://svelte.manapotion.org">Svelte</a>, and
<b>vanilla JS</b>
support.
</h2>
<div class="flex items-center justify-center gap-3 sm:justify-start">
<a
href="https://github.com/verekia/manapotion"
target="_blank"
class="flex items-center gap-2 rounded-md bg-white/15 px-3 py-1.5 font-medium hover:bg-white/5"
>
${GitHubIcon} GitHub
</a>
<a
href="https://twitter.com/verekia"
target="_blank"
class="flex items-center gap-2 rounded-md bg-white/15 px-3 py-1.5 font-medium hover:bg-white/5"
>
${TwitterIcon} Twitter
</a>
<a
href="https://discord.gg/VXYxGrP8EJ"
target="_blank"
class="flex items-center gap-2 rounded-md bg-white/15 px-3 py-1.5 font-medium hover:bg-white/5"
>
${DiscordIcon} Discord
</a>
</div>
</div>
</div>
<div class="mt-10 text-gray-200">
<div>⚡️ <b>Reactive</b> (re-renders components on changes)</div>
<div>🗿 <b>Non-reactive</b> (managed by events or animation frame)</div>
</div>
<div class="cols-1 mt-5 grid gap-10 md:grid-cols-2 lg:grid-cols-3">
<section>
<h2 class="section-heading">🌐 Browser</h2>
${Item({
name: 'isFullscreen',
label: html`<span id="isFullscreen"></span>`,
extra: html`<button
id="fullscreenButton"
class="btn"
onclick="window.handleToggleFullscreen()"
></button>`,
})}
${Item({
name: 'isPageVisible',
label: html`<span id="isPageVisible"></span>`,
})}
${Item({
name: 'isPageFocused',
label: html`<span id="isPageFocused"></span>`,
})}
${Item({
name: 'isDesktop',
label: html`<span id="isDesktop"></span>`,
})}
${Item({
name: 'isMobile',
label: html`<span id="isMobile"></span>`,
})}
${Item({
name: 'isPortrait',
label: html`<span id="isPortrait"></span>`,
extra: html`<span class="text-sm">Ratio-based</span>`,
})}
${Item({
name: 'isLandscape',
label: html`<span id="isLandscape"></span>`,
extra: html`<span class="text-sm">Ratio-based</span>`,
})}
${Item({
name: 'width,height',
value: html`<span id="windowSize" class="tabular-nums"></span>`,
})}
<div class="mt-2">
<h2>Force mobile orientation (use after fullscreen)</h2>
<div class="flex flex-wrap gap-2">
<button class="btn" onclick="window.lockOrientation('landscape')">Landscape</button>
<button class="btn" onclick="window.lockOrientation('portrait')">Portrait</button>
<button class="btn" onclick="window.unlockOrientation()">Unlock orientation</button>
</div>
</div>
<div class="mt-2">
<h2>Keyboard lock (use after fullscreen on desktop)</h2>
<div class="flex flex-wrap gap-2">
<button
class="btn"
onclick="window.lockKeys(['Escape', 'KeyW', 'KeyA', 'KeyS', 'KeyD'])"
>
Lock Esc and WASD
</button>
<button class="btn" onclick="window.unlockKeys()">Release keys</button>
</div>
</div>
</section>
<section>
<h2 class="section-heading">🖱️ Mouse</h2>
${Item({
name: 'locked',
label: html`<span id="isMouseLocked"></span>`,
extra: html`<button
id="mouseLockButton"
class="btn"
onclick="window.handleTogglePointerLock()"
>
Lock
</button>`,
})}
${Item({
name: 'buttons.left',
label: html`<span id="mouse-left"></span>`,
})}
${Item({
name: 'buttons.middle',
label: html`<span id="mouse-middle"></span>`,
})}
${Item({
name: 'buttons.right',
label: html`<span id="mouse-right"></span>`,
})}
${Item({
name: 'position',
value: html`<span id="mouse-position" class="tabular-nums"></span>`,
})}
${Item({
name: 'movement',
value: html`<span id="mouse-movement" class="tabular-nums"></span>`,
})}
${Item({
name: 'wheel.y',
value: html`<span id="mouse-scroll-y" class="tabular-nums"></span>`,
})}
</section>
</div>
</main>
`
23 changes: 23 additions & 0 deletions examples/vanilla/src/components/Item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import html from '../html'

const Item = ({
name,
label,
value,
extra,
}: {
name: string
value?: string
label?: string
extra?: string
}) =>
html`<div class="item">
<span>🗿</span>
<span class="item--main">
<span class="item--name">${name}</span>
<span>${label ?? ''}${value ?? ''}</span>
</span>
${extra ?? ''}
</div>`

export default Item
Loading

0 comments on commit 46152c7

Please sign in to comment.