Skip to content

Commit e892932

Browse files
Merge pull request #570 from NullVoxPopuli/add-cell-util
feat(util): add cell
2 parents 2cd0974 + bad3c1e commit e892932

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed

ember-resources/package.json

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"./core/class-based": "./dist/core/class-based/index.js",
1414
"./core/function-based": "./dist/core/function-based/index.js",
1515
"./util": "./dist/util/index.js",
16+
"./util/cell": "./dist/util/cell.js",
1617
"./util/map": "./dist/util/map.js",
1718
"./util/helper": "./dist/util/helper.js",
1819
"./util/remote-data": "./dist/util/remote-data.js",
@@ -33,6 +34,9 @@
3334
"util": [
3435
"dist/util/index.d.ts"
3536
],
37+
"util/cell": [
38+
"dist/util/cell.d.ts"
39+
],
3640
"util/function": [
3741
"dist/util/function.d.ts"
3842
],

ember-resources/src/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ export { Resource } from './core/class-based';
33
export { resource, resourceFactory } from './core/function-based';
44
export { use } from './core/use';
55

6+
// Public API -- Utilities
7+
export { cell } from 'util/cell';
8+
69
// Public Type Utilities
710
export type { ExpandArgs } from './core/class-based/types';
811
export type { ArgsWrapper, Thunk } from './core/types';

ember-resources/src/util/cell.ts

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { tracked } from '@glimmer/tracking';
2+
import { assert } from '@ember/debug';
3+
4+
class Cell<T> {
5+
@tracked current: T | undefined;
6+
7+
constructor();
8+
constructor(initialValue: T);
9+
constructor(initialValue?: T) {
10+
this.current = initialValue;
11+
}
12+
13+
toggle = () => {
14+
assert(
15+
`toggle can only be used when 'current' is a boolean type`,
16+
typeof this.current === 'boolean' || this.current === undefined
17+
);
18+
19+
(this.current as boolean) = !this.current;
20+
};
21+
}
22+
23+
/**
24+
* Small state utility for helping reduce the number of imports
25+
* when working with resources in isolation.
26+
*
27+
* The return value is an instance of a class with a single
28+
* `@tracked` property, `current`. If `current` is a boolean,
29+
* there is a `toggle` method available as well.
30+
*
31+
* For example, a Clock:
32+
*
33+
* ```js
34+
* import { resource, cell } from 'ember-resources';
35+
*
36+
* const Clock = resource(({ on }) => {
37+
* let time = cell(new Date());
38+
* let interval = setInterval(() => time.current = new Date(), 1000);
39+
*
40+
* on.cleanup(() => clearInterval(interval));
41+
*
42+
* let formatter = new Intl.DateTimeFormat('en-US', {
43+
* hour: 'numeric',
44+
* minute: 'numeric',
45+
* second: 'numeric',
46+
* hour12: true,
47+
* });
48+
*
49+
* return () => formatter.format(time.current);
50+
* });
51+
*
52+
* <template>
53+
* It is: <time>{{Clock}}</time>
54+
* </template>
55+
* ```
56+
*/
57+
export function cell<T>(initialValue?: T): Cell<T> {
58+
if (initialValue) {
59+
return new Cell(initialValue);
60+
}
61+
62+
return new Cell();
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { render, settled } from '@ember/test-helpers';
2+
import { hbs } from 'ember-cli-htmlbars';
3+
import { module, test } from 'qunit';
4+
import { setupRenderingTest } from 'ember-qunit';
5+
6+
import { cell } from 'ember-resources';
7+
8+
module('Utils | cell | rendering', function (hooks) {
9+
setupRenderingTest(hooks);
10+
11+
test('it works', async function (assert) {
12+
let state = cell();
13+
14+
this.setProperties({ state });
15+
16+
await render(hbs`{{this.state.current}}`);
17+
18+
assert.dom().doesNotContainText('hello');
19+
20+
state.current = 'hello';
21+
22+
await settled();
23+
24+
assert.dom().hasText('hello');
25+
});
26+
});

0 commit comments

Comments
 (0)