Skip to content

Commit 856d6e0

Browse files
committed
refactor: Added support for strict null checks
Banned use of `null` keyword for simplicity, as peppering code with both `null` and `undefined` isn't the best thing ever.
1 parent 133670d commit 856d6e0

25 files changed

+113
-97
lines changed

components/checkbox/checkbox.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ export class SuiCheckbox implements ICustomValueAccessorHost<boolean> {
3737
@Input()
3838
public isReadonly:boolean;
3939

40-
public get checkedAttribute():string {
41-
return this.isChecked ? "" : null;
40+
public get checkedAttribute():string | undefined {
41+
return this.isChecked ? "" : undefined;
4242
}
4343

44-
public get isDisabledAttribute():string {
45-
return this.isDisabled ? "disabled" : null;
44+
public get isDisabledAttribute():string | undefined {
45+
return this.isDisabled ? "disabled" : undefined;
4646
}
4747

4848
constructor() {

components/checkbox/radiobutton.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ export class SuiRadioButton<T> implements ICustomValueAccessorHost<T> {
4444
@Input()
4545
public isReadonly:boolean;
4646

47-
public get checkedAttribute():string {
48-
return this.isChecked ? "" : null;
47+
public get checkedAttribute():string | undefined {
48+
return this.isChecked ? "" : undefined;
4949
}
5050

51-
public get isDisabledAttribute():string {
52-
return this.isDisabled ? "disabled" : null;
51+
public get isDisabledAttribute():string | undefined {
52+
return this.isDisabled ? "disabled" : undefined;
5353
}
5454

5555
constructor() {

components/dropdown/dropdown.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class DropdownService {
2121
public autoCloseMode:DropdownAutoCloseType;
2222

2323
// Keep track of the containing dropdown so we can open it as necessary.
24-
public parent:DropdownService;
24+
public parent?:DropdownService;
2525
// Also keep track of dropdowns nested in this one so we can close them as necessary.
2626
public children:DropdownService[];
2727
public get isNested():boolean {
@@ -94,7 +94,7 @@ export class DropdownService {
9494
// Wipes any nested data, so all services can be cleanly reattached.
9595
public clearChildren():void {
9696
this.children.forEach(c => {
97-
c.parent = null;
97+
c.parent = undefined;
9898
});
9999
this.children = [];
100100
}

components/dropdown/dropdown.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ export class SuiDropdown implements AfterContentInit {
5858
}
5959

6060
@HostBinding("attr.tabindex")
61-
public get tabIndex():number {
62-
return (this.isDisabled || this.service.isNested) ? null : 0;
61+
public get tabIndex():number | undefined {
62+
return (this.isDisabled || this.service.isNested) ? undefined : 0;
6363
}
6464

6565
@Input()

components/modal/modal-config.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ export const ModalSize = {
1111
};
1212

1313
// Stores a basic set of configuration options for a modal.
14-
export class ModalConfig<T, U = null, V = null> {
14+
export class ModalConfig<T, U = undefined, V = undefined> {
1515
// Determines whether the modal can be closed with a close button, clicking outside, or the escape key.
1616
public isClosable:boolean;
1717
// Value to deny with when closing via `isClosable`.
1818
public closeResult:V;
1919

2020
// Data to pass to the modal instance when opened.
21-
public context:T;
21+
public context?:T;
2222

2323
// Size used to display the modal.
2424
public size:ModalSize;
@@ -35,7 +35,7 @@ export class ModalConfig<T, U = null, V = null> {
3535
// Duration of the modal & dimmer transitions.
3636
public transitionDuration:number;
3737

38-
constructor(context:T = null, isClosable:boolean = true) {
38+
constructor(context:T | undefined = undefined, isClosable:boolean = true) {
3939
// Initialise with default values.
4040
this.isClosable = isClosable;
4141
this.context = context;
@@ -52,21 +52,21 @@ export class ModalConfig<T, U = null, V = null> {
5252
}
5353

5454
// Used when creating a modal from a `TemplateRef`.
55-
export class TemplateModalConfig<T, U = null, V = null> extends ModalConfig<T, U, V> {
55+
export class TemplateModalConfig<T, U = undefined, V = undefined> extends ModalConfig<T, U, V> {
5656
public template:ModalTemplate<T, U, V>;
5757

58-
constructor(template:ModalTemplate<T, U, V>, context:T = null, isClosable:boolean = true) {
58+
constructor(template:ModalTemplate<T, U, V>, context:T | undefined = undefined, isClosable:boolean = true) {
5959
super(context, isClosable);
6060

6161
this.template = template;
6262
}
6363
}
6464

6565
// Used when creating a modal from an existing component.
66-
export class ComponentModalConfig<T, U = null, V = null> extends ModalConfig<T, U, V> {
66+
export class ComponentModalConfig<T, U = undefined, V = undefined> extends ModalConfig<T, U, V> {
6767
public component:Function;
6868

69-
constructor(component:Function, context:T = null, isClosable:boolean = true) {
69+
constructor(component:Function, context:T | undefined = undefined, isClosable:boolean = true) {
7070
super(context, isClosable);
7171

7272
this.component = component;

components/modal/modal-controls.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export class ModalControls<T, U> {
1414
}
1515

1616
// Injected into custom modal components, to allow control of the modal, and access to a context object.
17-
export class Modal<T, U = null, V = null> extends ModalControls<U, V> {
17+
export class Modal<T, U = undefined, V = undefined> extends ModalControls<U, V> {
1818
public context:T;
1919

2020
constructor(controls:ModalControls<U, V>, context:T) {

components/modal/modal.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class SuiModalService {
5454
// Move all of the DOM elements inside the component to the main modal element.
5555
// This is done so that CSS classes apply correctly. It does stop any custom styles from working however,
5656
// so other ways may have to be investigated.
57-
while (contentElement.hasChildNodes()) {
57+
while (contentElement.hasChildNodes() && contentElement.parentElement && contentElement.firstChild) {
5858
contentElement.parentElement.appendChild(contentElement.removeChild(contentElement.firstChild));
5959
}
6060
// Remove the generated component's 'empty shell' from the DOM.
@@ -69,7 +69,7 @@ export class SuiModalService {
6969
this._applicationRef.attachView(componentRef.hostView);
7070

7171
// Move the new modal component DOM to the document body.
72-
document.querySelector("body").appendChild(componentRef.location.nativeElement);
72+
document.querySelector("body")!.appendChild(componentRef.location.nativeElement);
7373

7474
// Initialise the generated modal with the provided config.
7575
modalComponent.loadConfig(modal);

components/modal/modal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export class SuiModal<T, U> implements OnInit, AfterViewInit {
138138

139139
constructor(private _renderer:Renderer2) {
140140
// Initialise with default configuration from `ModalConfig` (to avoid writing defaults twice).
141-
const config = new ModalConfig<null, T, U>();
141+
const config = new ModalConfig<undefined, T, U>();
142142
this.loadConfig(config);
143143

144144
// Event emitters for each of the possible modal outcomes.
@@ -219,7 +219,7 @@ export class SuiModal<T, U> implements OnInit, AfterViewInit {
219219
// Decides whether the modal needs to reposition to allow scrolling.
220220
private updateScroll():void {
221221
// Semantic UI modal margin is 3.5rem, which is relative to the global font size, so for compatibility:
222-
const fontSize = parseFloat(window.getComputedStyle(document.documentElement, null).getPropertyValue("font-size"));
222+
const fontSize = parseFloat(window.getComputedStyle(document.documentElement).getPropertyValue("font-size"));
223223
const margin = fontSize * 3.5;
224224

225225
// _mustAlwaysScroll works by stopping _mustScroll from being automatically updated, so it stays `true`.

components/popup/popup-arrow.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@ export class SuiPopupArrow {
7777
@Input()
7878
public inverted:boolean;
7979

80-
public get direction():string {
80+
public get direction():string | undefined {
8181
if (this.placement) {
8282
return this.placement.split(" ").shift();
8383
}
8484
}
8585

86-
public get alignment():string {
86+
public get alignment():string | undefined {
8787
if (this.placement) {
8888
const alignment = this.placement.split(" ").pop();
8989
if (alignment === this.direction) {

components/popup/popup.directive.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@ export class SuiPopupDirective implements IPopup {
8181
}
8282

8383
// Stores reference to generated popup component.
84-
private _componentRef:ComponentRef<SuiPopup>;
84+
private _componentRef?:ComponentRef<SuiPopup>;
8585

8686
// Returns generated popup instance.
8787
private get _popup():SuiPopup {
88-
return this._componentRef.instance;
88+
// Use non-null assertion as we only access this when a popup exists.
89+
return this._componentRef!.instance;
8990
}
9091

9192
// `setTimeout` timer pointer for delayed popup open.
@@ -123,14 +124,16 @@ export class SuiPopupDirective implements IPopup {
123124
this._popup.anchor = this._element;
124125

125126
// Move the generated element to the body to avoid any positioning issues.
126-
document.querySelector("body").appendChild(this._componentRef.location.nativeElement);
127+
document.querySelector("body")!.appendChild(this._componentRef.location.nativeElement);
127128

128129
// When the popup is closed (onClose fires on animation complete),
129130
this._popup.onClose.subscribe(() => {
130-
// Destroy the component reference (which removes the popup from the DOM).
131-
this._componentRef.destroy();
132-
// Unset the reference pointer to enable a new popup to be created on next open.
133-
this._componentRef = null;
131+
if (this._componentRef) {
132+
// Destroy the component reference (which removes the popup from the DOM).
133+
this._componentRef.destroy();
134+
// Unset the reference pointer to enable a new popup to be created on next open.
135+
this._componentRef = undefined;
136+
}
134137
});
135138
}
136139

0 commit comments

Comments
 (0)