Skip to content

feat(schematics): create drag-drop schematic #13368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/cdk/schematics/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ exports_files(["#bazel_workaround.txt"])

filegroup(
name = "schematics_assets",
srcs = glob(["**/*.json"]) + ["README.md"],
srcs = glob(["**/files/**/*", "**/*.json"]) + ["README.md"],
)

ts_library(
name = "schematics",
module_name = "@angular/cdk/schematics",
srcs = glob(["**/*.ts"], exclude=["**/*.spec.ts"]),
srcs = glob(["**/*.ts"], exclude=["**/files/**/*.ts", "**/*.spec.ts"]),
tsconfig = ":tsconfig.json",
deps = [
"@npm//:@schematics/angular",
Expand Down Expand Up @@ -51,7 +51,7 @@ jasmine_node_test(

ts_library(
name = "schematics_test_sources",
srcs = glob(["**/*.spec.ts"]),
srcs = glob(["**/*.spec.ts"], exclude = ["**/files/**/*.spec.ts"]),
deps = [
":schematics",
"@npm//:@schematics/angular",
Expand Down
6 changes: 6 additions & 0 deletions src/cdk/schematics/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
"factory": "./ng-add/index",
"schema": "./ng-add/schema.json",
"aliases": ["install"]
},
"drag-drop": {
"description": "Generates a component using the Drag and Drop module",
"factory": "./ng-generate/drag-drop/index",
"schema": "./ng-generate/drag-drop/schema.json",
"aliases": ["dragdrop", "drag-and-drop"]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.container {
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
}

.list {
border: solid 1px #ccc;
min-height: 60px;
background: white;
border-radius: 4px;
display: block;
overflow: hidden;
}

.list-item {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
box-sizing: border-box;
cursor: move;
background: white;
color: black;
font-size: 14px;
}

.list-item:last-child {
border: none;
}

/* Highlight the list item that is being dragged. */
.cdk-drag-preview {
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

/* Animate items as they're being sorted. */
.cdk-drop-dragging .cdk-drag {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

/* Animate an item that has been dropped. */
.cdk-drag-animating {
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1);
}

.cdk-drag-placeholder {
opacity: 0;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="container">
<h2>To do</h2>

<cdk-drop #todoList [data]="todo" [connectedTo]="doneList" class="list" (dropped)="drop($event)">
<div class="list-item" *ngFor="let item of todo" cdkDrag>{{item}}</div>
</cdk-drop>
</div>

<div class="container">
<h2>Done</h2>

<cdk-drop #doneList [data]="done" [connectedTo]="todoList" class="list" (dropped)="drop($event)">
<div class="list-item" *ngFor="let item of done" cdkDrag>{{item}}</div>
</cdk-drop>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { DragDropModule } from '@angular/cdk/drag-drop';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';

describe('<%= classify(name) %>Component', () => {
let component: <%= classify(name) %>Component;
let fixture: ComponentFixture<<%= classify(name) %>Component>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ <%= classify(name) %>Component ],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this going to end up with extra space inside the square brackets? E.g. [ MyComponent ].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imports: [
NoopAnimationsModule,
DragDropModule,
]
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(<%= classify(name) %>Component);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should compile', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Component<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection !== 'Default') { %>, ChangeDetectionStrategy<% }%> } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';

@Component({
selector: '<%= selector %>',<% if(inlineTemplate) { %>
template: `
<%= indentTextContent(resolvedFiles.template, 4) %>
`,<% } else { %>
templateUrl: './<%= dasherize(name) %>.component.html',<% } if(inlineStyle) { %>
styles: [`
<%= indentTextContent(resolvedFiles.stylesheet, 4) %>
`],<% } else { %>
styleUrls: ['./<%= dasherize(name) %>.component.<%= styleext %>'],<% } %><% if(!!viewEncapsulation) { %>
encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>,
changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %>
})
export class <%= classify(name) %>Component {
todo = [
'Get to work',
'Pick up groceries',
'Go home',
'Fall asleep'
];

done = [
'Get up',
'Brush teeth',
'Take a shower',
'Check e-mail',
'Walk dog'
];

drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
}
}
105 changes: 105 additions & 0 deletions src/cdk/schematics/ng-generate/drag-drop/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
import {createTestApp} from '../../testing';
import {getFileContent} from '@schematics/angular/utility/test';
import {Schema} from './schema';

describe('CDK drag-drop schematic', () => {
let runner: SchematicTestRunner;

const baseOptions: Schema = {
name: 'foo',
// TODO(devversion): rename project to something that is not tied to Material. This involves
// updating the other tests as well because `createTestApp` is responsible for creating
// the project.
project: 'material',
};

beforeEach(() => {
runner = new SchematicTestRunner('schematics', require.resolve('../../collection.json'));
});

it('should create drag-drop files and add them to module', () => {
const tree = runner.runSchematic('drag-drop', baseOptions, createTestApp(runner));
const moduleContent = getFileContent(tree, '/projects/material/src/app/app.module.ts');
const files = tree.files;

expect(files).toContain('/projects/material/src/app/foo/foo.component.css');
expect(files).toContain('/projects/material/src/app/foo/foo.component.html');
expect(files).toContain('/projects/material/src/app/foo/foo.component.spec.ts');
expect(files).toContain('/projects/material/src/app/foo/foo.component.ts');

expect(moduleContent).toMatch(/import.*Foo.*from '.\/foo\/foo.component'/);
expect(moduleContent).toMatch(/declarations:\s*\[[^\]]+?,\r?\n\s+FooComponent\r?\n/m);
});

it('should add drag-drop module', () => {
const tree = runner.runSchematic('drag-drop', baseOptions, createTestApp(runner));
const moduleContent = getFileContent(tree, '/projects/material/src/app/app.module.ts');

expect(moduleContent).toContain('DragDropModule');
});

describe('styleext option', () => {
it('should respect the option value', () => {
const tree = runner.runSchematic(
'drag-drop', {styleext: 'scss', ...baseOptions}, createTestApp(runner));

expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss');
});

it('should fall back to the @schematics/angular:component option value', () => {
const tree = runner.runSchematic(
'drag-drop', baseOptions, createTestApp(runner, {style: 'less'}));

expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less');
});
});

describe('inlineStyle option', () => {
it('should respect the option value', () => {
const tree = runner.runSchematic(
'drag-drop', {inlineStyle: true, ...baseOptions}, createTestApp(runner));

expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});

it('should fall back to the @schematics/angular:component option value', () => {
const tree = runner.runSchematic(
'drag-drop', baseOptions, createTestApp(runner, {inlineStyle: true}));

expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
});

describe('inlineTemplate option', () => {
it('should respect the option value', () => {
const tree = runner.runSchematic(
'drag-drop', {inlineTemplate: true, ...baseOptions}, createTestApp(runner));

expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});

it('should fall back to the @schematics/angular:component option value', () => {
const tree = runner.runSchematic(
'drag-drop', baseOptions, createTestApp(runner, {inlineTemplate: true}));

expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
});

describe('spec option', () => {
it('should respect the option value', () => {
const tree = runner.runSchematic(
'drag-drop', {spec: false, ...baseOptions}, createTestApp(runner));

expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});

it('should fall back to the @schematics/angular:component option value', () => {
const tree = runner.runSchematic(
'drag-drop', baseOptions, createTestApp(runner, {skipTests: true}));

expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
});
});
32 changes: 32 additions & 0 deletions src/cdk/schematics/ng-generate/drag-drop/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {chain, noop, Rule, Tree} from '@angular-devkit/schematics';
import {addModuleImportToModule, buildComponent, findModuleFromOptions} from '../../utils';
import {Schema} from './schema';

/** Scaffolds a new Angular component that uses the Drag and Drop module. */
export default function(options: Schema): Rule {
return chain([
buildComponent({...options}, {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__styleext__',
}),
options.skipImport ? noop() : addDragDropModulesToModule(options)
]);
}

/** Adds the required modules to the main module of the CLI project. */
function addDragDropModulesToModule(options: Schema) {
return (host: Tree) => {
const modulePath = findModuleFromOptions(host, options)!;

addModuleImportToModule(host, modulePath, 'DragDropModule', '@angular/cdk/drag-drop');
return host;
};
}
Loading