Skip to content

Commit 25dc38c

Browse files
committed
added documentation to libs, removed few todo items
1 parent 0e58561 commit 25dc38c

File tree

7 files changed

+363
-20
lines changed

7 files changed

+363
-20
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Although the project is not production-ready one can still experiment with it us
3838
- Ember Route `model`, `beforeModel` and `afterModel` hooks are static properties instead of instance methods.
3939
- No sticky queryParams, instead link building is explicit with `<LinkTo @query={{hash param=value}}/>` or with object helpers `<LinkTo @query={{assign (hash active=true) this.router.queryParams}}/>`.
4040
- No `{{outlet}}`, instead parent routes included in the child route template with `{{yield}}`. This allows compiling individual route files for the browser without a magical build step.
41+
- No need for initializers and instance initializers, all code runs in module file import and execution order.
4142
- Easily sharable/downloadable/distributable emberx components and routes with npm.
4243

4344
### API Design

TODO

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,11 @@
1-
- queryParam change should rerun model() hook
2-
- queryParams should be sticky, and all params and queryParams should be returned on the resolutions
31
- history back doesnt resolve the routes currently
4-
52
- @emberx/test-helper tests not runnable on node.js!: routerjs/vendor location-bar prevents the app to be runable on node.js.
6-
- Create an issue + PR on @glimmer/core(remove module flag or make it work with a better export). Also make it work with
7-
explicit paths.
8-
9-
- RSVP library is buggy/build strangely(QunitX url & wait based tests failing due to some _state error. Solve it. Tests pass on webpack)
10-
11-
queryParams implementation needed for examples/blog/routes/preview/user.ts
12-
13-
14-
then do router tests
153

164
// NOTE: @emberx/rsvp: RSVP.defer(); NOTE: probably should just use rsvp npm package.
175
// NOTE: @emberx/runloop: later, once, next, cancel, debounce, throttle, currentLoop(?) NO, more importantly and a test-waiter system to register test events
186

19-
// I need something like await settled() for next queue; and and API to declare it in the app code.
20-
// all rsvp? because it has RSVP.hash, RSVP.defer, RSVP.filter(?), RSVP.later
21-
// runloop: later, once(setTimeout, 0), next(), cancel, debounce, throttle, currentLoop(?),
22-
// merge runloop with RSVP.
23-
247
glimmer level dom change wait is hooked to global-context on @ember/application
25-
268
also wraps fetch to implement the similar behavior
27-
instead we will need to monkey-patch fetch? or implement our fetch
289

2910
- avoid running model hooks
3011
- Avoid running model hooks when redirecting in the middle of another transition.
@@ -35,7 +16,6 @@ instead we will need to monkey-patch fetch? or implement our fetch
3516
Ember.Application = boot, register services, reset state, viist, rootElement, unregister, resolver, lookup,
3617
autoboot: false
3718

38-
3919
test-helpers: this.owner
4020

