├── examples ├── storybook │ ├── index.ts │ ├── .gitignore │ ├── .storybook │ │ ├── config.js │ │ └── tsconfig.json │ └── package.json └── .yarnrc ├── tests └── integration │ ├── src │ ├── assets │ │ └── .gitkeep │ ├── app │ │ ├── app.component.css │ │ ├── app.component.ts │ │ ├── app.component.html │ │ ├── app.module.ts │ │ └── app.component.spec.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── styles.css │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── test.ts │ └── polyfills.ts │ ├── e2e │ ├── tsconfig.json │ ├── src │ │ ├── app.po.ts │ │ └── app.e2e-spec.ts │ └── protractor.conf.js │ ├── .editorconfig │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── browserslist │ ├── tsconfig.json │ ├── .gitignore │ ├── README.md │ ├── karma.conf.js │ ├── package.json │ ├── tslint.json │ └── angular.json ├── src ├── typings.d.ts ├── paths.js ├── clean.js ├── tsconfig.json ├── templates.js └── generate.js ├── .npmignore ├── scripts ├── deploy.sh └── run-integration-test.sh ├── tasks ├── clean.js └── generate.js ├── .travis.yml ├── config └── tsconfig-aot.json ├── .gitignore ├── package.json └── README.md /examples/storybook/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/integration/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/integration/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/.yarnrc: -------------------------------------------------------------------------------- 1 | yarn-offline-mirror false 2 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@carbon/icon-helpers'; 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | **/__mocks__/** 2 | **/__tests__/** 3 | **/examples/** 4 | **/tasks/** -------------------------------------------------------------------------------- /examples/storybook/.gitignore: -------------------------------------------------------------------------------- 1 | # icons-angular stories are generated dynamically ... 2 | stories 3 | -------------------------------------------------------------------------------- /tests/integration/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /tests/integration/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /tests/integration/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carbon-design-system/carbon-icons-angular/HEAD/tests/integration/src/favicon.ico -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit with nonzero exit code if anything fails 4 | 5 | # exit with an error if the build fails 6 | if [[ ${TRAVIS_TEST_RESULT=0} == 1 ]]; then 7 | exit 1; 8 | fi 9 | 10 | #deploy with semantic-release 11 | npm run semantic-release 12 | -------------------------------------------------------------------------------- /tests/integration/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'integration'; 10 | } 11 | -------------------------------------------------------------------------------- /tests/integration/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/integration/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /tests/integration/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root .content span')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/storybook/.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from '@storybook/angular'; 2 | import "core-js/es"; 3 | 4 | // automatically import all files ending in *.stories.ts 5 | const req = require.context('../stories', true, /.stories.ts$/); 6 | function loadStories() { 7 | req.keys().forEach(filename => req(filename)); 8 | } 9 | 10 | configure(loadStories, module); 11 | -------------------------------------------------------------------------------- /tests/integration/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Integration 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/integration/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tests/integration/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tasks/clean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright IBM Corp. 2018, 2018 3 | * 4 | * This source code is licensed under the Apache-2.0 license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const { clean } = require('../src/clean'); 9 | const { reporter } = require('@carbon/cli-reporter'); 10 | 11 | clean().catch(error => { 12 | reporter.error(error); 13 | }); 14 | -------------------------------------------------------------------------------- /scripts/run-integration-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit with nonzero exit code if anything fails 4 | 5 | cd dist 6 | npm pack 7 | mv carbon-icons-angular-0.0.0.tgz ../ 8 | cd ../ 9 | 10 | cd tests/integration 11 | 12 | echo "installing dependencies" 13 | npm i 14 | npm i ../../carbon-icons-angular-0.0.0.tgz 15 | 16 | echo "testing" 17 | npm run test 18 | 19 | echo "building" 20 | npm run build 21 | -------------------------------------------------------------------------------- /tests/integration/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /tests/integration/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /tests/integration/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

Icons integration test

2 | 3 |

Default icons

4 | 5 | 6 | 7 |

IBM Q icons

8 | 9 | 10 | 11 |

Watson Health icons

