@@ -12,7 +12,8 @@ ES6 or TypeScript.
12
12
### General
13
13
14
14
#### Write useful comments
15
- Comments that explain what some block of code does are nice; they can tell you something in less time than it would take to follow through the code itself.
15
+ Comments that explain what some block of code does are nice; they can tell you something in less
16
+ time than it would take to follow through the code itself.
16
17
17
18
Comments that explain why some block of code exists at all, or does something the way it does,
18
19
are _ invaluable_ . The "why" is difficult, or sometimes impossible, to track down without seeking out
@@ -42,8 +43,8 @@ if (!$attrs['tabindex']) {
42
43
For example, rather than doing this:
43
44
``` html
44
45
<md-button >Basic button</md-button >
45
- <md-button class =" md -fab" >FAB</md-button >
46
- <md-button class =" md -icon-button" >pony</md-button >
46
+ <md-button class =" mat -fab" >FAB</md-button >
47
+ <md-button class =" mat -icon-button" >pony</md-button >
47
48
```
48
49
49
50
do this:
@@ -58,19 +59,122 @@ Keeping modules to a single responsibility makes the code easier to test, consum
58
59
ES6 modules offer a straightforward way to organize code into logical, granular units.
59
60
Ideally, individual files are 200 - 300 lines of code.
60
61
62
+ As a rule of thumb, once a file draws near 400 lines (barring abnormally long constants / comments),
63
+ start considering how to refactor into smaller pieces.
64
+
61
65
#### Less is more
62
66
Once a feature is released, it never goes away. We should avoid adding features that don't offer
63
67
high user value for price we pay both in maintenance, complexity, and payload size. When in doubt,
64
68
leave it out.
65
69
66
70
This applies especially so to providing two different APIs to accomplish the same thing. Always
67
- prefer sticking to a _ single_ API for accomplishing something.
71
+ prefer sticking to a _ single_ API for accomplishing something.
72
+
73
+ ### 100 column limit
74
+ All code and docs in the repo should be 100 columns or fewer. This applies to TypeScript, SCSS,
75
+ HTML, bash scripts, and markdown files.
68
76
69
77
### TypeScript
70
78
71
- #### Provide function descriptions
72
- For functions that are more complicated than a simple getter/setter, provide at least a brief
73
- sentence explaining what the function does and/or _ why_ it does something.
79
+ #### Typing
80
+ Avoid ` any ` where possible. If you find yourself using ` any ` , consider whether a generic may be
81
+ appropriate in your case.
82
+
83
+ For methods and properties that are part of a component's public API, all types must be explicitly
84
+ specified because our documentation tooling cannot currently infer types in places where TypeScript
85
+ can.
86
+
87
+ #### Fluent APIs
88
+ When creating a fluent or builder-pattern style API, use the ` this ` return type for methods:
89
+ ```
90
+ class ConfigBuilder {
91
+ withName(name: string): this {
92
+ this.config.name = name;
93
+ return this;
94
+ }
95
+ }
96
+ ```
97
+
98
+ #### Access modifiers
99
+ * Omit the ` public ` keyword as it is the default behavior.
100
+ * Use ` private ` when appropriate and possible, prefixing the name with an underscore.
101
+ * Use ` protected ` when appropriate and possible with no prefix.
102
+ * Prefix * library-internal* properties and methods with an underscore without using the ` private `
103
+ keyword. This is necessary for anything that must be public (to be used by Angular), but should not
104
+ be part of the user-facing API. This typically applies to symbols used in template expressions,
105
+ ` @ViewChildren ` / ` @ContentChildren ` properties, host bindings, and ` @Input ` / ` @Output ` properties
106
+ (when using an alias).
107
+
108
+ Additionally, the ` @docs-private ` JsDoc annotation can be used to hide any symbol from the public
109
+ API docs.
110
+
111
+ #### JsDoc comments
112
+
113
+ All public APIs must have user-facing comments. These are extracted and shown in the documation
114
+ on [ material.angular.io] ( https://material.angular.io ) .
115
+
116
+ Private and internal APIs should have JsDoc when they are not obvious. Ultimately it is the purview
117
+ of the code reviwer as to what is "obvious", but the rule of thumb is that * most* classes,
118
+ properties, and methods should have a JsDoc description.
119
+
120
+ Properties should have a concise description of what the property means:
121
+ ``` ts
122
+ /** The label position relative to the checkbox. Defaults to 'after' */
123
+ @Input () labelPosition : ' before' | ' after' = ' after' ;
124
+ ```
125
+
126
+ Methods blocks should describe what the function does and provide a description for each parameter
127
+ and the return value:
128
+ ``` ts
129
+ /**
130
+ * Opens a modal dialog containing the given component.
131
+ * @param component Type of the component to load into the dialog.
132
+ * @param config Dialog configuration options.
133
+ * @returns Reference to the newly-opened dialog.
134
+ */
135
+ open <T >(component : ComponentType < T > , config ?: MdDialogConfig ): MdDialogRef < T > { ... }
136
+ ```
137
+
138
+ Boolean properties and return values should use "Whether..." as opposed to "True if...":
139
+ ``` ts
140
+ /** Whether the button is disabled. */
141
+ disabled : boolean = false ;
142
+ ```
143
+
144
+ #### Naming
145
+
146
+ ##### General
147
+ * Prefer writing out words instead of using abbreviations.
148
+ * Prefer * exact* names over short names (within reason). E.g., ` labelPosition ` is better than
149
+ ` align ` because the former much more exactly communicates what the property means.
150
+ * Except for ` @Input ` properties, use ` is ` and ` has ` prefixes for boolean properties / methods.
151
+
152
+ ##### Classes
153
+ Classes should be named based on what they're responsible for. Names should capture what the code
154
+ * does* , not how it is used:
155
+ ```
156
+ /** NO: */
157
+ class RadioService { }
158
+
159
+ /** YES: */
160
+ class UniqueSelectionDispatcher { }
161
+ ```
162
+
163
+ Avoid suffixing a class with "Service", as it communicates nothing about what the class does. Try to
164
+ think of the class name as a person's job title.
165
+
166
+ ##### Methods
167
+ The name of a method should capture the action that is performed * by* that method.
168
+
169
+ ### Angular
170
+
171
+ #### Host bindings
172
+ Prefer using the ` host ` object in the directive configuration instead of ` @HostBinding ` and
173
+ ` @HostListener ` . We do this because TypeScript preserves the type information of methods with
174
+ decorators, and when one of the arguments for the method is a native ` Event ` type, this preserved
175
+ type information can lead to runtime errors in non-browser environments (e.g., server-side
176
+ pre-rendering).
177
+
74
178
75
179
### CSS
76
180
@@ -83,18 +187,18 @@ elements like input and button.
83
187
84
188
#### Use lowest specificity possible
85
189
Always prioritize lower specificity over other factors. Most style definitions should consist of a
86
- single element or css selector plus necessary state modifiers. Avoid SCSS nesting for the sake of
87
- code organization. This will allow users to much more easily override styles.
190
+ single element or css selector plus necessary state modifiers. ** Avoid SCSS nesting for the sake of
191
+ code organization.** This will allow users to much more easily override styles.
88
192
89
193
For example, rather than doing this:
90
194
``` scss
91
- md -calendar {
195
+ .mat -calendar {
92
196
display : block ;
93
197
94
- .md -month {
198
+ .mat -month {
95
199
display : inline-block ;
96
200
97
- .md -date.md -selected {
201
+ .mat -date.mat -selected {
98
202
font-weight : bold ;
99
203
}
100
204
}
@@ -103,15 +207,15 @@ md-calendar {
103
207
104
208
do this:
105
209
``` scss
106
- md -calendar {
210
+ .mat -calendar {
107
211
display : block ;
108
212
}
109
213
110
- .md -calendar-month {
214
+ .mat -calendar-month {
111
215
display : inline-block ;
112
216
}
113
217
114
- .md -calendar-date.md -selected {
218
+ .mat -calendar-date.mat -selected {
115
219
font-weight : bold ;
116
220
}
117
221
```
@@ -123,7 +227,7 @@ The end-user of a component should be the one to decide how much margin a compon
123
227
This makes it easier to override styles when necessary. For example, rather than
124
228
125
229
``` scss
126
- : host {
230
+ the- host-element {
127
231
// ...
128
232
129
233
.some-child-element {
@@ -134,7 +238,7 @@ This makes it easier to override styles when necessary. For example, rather than
134
238
135
239
you can write
136
240
``` scss
137
- : host {
241
+ the- host-element {
138
242
// ...
139
243
color : red ;
140
244
}
@@ -156,11 +260,11 @@ This is a low-effort task that makes a big difference for low-vision users. Exam
156
260
When it is not super obvious, include a brief description of what a class represents. For example:
157
261
``` scss
158
262
// The calendar icon button used to open the calendar pane.
159
- .md -datepicker-button { ... }
263
+ .mat -datepicker-button { ... }
160
264
161
265
// Floating pane that contains the calendar at the bottom of the input.
162
- .md -datepicker-calendar-pane { ... }
266
+ .mat -datepicker-calendar-pane { ... }
163
267
164
268
// Portion of the floating panel that sits, invisibly, on top of the input.
165
- .md -datepicker-input-mask { }
269
+ .mat -datepicker-input-mask { }
166
270
```
0 commit comments