Skip to content

Commit

Permalink
feat(util): add cell util
Browse files Browse the repository at this point in the history
This is a small util that provides a single tracked property
for easily creating tracked state within the function-based
resources.
  • Loading branch information
NullVoxPopuli committed Jul 29, 2022
1 parent 2cd0974 commit ebc4c30
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 0 deletions.
4 changes: 4 additions & 0 deletions ember-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"./core/class-based": "./dist/core/class-based/index.js",
"./core/function-based": "./dist/core/function-based/index.js",
"./util": "./dist/util/index.js",
"./util/cell": "./dist/util/cell.js",
"./util/map": "./dist/util/map.js",
"./util/helper": "./dist/util/helper.js",
"./util/remote-data": "./dist/util/remote-data.js",
Expand All @@ -33,6 +34,9 @@
"util": [
"dist/util/index.d.ts"
],
"util/cell": [
"dist/util/cell.d.ts"
],
"util/function": [
"dist/util/function.d.ts"
],
Expand Down
3 changes: 3 additions & 0 deletions ember-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ export { Resource } from './core/class-based';
export { resource, resourceFactory } from './core/function-based';
export { use } from './core/use';

// Public API -- Utilities
export { cell } from 'util/cell';

// Public Type Utilities
export type { ExpandArgs } from './core/class-based/types';
export type { ArgsWrapper, Thunk } from './core/types';
57 changes: 57 additions & 0 deletions ember-resources/src/util/cell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { tracked } from '@glimmer/tracking';
import { assert } from '@ember/debug';

class Cell<T> {
@tracked current: T;

constructor(initialValue: T) {
this.current = initialValue;
}

toggle = () => {
assert(
`toggle can only be used when 'current' is a boolean type`,
typeof this.current === 'boolean' || this.current === undefined
);

(this.current as boolean) = !this.current;
};
}

/**
* Small state utility for helping reduce the number of imports
* when working with resources in isolation.
*
* The return value is an instance of a class with a single
* `@tracked` property, `current`. If `current` is a boolean,
* there is a `toggle` method available as well.
*
* For example, a Clock:
*
* ```js
* import { resource, cell } from 'ember-resources';
*
* const Clock = resource(({ on }) => {
* let time = cell(new Date());
* let interval = setInterval(() => time.current = new Date(), 1000);
*
* on.cleanup(() => clearInterval(interval));
*
* let formatter = new Intl.DateTimeFormat('en-US', {
* hour: 'numeric',
* minute: 'numeric',
* second: 'numeric',
* hour12: true,
* });
*
* return () => formatter.format(time.current);
* });
*
* <template>
* It is: <time>{{Clock}}</time>
* </template>
* ```
*/
export function cell<T>(initialValue: T): Cell<T> {
return new Cell(initialValue);
}
26 changes: 26 additions & 0 deletions testing/ember-app/tests/utils/cell/rendering-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { render, settled } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';

import { cell } from 'ember-resources';

module('Utils | cell | rendering', function (hooks) {
setupRenderingTest(hooks);

test('it works', async function (assert) {
let state = cell();

this.setProperties({ state });

await render(hbs`{{this.state.current}}`);

assert.dom().doesNotContainText('hello');

state.current = 'hello';

await settled();

assert.dom().hasText('hello');
});
});

0 comments on commit ebc4c30

Please sign in to comment.