4121
think about error and loading routes
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# @emberx/component - Ember/Glimmer Components for node.js and browser
2+
3+
This fully tested library allows you to build advanced and very fast browser UI components:
4+
5+
```ts
6+
import Component, { hbs, renderComponent, action, tracked } from '@emberx/component';
7+
8+
class UserDisplay extends Component {
9+
@tracked count = 55;
10+
@tracked loadingMessage: string | null;
11+
@tracked user: object | null;
12+
13+
static template = hbs`
14+
<h1>This is basic route</h1>
15+
16+
<span id="counter">Counter: {{this.count}}</span>
17+
18+
{{#if this.loadingMessage}}
19+
<p id="loading-user">{{this.loadingMessage}}</p>
20+
{{/if}}
21+
22+
{{#if this.user}}
23+
<p id="user-details" class="text-center">Testing it: {{this.user.firstName}} {{this.user.lastName}}</p>
24+
{{else}}
25+
<button type="button" {{on "click" (fn this.fetchUserWithFetch "izelnakri")}} id="fetch-user-with-fetch">Fetch user with fetch</button>
26+
{{/if}}
27+
28+
<button type="button" {{on "click" this.increaseCounter}} id="increase-counter">Increase counter</button>
29+
`;
30+
31+
@action
32+
increaseCounter() {
33+
this.count++;
34+
}
35+
36+
@action
37+
async fetchUserWithFetch(username: string): Promise<void> {
38+
this.user = null;
39+
this.loadingMessage = 'Fetching user...';
40+
41+
try {
42+
let response = await fetch(`/users?username=${username}`);
43+
this.user = await response.json();
44+
} finally {
45+
this.loadingMessage = null;
46+
}
47+
}
48+
}
49+
50+
51+
// Usage:
52+
53+
renderComponent(UserDisplay, { element: document.getElementById('app') });
54+
```
55+
56+
EmberX Components are composable, they allow embedding other EmberX components, helpers and modifiers:
57+
58+
```ts
59+
import Component, { hbs, renderComponent, action, tracked } from '@emberx/component';
60+
61+
class Table extends Component<{ headRows: object }> {
62+
static template = hbs`
63+
<table class="my-table">
64+
<thead>
65+
{{#each @headRows as |headRow|}}
66+
<tr>
67+
{{#each headRow as |rowData|}}
68+
<th scope="row">{{headRow[0]}}</th>
69+
{{/each}}
70+
</tr>
71+
{{/each}}
72+
</thead>
73+
{{yield}}
74+
</table>
75+
`
76+
}
77+
78+
class UserTable extends Component<{ users: User[] }>{
79+
static includes = { Table };
80+
81+
static template = hbs`
82+
<Table @headRows={{this.head}}>
83+
<tbody>
84+
{{#each @users as |user|}}
85+
<tr {{on "click" (fn this.sortUsersByCreatedAt "createdAt")}}>
86+
<td>{{user.firstname}}</td>
87+
<td>{{user.lastName}}</td>
88+
<td>{{user.createdAt}}</td>
89+
</tr>
90+
{{/each}}
91+
</tbody>
92+
</Table>
93+
`
94+
95+
@tracked sortDirection = 'desc';
96+
@tracked sortedUsers: User[] | null = null;
97+
98+
get head() {
99+
return [
100+
['List of users'],
101+
['First name', 'Last name', 'Created at']
102+
];
103+
}
104+
105+
@action
106+
sortUsersByCreatedAt(sortProperty) {
107+
this.users = this.users.sortBy(sortProperty, this.sortDirection);
108+
this.sortDirection = this.sortDirection === 'desc' ? 'asc' : 'desc';
109+
}
110+
}
111+
112+
// Usage:
113+
114+
renderComponent(UserTable, { element: document.getElementById('app') });
115+
```

packages/@emberx/helper/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# @emberx/helper - Reactive UI functions for node.js and browser
2+
3+
EmberX helpers are UI functions that return data when its parameters or related services state changes:
4+
5+
```
6+
// Helper definition:
7+
import helper from '@emberx/helper';
8+
9+
const translate = helper(([key, intl], _hash, services) => {
10+
return services.intl.t(key);
11+
});
12+
13+
export default translate;
14+
15+
// Helper usage:
16+
import Component, { service, tracked } from '@emberx/component';
17+
18+
export default class UserDisplay extends Component {
19+
@service intl;
20+
21+
user = {
22+
id: 1,
23+
firstName: 'Izel',
24+
lastName: 'Nakri'
25+
};
26+
27+
static includes = {
28+
translate,
29+
};
30+
static template = `
31+
<div id="intro">
32+
<LinkTo @route="user.posts" @model="{{this.user.id}}">{{translate "user-page.posts-link" this.user.firstName}}</LinkTo>
33+
34+
<h5>Current locale is: {{this.intl.currentLocale}}</h5>
35+
<button type="button" {{on "click" this.changeLocale}}>Change locale</button>
36+
37+
<h5>Localized button example:</h5>
38+
<button type="button">{{translate "button.save"}}</button>
39+
</div>
40+
`;
41+
42+
@action changeLocale(): void {
43+
this.intl.currentLocale = this.intl.currentLocale === 'en' ? 'es' : 'en';
44+
}
45+
}
46+
47+
// Rendering:
48+
49+
renderComponent(UserDisplay, { element: document.getElementById('app') });
50+
```

packages/@emberx/router/README.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# @emberx/router: Fast, advanced, flexible routing library for browsers and node.js
2+
3+
This is a futuristic take on the router of ember.js, which is the most advanced and mature
4+
routing solution I've seen so far in frontend development. It supports named routes, queryParameters,
5+
dynamic link segments, redirections, promise-aware route-template render delayin for SSR,
6+
parent-children route relationships. The router is fully testable with `visit` and `currentURL` helpers
7+
for `@emberx/test-helpers`.
8+
9+
```ts
10+
// in index.ts:
11+
12+
import startRouter from './start-router';
13+
14+
const Router = startRouter();
15+
16+
export default Router.visit(`${document.location.pathname}/${document.location.search}`);
17+
18+
// ===================================================
19+
// in ./start-router.ts:
20+
21+
import Router from '@emberx/router';
22+
import IndexRoute from './routes/index/route.ts';
23+
import PostsRoute from './routes/posts/route.ts';
24+
import PostsIndexRoute from './routes/posts/index/route.ts';
25+
import PostsPostRoute from './routes/posts/post/route.ts';
26+
27+
Router.addServices({
28+
intl: new LocaleService(),
29+
});
30+
31+
let router = Router.start([
32+
{
33+
path: '/',
34+
name: 'index',
35+
route: IndexRoute
36+
},
37+
{
38+
path: '/posts',
39+
name: 'posts',
40+
route: PostsRoute,
41+
indexRoute: PostsIndexRoute
42+
},
43+
{
44+
path: '/posts/:slug',
45+
name: 'posts.post',
46+
route: PostsPostRoute
47+
},
48+
{
49+
path: '/posts/:blog_post_id/comments',
50+
name: 'posts.post.comments',
51+
route: PostsPostCommentsRoute
52+
},
53+
]);
54+
55+
export default router;
56+
57+
// ===================================================
58+
// in ./routes/index/route.ts:
59+
60+
import { Route, hbs, service } from '@emberx/router';
61+
import { WelcomeBanner } from './components/welcome-banner';
62+
import translate from './helpers/translate';
63+
import RSVP from 'rsvp';
64+
65+
export default class PostsPostRoute extends Route {
66+
@service intl;
67+
68+
static model(params, transition) {
69+
return RSVP.hash({ comments: fetchComments() }); // NOTE: RSVP.hash() returns a promise that waits for promises inside the hash
70+
}
71+
72+
static includes = { WelcomeBanner, translate };
73+
74+
static template = hbs`
75+
<WelcomeBanner />
76+
77+
<h5>{{translate "post-page.welcome"}}</h5>
78+
<LinkTo @route="posts" @model={{11}} data-test-preview-link>All posts</LinkTo>
79+
<LinkTo @route="posts.post" @query={{hash preview=true}} @model={{11}} data-test-preview-reviewed-comments-link>View post 11</LinkTo>
80+
<LinkTo @route="posts.post" @query={{hash preview=true asUser=22}} @model={{12}} data-test-preview-reviewed-comments-link>View post 12 in preview mode by user 22</LinkTo>
81+
<LinkTo @route="posts.post" @query={{hash priviledge="admin"}} @model={{11}} data-test-preview-pending-comments-link>View this post in admin priviledge mode</LinkTo>
82+
83+
<LinkTo @route="posts.post.comments" @model={{11}} data-test-preview-all-comments-link>See comments in detail</LinkTo>
84+
85+
{{#each this.model.comments as |comment index|}}
86+
<div data-test-comment="{{index}}">
87+
<p>{{comment.content}} | <span class="{{comment.status}}">{{comment.status}}</span></p>
88+
<p>{{comment.postedAt}}</p>
89+
</div>
90+
{{/each}}
91+
92+
{{yield}} <!-- PostsPostCommentRoute can use this route in its template and extend it thanks to yield -->
93+
94+
<button {{on "click" this.changeLocale}}>{{translate "buttons.change-locale"}}</button>
95+
`;
96+
97+
@action
98+
async changeLocale() {
99+
await this.intl.changeLocaleToRandomLocale();
100+
console.log('locale changed to:', this.intl.currentLocale);
101+
}
102+
}
103+
```

packages/@emberx/string/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# @emberx/string - String transformation methods for node.js and browser
2+
3+
General purpose string utility methods for node.js and browser, extraced from ember.js:
4+
5+
```js
6+
import { camelize, capitalize, classify, dasherize, decamelize, underscore } from '@emberx/string';
7+
8+
camelize('Green house') // => greenHouse
9+
capitalize('privateDocs/ownerInvoice') // => Private_docs/Owner_invoice
10+
classify('my favorite items') // => MyFavoriteItems
11+
dasherize('innerHTML') // => inner-html
12+
decamelize('PrivateDocs/OwnerInvoice') // => private_docs/owner_invoice
13+
underscore('css-class-name') // => css_class_name
14+
```

0 commit comments

Comments
 (0)