Skip to content

Commit b919a48

Browse files
devversionjelbourn
authored andcommitted
feat(ng-add): set up gestures in CLI projects (#12734)
Introduces a new option for the `ng-add` schematic that enables automatic set up of HammerJS in the CLI project. By default, gestures will be set up if someone runs `ng add @angular/material`.
1 parent dad0ed0 commit b919a48

File tree

8 files changed

+112
-4
lines changed

8 files changed

+112
-4
lines changed

guides/schematics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ This schematic will:
2020
- Add Prebuilt or Setup Custom Theme
2121
- Add Roboto fonts to your index.html
2222
- Apply simple CSS reset to body
23-
23+
- Install and load `hammerjs` for gestures in your project.
2424

2525
## Generator Schematics
2626
In addition to the install schematic, Angular Material has three schematics it comes packaged with:
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Rule, Tree} from '@angular-devkit/schematics';
10+
import {getWorkspace} from '@schematics/angular/utility/config';
11+
import {getProjectFromWorkspace} from '../../utils/get-project';
12+
import {Schema} from '../schema';
13+
import {getProjectMainFile} from './project-main-file';
14+
15+
const hammerjsImportStatement = `import 'hammerjs';`;
16+
17+
/** Adds HammerJS to the main file of the specified Angular CLI project. */
18+
export function addHammerJsToMain(options: Schema): Rule {
19+
return (host: Tree) => {
20+
const workspace = getWorkspace(host);
21+
const project = getProjectFromWorkspace(workspace, options.project);
22+
const mainFile = getProjectMainFile(project);
23+
24+
const recorder = host.beginUpdate(mainFile);
25+
const buffer = host.read(mainFile);
26+
27+
if (!buffer) {
28+
return console.error(`Could not read the project main file (${mainFile}). Please manually ` +
29+
`import HammerJS in your main TypeScript file.`);
30+
}
31+
32+
const fileContent = buffer.toString('utf8');
33+
34+
if (fileContent.includes(hammerjsImportStatement)) {
35+
return console.log(`HammerJS is already imported in the project main file (${mainFile}).`);
36+
}
37+
38+
recorder.insertRight(0, `${hammerjsImportStatement}\n`);
39+
host.commitUpdate(recorder);
40+
};
41+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {SchematicsException} from '@angular-devkit/schematics';
10+
import {WorkspaceProject} from '@schematics/angular/utility/config';
11+
12+
/** Looks for the main TypeScript file in the given project and returns its path. */
13+
export function getProjectMainFile(project: WorkspaceProject): string {
14+
const buildTarget = project.architect.build.options;
15+
16+
if (buildTarget.main) {
17+
return buildTarget.main;
18+
}
19+
20+
throw new SchematicsException(
21+
'Could not find the project main file inside of the workspace config.');
22+
}

src/lib/schematics/install/index.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,19 @@ describe('material-install-schematic', () => {
3434

3535
expect(packageJson.dependencies['@angular/material']).toBeDefined();
3636
expect(packageJson.dependencies['@angular/cdk']).toBeDefined();
37+
expect(packageJson.dependencies['hammerjs']).toBeDefined();
3738
expect(packageJson.dependencies['@angular/animations']).toBe(angularCoreVersion,
3839
'Expected the @angular/animations package to have the same version as @angular/core.');
3940
});
4041

42+
it('should add hammerjs import to project main file', () => {
43+
const tree = runner.runSchematic('ng-add', {}, appTree);
44+
const fileContent = getFileContent(tree, '/projects/material/src/main.ts');
45+
46+
expect(fileContent).toContain(`import 'hammerjs';`,
47+
'Expected the project main file to contain a HammerJS import.');
48+
});
49+
4150
it('should add default theme', () => {
4251
const tree = runner.runSchematic('ng-add', {}, appTree);
4352

@@ -106,4 +115,23 @@ describe('material-install-schematic', () => {
106115
expect(htmlContent).toContain(
107116
'body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }');
108117
});
118+
119+
describe('gestures disabled', () => {
120+
121+
it('should not add hammerjs to package.json', () => {
122+
const tree = runner.runSchematic('ng-add', {gestures: false}, appTree);
123+
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
124+
125+
expect(packageJson.dependencies['hammerjs'])
126+
.toBeUndefined(`Expected 'hammerjs' to be not added to the package.json`);
127+
});
128+
129+
it('should not add hammerjs import to project main file', () => {
130+
const tree = runner.runSchematic('ng-add', {gestures: false}, appTree);
131+
const fileContent = getFileContent(tree, '/projects/material/src/main.ts');
132+
133+
expect(fileContent).not.toContain(`import 'hammerjs';`,
134+
'Expected the project main file to not contain a HammerJS import.');
135+
});
136+
});
109137
});

src/lib/schematics/install/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ import {getProjectFromWorkspace} from '../utils/get-project';
2222
import {addPackageToPackageJson, getPackageVersionFromPackageJson} from '../utils/package-json';
2323
import {getProjectStyleFile} from '../utils/project-style-file';
2424
import {addFontsToIndex} from './fonts/material-fonts';
25+
import {addHammerJsToMain} from './gestures/hammerjs-import';
2526
import {Schema} from './schema';
2627
import {addThemeToAppStyles} from './theming/theming';
27-
import {materialVersion, requiredAngularVersionRange} from './version-names';
28+
import {hammerjsVersion, materialVersion, requiredAngularVersionRange} from './version-names';
2829

2930
/**
3031
* Scaffolds the basics of a Angular Material application, this includes:
@@ -39,7 +40,8 @@ export default function(options: Schema): Rule {
3940
}
4041

4142
return chain([
42-
options && options.skipPackageJson ? noop() : addMaterialToPackageJson(),
43+
options && options.skipPackageJson ? noop() : addMaterialToPackageJson(options),
44+
options && options.gestures ? addHammerJsToMain(options) : noop(),
4345
addThemeToAppStyles(options),
4446
addAnimationRootConfig(options),
4547
addFontsToIndex(options),
@@ -48,7 +50,7 @@ export default function(options: Schema): Rule {
4850
}
4951

5052
/** Add material, cdk, animations to package.json if not already present. */
51-
function addMaterialToPackageJson() {
53+
function addMaterialToPackageJson(options: Schema) {
5254
return (host: Tree, context: SchematicContext) => {
5355
// Version tag of the `@angular/core` dependency that has been loaded from the `package.json`
5456
// of the CLI project. This tag should be preferred because all Angular dependencies should
@@ -60,6 +62,10 @@ function addMaterialToPackageJson() {
6062
addPackageToPackageJson(host, 'dependencies', '@angular/animations',
6163
ngCoreVersionTag || requiredAngularVersionRange);
6264

65+
if (options.gestures) {
66+
addPackageToPackageJson(host, 'dependencies', 'hammerjs', hammerjsVersion);
67+
}
68+
6369
context.addTask(new NodePackageInstallTask());
6470

6571
return host;

src/lib/schematics/install/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
"enum": ["indigo-pink", "deeppurple-amber", "pink-bluegrey", "purple-green", "custom"],
1414
"default": "indigo-pink",
1515
"description": "The theme to apply"
16+
},
17+
"gestures": {
18+
"type": "boolean",
19+
"default": true,
20+
"description": "Whether gesture support should be set up or not."
1621
}
1722
},
1823
"required": []

src/lib/schematics/install/schema.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export interface Schema {
1010
/** Whether to skip package.json install. */
1111
skipPackageJson: boolean;
1212

13+
/** Whether gesture support should be set up or not. */
14+
gestures: boolean;
15+
1316
/** Name of pre-built theme to install. */
1417
theme: 'indigo-pink' | 'deeppurple-amber' | 'pink-bluegrey' | 'purple-green' | 'custom';
1518

src/lib/schematics/install/version-names.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ export const materialVersion =
1717
*/
1818
export const requiredAngularVersionRange = '0.0.0-NG';
1919

20+
/** HammerJS version that should be installed if gestures will be set up. */
21+
export const hammerjsVersion = '^2.0.8';
22+
2023
/** Loads the full version from the given Angular package gracefully. */
2124
function loadPackageVersionGracefully(packageName: string): string | null {
2225
try {

0 commit comments

Comments
 (0)