12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/integration/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { _4KModule, QCircuitComposerModule, WatsonHealth_3DCursorModule } from '@carbon/icons-angular'; 5 | 6 | import { AppComponent } from './app.component'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AppComponent 11 | ], 12 | imports: [ 13 | BrowserModule, 14 | _4KModule, 15 | QCircuitComposerModule, 16 | WatsonHealth_3DCursorModule 17 | ], 18 | providers: [], 19 | bootstrap: [AppComponent] 20 | }) 21 | export class AppModule { } 22 | -------------------------------------------------------------------------------- /examples/storybook/.storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "", 4 | "declaration": true, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "es2016", 9 | "dom" 10 | ], 11 | "sourceMap": true, 12 | "mapRoot": "./../", 13 | "module": "es2015", 14 | "moduleResolution": "node", 15 | "outDir": "./../dist", 16 | "rootDirs": ["./../stories"], 17 | "target": "es5", 18 | "inlineSources": true, 19 | "typeRoots": ["./../node_modules/@types"] 20 | }, 21 | "files": [ 22 | "./../index.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/paths.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright IBM Corp. 2018, 2018 3 | * 4 | * This source code is licensed under the Apache-2.0 license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const { resolve } = require('path'); 9 | 10 | module.exports = { 11 | TS: resolve(__dirname, '../ts'), 12 | DIST: resolve(__dirname, '../dist'), 13 | ESM5: resolve(__dirname, '../dist/esm5'), 14 | ESM2015: resolve(__dirname, '../dist/esm2015'), 15 | FESM5: resolve(__dirname, '../dist/fesm5'), 16 | FESM2015: resolve(__dirname, '../dist/fesm2015'), 17 | BUNDLES: resolve(__dirname, '../dist/bundles') 18 | }; 19 | -------------------------------------------------------------------------------- /tests/integration/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: node_js 3 | node_js: 4 | - "12" 5 | addons: 6 | chrome: stable 7 | before_install: 8 | - "google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &" 9 | before_script: 10 | - "export DISPLAY=:99.0" 11 | - "sh -e /etc/init.d/xvfb start" 12 | - "sleep 3" 13 | - "sudo chown root /opt/google/chrome/chrome-sandbox" 14 | - "sudo chmod 4755 /opt/google/chrome/chrome-sandbox" 15 | script: 16 | - yarn build 17 | # - yarn test 18 | deploy: 19 | provider: script 20 | script: "bash ./scripts/deploy.sh" 21 | skip_cleanup: true 22 | on: 23 | all_branches: true 24 | notifications: 25 | email: false 26 | -------------------------------------------------------------------------------- /src/clean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright IBM Corp. 2018, 2018 3 | * 4 | * This source code is licensed under the Apache-2.0 license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const { remove } = require('fs-extra'); 9 | const paths = require('./paths'); 10 | 11 | async function clean() { 12 | cleanSome([ 13 | paths.TS, 14 | paths.DIST, 15 | paths.ESM5, 16 | paths.ESM2015, 17 | paths.FESM5, 18 | paths.FESM2015, 19 | paths.BUNDLES 20 | ]); 21 | } 22 | 23 | async function cleanSome(paths) { 24 | return Promise.all(paths.map(path => remove(path))); 25 | } 26 | 27 | module.exports = { 28 | clean, 29 | cleanSome, 30 | }; 31 | -------------------------------------------------------------------------------- /tests/integration/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /config/tsconfig-aot.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "", 4 | "declaration": true, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "es2016", 9 | "dom" 10 | ], 11 | "sourceMap": true, 12 | "module": "es2015", 13 | "moduleResolution": "node", 14 | "outDir": "./../dist/lib", 15 | "rootDir": "./../ts", 16 | "target": "es5", 17 | "inlineSources": true, 18 | "typeRoots": ["./../node_modules/@types"] 19 | }, 20 | "include": [ 21 | "./../ts/**/*" 22 | ], 23 | "exclude": [ 24 | "./../ts/**/public-api.ts" 25 | ], 26 | "angularCompilerOptions": { 27 | "strictMetadataEmit": true, 28 | "genDir": "./../waste" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/integration/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /tests/integration/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('integration app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build folders 2 | /build 3 | packages/*/build/ 4 | packages/*/examples/*/build/ 5 | es 6 | lib 7 | dist 8 | umd 9 | css 10 | ts 11 | 12 | # Netlify deploy folder 13 | /demo/* 14 | !/demo/index.html 15 | 16 | # Config files 17 | .npmrc 18 | 19 | # Cache folders 20 | .cache 21 | 22 | # Logs 23 | logs 24 | *.log 25 | 26 | # Runtime data 27 | pids 28 | *.pid 29 | *.seed 30 | 31 | # Certificates 32 | *.crt 33 | *.pem 34 | 35 | # Editor 36 | .DS_Store 37 | *.swp 38 | .idea 39 | .vscode 40 | 41 | # Coverage directory used by tools like istanbul, also includes default junit 42 | # output file 43 | coverage 44 | /junit.xml 45 | 46 | # Dependency directory 47 | node_modules 48 | 49 | # Generated by npm@5, but project currently uses Yarn 50 | package-lock.json 51 | !tests/integration/package-lock.json 52 | *.tgz 53 | -------------------------------------------------------------------------------- /tests/integration/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /tests/integration/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "angularCompilerOptions": { 3 | "enableIvy": false, 4 | "skipTemplateCodegen": true, 5 | "strictMetadataEmit": true, 6 | "fullTemplateTypeCheck": true, 7 | "enableResourceInlining": true 8 | }, 9 | "buildOnSave": false, 10 | "compileOnSave": false, 11 | "compilerOptions": { 12 | "baseUrl": ".", 13 | "target": "es5", 14 | "module": "es2015", 15 | "moduleResolution": "node", 16 | "outDir": "AUTOGENERATED", 17 | "declaration": true, 18 | "declarationDir": "AUTOGENERATED", 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "skipLibCheck": true, 22 | "emitDecoratorMetadata": true, 23 | "experimentalDecorators": true, 24 | "importHelpers": true, 25 | "lib": [ 26 | "dom", 27 | "es2018" 28 | ] 29 | }, 30 | "exclude": [ 31 | "**/node_modules/**", 32 | "dist", 33 | "**/*.ngfactory.ts", 34 | "**/*.shim.ts", 35 | "**/*.spec.ts" 36 | ], 37 | "files": [ 38 | "AUTOGENERATED" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /tests/integration/README.md: -------------------------------------------------------------------------------- 1 | # Integration 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.23. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /tests/integration/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/integration'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /examples/storybook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@carbon/icons-angular-examples-storybook", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "build": "node --max_old_space_size=3512 node_modules/@storybook/angular/bin/build.js -o build", 9 | "develop": "start-storybook -p 3000" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@angular-devkit/build-angular": "^0.803.23", 15 | "@angular-devkit/core": "8.3.23", 16 | "@angular/common": "8.2.14", 17 | "@angular/compiler": "8.2.14", 18 | "@angular/compiler-cli": "^8.2.14", 19 | "@angular/core": "8.2.14", 20 | "@angular/forms": "8.2.14", 21 | "@angular/platform-browser": "8.2.14", 22 | "@angular/platform-browser-dynamic": "8.2.14", 23 | "@babel/core": "7.8.3", 24 | "@storybook/angular": "^5.2.0", 25 | "autoprefixer": "8.1.0", 26 | "babel-loader": "^8.0.6", 27 | "core-js": "3.1.3", 28 | "rxjs": "6.4.0", 29 | "tslint": "5.17.0", 30 | "typescript": ">=3.1 < 3.6", 31 | "zone.js": "0.9.1", 32 | "@angular/cli": "8.3.23", 33 | "ts-node": "~7.0.0", 34 | "tsickle": ">=0.34.0", 35 | "tslib": "^1.9.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/integration/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "integration", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build --prod --aot", 8 | "test": "ng test --no-watch", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~9.1.3", 15 | "@angular/common": "~9.1.3", 16 | "@angular/compiler": "~9.1.3", 17 | "@angular/core": "~9.1.3", 18 | "@angular/forms": "~9.1.3", 19 | "@angular/platform-browser": "~9.1.3", 20 | "@angular/platform-browser-dynamic": "~9.1.3", 21 | "@angular/router": "~9.1.3", 22 | "rxjs": "~6.5.5", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.10.2", 25 | "@carbon/icons-angular": "latest" 26 | }, 27 | "devDependencies": { 28 | "@angular-devkit/build-angular": "~0.901.2", 29 | "@angular/cli": "~9.1.2", 30 | "@angular/compiler-cli": "~9.1.3", 31 | "@angular/language-service": "~9.1.3", 32 | "@types/node": "^12.11.1", 33 | "@types/jasmine": "~3.3.8", 34 | "@types/jasminewd2": "~2.0.3", 35 | "codelyzer": "^5.1.2", 36 | "jasmine-core": "~3.4.0", 37 | "jasmine-spec-reporter": "~4.2.1", 38 | "karma": "~4.1.0", 39 | "karma-chrome-launcher": "~2.2.0", 40 | "karma-coverage-istanbul-reporter": "~2.0.1", 41 | "karma-jasmine": "~2.0.1", 42 | "karma-jasmine-html-reporter": "^1.4.0", 43 | "protractor": "~5.4.0", 44 | "ts-node": "~7.0.0", 45 | "tslint": "~5.15.0", 46 | "typescript": "~3.8.3" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/integration/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { By } from '@angular/platform-browser'; 3 | import { AppComponent } from './app.component'; 4 | 5 | import { _4KModule, QCircuitComposerModule, WatsonHealth_3DCursorModule } from '@carbon/icons-angular'; 6 | 7 | describe('AppComponent', () => { 8 | beforeEach(async(() => { 9 | TestBed.configureTestingModule({ 10 | declarations: [ 11 | AppComponent 12 | ], 13 | imports: [ 14 | _4KModule, 15 | QCircuitComposerModule, 16 | WatsonHealth_3DCursorModule 17 | ] 18 | }).compileComponents(); 19 | })); 20 | 21 | it('should create the app', () => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | const app = fixture.debugElement.componentInstance; 24 | expect(app).toBeTruthy(); 25 | }); 26 | 27 | it(`should have a standard icon`, () => { 28 | const fixture = TestBed.createComponent(AppComponent); 29 | const icon = fixture.debugElement.query(By.css('ibm-icon-4-k')); 30 | expect(icon.nativeElement.firstElementChild.tagName).toEqual('svg'); 31 | }); 32 | 33 | it(`should have a ibm q icon`, () => { 34 | const fixture = TestBed.createComponent(AppComponent); 35 | const icon = fixture.debugElement.query(By.css('ibm-icon-q-circuit-composer')); 36 | expect(icon.nativeElement.firstElementChild.tagName).toEqual('svg'); 37 | }); 38 | 39 | it(`should have a watson health icon`, () => { 40 | const fixture = TestBed.createComponent(AppComponent); 41 | const icon = fixture.debugElement.query(By.css('ibm-icon-watson-health-3-d-cursor')); 42 | expect(icon.nativeElement.firstElementChild.tagName).toEqual('svg'); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /tests/integration/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "array-type": false, 5 | "arrow-parens": false, 6 | "deprecation": { 7 | "severity": "warning" 8 | }, 9 | "component-class-suffix": true, 10 | "contextual-lifecycle": true, 11 | "directive-class-suffix": true, 12 | "directive-selector": [ 13 | true, 14 | "attribute", 15 | "app", 16 | "camelCase" 17 | ], 18 | "component-selector": [ 19 | true, 20 | "element", 21 | "app", 22 | "kebab-case" 23 | ], 24 | "import-blacklist": [ 25 | true, 26 | "rxjs/Rx" 27 | ], 28 | "interface-name": false, 29 | "max-classes-per-file": false, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-consecutive-blank-lines": false, 47 | "no-console": [ 48 | true, 49 | "debug", 50 | "info", 51 | "time", 52 | "timeEnd", 53 | "trace" 54 | ], 55 | "no-empty": false, 56 | "no-inferrable-types": [ 57 | true, 58 | "ignore-params" 59 | ], 60 | "no-non-null-assertion": true, 61 | "no-redundant-jsdoc": true, 62 | "no-switch-case-fall-through": true, 63 | "no-var-requires": false, 64 | "object-literal-key-quotes": [ 65 | true, 66 | "as-needed" 67 | ], 68 | "object-literal-sort-keys": false, 69 | "ordered-imports": false, 70 | "quotemark": [ 71 | true, 72 | "single" 73 | ], 74 | "trailing-comma": false, 75 | "no-conflicting-lifecycle": true, 76 | "no-host-metadata-property": true, 77 | "no-input-rename": true, 78 | "no-inputs-metadata-property": true, 79 | "no-output-native": true, 80 | "no-output-on-prefix": true, 81 | "no-output-rename": true, 82 | "no-outputs-metadata-property": true, 83 | "template-banana-in-box": true, 84 | "template-no-negated-async": true, 85 | "use-lifecycle-interface": true, 86 | "use-pipe-transform-interface": true 87 | }, 88 | "rulesDirectory": [ 89 | "codelyzer" 90 | ] 91 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/ng-packagr/package.schema.json", 3 | "name": "@carbon/icons-angular", 4 | "description": "Angular components for icons in digital and software products using the Carbon Design System", 5 | "version": "0.0.0", 6 | "license": "Apache-2.0", 7 | "main": "lib/index.js", 8 | "ngPackage": { 9 | "lib": { 10 | "entryFile": "ts/index.ts" 11 | }, 12 | "whitelistedNonPeerDependencies": [ 13 | "@carbon/icon-helpers" 14 | ] 15 | }, 16 | "release": { 17 | "pkgRoot": "dist", 18 | "branches": [ 19 | { 20 | "name": "master", 21 | "channel": "latest" 22 | }, 23 | { 24 | "name": "next", 25 | "channel": "next" 26 | }, 27 | { 28 | "name": "v10", 29 | "channel": "carbon-v10", 30 | "range": "10.X" 31 | } 32 | ] 33 | }, 34 | "repository": "https://github.com/carbon-design-system/carbon-icons-angular", 35 | "bugs": "https://github.com/carbon-design-system/carbon-icons-angular/issues", 36 | "keywords": [ 37 | "ibm", 38 | "elements", 39 | "carbon", 40 | "carbon-elements", 41 | "carbon-design-system", 42 | "icons", 43 | "angular" 44 | ], 45 | "publishConfig": { 46 | "access": "public", 47 | "directory": "dist" 48 | }, 49 | "scripts": { 50 | "build": "yarn clean && yarn build:generate", 51 | "build:generate": "node tasks/generate.js", 52 | "build:storybook": "cd examples/storybook && yarn && yarn build", 53 | "clean": "node tasks/clean.js", 54 | "semantic-release": "semantic-release", 55 | "test": "bash scripts/run-integration-test.sh" 56 | }, 57 | "peerDependencies": { 58 | "@angular/compiler": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", 59 | "@angular/core": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" 60 | }, 61 | "dependencies": { 62 | "@carbon/icon-helpers": "10.6.0" 63 | }, 64 | "devDependencies": { 65 | "@angular/compiler": "9.1.1", 66 | "@angular/compiler-cli": "9.1.1", 67 | "@angular/core": "9.1.1", 68 | "@carbon/cli-reporter": "10.3.0", 69 | "@carbon/icons": "10.18.0", 70 | "change-case": "3.0.2", 71 | "fs-extra": "7.0.1", 72 | "ng-packagr": "9.1.0", 73 | "semantic-release": "17.2.3", 74 | "typescript": "3.8.3", 75 | "zone.js": "0.10.3", 76 | "rollup": "2.3.3" 77 | }, 78 | "sideEffects": false 79 | } 80 | -------------------------------------------------------------------------------- /tests/integration/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /tasks/generate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright IBM Corp. 2018, 2018 3 | * 4 | * This source code is licensed under the Apache-2.0 license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const { 9 | generate, 10 | emitModule, 11 | writeBundles, 12 | writeMetadata, 13 | writeMegaBundle 14 | } = require('../src/generate'); 15 | const { reporter } = require('@carbon/cli-reporter'); 16 | const cluster = require('cluster'); 17 | const numCPUs = require('os').cpus().length; 18 | const ts = require('typescript'); 19 | 20 | if (cluster.isMaster) { 21 | console.log(`Master ${process.pid} is running`); 22 | 23 | // Fork workers. 24 | for (let i = 0; i < numCPUs; i++) { 25 | cluster.fork(); 26 | } 27 | 28 | // handles distributing compilation tasks to workers 29 | // and reporting the state (finished/error/etc) 30 | const buildIcons = (namespaceArray, resolve, reject) => { 31 | console.log('starting parallel ng compile'); 32 | let lastIcon = 0; 33 | let finishedWorkers = 0; 34 | for (const id in cluster.workers) { 35 | const worker = cluster.workers[id]; 36 | 37 | worker.send({ state: 'ready' }); 38 | 39 | worker.on('message', ({ state }) => { 40 | if ((state === 'done' || state === 'waiting') && lastIcon < namespaceArray.length) { 41 | worker.send({ state: 'build', namespace: namespaceArray[lastIcon] }); 42 | lastIcon++; 43 | console.log(`${namespaceArray.length - lastIcon} icons left`); 44 | } else if (lastIcon >= namespaceArray.length) { 45 | finishedWorkers++; 46 | if (finishedWorkers === numCPUs) { 47 | resolve(); 48 | } 49 | } else if (state === 'error') { 50 | reject("error in a worker"); 51 | throw new Error("error in a worker"); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | generate() 58 | .then(namespaceArray => { 59 | return new Promise((resolve, reject) => { 60 | buildIcons(namespaceArray, resolve, reject); 61 | }); 62 | }) 63 | .then(() => { 64 | console.log('writing the megabundle'); 65 | return writeMegaBundle() 66 | }) 67 | .then(() => { 68 | console.log('writing metadata'); 69 | return writeMetadata(); 70 | }) 71 | .then(() => { 72 | console.log('shutting down workers'); 73 | for (const id in cluster.workers) { 74 | const worker = cluster.workers[id]; 75 | worker.kill(); 76 | } 77 | }) 78 | .catch(error => { 79 | reporter.error(error); 80 | }); 81 | 82 | cluster.on('exit', (worker, code, signal) => { 83 | console.log(`worker ${worker.process.pid} died - ${code} : ${signal}`); 84 | }); 85 | } else { 86 | console.log(`Worker ${process.pid} started`); 87 | process.on('message', ({ state, namespace }) => { 88 | if (state === 'ready') { 89 | console.log(`Worker ${process.pid} waiting...`); 90 | process.send({ state: 'waiting' }); 91 | } else if (state === 'build') { 92 | console.log(`Worker ${process.pid} building ${namespace}`); 93 | emitModule(namespace, ts.ScriptTarget.ES2015);//es2015 94 | emitModule(namespace, ts.ScriptTarget.ES5); 95 | Promise.all([ 96 | writeBundles(namespace) 97 | ]).then(() =>{ 98 | process.send({ state: 'done' }); 99 | }).catch((error) => { 100 | console.error(error); 101 | process.send({ state: 'error' }); 102 | }); 103 | } 104 | }); 105 | } 106 | -------------------------------------------------------------------------------- /tests/integration/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "integration": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/integration", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "tsconfig.app.json", 21 | "aot": true, 22 | "assets": [ 23 | "src/favicon.ico", 24 | "src/assets" 25 | ], 26 | "styles": [ 27 | "src/styles.css" 28 | ], 29 | "scripts": [], 30 | "preserveSymlinks": true 31 | }, 32 | "configurations": { 33 | "production": { 34 | "fileReplacements": [ 35 | { 36 | "replace": "src/environments/environment.ts", 37 | "with": "src/environments/environment.prod.ts" 38 | } 39 | ], 40 | "optimization": true, 41 | "outputHashing": "all", 42 | "sourceMap": false, 43 | "extractCss": true, 44 | "namedChunks": false, 45 | "extractLicenses": true, 46 | "vendorChunk": false, 47 | "buildOptimizer": true, 48 | "budgets": [ 49 | { 50 | "type": "initial", 51 | "maximumWarning": "2mb", 52 | "maximumError": "5mb" 53 | }, 54 | { 55 | "type": "anyComponentStyle", 56 | "maximumWarning": "6kb", 57 | "maximumError": "10kb" 58 | } 59 | ] 60 | } 61 | } 62 | }, 63 | "serve": { 64 | "builder": "@angular-devkit/build-angular:dev-server", 65 | "options": { 66 | "browserTarget": "integration:build" 67 | }, 68 | "configurations": { 69 | "production": { 70 | "browserTarget": "integration:build:production" 71 | } 72 | } 73 | }, 74 | "extract-i18n": { 75 | "builder": "@angular-devkit/build-angular:extract-i18n", 76 | "options": { 77 | "browserTarget": "integration:build" 78 | } 79 | }, 80 | "test": { 81 | "builder": "@angular-devkit/build-angular:karma", 82 | "options": { 83 | "main": "src/test.ts", 84 | "polyfills": "src/polyfills.ts", 85 | "tsConfig": "tsconfig.spec.json", 86 | "karmaConfig": "karma.conf.js", 87 | "assets": [ 88 | "src/favicon.ico", 89 | "src/assets" 90 | ], 91 | "styles": [ 92 | "src/styles.css" 93 | ], 94 | "scripts": [], 95 | "preserveSymlinks": true 96 | } 97 | }, 98 | "lint": { 99 | "builder": "@angular-devkit/build-angular:tslint", 100 | "options": { 101 | "tsConfig": [ 102 | "tsconfig.app.json", 103 | "tsconfig.spec.json", 104 | "e2e/tsconfig.json" 105 | ], 106 | "exclude": [ 107 | "**/node_modules/**" 108 | ] 109 | } 110 | }, 111 | "e2e": { 112 | "builder": "@angular-devkit/build-angular:protractor", 113 | "options": { 114 | "protractorConfig": "e2e/protractor.conf.js", 115 | "devServerTarget": "integration:serve" 116 | }, 117 | "configurations": { 118 | "production": { 119 | "devServerTarget": "integration:serve:production" 120 | } 121 | } 122 | } 123 | } 124 | } 125 | }, 126 | "defaultProject": "integration", 127 | "cli": { 128 | "analytics": "3d106941-4aab-494e-aec2-e68eaedeb2ca" 129 | } 130 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :stop_sign: @carbon/icons-angular - DEPRECATED :stop_sign: 2 | 3 | This library is deprecated in favor of [`@carbon/icons`](https://www.npmjs.com/package/@carbon/icons). 4 | 5 | @carbon/icons is the main icons package for Carbon Design System, hence you'll get updates as soon as they are made. 6 | Additionally, the unpacked size is significantly lower, 38MB compared to 148MB. 7 | 8 | To get started with @carbon/icons check out the 9 | [code sandbox demo](https://codesandbox.io/s/gracious-diffie-7khcp3?file=/src/app/app.module.ts). 10 | 11 | There are comments added to files to guide you through the usage. The relevant files to look at are: 12 | 13 | * [app.module.ts](https://codesandbox.io/s/gracious-diffie-7khcp3?file=/src/app/app.module.ts) 14 | * [app.component.html](https://codesandbox.io/s/gracious-diffie-7khcp3?file=/src/app/app.component.html) 15 | * [typings.d.ts](https://codesandbox.io/s/gracious-diffie-7khcp3?file=/src/typings.d.ts) 16 | 17 | --------------------------------------------------------------------------------- 18 | 19 | > Angular components for icons in digital and software products using the Carbon 20 | > Design System 21 | 22 | ## Getting started 23 | 24 | To install `@carbon/icons-angular` in your project, you will need to run the 25 | following command using [npm](https://www.npmjs.com/): 26 | 27 | ```bash 28 | npm install -S @carbon/icons-angular 29 | ``` 30 | 31 | If you prefer [Yarn](https://yarnpkg.com/en/), use the following command 32 | instead: 33 | 34 | ```bash 35 | yarn add @carbon/icons-angular 36 | ``` 37 | 38 | ## Usage 39 | 40 | Icons in this package support the following sizes: `16`, `20`, `24`, and `32` 41 | pixels. These sizes refer to the width and height of the icon. To reduce bundle 42 | sizes each icon is exported as it's own module, you can use an icon component in 43 | your project by doing the following: 44 | 45 | In your module: 46 | 47 | ```ts 48 | import { AddModule } from '@carbon/icons-angular'; 49 | 50 | @NgModule({ 51 | // ... 52 | imports: [ 53 | // ... 54 | AddModule, 55 | // ... 56 | ], 57 | // ... 58 | }) 59 | export class MyModule {} 60 | ``` 61 | 62 | In your component template: 63 | 64 | ```html 65 | 66 | 67 | 68 | 69 | 70 | 71 | ``` 72 | 73 | ### Migration notes 74 | 75 | Previously (all `v10` versions) a pattern like the following was required 76 | 77 | ```ts 78 | import { Add32Module } from '@carbon/icons-angular/lib/add/32.js'; 79 | 80 | @NgModule({ 81 | // ... 82 | imports: [ 83 | // ... 84 | Add32Module, 85 | // ... 86 | ], 87 | // ... 88 | }) 89 | export class MyModule {} 90 | ``` 91 | This is no longer supported. All icon module imports must switch to the format outlined above. 92 | 93 | ### API 94 | 95 | Options available to the icon directive or component: 96 | 97 | [#](#size) **`@Input() size: string;`** 98 | 99 | Choses the size of the component. 100 | 101 | Example: 102 | 103 | ```html 104 | 105 | ``` 106 | 107 | 108 | [#](#innerClass) **`@Input() innerClass: string;`** 109 | 110 | Applies a `classList` to the inner SVG. Use the normal `class` attribute to 111 | apply classes to the host element. 112 | 113 | Example: 114 | 115 | ```html 116 | 117 | ``` 118 | 119 | would result in 120 | 121 | ```html 122 | 123 | 124 | 125 | ``` 126 | 127 | [#](#ariaLabel) **`@Input() ariaLabel: string;`** 128 | 129 | If supplied, should provide an accessible description of the icon. 130 | 131 | Example: 132 | 133 | ```html 134 | 135 | ``` 136 | 137 | [#](#ariaLabelledby) **`@Input() ariaLabelledby: string;`** 138 | 139 | If supplied, should link to an element providing an accessible description of 140 | the icon. 141 | 142 | Example: 143 | 144 | ```html 145 | 146 | 147 | ``` 148 | 149 | [#](#ariaHidden) **`@Input() ariaHidden: boolean;`** 150 | 151 | Controls the visibility of the underlying SVG to screen readers. 152 | 153 | Example: 154 | 155 | ```html 156 | 157 | ``` 158 | 159 | [#](#title) **`@Input() title: string;`** 160 | 161 | Adds a `` element to the inner SVG. Most browsers will display this text 162 | as a tooltip when the icon is hovered. 163 | 164 | Example: 165 | 166 | ```html 167 | <ibm-icon-add size="16" title="Add a new item"></ibm-icon-add> 168 | ``` 169 | 170 | [#](#focusable) **`@Input() focusable: boolean;`** 171 | 172 | Enables or disables the `focusable` attribute. Set this to explicitly control 173 | whether the underlying element should receive focus. Defaults to `false` in most 174 | cases. 175 | 176 | Example: 177 | 178 | ```html 179 | <ibm-icon-add size="16" focusable="false"></ibm-icon-add> 180 | ``` 181 | 182 | ## 🙌 Contributing 183 | 184 | We're always looking for contributors to help us fix bugs, build new features, 185 | or help us improve the project documentation. If you're interested, definitely 186 | check out our [Contributing Guide](/.github/CONTRIBUTING.md)! 👀 187 | 188 | ## 📝 License 189 | 190 | Licensed under the [Apache 2.0 License](/LICENSE). 191 | -------------------------------------------------------------------------------- /src/templates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright IBM Corp. 2018, 2018 3 | * 4 | * This source code is licensed under the Apache-2.0 license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const { param, pascal } = require('change-case'); 9 | const { toString } = require('@carbon/icon-helpers'); 10 | 11 | const classCase = str => { 12 | const pascalled = pascal(str); 13 | if (Number.isNaN(Number(pascalled[0]))) { 14 | return pascalled; 15 | } 16 | // append a _ if the string starts with a number 17 | return `_${pascalled}`; 18 | }; 19 | 20 | const componentTemplate = namespace => ` 21 | @Component({ 22 | selector: "ibm-icon-${param(namespace)}", 23 | template: \` 24 | <svg 25 | ibmIcon${pascal(namespace)} 26 | [size]="size" 27 | [ariaLabel]="ariaLabel" 28 | [ariaLabelledby]="ariaLabelledby" 29 | [ariaHidden]="ariaHidden" 30 | [title]="title" 31 | [isFocusable]="focusable" 32 | [attr.class]="innerClass"> 33 | </svg> 34 | \` 35 | }) 36 | export class ${classCase(namespace)}Component { 37 | @Input() ariaLabel: string; 38 | @Input() ariaLabelledby: string; 39 | @Input() ariaHidden: boolean; 40 | @Input() title: string; 41 | @Input() focusable: boolean = false; 42 | @Input() innerClass: string; 43 | @Input() size: string; 44 | } 45 | `; 46 | 47 | const formatIconObject = icon => ` 48 | "${icon.size}": { 49 | metadata: ${JSON.stringify(icon)}, 50 | svg: \`${toString(icon.descriptor)}\` 51 | }, 52 | `; 53 | 54 | const directiveTemplate = (namespace, iconMeta) => ` 55 | @Directive({ 56 | selector: "[ibmIcon${pascal(namespace)}]" 57 | }) 58 | export class ${classCase( 59 | namespace 60 | )}Directive implements AfterViewInit { 61 | static titleIdCounter = 0; 62 | 63 | @Input() ariaLabel: string; 64 | @Input() ariaLabelledby: string; 65 | @Input() ariaHidden: boolean; 66 | @Input() title: string; 67 | @Input() isFocusable: boolean = false; 68 | @Input() size: string; 69 | 70 | protected icons = { 71 | ${iconMeta.output.reduce((str, icon) => `${str}${formatIconObject(icon)}`, '')} 72 | }; 73 | 74 | constructor(protected elementRef: ElementRef) {} 75 | 76 | ngAfterViewInit() { 77 | const svg = this.elementRef.nativeElement; 78 | svg.setAttribute("xmlns", "http://www.w3.org/2000/svg"); 79 | 80 | const icon = this.icons[this.size] 81 | 82 | const domParser = new DOMParser(); 83 | const rawSVG = icon.svg; 84 | const svgElement = domParser.parseFromString(rawSVG, "image/svg+xml").documentElement; 85 | 86 | let node = svgElement.firstChild; 87 | while (node) { 88 | // importNode makes a clone of the node 89 | // this ensures we keep looping over the nodes in the parsed document 90 | svg.appendChild(svg.ownerDocument.importNode(node, true)); 91 | node = node.nextSibling; 92 | } 93 | 94 | const attributes = getAttributes({ 95 | width: icon.metadata.descriptor.attrs.height, 96 | height: icon.metadata.descriptor.attrs.height, 97 | viewBox: icon.metadata.descriptor.attrs.viewBox, 98 | title: this.title, 99 | "aria-label": this.ariaLabel, 100 | "aria-labelledby": this.ariaLabelledby, 101 | "aria-hidden": this.ariaHidden, 102 | focusable: this.isFocusable.toString() 103 | }); 104 | 105 | const attrKeys = Object.keys(attributes); 106 | for (let i = 0; i < attrKeys.length; i++) { 107 | const key = attrKeys[i]; 108 | const value = attributes[key]; 109 | if (key === "title") { 110 | continue; 111 | } 112 | if (value) { 113 | svg.setAttribute(key, value); 114 | } 115 | } 116 | 117 | if (attributes.title) { 118 | const title = document.createElement("title"); 119 | title.textContent = attributes.title; 120 | ${classCase(namespace)}Directive.titleIdCounter++; 121 | title.setAttribute("id", \`${param(namespace)}-$\{${classCase( 122 | namespace 123 | )}Directive.titleIdCounter}\`); 124 | svg.appendChild(title); 125 | svg.setAttribute("aria-labelledby", \`${param( 126 | namespace 127 | )}-$\{${classCase(namespace)}Directive.titleIdCounter}\`); 128 | } 129 | } 130 | } 131 | `; 132 | 133 | const formatModuleDeclarations = namespace => ` 134 | ${classCase(namespace)}Component, 135 | ${classCase(namespace)}Directive, 136 | `; 137 | 138 | const moduleTemplate = (namespace, iconMeta) => ` 139 | import { 140 | NgModule, 141 | Component, 142 | Directive, 143 | ElementRef, 144 | Input, 145 | AfterViewInit 146 | } from "@angular/core"; 147 | import { getAttributes } from "@carbon/icon-helpers"; 148 | 149 | ${componentTemplate(namespace)} 150 | 151 | ${directiveTemplate(namespace, iconMeta)} 152 | 153 | @NgModule({ 154 | declarations: [ 155 | ${formatModuleDeclarations(namespace)} 156 | ], 157 | exports: [ 158 | ${formatModuleDeclarations(namespace)} 159 | ] 160 | }) 161 | export class ${classCase(namespace)}Module {} 162 | `; 163 | 164 | const rootPublicApi = namespaces => 165 | namespaces.reduce( 166 | (str, name) => `${str} 167 | export * from "./${name}/icon";`,''); 168 | 169 | const tsRootPublicApi = namespaces => 170 | namespaces.reduce( 171 | (str, name) => `${str} 172 | export * from "./${name}";`, ''); 173 | 174 | const flatRootPublicApi = namespaces => 175 | namespaces.reduce( 176 | (str, name) => `${str} 177 | export * from "./${name.split('/').join('-')}";`, ''); 178 | 179 | const jsRootPublicApi = namespaces => 180 | namespaces.reduce( 181 | (str, name) => `${str} 182 | export * from "./${name}/index";`, ''); 183 | 184 | module.exports = { 185 | moduleTemplate, 186 | rootPublicApi, 187 | tsRootPublicApi, 188 | jsRootPublicApi, 189 | flatRootPublicApi 190 | }; 191 | -------------------------------------------------------------------------------- /src/generate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright IBM Corp. 2018, 2018 3 | * 4 | * This source code is licensed under the Apache-2.0 license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const iconMetadata = require('@carbon/icons/metadata.json'); 9 | const { reporter } = require('@carbon/cli-reporter'); 10 | const fs = require('fs-extra'); 11 | 12 | const { createEmitCallback } = require('ng-packagr/lib/ngc/create-emit-callback'); 13 | const { downlevelConstructorParameters } = require('ng-packagr/lib/ts/ctor-parameters'); 14 | 15 | const ts = require('typescript'); 16 | const ng = require('@angular/compiler-cli'); 17 | const rollup = require('rollup'); 18 | const { pascal } = require('change-case'); 19 | 20 | const { 21 | moduleTemplate, 22 | rootPublicApi, 23 | tsRootPublicApi, 24 | jsRootPublicApi, 25 | flatRootPublicApi 26 | } = require('./templates'); 27 | 28 | // local utilities 29 | const paths = require('./paths'); 30 | 31 | const getNamespace = (iconMeta) => { 32 | if (iconMeta.namespace.length > 0) { 33 | return `${iconMeta.namespace.join('/')}/${iconMeta.name}`; 34 | } 35 | return iconMeta.name; 36 | }; 37 | 38 | /** 39 | * 40 | * @param {*} namespace 41 | * @param {*} scriptTarget ts.ScriptTarget 42 | */ 43 | function emitModule(namespace, scriptTarget) { 44 | let modulePath = ''; 45 | if (scriptTarget === ts.ScriptTarget.ES2015) { 46 | modulePath = 'esm2015'; 47 | } else if (scriptTarget === ts.ScriptTarget.ES5) { 48 | modulePath = 'esm5'; 49 | } 50 | 51 | const options = { 52 | fileName: 'icon.ts', 53 | scriptTarget, 54 | outPath: `${paths.DIST}/${modulePath}/${namespace}`, 55 | moduleId: `${namespace.split('/').join('-')}`, 56 | sourceFile: `${paths.TS}/${namespace}/icon.ts`, 57 | declarationPath: `${paths.DIST}/${namespace}`, 58 | sourcePath: `${paths.TS}/${namespace}` 59 | }; 60 | 61 | ngCompile(options); 62 | } 63 | 64 | /** 65 | * 66 | * @param {{ 67 | * fileName: string, 68 | * scriptTarget: ScriptTarget, 69 | * outPath: string, 70 | * moduleId: string, 71 | * sourceFile: string, 72 | * sourcePath: string, 73 | * declarationPath: string 74 | * }} options 75 | */ 76 | function ngCompile(options) { 77 | const extraOptions = { 78 | moduleResolution: ts.ModuleResolutionKind.NodeJs, 79 | target: options.scriptTarget, 80 | experimentalDecorators: true, 81 | 82 | // sourcemaps 83 | sourceMap: false, 84 | inlineSources: true, 85 | inlineSourceMap: true, 86 | 87 | outDir: options.outPath, 88 | declaration: true, 89 | 90 | // ng compiler to options 91 | enableResourceInlining: true, 92 | 93 | // these are required to set the appropriate EmitFlags 94 | flatModuleId: options.moduleId, 95 | flatModuleOutFile: 'index.js', 96 | }; 97 | 98 | // read the config from disk, and add/override some fields 99 | const config = ng.readConfiguration(`${__dirname}/tsconfig.json`, extraOptions); 100 | 101 | const overrideOptions = { 102 | basePath: options.sourcePath, 103 | rootDir: options.sourcePath, 104 | declarationDir: options.declarationPath, 105 | }; 106 | 107 | config.options = { ...config.options, ...overrideOptions }; 108 | config.rootNames = [options.sourceFile]; 109 | 110 | // typescript compiler host, used by ngc 111 | const tsHost = ts.createCompilerHost(config.options, true); 112 | 113 | // ngc compiler host 114 | const ngHost = ng.createCompilerHost({ 115 | options: config.options, 116 | tsHost 117 | }); 118 | 119 | // create the program (typecheck, etc) 120 | const program = ng.createProgram({ 121 | rootNames: config.rootNames, 122 | options: config.options, 123 | host: ngHost 124 | }); 125 | 126 | // collect all diagnostic messages 127 | const diagMessages = [ 128 | ...program.getTsOptionDiagnostics(), 129 | ...program.getNgOptionDiagnostics(), 130 | ...program.getTsSyntacticDiagnostics(), 131 | ...program.getTsSemanticDiagnostics(), 132 | ...program.getNgSemanticDiagnostics(), 133 | ...program.getNgStructuralDiagnostics() 134 | ]; 135 | 136 | const beforeTs = []; 137 | if (!config.options.annotateForClosureCompiler) { 138 | beforeTs.push(downlevelConstructorParameters(() => program.getTsProgram().getTypeChecker())); 139 | } 140 | 141 | // don't emit if the program won't compile 142 | if (ng.exitCodeFromResult(diagMessages) === 0) { 143 | const emitFlags = config.options.declaration ? config.emitFlags : ng.EmitFlags.JS; 144 | const result = program.emit({ 145 | emitFlags, 146 | emitCallback: createEmitCallback(config.options), 147 | customTransformers: { 148 | beforeTs 149 | } 150 | }); 151 | diagMessages.push(...result.diagnostics); 152 | } 153 | 154 | // everything went well, no need to log anything 155 | if (diagMessages.length === 0) { 156 | return; 157 | } 158 | 159 | // error handling 160 | const exitCode = ng.exitCodeFromResult(diagMessages); 161 | const formattedDiagnostics = ng.formatDiagnostics(diagMessages); 162 | if (exitCode !== 0) { 163 | throw new Error(formattedDiagnostics); 164 | } else { 165 | console.log(formattedDiagnostics); 166 | } 167 | } 168 | 169 | const getRollupInputOptions = ({sourceType, namespace}) => ({ 170 | external: [ 171 | '@angular/core', 172 | '@carbon/icon-helpers' 173 | ], 174 | input: `${paths.DIST}/${sourceType}/${namespace ? namespace : ''}/index.js`, 175 | onwarn(warning) { 176 | if (warning.code === 'UNUSED_EXTERNAL_IMPORT') { 177 | return; 178 | } 179 | } 180 | }); 181 | 182 | const getRollupOutputOptions = ({file, format, name}) => ({ 183 | file, 184 | format, 185 | globals: { 186 | '@angular/core': 'ng.core', 187 | '@carbon/icon-helpers': 'CarbonIconHelpers' 188 | }, 189 | name 190 | }); 191 | 192 | async function writeMegaBundle() { 193 | const inputOptions = getRollupInputOptions({ 194 | sourceType: 'esm5' 195 | }); 196 | 197 | const outputOptions = getRollupOutputOptions({ 198 | file: `${paths.BUNDLES}/carbon-icons-angular.umd.js`, 199 | format: 'umd', 200 | name: 'CarbonIconsAngular' 201 | }); 202 | 203 | const bundle = await rollup.rollup(inputOptions); 204 | return bundle.write(outputOptions); 205 | } 206 | 207 | async function writeBundles(namespace) { 208 | const formats = ['esm5', 'esm2015', 'bundles']; 209 | const bundles = []; 210 | 211 | for (const format of formats) { 212 | const inputOptions = getRollupInputOptions({ 213 | sourceType: format === 'bundles' ? 'esm5' : format, 214 | namespace 215 | }); 216 | 217 | let outputOptions = {}; 218 | 219 | if (format === 'bundles') { 220 | outputOptions = getRollupOutputOptions({ 221 | file: `${paths.BUNDLES}/${namespace.split('/').join('-')}.umd.js`, 222 | format: 'umd', 223 | name: `CarbonIconsAngular.${pascal(namespace)}` 224 | }); 225 | } else { 226 | outputOptions = getRollupOutputOptions({ 227 | file: `${paths.DIST}/f${format}/${namespace.split('/').join('-')}.js`, 228 | format: 'es', 229 | name: `CarbonIconsAngular.${pascal(namespace)}` 230 | }); 231 | } 232 | 233 | 234 | const bundle = await rollup.rollup(inputOptions); 235 | bundles.push(bundle.write(outputOptions)); 236 | } 237 | 238 | return Promise.all(bundles); 239 | } 240 | 241 | async function writeMetadata() { 242 | const packageJson = require('../package.json'); 243 | 244 | // use paths relative to the built files and the `package.json`s final location next to them 245 | packageJson.esm5 = './esm5/index.js'; 246 | packageJson.esm2015 = './esm2015/index.js'; 247 | packageJson.fesm5 = './fesm5/index.js'; 248 | packageJson.fesm2015 = './fesm2015/index.js'; 249 | packageJson.bundles = './bundles/carbon-icons-angular.umd.js'; 250 | packageJson.main = './bundles/carbon-icons-angular.umd.js'; 251 | packageJson.module = './fesm5/index.js'; 252 | packageJson.typings = './index.d.ts'; 253 | packageJson.metadata = './index.metadata.json'; 254 | 255 | const metadataJson = { 256 | __symbolic: 'module', 257 | version: 4, 258 | metadata: {}, 259 | exports: [], 260 | importAs: '@carbon/icons-angular' 261 | }; 262 | 263 | for (const iconMeta of iconMetadata.icons) { 264 | metadataJson.exports.push({ 265 | from: `./${getNamespace(iconMeta)}` 266 | }); 267 | } 268 | 269 | await fs.writeFile(`${paths.DIST}/package.json`, JSON.stringify(packageJson)); 270 | await fs.writeFile(`${paths.DIST}/index.metadata.json`, JSON.stringify(metadataJson)); 271 | } 272 | 273 | async function writeIndexes(icons) { 274 | const namespaces = icons.map(iconMeta => getNamespace(iconMeta)); 275 | await Promise.all([ 276 | fs.writeFile(`${paths.DIST}/index.d.ts`, tsRootPublicApi(namespaces)), 277 | fs.writeFile(`${paths.ESM5}/index.js`, jsRootPublicApi(namespaces)), 278 | fs.writeFile(`${paths.ESM2015}/index.js`, jsRootPublicApi(namespaces)), 279 | fs.writeFile(`${paths.FESM5}/index.js`, flatRootPublicApi(namespaces)), 280 | fs.writeFile(`${paths.FESM2015}/index.js`, flatRootPublicApi(namespaces)) 281 | ]); 282 | } 283 | 284 | async function generateComponents(icons) { 285 | for (const iconMeta of icons) { 286 | const namespace = getNamespace(iconMeta); 287 | await fs.ensureDir(`${paths.TS}/${namespace}`); 288 | 289 | const moduleString = moduleTemplate(namespace, iconMeta); 290 | await fs.writeFile(`${paths.TS}/${namespace}/icon.ts`, moduleString); 291 | } 292 | 293 | // get all the namespaces to build the import definitions 294 | const namespaces = icons.map(iconMeta => getNamespace(iconMeta)); 295 | await fs.writeFile(`${paths.TS}/index.ts`, rootPublicApi(namespaces)); 296 | return namespaces; 297 | } 298 | 299 | async function generate() { 300 | reporter.log('Prepping build dirs...'); 301 | try { 302 | // ensure our build directories are created 303 | await Promise.all([ 304 | fs.ensureDir(paths.TS), 305 | fs.ensureDir(paths.DIST), 306 | fs.ensureDir(paths.ESM5), 307 | fs.ensureDir(paths.ESM2015), 308 | fs.ensureDir(paths.FESM5), 309 | fs.ensureDir(paths.FESM2015), 310 | fs.ensureDir(paths.BUNDLES) 311 | ]); 312 | } catch (err) { 313 | reporter.error(err); 314 | } 315 | 316 | reporter.log('Generating source components...'); 317 | await writeIndexes(iconMetadata.icons); 318 | return await generateComponents(iconMetadata.icons); 319 | } 320 | 321 | module.exports = { 322 | generate, 323 | writeMegaBundle, 324 | writeMetadata, 325 | emitModule, 326 | writeBundles, 327 | getNamespace 328 | }; 329 | --------------------------------------------------------------------------------