sinuous-bind
brings the bind
element directives of Svelte to Sinuous.
Don't do
`
<input value=${state} oninput=${e => state(e.target.value)} />
`
Do
`
<input bind=${state} />
`
size | esm | cdn |
---|---|---|
sinuous-bind |
https://unpkg.com/sinuous-bind@latest/dist/all.min.js | |
sinuous-bind/bind |
https://unpkg.com/sinuous-bind@latest/dist/bind.min.js | |
sinuous-bind/bindArea |
https://unpkg.com/sinuous-bind@latest/dist/bindArea.min.js | |
sinuous-bind/bindGroup |
https://unpkg.com/sinuous-bind@latest/dist/bindGroup.min.js | |
sinuous-bind/bindMedia |
https://unpkg.com/sinuous-bind@latest/dist/bindMedia.min.js |
There are two ways to consume sinuous-bind:
Run the following inside your project directory to get all the bind packages:
npm install sinuous-bind
Import all the packages into the root of your project like so:
import "sinuous-bind";
Alternatively, bring in any or all of the packages, depending on what you need:
import "sinuous-bind/bind";
import "sinuous-bind/bindGroup";
import "sinuous-bind/bindArea";
import "sinuous-bind/bindMedia";
These packages are not tree-shakeable. If you import the submodule, you will be stuck with it in your bundle.
Put this in your html to get all the packages:
<script src="https://unpkg.com/sinuous-bind@latest/dist/all.min.js"></script>
Alternatively, you can bring in just what you need (though you must include the top one):
<script src="https://unpkg.com/sinuous-bind@latest/dist/bind.min.js"></script>
<script src="https://unpkg.com/sinuous-bind@latest/dist/bindArea.min.js"></script>
<script src="https://unpkg.com/sinuous-bind@latest/dist/bindGroup.min.js"></script>
<script src="https://unpkg.com/sinuous-bind@latest/dist/bindMedia.min.js"></script>
You must also bring in Sinuous:
<script src="https://unpkg.com/sinuous/dist/all.js"></script>
If you have brought in sinuous-bind/dist/all.min.js
, setup is something like what follows:
window.bindAll.enableBind(window.S);
Alternatively, if you brought in only sinuous-bind/dist/bind.min.js
, setup is as follows:
window.bind.enableBind(window.S);
If you have brought in more than one package, setup is something like this:
let w = window;
let { register, enableBind } = w.bind;
register(w.bindArea.getBindArea);
register(w.bindGroup.getBindGroup);
register(w.bindMedia.getBindMedia);
enableBind(w.S);
Unlike the esm format, the cdn format requires the basic bind package (sinuous-bind/dist/bind.min.js
) for any of the others to be enabled.
sinuous-bind/bind
bind
can take two kinds of arguments
bind=${<observable>}
bind=${[<observable> [, <attribute> [, <event> [, <boolean>]]]]}
<attribute>
defaults to "value"
<event>
defaults to "oninput"
<boolean>
true
to set the attribute with a Sinuous subscribe
. This is necessary for things like a contentEditable
binding to textContent
or innerHTML
.Generally, bind=${state}
is sufficient.
bind
will attempt to coerce values to numerical values, but will not attempt to coerce booleans or the empty string.
<input>
(implicit)function component() {
const state = o("");
return html`
<input bind=${state} />
`;
}
<input>
(explicit)function component() {
const state = o("");
return html`
<input bind=${[state, "value", "oninput"]} />
`;
}
<input type="range">
function component() {
const state = o(5);
return html`
<input type="range" bind=${state} min="0" max="10" />
`;
}
contentEditable
function component() {
const state = o("");
return html`
<div contentEditable bind=${[state, "textContent", , true]} />
`;
}
Takes "textContent"
or "innerHTML"
as the second element of the array. Requires true
as the fourth element.
<input type="checkbox">
function component() {
const state = o("");
return html`
<input type="checkbox" bind=${[state, "checked", "onchange"]} />
`;
}
<input type="radio">
function component() {
const state = o("");
return html`
<input type="radio" bind=${[state, "checked", "onchange"]} />
`;
}
<select>
function component() {
const state = o(1);
return html`
<select bind=${state}>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
`;
}
Gotchas: It won't work with the multiple
attribute. Also, it won't sync until user action. If you need either of these things, use sinuous-bind/bindGroup
ref
function component() {
const ref = o();
return html`
<div ref=${ref}></div>
`;
}
Gotchas: The value will not be passed into the ref
observable until the call to html
is made. The DOM node has to be created before it can be passed to ref
.
sinuous-bind/bindArea
Both bind:area
and bindArea
work.
All bind:area
bindings are read-only.
bind:area
accepts an object of observables, with any of the following keys:
clientWidth
, clientHeight
, offsetWidth
, offsetHeight
, scrollLeft
, scrollTop
All these keys can be updated whenever the element is resized. Additionally, scrollLeft
and scrollTop
are updated whenever the element is scrolled.
Effects: Set a function on the object passed to bind:area
with the key effect
. The effect
will be called on resize and scroll. Set a function with any other key, and it will be called on resize, only.
Gotchas: bind:area
sets position: relative
on the bound element. Do not set the style on the element unless you set position
.
function component() {
const clientWidth = o();
return html`
<div bind:area=${{ clientWidth }}></div>
`;
}
function component() {
const clientWidth = o();
const clientHeight = o();
const offsetHeight = o();
return html`
<div bind:area=${{ clientWidth, clientHeight, offsetHeight }}></div>
`;
}
function component() {
const clientWidth = o();
const clientHeight = o();
const scrollLeft = o();
const scrollTop = o();
return html`
<div
bind:area=${{ clientWidth, clientHeight, scrollLeft, scrollTop }}
></div>
`;
}
function component() {
const clientWidth = o();
const arbitraryEffect = () => console.log("resizing only");
const scrollLeft = o();
const effect = () => console.log("resizing and/or scrolling");
return html`
<div
bind:area=${{ clientWidth, arbitraryEffect, scrollLeft, effect }}
></div>
`;
}
sinuous-bind/bindGroup
Both bind:group
and bindGroup
work.
Like bind
, bind:group
will attempt to coerce values to numerical values, but will not attempt to coerce booleans or the empty string.
function component() {
const state = o(1);
return html`
<select bind:group=${state}>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
`;
}
function component() {
const state = o([1, 2]);
return html`
<select bind:group=${state} multiple>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
`;
}
function component() {
const state = o(1);
return html`
<input type="radio" bind:group=${state} value="1" />
<input type="radio" bind:group=${state} value="2" />
<input type="radio" bind:group=${state} value="3" />
`;
}
function component() {
const state = o([1, 2]);
return html`
<input type="checkbox" bind:group=${state} value="1" />
<input type="checkbox" bind:group=${state} value="2" />
<input type="checkbox" bind:group=${state} value="3" />
`;
}
sinuous-bind/bindMedia
Both bind:media
and bindMedia
work.
Read-only Properties: duration, buffered, seekable, seeking, played, ended
Read/Write Properties: currentTime, playbackRate, paused, volume
Video-only Properties videoWidth, videoHeight
function component() {
const currentTime = o();
const playbackRate = o();
const paused = o();
const volume = o();
const duration = o();
const buffered = o();
const seekable = o();
const seeking = o();
const played = o();
const ended = o();
const videoWidth = o();
const videoHeight = o();
const state = {
currentTime,
playbackRate,
paused,
volume,
duration,
buffered,
seekable,
seeking,
played,
ended,
videoWidth,
videoHeight
};
return html`
<video controls bind:media=${state}>
<source src=http://video.com type=video/webm />
</video>
`;
}
function component() {
const currentTime = o();
const playbackRate = o();
const paused = o();
const volume = o();
const duration = o();
const buffered = o();
const seekable = o();
const seeking = o();
const played = o();
const ended = o();
const state = {
currentTime,
playbackRate,
paused,
volume,
duration,
buffered,
seekable,
seeking,
played,
ended
};
return html`
<audio controls bind:media=${state}>
<source src=http://audio.com type=audio/webm />
</audio>
`;
}
Rich Harris and the rest of the Svelte team