1 | # Current "Best Practice" Conventions
|
2 |
|
3 |
|
4 | - Please use [JS Standard Style](https://standardjs.com/) as a coding style guide.
|
5 | - `ES6 class` rather than ES5 to create class.
|
6 | - CSS declaration using `csjs-inject`.
|
7 | - CSS files:
|
8 |
|
9 | **if** the CSS section of an UI component is too important, CSS declarations should be put in a different file and in a different folder.
|
10 |
|
11 | The folder should be named `styles` and the file should be named with the extension `-styles.css`.
|
12 |
|
13 | e.g: `file-explorer.js` being an UI component `file-explorer-styles.css` is created in the `styles` folder right under `file-explorer.js`
|
14 |
|
15 | **if** the CSS section of an UI component is rather limited it is preferable to put it in the corresponding JS file.
|
16 |
|
17 | - HTML declaration using `yo-yo`.
|
18 |
|
19 | - A module trigger events using `event` property:
|
20 | `self.event = new EventManager()`.
|
21 | Events can then be triggered:
|
22 | `self.event.trigger('eventName', [param1, param2])`
|
23 | - `self._view` is the HTML view renderered by `yo-yo` in the `render` function.
|
24 | - `render()` this function should be called at the first rendering (make sure that the returned node element is put on the DOM), and should *not* by called again from outside the component.
|
25 | - `update()` call this function to update the DOM when the state of the component has changed (this function must be called after the initial call to `render()`).
|
26 | - for all functions / properties, prefixing by underscore (`_`) means the scope is private, and they should **not** be accessed not changed from outside the component.
|
27 | - constructor arguments: There is no fixed rule whether it is preferrable to use multiples arguments or a single option *{}* argument (or both).
|
28 | We recommend:
|
29 | - use a specific slot for **obligatory** arguments and/or for complex arguments (meaning not boolean, not string, etc...).
|
30 | - put arguments in an option *{}* for non critical and for optionnal arguments.
|
31 | - if a component has more than 4/5 parameters, it is recommended to find a way to group some in one or more *opt* arguments.
|
32 |
|
33 | - look them up, discuss them, update them.
|
34 |
|
35 | ## Module Definition (example)
|
36 | ```js
|
37 | // user-card.js
|
38 | var yo = require('yo-yo')
|
39 | var csjs = require('csjs-inject')
|
40 | var EventManager = require('remix-lib').EventManager
|
41 |
|
42 | var css = csjs`
|
43 | .userCard {
|
44 | position : relative;
|
45 | box-sizing : border-box;
|
46 | display : flex;
|
47 | flex-direction : column;
|
48 | align-items : center;
|
49 | border : 1px solid black;
|
50 | width : 400px;
|
51 | padding : 50px;
|
52 | }
|
53 | .clearFunds { background-color: lightblue; }
|
54 | `
|
55 |
|
56 | class UserCard {
|
57 | constructor (api, events, opts = {}) {
|
58 | var self = this
|
59 |
|
60 | self.event = new EventManager()
|
61 | self.opts = opts
|
62 | self._api = api
|
63 | self._consumedEvents = events
|
64 | self._view = undefined
|
65 |
|
66 | events.funds.register('fundsChanged', function (amount) {
|
67 | if (amount < self.state._funds) self.state.totalSpend += self.state._funds - amount
|
68 | self.state._funds = amount
|
69 | self.render()
|
70 | })
|
71 | self.event.trigger('eventName', [param1, param2])
|
72 | }
|
73 | render () {
|
74 | var self = this
|
75 | var view = yo`
|
76 | <div class=${css.userCard}>
|
77 | <h1> @${self.state._nickname} </h1>
|
78 | <h2> Welcome, ${self.state.title || ''} ${self.state.name || 'anonymous'} ${self.state.surname} </h2>
|
79 | <ul> <li> User Funds: $${self.state._funds} </li> </ul>
|
80 | <ul> <li> Spent Funds: $${self.state.totalSpend} </li> </ul>
|
81 | <button class=${css.clearFunds} onclick=${e=>self._spendAll.call(self, e)}> spend all funds </button>
|
82 | </div>
|
83 | `
|
84 | if (!self._view) {
|
85 | self._view = view
|
86 | }
|
87 | return self._view
|
88 | }
|
89 | update () {
|
90 | yo.update(this._view, this.render())
|
91 | }
|
92 | setNickname (name) {
|
93 | this._nickname = name
|
94 | }
|
95 | getNickname () {
|
96 | var self = this
|
97 | return `@${self.state._nickname}`
|
98 | }
|
99 | getFullName () {
|
100 | var self = this
|
101 | return `${self.state.title} ${self.state.name} ${self.state.surname}`
|
102 | }
|
103 | _spendAll (event) {
|
104 | var self = this
|
105 | self._appAPI.clearUserFunds()
|
106 | }
|
107 | _constraint (msg) { throw new Error(msg) }
|
108 | }
|
109 |
|
110 | module.exports = UserCard
|
111 | ```
|
112 | ## Module Usage (example)
|
113 | ```js
|
114 | /*****************************************************************************/
|
115 | // 1. SETUP CONTEXT
|
116 | var EventManager = require('remix-lib').EventManager
|
117 | var funds = { event: new EventManager() }
|
118 | var userfunds = 15
|
119 | function getUserFunds () { return userfunds }
|
120 | function clearUserFunds () {
|
121 | var spent = userfunds
|
122 | userfunds = 0
|
123 | console.log(`all funds of ${usercard.getFullName()} were spent.`)
|
124 | funds.event.trigger('fundsChanged', [userfunds])
|
125 | return spent
|
126 | }
|
127 | setInterval(function () {
|
128 | userfunds++
|
129 | funds.event.trigger('fundsChanged', [userfunds])
|
130 | }, 100)
|
131 |
|
132 | /*****************************************************************************/
|
133 | // 2. EXAMPLE USAGE
|
134 | var UserCard = require('./user-card')
|
135 |
|
136 | var usercard = new UserCard(
|
137 | { getUserFunds, clearUserFunds },
|
138 | { funds: funds.event },
|
139 | {
|
140 | title: 'Dr.',
|
141 | name: 'John',
|
142 | surname: 'Doe',
|
143 | nickname: 'johndoe99'
|
144 | })
|
145 |
|
146 | var el = usercard.render()
|
147 | document.body.appendChild(el)
|
148 | setTimeout(function () {
|
149 | userCard.setNickname('new name')
|
150 | usercard.update()
|
151 | }, 5000)
|
152 |
|
153 | ```
|