Skip to content

Commit 7ae53c7

Browse files
authored
Vanilla Inputs.file (#266)
* pass file.size to AbstractFile * 0.11.1 * excise LocalFile implementation * fix file test
1 parent 5193dd2 commit 7ae53c7

File tree

5 files changed

+42
-63
lines changed

5 files changed

+42
-63
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ Observable Inputs is a small, free, [open-source](./LICENSE) JavaScript library
77
```html
88
<!DOCTYPE html>
99
<body>
10-
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@observablehq/inputs@0.11/dist/index.css">
10+
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@observablehq/inputs@0.12/dist/index.css">
1111
<script type="module">
1212
13-
import * as Inputs from "https://cdn.jsdelivr.net/npm/@observablehq/inputs@0.11/+esm";
13+
import * as Inputs from "https://cdn.jsdelivr.net/npm/@observablehq/inputs@0.12/+esm";
1414
1515
// Create a numeric slider allowing a value between 0 and 100 (inclusive).
1616
const slider = Inputs.range([0, 100], {label: "x"});
@@ -484,7 +484,7 @@ The available *options* are:
484484

485485
Note that the value of file input cannot be set programmatically; it can only be changed by the user.
486486

487-
(In vanilla JavaScript, the Inputs.file method is not exposed directly. Instead, an Inputs.fileOf method is exposed which takes an AbstractFile implementation and returns the Inputs.file method. This avoids a circular dependency between Observable Inputs and the Observable standard library.)
487+
(In vanilla JavaScript, the Inputs.file method has an additional *transform* option which allows the native File object to be converted into an Observable FileAttachment.)
488488

489489
## Utilities
490490

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@observablehq/inputs",
33
"description": "Lightweight user interface components",
4-
"version": "0.11.0",
4+
"version": "0.12.0",
55
"author": {
66
"name": "Observable, Inc.",
77
"url": "https://observablehq.com"

src/file.js

+34-53
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,38 @@ import {maybeWidth} from "./css.js";
33
import {maybeLabel} from "./label.js";
44
import {createText} from "./text.js";
55

6-
export function fileOf(AbstractFile) {
7-
8-
class LocalFile extends AbstractFile {
9-
constructor(file) {
10-
super(file.name, file.type, file.lastModified);
11-
Object.defineProperty(this, "_", {value: file});
12-
Object.defineProperty(this, "_url", {writable: true});
13-
}
14-
async url() {
15-
return this._url || (this._url = URL.createObjectURL(this._));
16-
}
17-
async blob() {
18-
return this._;
19-
}
20-
async stream() {
21-
return this._.stream();
22-
}
23-
}
24-
25-
return function file({
26-
label,
27-
required,
28-
accept,
29-
capture,
30-
multiple,
31-
disabled,
32-
width,
33-
value, // eslint-disable-line no-unused-vars
34-
submit, // eslint-disable-line no-unused-vars
35-
...options
36-
} = {}) {
37-
const input = html`<input
38-
type=file
39-
name=file
40-
disabled=${disabled}
41-
required=${required}
42-
accept=${accept}
43-
capture=${capture}
44-
multiple=${multiple}
45-
>`;
46-
const form = html`<form class=__ns__ style=${maybeWidth(width)}>
47-
${maybeLabel(label, input)}<div class=__ns__-input>
48-
${input}
49-
</div>
50-
</form>`;
51-
return createText(form, input, undefined, options, {
52-
get: (input) => multiple ? Array.from(input.files, file => new LocalFile(file))
53-
: input.files.length ? new LocalFile(input.files[0])
54-
: null,
55-
set: () => {}, // ignored
56-
same: () => false // ignored
57-
});
58-
};
6+
export function file({
7+
label,
8+
required,
9+
accept,
10+
capture,
11+
multiple,
12+
disabled,
13+
width,
14+
value, // eslint-disable-line no-unused-vars
15+
submit, // eslint-disable-line no-unused-vars
16+
transform = (file) => file,
17+
...options
18+
} = {}) {
19+
const input = html`<input
20+
type=file
21+
name=file
22+
disabled=${disabled}
23+
required=${required}
24+
accept=${accept}
25+
capture=${capture}
26+
multiple=${multiple}
27+
>`;
28+
const form = html`<form class=__ns__ style=${maybeWidth(width)}>
29+
${maybeLabel(label, input)}<div class=__ns__-input>
30+
${input}
31+
</div>
32+
</form>`;
33+
return createText(form, input, undefined, options, {
34+
get: (input) => multiple ? Array.from(input.files, (file) => transform(file))
35+
: input.files.length ? transform(input.files[0])
36+
: null,
37+
set: () => {}, // ignored
38+
same: () => false // ignored
39+
});
5940
}

src/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export {checkbox, radio, toggle} from "./checkbox.js";
33
export {color} from "./color.js";
44
export {date, datetime} from "./date.js";
55
export {form} from "./form.js";
6-
export {fileOf} from "./file.js";
6+
export {file} from "./file.js";
77
export {range, number} from "./range.js";
88
export {search, searchFilter} from "./search.js";
99
export {select} from "./select.js";

test/inputs/files.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import * as Inputs from "../../src/index.js";
22

3-
const Inputs_file = Inputs.fileOf(class AbstractFile {});
4-
53
export async function file() {
6-
return Inputs_file();
4+
return Inputs.file();
75
}
86

97
export async function fileLabel() {
10-
return Inputs_file({label: "dollars&pounds"});
8+
return Inputs.file({label: "dollars&pounds"});
119
}
1210

1311
export async function fileWide() {
14-
return Inputs_file({width: "20em"});
12+
return Inputs.file({width: "20em"});
1513
}

0 commit comments

Comments
 (0)