Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event passing examples. New disable/enable calls. #12

Merged
merged 1 commit into from
Feb 5, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -80,7 +80,7 @@ Or, 🌐 use the CDN: `<script src="https://cdn.jsdelivr.net/gh/gnat/surreal/sur
* Can be any of:
* CSS selector: `".button"`, `"#header"`, `"h1"`, `"body > .block"`
* Variables: `body`, `e`, `some_element`
* Events: `event.target` will be used.
* Events: `event.currentTarget` will be used.
* Surreal selectors: `me()`,`any()`
* Adding a `start=` parameter provides a starting DOM location to select from. Default is `document`
* ▶️ `any('button', start='header').classAdd('red')`
@@ -129,17 +129,18 @@ See: [Quick Start](#quick-start) and [Reference](#reference) and [No Surreal Nee
<script>
// Every second animate something new.
me().on("click", async ev => {
me(ev).styles({ "transition": "background 1s" })
let el = me(ev) // Save target because async will lose it.
me(el).styles({ "transition": "background 1s" })
await sleep(1000)
me(ev).styles({ "background": "red" })
me(el).styles({ "background": "red" })
await sleep(1000)
me(ev).styles({ "background": "green" })
me(el).styles({ "background": "green" })
await sleep(1000)
me(ev).styles({ "background": "blue" })
me(el).styles({ "background": "blue" })
await sleep(1000)
me(ev).styles({ "background": "none" })
me(el).styles({ "background": "none" })
await sleep(1000)
me(ev).remove()
me(el).remove()
})
</script>
</div>
@@ -230,6 +231,12 @@ Looking for stuff [we recommend doing in vanilla JS](#no-surreal)?
* Wraps `removeEventListener`
* 🔗 `offAll`
* ▶️ `me().offAll()`
* 🔗 `disable`
* ▶️ `me().disable()`
* Easy alternative to `off()`. Disables click, key, submit events.
* 🔗 `enable`
* ▶️ `me().enable()`
* Opposite of `disable()`
* 🌐 `sleep`
* ▶️ `await sleep(1000, ev => { alert(ev) })`
* `async` version of `setTimeout`
@@ -318,7 +325,7 @@ Append / Prepend elements.

## 🔎 Technical FAQ
* Can I locally scope functions to `<script>` ?
* Recommended: Scope inside an event.
* Recommended: Scope inside an event.
* `me().on('click', ev => { /* add and call function here */ })`
* Alternative: Use `<script type="module">`
* Tradeoff: `me()` will no longer see `parentElement` so, an explicit selector is required: `me(".mybutton")`
62 changes: 52 additions & 10 deletions example.html
Original file line number Diff line number Diff line change
@@ -4,10 +4,11 @@
<title>Quick and Dirty Testing for Surreal</title>
<!-- ... or add as inline <script> ! -->
<script src="https://cdn.jsdelivr.net/gh/gnat/surreal/surreal.js"></script>
<link rel="stylesheet" href="tests/reset.css?11" /> <!-- NOTE: You can remove "?11" it is only for cache-busting on github. -->
<link rel="stylesheet" href="tests/reset.css?12" /> <!-- NOTE: You can remove "?11" it is only for cache-busting on github. -->
<meta http-equiv="cache-control" content="no-cache" />
</head>
<body>
<!-- Basic examples -->
<button>👁️ Click me to fade out and remove.
<script>
me().on("click", ev => { me(ev).fadeOut() })
@@ -28,8 +29,10 @@
any(".yeet.noot").classAdd('.active')
</script>
</div>
<!-- Basic async examples -->
<div id="random">I should turn grey after 2 seconds.
<script>
// Basic usage with id. Runs immediately.
(async ()=>{
me("#random").classAdd('active')
await sleep(2000)
@@ -41,21 +44,23 @@
<script>
// Now you're thinking with events!
me().on("ping", async ev => {
me(ev).styles({"background":"hotpink", "color":"purple"})
await sleep(2000)
me(ev).trigger("pong")
let el = me(ev)
me(el).styles({"background":"hotpink", "color":"purple"})
await sleep(1000)
me(el).trigger("pong")
})
me().on("pong", async ev => {
me(ev).styles({"background":"blue", "color":"#002200"})
await sleep(2000)
me(ev).trigger("ping")
let el = me(ev)
me(el).styles({"background":"blue", "color":"#002200"})
await sleep(1000)
me(el).trigger("ping")
})
me().styles({"transition":"all 2s"}).trigger("pong")
</script>
</div>
<div>I should be animated using timeline / async until finished!
<script>
// Now you're thinking with async!
// Now you're thinking with async! Runs immediately.
(async (el = me()) => {
me(el).styles({"transition": "all 2s"})
me(el).styles({"background":"#0030F7", "color":"#002200"})
@@ -67,6 +72,7 @@
me(el).styles({"background":"#00C08C", "color":"#660033"})
await sleep(2000)

// New element!
var el_new = createElement("div")
me(el_new).styles({"transition":"all 2s", "opacity":"0", "height":"0%"})
el_new.innerText = "🔥🔥🔥🔥🔥🔥"
@@ -78,9 +84,9 @@
</div>
<div>I should be surrounded by diamonds after a few seconds.
<script>
// Now you're thinking with async!
// Now you're thinking with async! Runs immediately.
(async (el = me()) => {
me(el).styles({"transition":"all 2s", "color":"#ccc"})
me(el).styles({"transition":"all 2s", "color":"#fff"})

var el_new = createElement("div")
el_new.innerText = "💎💎💎"
@@ -99,5 +105,41 @@
})()
</script>
</div>
<!-- Event examples -->
<div thick>📬 I close instantly from a child button event.
<script>
me().on("close", (ev) => { me(ev).remove() }) // Recieve "close" event.
</script>
<button class="close">✉️ Send "close"
<script>
me().on("click", (ev) => { me(ev).disabled = true; me(ev).trigger("close") })
</script>
</button>
</div>
<div thick>📭 I stay open because of <strong>stopPropagation()</strong>
<script>
me().on("close", (ev) => { me(ev).remove() }) // I will never recieve "close" event because of stopPropagation()
</script>
<div thick>📬 I close dramatically from a child button <strong>async</strong> event
<script>
me().on("close", async (ev) => {
ev.stopPropagation() // Event stops here.
let el = me(ev) // Save because event currentTarget will be lost after await
me(el).styles({"transition":"all 1s", "background":"green"})
await sleep(1000)
me(el).styles({"background":"orange"})
await sleep(1000)
me(el).styles({"opacity":"0"})
await sleep(1000)
me(el).remove()
})
</script>
<button class="close">✉️ Send "close"
<script>
me().on("click", ev => { me(ev).disable(); me(ev).trigger("close"); }) // Use disable() to stop clicking more than once.
</script>
</button>
</div>
</div>
</body>
</html>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "surreal",
"version": "1.0.1",
"version": "1.0.2",
"description": "Surreal",
"repository": {
"type": "git",
34 changes: 25 additions & 9 deletions surreal.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Welcome to Surreal 1.0.1
// Welcome to Surreal 1.0.2
// Documentation: https://github.com/gnat/surreal
// Locality of Behavior (LoB): https://htmx.org/essays/locality-of-behaviour/
var $ = { // You can use a different name than "$", but you must change the reference in any plugins you use!
@@ -8,7 +8,7 @@ var $ = { // You can use a different name than "$", but you must change the refe
// Table of contents and convenient call chaining sugar. For a familiar "jQuery like" syntax. 🙂
// Check before adding new: https://youmightnotneedjquery.com/
sugar(e) {
if (e == null) { console.warn(`Cannot use "${e}". Missing a character?`) }
if (e == null) { console.warn(`Surreal: Cannot use "${e}". Missing a character?`) }

// General
e.run = (value) => { return $.run(e, value) }
@@ -28,6 +28,8 @@ var $ = { // You can use a different name than "$", but you must change the refe
e.off = (name, fn) => { return $.off(e, name, fn) }
e.offAll = (name) => { return $.offAll(e, name) }
e.off_all = e.offAll
e.disable = (name) => { return $.disable(e) }
e.enable = (name) => { return $.enable(e) }
e.trigger = (name) => { return $.trigger(e, name) }
e.halt = () => { return $.halt(e) }

@@ -54,7 +56,7 @@ var $ = { // You can use a different name than "$", but you must change the refe
// </div>
me(selector=null, start=document, warning=true) {
if (selector == null) return $.sugar(start.currentScript.parentElement) // Just local me() in <script>
if (selector instanceof Event) return $.me(selector.currentTarget) // Events return event.currentTarget
if (selector instanceof Event) return selector.currentTarget ? $.me(selector.currentTarget) : (console.warn(`Surreal: Event currentTarget is null. Please save your element because async will lose it`), null) // Events try currentTarget
if (typeof selector == 'string' && isSelector(selector, start, warning)) return $.sugar(start.querySelector(selector)) // String selector.
if ($.isNodeList(selector)) return $.me(selector[0]) // If we got a list, just take the first element.
if ($.isNode(selector)) return $.sugar(selector) // Valid element.
@@ -66,7 +68,7 @@ var $ = { // You can use a different name than "$", but you must change the refe
// Example: any('button')
any(selector, start=document, warning=true) {
if (selector == null) return $.sugar([start.currentScript.parentElement]) // Just local me() in <script>
if (selector instanceof Event) return $.any(selector.currentTarget) // Events return event.currentTarget
if (selector instanceof Event) return selector.currentTarget ? $.any(selector.currentTarget) : (console.warn(`Surreal: Event currentTarget is null. Please save your element because async will lose it`), null) // Events try currentTarget
if (typeof selector == 'string' && isSelector(selector, start, true, warning)) return $.sugar(Array.from(start.querySelectorAll(selector))) // String selector.
if ($.isNode(selector)) return $.sugar([selector]) // Single element. Convert to Array.
if ($.isNodeList(selector)) return $.sugar(Array.from(selector)) // Valid NodeList or Array.
@@ -152,7 +154,21 @@ var $ = { // You can use a different name than "$", but you must change the refe

offAll(e) {
if ($.isNodeList(e)) e.forEach(_ => { offAll(_) })
if ($.isNode(e)) e = e.cloneNode(true)
if ($.isNode(e)) e.parentNode.replaceChild(e.cloneNode(true), e)
return e
},

// Easy alternative to off(). Disables click, key, submit events.
disable(e) {
if ($.isNodeList(e)) e.forEach(_ => { disable(_) })
if ($.isNode(e)) e.disabled = true
return e
},

// For reversing disable()
enable(e) {
if ($.isNodeList(e)) e.forEach(_ => { enable(_) })
if ($.isNode(e)) e.disabled = false
return e
},

@@ -210,7 +226,7 @@ var $ = { // You can use a different name than "$", but you must change the refe

// Puts Surreal functions except for "restricted" in global scope.
globalsAdd() {
console.log(`Surreal: adding convenience globals to window`)
console.log(`Surreal: Adding convenience globals to window.`)
restricted = ['$', 'sugar']
for (const [key, value] of Object.entries(this)) {
if (!restricted.includes(key)) window[key] != 'undefined' ? window[key] = value : console.warn(`Surreal: "${key}()" already exists on window. Skipping to prevent overwrite.`)
@@ -231,11 +247,11 @@ var $ = { // You can use a different name than "$", but you must change the refe
// ⚙️ Used internally by DOM functions. Warning when selector is invalid. Likely missing a "#" or "."
isSelector(selector="", start=document, all=false, warning=true) {
if (all && start.querySelectorAll(selector) == null) {
if (warning) console.warn(`"${selector}" was not found. Missing a character? (. #)`)
if (warning) console.warn(`Surreal: "${selector}" was not found. Missing a character? (. #)`)
return false
}
if (start.querySelector(selector) == null) {
if (warning) console.warn(`"${selector}" was not found. Missing a character? (. #)`)
if (warning) console.warn(`Surreal: "${selector}" was not found. Missing a character? (. #)`)
return false
}
return true // Valid.
@@ -285,7 +301,7 @@ $.sugars['fade_out', 'fade_in'] = $.sugars['fadeOut', 'fadeIn']

