const a1_1 = view(slider({
min: 0,
max: 1,
step: 0.01,
format: v => `${Math.round(100 * v)} per cent`,
description: "Zero to one, formatted with a custom function"
}))
More fancy slider techniques
const buttonDemo = md`---
## Buttons
~~~js
import {button} from "@jashkenas/inputs"
~~~`
const b = view(button())
(() => {
b;
return !this;
})()
(() => {
{
b1;
return new Date(Date.now()).toUTCString()
}
})()
function button(config = {}) {
const {
value = "Ok", title, description, disabled
} = typeof config === "string" ? {value: config} : config;
const form = input({
type: "button", title, description,
attributes: {disabled, value}
});
form.output.remove();
return form;
}
const selectDemo = md`---
## Dropdown Menus and Multiselects
~~~js
import {select} from "@jashkenas/inputs"
~~~`
const dd = view(select(["Spring", "Summer", "Fall", "Winter"]))
dd
const dd1 = view(select({
title: "Stooges",
description: "Please pick your favorite stooge.",
options: ["Curly", "Larry", "Moe", "Shemp"],
value: "Moe"
}))
const dd2 = view(select({
description: "As a child, which vegetables did you refuse to eat?",
options: ["Spinach", "Broccoli", "Brussels Sprouts", "Cauliflower", "Kale", "Turnips", "Green Beans", "Asparagus"],
multiple: true
}))
dd2
const dd3raw = select({
title: "How are you feeling today?",
options: [
{ label: "🤷", value: "shrug" },
{ label: "😂", value: "tears-of-joy" },
{ label: "😍", value: "loving-it" },
{ label: "🤔", value: "hmmm" },
{ label: "😱", value: "yikes", disabled: true },
{ label: "😈", value: "mischievous" },
{ label: "💩", value: "poo" }
],
value: "hmmm"
});
dd3raw.input.style.fontSize = "30px";
dd3raw.input.style.marginTop = "8px";
dd3
function select(config = {}) {
let {
value: formValue,
title,
description,
disabled,
submit,
multiple,
size,
options
} = Array.isArray(config) ? {options: config} : config;
options = options.map((o) =>
typeof o === "object" ? o : {value: o, label: o}
);
const form = input({
type: "select",
title,
description,
submit,
attributes: {disabled},
getValue: (input) => {
const selected = Array.prototype.filter
.call(input.options, (i) => i.selected)
.map((i) => i.value);
return multiple ? selected : selected[0];
},
form: html`<form>
<select name="input" multiple=${multiple} size=${multiple ? size || options.length : undefined}>
${options.map(
({value, label, disabled}) =>
html`<option value=${value} selected=${
Array.isArray(formValue)
? formValue.includes(value)
: formValue === value
} disabled=${disabled}>${label}</option>`
)}
</select>
</form>`
});
form.output.remove();
return form;
}
const as = view(autoSelect({
options: usa.objects.states.geometries.map(d => d.properties.name),
placeholder: "Search for a US state . . ."
}))
as
const c = view(color())
const coords1 = view(coordinates())
coords1
const coords2 = view(coordinates({
title: "Hometown",
description: "Enter the coordinates of where you were born",
value: [-122.27, 37.87],
submit: true
}))
coords2
import {DOM} from "/components/DOM.js";
const worldMapCoordinatesDemo = md` ---
## World Map Coordinates
*value: an array pair of \`[longitude, latitude]\`, e.g. * \`[-122.27, 37.87]\`
~~~js
import {worldMapCoordinates} from "@jashkenas/inputs"
~~~`
const worldMap1 = view(worldMapCoordinates([-122.27, 37.87]))
worldMap1
const usaMapCoordinatesDemo = md` ---
## U.S.A. Map Coordinates
*value: an array pair of \`[longitude, latitude]\`, e.g. * \`[-122.27, 37.87]\`
~~~js
import {usaMapCoordinates} from "@jashkenas/inputs"
~~~`
const usaMap1 = view(usaMapCoordinates([-122.27, 37.87]))
usaMap1
const usaMap2 = view(usaMapCoordinates({
title: "A Mini Map",
description: "Defaults to New York City",
width: 200,
value: [-74, 40.71]
}))
usaMap2
const dateDemo = md` ---
## Dates
*value: a YYYY-MM-DD formatted string: * \`"2016-11-08"\`
~~~js
import {date} from "@jashkenas/inputs"
~~~`
const d = view(date())
const d1 = view(date({
title: "2017",
min: "2017-01-01",
max: "2017-12-31",
value: "2017-01-01",
description: "Only dates within the 2017 calendar year are allowed"
}))
function date(config = {}) {
const { min, max, value, title, description, disabled, display } =
typeof config === "string" ? { value: config } : config;
return input({
type: "date",
title,
description,
display,
attributes: { min, max, disabled, value }
});
}
const timeDemo = md` ---
## Times
*value: a HH:MM:SS formatted string: * \`"09:30:45"\`
<br>*(Time values are always in 24-hour format)*
~~~js
import {time} from "@jashkenas/inputs"
~~~`
const t = view(time())
t
const t1 = view(time({
title: "Afternoon",
min: "12:00:00",
max: "23:59:59",
value: "13:00:00",
step: 1,
description: "Only times after noon are allowed, and seconds are included"
}))
const fileDemo = md`---
## File Upload
*Use the JavaScript [File API](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications) to work with uploaded file contents.*
\`import {file} from "@jashkenas/inputs"\``
const e = view(file())
const e1 = view(file({
title: "Photographs",
description: "Only .jpg files are allowed in this example. Choose some images, and they’ll appear in the cell below.",
accept: ".jpg",
multiple: true,
}))
import { Files } from "@observablehq/stdlib";
async () => {
const div = html`<div>`;
for (var j = 0; j < e1.length; j++) {
let file = e1[j];
let img = html`<img height="125px" style="margin: 2px;" />`;
img.src = await Files.url(e1[j]);
div.append(img);
}
return div;
}
const textDemo = md`---
## Text Inputs
~~~js
import {text} from "@jashkenas/inputs"
~~~`
const textareaDemo = md`---
## Textareas
~~~js
import {textarea} from "@jashkenas/inputs"
~~~`
const g = view(textarea())
g
const g1 = view(textarea({
title: "Your Great American Novel",
placeholder: "Insert story here...",
spellcheck: true,
width: "100%",
rows: 10,
submit: "Publish"
}))
function textarea(config = {}) {
const {
value = "",
title,
description,
autocomplete,
cols = 45,
rows = 3,
width,
height,
maxlength,
placeholder,
spellcheck,
wrap,
disabled
} = typeof config === "string" ? { value: config } : config;
const container = document.createElement("div");
const textarea = document.createElement("textarea");
if (autocomplete != null) textarea.autocomplete = autocomplete;
if (cols != null) textarea.cols = cols;
if (rows != null) textarea.rows = rows;
if (maxlength != null) textarea.maxLength = maxlength;
if (placeholder != null) textarea.placeholder = placeholder;
if (spellcheck != null) textarea.spellcheck = spellcheck;
if (wrap != null) textarea.wrap = wrap;
if (disabled != null) textarea.disabled = disabled;
if (width != null) textarea.style.width = width;
if (height != null) textarea.style.height = height;
textarea.value = value;
if (title) {
const label = document.createElement("div");
label.style.fontWeight = "bold";
label.textContent = title;
container.appendChild(label);
}
container.appendChild(textarea);
if (description) {
const desc = document.createElement("div");
desc.style.fontStyle = "italic";
desc.textContent = description;
container.appendChild(desc);
}
container.value = textarea.value;
textarea.addEventListener("input", () => {
container.value = textarea.value;
container.dispatchEvent(new CustomEvent("input"));
});
Object.defineProperty(container, "input", {
get: () => textarea
});
return container;
}
const radioDemo = md`---
## Radio Buttons
~~~js
import {radio} from "@jashkenas/inputs"
~~~`
const r = view(radio(["Lust", "Gluttony", "Greed", "Sloth", "Wrath", "Envy", "Pride"]))
const r1 = view(radio({
title: 'Contact Us',
description: 'Please select your preferred contact method',
options: [
{ label: 'By Email', value: 'email' },
{ label: 'By Phone', value: 'phone' },
{ label: 'By Pager', value: 'pager' },
],
value: 'pager'
}))
const checkboxDemo = md`---
## Checkboxes
~~~js
import {checkbox} from "@jashkenas/inputs"
~~~`
const ch = view(checkbox(["Lust", "Gluttony", "Greed", "Sloth", "Wrath", "Envy", "Pride"]))
ch
const ch1 = view(checkbox({
title: "Colors",
description: "Please select your favorite colors",
options: [
{ value: "r", label: "Red" },
{ value: "o", label: "Orange" },
{ value: "y", label: "Yellow" },
{ value: "g", label: "Green" },
{ value: "b", label: "Blue" },
{ value: "i", label: "Indigo" },
{ value: "v", label: "Violet" }
],
value: ["r", "g", "b"],
submit: true
}))
ch1
const ch3 = view(checkbox({
description: "Just a single checkbox to toggle",
options: [{ value: "toggle", label: "On" }],
value: "toggle"
}))
ch3
function checkbox(config = {}) {
let {
value,
title,
description,
disabled,
options,
} = Array.isArray(config) ? {options: config} : config;
return Inputs.checkbox(options, {
value,
label: title === undefined ? description : title,
format: o => typeof o === "object" ? o.label : o,
keyof: o => typeof o === "object" ? o.label : o,
valueof: o => typeof o === "object" ? o.value : o,
disabled: disabled || options.filter(o => typeof o === "object" && o.disabled).map(o => o.value)
});
}
const passwordDemo = md`---
## Passwords
~~~js
import {password} from "@jashkenas/inputs"
~~~`
const i = view(password({value: "password"}))
i
const i1 = view(password({
title: "Your super secret password",
description: "Less than 12 characters, please.",
minlength: 6,
maxlength: 12
}))
const usa = (await fetch("https://cdn.jsdelivr.net/npm/us-atlas@^2.1/us/states-10m.json")).json()
const nation = topojson.feature(usa, usa.objects.nation)
const states = topojson.feature(usa, usa.objects.states)
const graticule = d3geo.geoGraticule10()
const license = (() => {
const license = md`License: [MIT](https://opensource.org/licenses/MIT)`;
license.value = "MIT";
return license;
})()