$.globalsAdd() // Full convenience.

console.log("Loaded Surreal.")
console.log("Surreal: Loaded.")

// 🌐 Optional global helpers.
const createElement = document.createElement.bind(document)
25 changes: 20 additions & 5 deletions tests/reset.css
Original file line number Diff line number Diff line change
@@ -20,8 +20,8 @@ html {
body {
font-size: 2rem;
padding: 1rem;
background: #222;
color: #CCC;
background: #adadad;
color: #ccc;
}
.active {
background: hsl(345deg 100% 47%);
@@ -37,14 +37,24 @@ body > div {
padding: 1rem;
border-radius: 1rem;
}
body div[thick] {
color: #222;
margin: 2rem;
padding: 3rem;
border-radius: 1rem;
background: #eee;
}
body div[thick] div[thick] {
background: #ccc;
}
button {
cursor: pointer;
color: #fff;
padding: 2rem 3rem;
margin: 2rem;
border: none;
background: hsl(345deg 100% 47%);
border-bottom: 0.5rem solid hsl(345deg 100% 28%);
background: hsl(262deg 86% 47%);
border-bottom: 0.5rem solid hsl(262deg 86% 28%);
border-radius: 12px;
text-shadow: 0 2px #222222AA;
}
@@ -56,9 +66,14 @@ button.blue {
border: none;
border-bottom: 0.5rem solid hsl(200deg 100% 28%);
}

button.invisible {
opacity: 0.2;
background: hsl(147, 60%, 50%);
border-bottom: 0.5rem solid hsl(147 80% 28%);
}
button.close {
background: hsl(345deg 90% 40%);
border-bottom: 0.5rem solid hsl(345deg 100% 28%);
border-radius: 12px;
}