2
0
mirror of https://github.com/iconify/iconify.git synced 2025-01-06 07:20:40 +00:00

Ember component (working but not fully tested yet)

This commit is contained in:
Vjacheslav Trushkin 2021-07-20 16:50:05 +03:00
parent b4379f2615
commit 915d747d02
57 changed files with 53347 additions and 0 deletions

View File

@ -0,0 +1,19 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.hbs]
insert_final_newline = false
[*.{diff,md}]
trim_trailing_whitespace = false

View File

@ -0,0 +1,9 @@
{
/**
Ember CLI sends analytics information by default. The data is completely
anonymous, but there are times when you might want to disable this behavior.
Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": false
}

View File

@ -0,0 +1,22 @@
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/coverage/
!.*
.*/
.eslintcache
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try

View File

@ -0,0 +1,58 @@
'use strict';
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
},
},
plugins: ['ember'],
extends: [
'eslint:recommended',
'plugin:ember/recommended',
'plugin:prettier/recommended',
],
env: {
browser: true,
},
rules: {},
overrides: [
// node files
{
files: [
'.eslintrc.js',
'.prettierrc.js',
'.template-lintrc.js',
'ember-cli-build.js',
'testem.js',
'blueprints/*/index.js',
'config/**/*.js',
'lib/*/index.js',
'server/**/*.js',
],
parserOptions: {
sourceType: 'script',
},
env: {
browser: false,
node: true,
},
plugins: ['node'],
extends: ['plugin:node/recommended'],
rules: {
// this can be removed once the following is fixed
// https://github.com/mysticatea/eslint-plugin-node/issues/77
'node/no-unpublished-require': 'off',
},
},
{
// Test files:
files: ['tests/**/*-test.{js,ts}'],
extends: ['plugin:qunit/recommended'],
},
],
};

26
packages/ember-demo/.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/.env*
/.pnp*
/.sass-cache
/.eslintcache
/connect.lock
/coverage/
/libpeerconnection.log
/npm-debug.log*
/testem.log
/yarn-error.log
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try

View File

@ -0,0 +1,21 @@
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/coverage/
!.*
.eslintcache
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try

View File

@ -0,0 +1,5 @@
'use strict';
module.exports = {
singleQuote: true,
};

View File

@ -0,0 +1,5 @@
'use strict';
module.exports = {
extends: 'recommended',
};

View File

@ -0,0 +1,25 @@
---
language: node_js
node_js:
- "10"
dist: xenial
addons:
chrome: stable
cache:
directories:
- $HOME/.npm
env:
global:
# See https://git.io/vdao3 for details.
- JOBS=1
branches:
only:
- master
script:
- npm test

View File

@ -0,0 +1,3 @@
{
"ignore_dirs": ["tmp", "dist"]
}

View File

@ -0,0 +1,56 @@
# ember-demo
This README outlines the details of collaborating on this Ember application.
A short introduction of this app could easily go here.
## Prerequisites
You will need the following things properly installed on your computer.
* [Git](https://git-scm.com/)
* [Node.js](https://nodejs.org/) (with npm)
* [Ember CLI](https://ember-cli.com/)
* [Google Chrome](https://google.com/chrome/)
## Installation
* `git clone <repository-url>` this repository
* `cd ember-demo`
* `npm install`
## Running / Development
* `ember serve`
* Visit your app at [http://localhost:4200](http://localhost:4200).
* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests).
### Code Generators
Make use of the many generators for code, try `ember help generate` for more details
### Running Tests
* `ember test`
* `ember test --server`
### Linting
* `npm run lint`
* `npm run lint:fix`
### Building
* `ember build` (development)
* `ember build --environment production` (production)
### Deploying
Specify what it takes to deploy your app.
## Further Reading / Useful Links
* [ember.js](https://emberjs.com/)
* [ember-cli](https://ember-cli.com/)
* Development Browser Extensions
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)

View File

@ -0,0 +1,12 @@
import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from 'ember-demo/config/environment';
export default class App extends Application {
modulePrefix = config.modulePrefix;
podModulePrefix = config.podModulePrefix;
Resolver = Resolver;
}
loadInitializers(App, config.modulePrefix);

View File

@ -0,0 +1,8 @@
<div>
Icons test:
<IconifyIcon @icon={{this.testIcon}} />
<IconifyIcon @icon={{iconData2}} />
<IconifyIcon @icon='demo' />
<IconifyIcon @icon='mdi:home' @inline={{true}} />
<IconifyIcon @icon='mdi:home' style='color: red; vertical-align: -0.125em' />
</div>

View File

@ -0,0 +1,19 @@
import Component from '@glimmer/component';
import { disableCache, addIcon } from '@iconify/ember/components/iconify-icon';
disableCache('all');
const iconData = {
body: '<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
width: 24,
height: 24,
};
addIcon('demo', iconData);
export default class IconDemoComponent extends Component {
iconData2 = iconData;
get testIcon() {
return iconData;
}
}

View File

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>EmberDemo</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{content-for "head"}}
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/ember-demo.css">
{{content-for "head-footer"}}
</head>
<body>
{{content-for "body"}}
<script src="{{rootURL}}assets/vendor.js"></script>
<script src="{{rootURL}}assets/ember-demo.js"></script>
{{content-for "body-footer"}}
</body>
</html>

View File

View File

@ -0,0 +1,9 @@
import EmberRouter from '@ember/routing/router';
import config from 'ember-demo/config/environment';
export default class Router extends EmberRouter {
location = config.locationType;
rootURL = config.rootURL;
}
Router.map(function () {});

View File

View File

View File

@ -0,0 +1,5 @@
{{page-title 'EmberDemo'}}
<IconDemo />
{{outlet}}

View File

@ -0,0 +1,18 @@
{
"schemaVersion": "1.0.0",
"packages": [
{
"name": "ember-cli",
"version": "3.27.0",
"blueprints": [
{
"name": "app",
"outputRepo": "https://github.com/ember-cli/ember-new-output",
"codemodsSource": "ember-app-codemods-manifest@1",
"isBaseBlueprint": true,
"options": []
}
]
}
]
}

View File

@ -0,0 +1,51 @@
'use strict';
module.exports = function (environment) {
let ENV = {
modulePrefix: 'ember-demo',
environment,
rootURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
// Here you can enable experimental features on an ember canary build
// e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
},
EXTEND_PROTOTYPES: {
// Prevent Ember Data from overriding Date.parse.
Date: false,
},
},
APP: {
// Here you can pass flags/options to your application instance
// when it is created
},
};
if (environment === 'development') {
// ENV.APP.LOG_RESOLVER = true;
// ENV.APP.LOG_ACTIVE_GENERATION = true;
// ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
// ENV.APP.LOG_VIEW_LOOKUPS = true;
}
if (environment === 'test') {
// Testem prefers this...
ENV.locationType = 'none';
// keep test console output quieter
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
}
if (environment === 'production') {
// here you can enable a production-specific feature
}
return ENV;
};

View File

@ -0,0 +1,6 @@
{
"application-template-wrapper": false,
"default-async-observers": true,
"jquery-integration": false,
"template-only-glimmer-components": true
}

View File

@ -0,0 +1,26 @@
'use strict';
const browsers = [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions',
];
// Ember's browser support policy is changing, and IE11 support will end in
// v4.0 onwards.
//
// See https://deprecations.emberjs.com/v3.x#toc_3-0-browser-support-policy
//
// If you need IE11 support on a version of Ember that still offers support
// for it, uncomment the code block below.
//
// const isCI = Boolean(process.env.CI);
// const isProduction = process.env.EMBER_ENV === 'production';
//
// if (isCI || isProduction) {
// browsers.push('ie 11');
// }
module.exports = {
browsers,
};

View File

@ -0,0 +1,24 @@
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function (defaults) {
let app = new EmberApp(defaults, {
// Add options here
});
// Use `app.import` to add additional libraries to the generated
// output files.
//
// If you need to use different assets in different
// environments, specify an object as the first parameter. That
// object's keys should be the environment name and the values
// should be the asset to use in that environment.
//
// If the library that you are including contains AMD or ES6
// modules that you would like to import into your application
// please specify an object with the list of modules as keys
// along with the exports of each module as its value.
return app.toTree();
};

42739
packages/ember-demo/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
{
"name": "ember-demo",
"version": "0.0.0",
"private": true,
"description": "Small description for ember-demo goes here",
"repository": "",
"license": "MIT",
"author": "",
"directories": {
"doc": "doc",
"test": "tests"
},
"scripts": {
"build": "ember build --environment=production",
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
"lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
"lint:hbs": "ember-template-lint .",
"lint:hbs:fix": "ember-template-lint . --fix",
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
"start": "ember serve",
"test": "npm-run-all lint test:*",
"test:ember": "ember test"
},
"devDependencies": {
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.2.5",
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"@iconify/ember": "0.0.1",
"babel-eslint": "^10.1.0",
"broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.11.3",
"ember-cli": "~3.27.0",
"ember-cli-app-version": "^5.0.0",
"ember-cli-babel": "^7.26.6",
"ember-cli-dependency-checker": "^3.2.0",
"ember-cli-htmlbars": "^5.7.1",
"ember-cli-inject-live-reload": "^2.0.2",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-data": "~3.27.1",
"ember-export-application-global": "^2.0.1",
"ember-fetch": "^8.0.4",
"ember-load-initializers": "^2.1.2",
"ember-maybe-import-regenerator": "^0.1.6",
"ember-page-title": "^6.2.2",
"ember-qunit": "^5.1.4",
"ember-resolver": "^8.0.2",
"ember-source": "~3.27.2",
"ember-template-lint": "^3.4.2",
"ember-welcome-page": "^4.0.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.4.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-qunit": "^6.1.1",
"loader.js": "^4.7.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.3.0",
"qunit": "^2.15.0",
"qunit-dom": "^1.6.0"
},
"engines": {
"node": "10.* || >= 12"
},
"ember": {
"edition": "octane"
}
}

View File

@ -0,0 +1,3 @@
# http://www.robotstxt.org
User-agent: *
Disallow:

View File

@ -0,0 +1,23 @@
'use strict';
module.exports = {
test_page: 'tests/index.html?hidepassed',
disable_watching: true,
launch_in_ci: ['Chrome'],
launch_in_dev: ['Chrome'],
browser_start_timeout: 120,
browser_args: {
Chrome: {
ci: [
// --no-sandbox is needed when running Chrome inside a container
process.env.CI ? '--no-sandbox' : null,
'--headless',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--mute-audio',
'--remote-debugging-port=0',
'--window-size=1440,900',
].filter(Boolean),
},
},
};

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>EmberDemo Tests</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{content-for "head"}}
{{content-for "test-head"}}
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link rel="stylesheet" href="{{rootURL}}assets/ember-demo.css">
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
{{content-for "head-footer"}}
{{content-for "test-head-footer"}}
</head>
<body>
{{content-for "body"}}
{{content-for "test-body"}}
<div id="qunit"></div>
<div id="qunit-fixture">
<div id="ember-testing-container">
<div id="ember-testing"></div>
</div>
</div>
<script src="/testem.js" integrity="" data-embroider-ignore></script>
<script src="{{rootURL}}assets/vendor.js"></script>
<script src="{{rootURL}}assets/test-support.js"></script>
<script src="{{rootURL}}assets/ember-demo.js"></script>
<script src="{{rootURL}}assets/tests.js"></script>
{{content-for "body-footer"}}
{{content-for "test-body-footer"}}
</body>
</html>

View File

@ -0,0 +1,26 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | icon-demo', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<IconDemo />`);
assert.dom(this.element).hasText('');
// Template block usage:
await render(hbs`
<IconDemo>
template block text
</IconDemo>
`);
assert.dom(this.element).hasText('template block text');
});
});

View File

@ -0,0 +1,12 @@
import Application from 'ember-demo/app';
import config from 'ember-demo/config/environment';
import * as QUnit from 'qunit';
import { setApplication } from '@ember/test-helpers';
import { setup } from 'qunit-dom';
import { start } from 'ember-qunit';
setApplication(Application.create(config.APP));
setup(QUnit.assert);
start();

View File

0
packages/ember-demo/vendor/.gitkeep vendored Normal file
View File

4
packages/ember/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.DS_Store
node_modules
lib
addon

View File

@ -0,0 +1,9 @@
.DS_Store
api-extractor.json
rollup.config.js
tsconfig.json
build.js
node_modules
src
lib
tests

View File

@ -0,0 +1,44 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"mainEntryPointFilePath": "lib/iconify-icon.d.ts",
"bundledPackages": [
"@iconify/types",
"@iconify/core",
"@iconify/utils",
"@cyberalien/redundancy"
],
"compiler": {},
"apiReport": {
"enabled": false
},
"docModel": {
"enabled": false
},
"dtsRollup": {
"enabled": true,
"untrimmedFilePath": "<projectFolder>/addon/components/iconify-icon.d.ts"
},
"tsdocMetadata": {
"enabled": false
},
"messages": {
"compilerMessageReporting": {
"default": {
"logLevel": "warning"
}
},
"extractorMessageReporting": {
"default": {
"logLevel": "warning"
},
"ae-missing-release-tag": {
"logLevel": "none"
}
},
"tsdocMessageReporting": {
"default": {
"logLevel": "warning"
}
}
}
}

View File

@ -0,0 +1 @@
export { default } from '@iconify/ember/components/iconify-icon';

107
packages/ember/build.js Normal file
View File

@ -0,0 +1,107 @@
const fs = require('fs');
const path = require('path');
const child_process = require('child_process');
const packagesDir = path.dirname(__dirname);
// List of commands to run
const commands = [];
// Parse command line
const compile = {
core: false,
lib: true,
rollup: true,
api: true,
cleanup: true,
};
process.argv.slice(2).forEach((cmd) => {
if (cmd.slice(0, 2) !== '--') {
return;
}
const parts = cmd.slice(2).split('-');
if (parts.length === 2) {
// Parse 2 part commands like --with-lib
const key = parts.pop();
if (compile[key] === void 0) {
return;
}
switch (parts.shift()) {
case 'with':
// enable module
compile[key] = true;
break;
case 'without':
// disable module
compile[key] = false;
break;
case 'only':
// disable other modules
Object.keys(compile).forEach((key2) => {
compile[key2] = key2 === key;
});
break;
}
}
});
// Check if required modules in same monorepo are available
const fileExists = (file) => {
try {
fs.statSync(file);
} catch (e) {
return false;
}
return true;
};
if (compile.lib && !fileExists(packagesDir + '/core/lib/modules.js')) {
compile.core = true;
}
// Compile core before compiling this package
if (compile.core) {
commands.push({
cmd: 'npm',
args: ['run', 'build'],
cwd: packagesDir + '/core',
});
}
// Compile other packages
Object.keys(compile).forEach((key) => {
if (key !== 'core' && compile[key]) {
commands.push({
cmd: 'npm',
args: ['run', 'build:' + key],
});
}
});
/**
* Run next command
*/
const next = () => {
const item = commands.shift();
if (item === void 0) {
process.exit(0);
}
if (item.cwd === void 0) {
item.cwd = __dirname;
}
const result = child_process.spawnSync(item.cmd, item.args, {
cwd: item.cwd,
stdio: 'inherit',
});
if (result.status === 0) {
process.nextTick(next);
} else {
process.exit(result.status);
}
};
next();

132
packages/ember/cleanup.js Normal file
View File

@ -0,0 +1,132 @@
const fs = require('fs');
/**
* Restore decorator in component
*/
function restoreDecorator(filename) {
const source = __dirname + '/' + filename;
let data = fs.readFileSync(source, 'utf8');
// Code to find/replace
const decorateStart = 'var __decorate =';
const decorateEnd = '};';
const decorate2Start =
'function __decorate(decorators, target, key, desc) {';
const decorate2End = '}';
const componentHeader =
'export class IconifyIconComponent extends Component {';
const componentHeader2 = 'class IconifyIconComponent extends Component {';
const addedLine = '@tracked _counter = 0;';
const footerStart = `__decorate([`;
const footerEnd = '], IconifyIconComponent.prototype, "_counter", void 0);';
// Check if already parsed
if (
data.indexOf(addedLine) !== -1 &&
data.indexOf(decorateStart) === -1 &&
data.indexOf(decorate2Start) === -1 &&
data.indexOf(footerStart) === -1
) {
console.log(`${filename} is already cleaned up`);
return;
}
// Split lines
let lines = data.split('\n');
/**
*
* @param {string} firstMatch First match, line must start with it
* @param {string} lastMatch Last match, exact line
* @param {number} middleCount Number of lines between start and end, all will be removed
* @param {string} key Text for error message
*/
const removeLines = (firstMatch, lastMatch, middleCount, key) => {
let found = false;
let removed = 0;
let replaced = false;
lines = lines.filter((line) => {
if (replaced) {
return true;
}
// Check for start
if (!found) {
const trimmed = line.trim();
if (trimmed.slice(0, firstMatch.length) === firstMatch) {
found = true;
return false;
}
return true;
}
// Remove line?
if (removed < middleCount) {
removed++;
return false;
}
// Last line
if (line.trim() !== lastMatch) {
throw new Error(
`Mismatch for last line for ${key} in ${filename}: "${line}"`
);
}
replaced = true;
return false;
});
if (!found) {
throw new Error(
`Could not do replacement for ${key} in ${filename}`
);
}
};
// Remove __decorate() polyfill
if (data.indexOf(decorate2Start) !== -1) {
removeLines(decorate2Start, decorate2End, 4, 'decorator polyfill 2');
} else {
removeLines(decorateStart, decorateEnd, 4, 'decorator polyfill');
}
// Remove __decorate()
removeLines(footerStart, footerEnd, 1, 'decorate()');
// Add decorator after class declaration
let added = false;
lines = lines.map((line) => {
if (added) {
return line;
}
const trimmed = line.trim();
if (trimmed === componentHeader || trimmed === componentHeader2) {
added = true;
return line + '\n ' + addedLine;
}
return line;
});
if (!added) {
throw new Error(`Could not find class declaration in ${filename}`);
}
// Save file
fs.writeFileSync(source, lines.join('\n'), 'utf8');
console.log(`Cleaned up ${filename}`);
}
function copyFile(source, target) {
fs.writeFileSync(
__dirname + '/' + target,
fs.readFileSync(__dirname + '/' + source)
);
console.log(`Created ${target}`);
}
restoreDecorator('lib/component.js');
restoreDecorator('addon/components/iconify-icon.js');
copyFile('src/iconify-icon.hbs', 'addon/components/iconify-icon.hbs');

5
packages/ember/index.js Normal file
View File

@ -0,0 +1,5 @@
'use strict';
module.exports = {
name: require('./package').name,
};

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Vjacheslav Trushkin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

8932
packages/ember/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
{
"name": "@iconify/ember",
"description": "Iconify icon component for Ember.",
"author": "Vjacheslav Trushkin",
"version": "0.0.1",
"license": "MIT",
"bugs": "https://github.com/iconify/iconify/issues",
"homepage": "https://iconify.design/",
"funding": "http://github.com/sponsors/cyberalien",
"repository": {
"type": "git",
"url": "https://github.com/iconify/iconify.git",
"directory": "packages/ember"
},
"keywords": [
"ember-addon"
],
"scripts": {
"build": "node build",
"build:lib": "tsc -b",
"build:rollup": "rollup -c rollup.config.js",
"build:api": "api-extractor run --local --verbose --config api-extractor.json",
"build:cleanup": "node cleanup"
},
"devDependencies": {
"@iconify/core": "^1.1.3",
"@iconify/types": "^1.0.6",
"@iconify/utils": "^1.0.7",
"@microsoft/api-extractor": "^7.18.4",
"@rollup/plugin-commonjs": "^18.1.0",
"@rollup/plugin-node-resolve": "^11.2.1",
"@rollup/plugin-typescript": "^8.2.3",
"rollup": "^2.53.2",
"typescript": "^4.2.4"
},
"dependencies": {
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"ember-cli-babel": "^7.26.6",
"ember-cli-htmlbars": "^5.7.1"
},
"ember": {
"edition": "octane"
},
"ember-addon": {}
}

3
packages/ember/readme.md Normal file
View File

@ -0,0 +1,3 @@
# Iconify for Ember
TODO

View File

@ -0,0 +1,20 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
// Write all packages
const config = [
{
input: 'src/iconify-icon.ts',
output: [
{
file: 'addon/components/iconify-icon.js',
format: 'esm',
},
],
external: ['@glimmer/component', '@glimmer/tracking'],
plugins: [resolve(), commonjs(), typescript()],
},
];
export default config;

View File

@ -0,0 +1,170 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
// Core
import { IconifyIconName, stringToIcon } from '@iconify/utils/lib/icon/name';
import { getIconData } from '@iconify/core/lib/storage/functions';
import { fullIcon, FullIconifyIcon } from '@iconify/utils/lib/icon';
// API
import { API } from '@iconify/core/lib/api/';
import type { IconifyIconLoaderAbort } from '@iconify/core/lib/interfaces/loader';
// Component stuff
import type { IconifyIconProps } from './props';
import type { RenderResult } from './render';
import { render } from './render';
/**
* Type for loading status
*/
interface CurrentIconAsString {
name: string;
className: string;
// Data if icon has been loaded
data?: FullIconifyIcon;
// Abort if icon is being loaded
abort?: IconifyIconLoaderAbort;
}
/**
* Empty icon
*/
const emptyIcon: RenderResult = {
width: 16,
height: 16,
preserveAspectRatio: 'xMidYMid meet',
viewBox: '0 0 16 16',
className: '',
body: '',
};
/**
* Component
*/
export class IconifyIconComponent extends Component<IconifyIconProps> {
// Dummy variable to force re-render
@tracked _counter = 0;
// Currently visible icon data, null if rendering object
_icon: CurrentIconAsString | null = null;
/**
* Abort loading icon
*/
_abortLoading() {
const icon = this._icon;
if (icon?.abort) {
icon.abort();
delete icon.abort;
}
}
/**
* Render
*/
get data(): RenderResult {
// Mention _counter to re-render
this._counter;
// Check icon
const icon = this.args.icon;
// Object
if (
typeof icon === 'object' &&
icon !== null &&
typeof icon.body === 'string'
) {
// Stop loading icon
if (this._icon) {
this._abortLoading();
this._icon = null;
}
// Render object
return render(fullIcon(icon), this.args, '');
}
// Already loaded
if (this._icon) {
const loaded = this._icon;
if (loaded.name === icon && loaded.data) {
return render(loaded.data, this.args, loaded.className);
}
}
// Invalid icon?
let iconName: IconifyIconName | null;
if (
typeof icon !== 'string' ||
(iconName = stringToIcon(icon, false, true)) === null
) {
if (this._icon) {
this._abortLoading();
this._icon = null;
}
return emptyIcon;
}
// Get class name
let className = 'iconify';
if (iconName.prefix !== '') {
className += ' iconify--' + iconName.prefix;
}
if (iconName.provider !== '') {
className += ' iconify--' + iconName.provider;
}
// Load icon
const data = getIconData(iconName);
if (!data) {
// Icon needs to be loaded
if (!this._icon || this._icon.name !== icon) {
// New icon to load
this._abortLoading();
this._icon = {
name: icon,
className,
abort: API.loadIcons([iconName], () => {
if (!this.isDestroyed && this._icon?.name === icon) {
// Loaded
const data = getIconData(iconName);
if (data) {
this._icon = {
name: icon,
className,
data,
};
this._counter++;
if (this.args.onLoad) {
this.args.onLoad(icon);
}
}
}
}),
};
}
} else {
// Got icon data
this._icon = {
name: icon,
className,
data,
};
return render(data, this.args, className);
}
return emptyIcon;
}
/**
* Remove loader callback
*/
willDestroy() {
super.willDestroy();
this._abortLoading();
}
}

View File

@ -0,0 +1,15 @@
<svg
xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink'
aria-hidden='true'
role='img'
width={{this.data.width}}
height={{this.data.height}}
preserveAspectRatio={{this.data.preserveAspectRatio}}
viewBox={{this.data.viewBox}}
style={{this.data.style}}
class={{this.data.className}}
...attributes
>
{{{this.data.body}}}
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@ -0,0 +1,291 @@
import type { IconifyJSON, IconifyIcon } from '@iconify/types';
// Core
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
import type {
IconifyIconSize,
IconifyHorizontalIconAlignment,
IconifyVerticalIconAlignment,
} from '@iconify/utils/lib/customisations';
import {
IconifyStorageFunctions,
storageFunctions,
allowSimpleNames,
} from '@iconify/core/lib/storage/functions';
import {
IconifyBuilderFunctions,
builderFunctions,
} from '@iconify/core/lib/builder/functions';
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
// Modules
import { coreModules } from '@iconify/core/lib/modules';
// API
import { API, IconifyAPIInternalStorage } from '@iconify/core/lib/api/';
import {
IconifyAPIFunctions,
IconifyAPIInternalFunctions,
APIFunctions,
APIInternalFunctions,
} from '@iconify/core/lib/api/functions';
import {
setAPIModule,
IconifyAPIModule,
IconifyAPISendQuery,
IconifyAPIPrepareQuery,
GetIconifyAPIModule,
} from '@iconify/core/lib/api/modules';
import { getAPIModule as getJSONPAPIModule } from '@iconify/core/lib/api/modules/jsonp';
import {
getAPIModule as getFetchAPIModule,
setFetch,
} from '@iconify/core/lib/api/modules/fetch';
import {
setAPIConfig,
PartialIconifyAPIConfig,
IconifyAPIConfig,
getAPIConfig,
GetAPIConfig,
} from '@iconify/core/lib/api/config';
import type {
IconifyIconLoaderCallback,
IconifyIconLoaderAbort,
} from '@iconify/core/lib/interfaces/loader';
// Cache
import { storeCache, loadCache } from '@iconify/core/lib/browser-storage';
import { toggleBrowserCache } from '@iconify/core/lib/browser-storage/functions';
import type {
IconifyBrowserCacheType,
IconifyBrowserCacheFunctions,
} from '@iconify/core/lib/browser-storage/functions';
// Properties
import type {
RawIconCustomisations,
IconifyIconOnLoad,
IconifyIconCustomisations,
IconifyIconProps,
} from './props';
// Component
import { IconifyIconComponent } from './component';
/**
* Export required types
*/
// Function sets
export {
IconifyStorageFunctions,
IconifyBuilderFunctions,
IconifyBrowserCacheFunctions,
IconifyAPIFunctions,
IconifyAPIInternalFunctions,
};
// JSON stuff
export { IconifyIcon, IconifyJSON, IconifyIconName };
// Customisations and icon props
export {
IconifyIconCustomisations,
IconifyIconSize,
IconifyHorizontalIconAlignment,
IconifyVerticalIconAlignment,
IconifyIconProps,
IconifyIconOnLoad,
};
// API
export {
IconifyAPIConfig,
IconifyIconLoaderCallback,
IconifyIconLoaderAbort,
IconifyAPIInternalStorage,
IconifyAPIModule,
GetAPIConfig,
IconifyAPIPrepareQuery,
IconifyAPISendQuery,
PartialIconifyAPIConfig,
};
// Builder functions
export { RawIconCustomisations, IconifyIconBuildResult };
/* Browser cache */
export { IconifyBrowserCacheType };
/**
* Enable and disable browser cache
*/
export const enableCache = (storage: IconifyBrowserCacheType) =>
toggleBrowserCache(storage, true);
export const disableCache = (storage: IconifyBrowserCacheType) =>
toggleBrowserCache(storage, false);
/* Storage functions */
/**
* Check if icon exists
*/
export const iconExists = storageFunctions.iconExists;
/**
* Get icon data
*/
export const getIcon = storageFunctions.getIcon;
/**
* List available icons
*/
export const listIcons = storageFunctions.listIcons;
/**
* Add one icon
*/
export const addIcon = storageFunctions.addIcon;
/**
* Add icon set
*/
export const addCollection = storageFunctions.addCollection;
/* Builder functions */
/**
* Calculate icon size
*/
export const calculateSize = builderFunctions.calculateSize;
/**
* Replace unique ids in content
*/
export const replaceIDs = builderFunctions.replaceIDs;
/**
* Build SVG
*/
export const buildIcon = builderFunctions.buildIcon;
/* API functions */
/**
* Load icons
*/
export const loadIcons = APIFunctions.loadIcons;
/**
* Add API provider
*/
export const addAPIProvider = APIFunctions.addAPIProvider;
/**
* Export internal functions that can be used by third party implementations
*/
export const _api = APIInternalFunctions;
/**
* Initialise stuff
*/
// Enable short names
allowSimpleNames(true);
// Set API
coreModules.api = API;
// Use Fetch API by default
let getAPIModule: GetIconifyAPIModule = getFetchAPIModule;
try {
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
// If window and document exist, attempt to load whatever module is available, otherwise use Fetch API
getAPIModule =
typeof fetch === 'function' && typeof Promise === 'function'
? getFetchAPIModule
: getJSONPAPIModule;
}
} catch (err) {
//
}
setAPIModule('', getAPIModule(getAPIConfig));
/**
* Function to enable node-fetch for getting icons on server side
*/
_api.setFetch = (nodeFetch: typeof fetch) => {
setFetch(nodeFetch);
if (getAPIModule !== getFetchAPIModule) {
getAPIModule = getFetchAPIModule;
setAPIModule('', getAPIModule(getAPIConfig));
}
};
/**
* Browser stuff
*/
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
// Set cache and load existing cache
coreModules.cache = storeCache;
loadCache();
interface WindowWithIconifyStuff {
IconifyPreload?: IconifyJSON[] | IconifyJSON;
IconifyProviders?: Record<string, PartialIconifyAPIConfig>;
}
const _window = window as WindowWithIconifyStuff;
// Load icons from global "IconifyPreload"
if (_window.IconifyPreload !== void 0) {
const preload = _window.IconifyPreload;
const err = 'Invalid IconifyPreload syntax.';
if (typeof preload === 'object' && preload !== null) {
(preload instanceof Array ? preload : [preload]).forEach((item) => {
try {
if (
// Check if item is an object and not null/array
typeof item !== 'object' ||
item === null ||
item instanceof Array ||
// Check for 'icons' and 'prefix'
typeof item.icons !== 'object' ||
typeof item.prefix !== 'string' ||
// Add icon set
!addCollection(item)
) {
console.error(err);
}
} catch (e) {
console.error(err);
}
});
}
}
// Set API from global "IconifyProviders"
if (_window.IconifyProviders !== void 0) {
const providers = _window.IconifyProviders;
if (typeof providers === 'object' && providers !== null) {
for (let key in providers) {
const err = 'IconifyProviders[' + key + '] is invalid.';
try {
const value = providers[key];
if (
typeof value !== 'object' ||
!value ||
value.resources === void 0
) {
continue;
}
if (!setAPIConfig(key, value)) {
console.error(err);
}
} catch (e) {
console.error(err);
}
}
}
}
}
/**
* Component
*/
export default IconifyIconComponent;

View File

@ -0,0 +1,38 @@
import type { IconifyIcon } from '@iconify/types';
import type { IconifyIconCustomisations as RawIconCustomisations } from '@iconify/utils/lib/customisations';
export { RawIconCustomisations };
// Allow rotation to be string
/**
* Icon customisations
*/
export type IconifyIconCustomisations = RawIconCustomisations & {
rotate?: string | number;
};
/**
* Callback for when icon has been loaded (only triggered for icons loaded from API)
*/
export type IconifyIconOnLoad = (name: string) => void;
/**
* Icon properties
*/
export interface IconifyIconProps extends IconifyIconCustomisations {
// Icon object or icon name (must be added to storage using addIcon for offline package)
icon: IconifyIcon | string;
// Style
color?: string;
// Shorthand properties
flip?: string;
align?: string;
// Unique id, used as base for ids for shapes. Use it to get consistent ids for server side rendering
id?: string;
// Callback to call when icon data has been loaded. Used only for icons loaded from API
onLoad?: IconifyIconOnLoad;
}

View File

@ -0,0 +1,127 @@
import type { IconifyIcon } from '@iconify/types';
import type { FullIconCustomisations } from '@iconify/utils/lib/customisations';
import {
defaults,
mergeCustomisations,
} from '@iconify/utils/lib/customisations';
import {
flipFromString,
alignmentFromString,
} from '@iconify/utils/lib/customisations/shorthand';
import { rotateFromString } from '@iconify/utils/lib/customisations/rotate';
import { iconToSVG } from '@iconify/utils/lib/svg/build';
import { replaceIDs } from '@iconify/utils/lib/svg/id';
import type { IconifyIconCustomisations, IconifyIconProps } from './props';
/**
* Render result
*/
export interface RenderResult {
width: string | number;
height: string | number;
viewBox: string;
preserveAspectRatio: string;
style?: string;
className: string;
body: string;
}
/**
* Render icon
*/
export const render = (
// Icon must be validated before calling this function
icon: Required<IconifyIcon>,
// Partial properties
props: IconifyIconProps,
// Class name
className: string
): RenderResult => {
// Get all customisations
const customisations = mergeCustomisations(
defaults,
props as IconifyIconCustomisations
) as FullIconCustomisations;
// Create empty style
let style = '';
// Get element properties
for (let key in props) {
const value = props[key];
if (value === void 0) {
continue;
}
switch (key) {
// Properties to ignore
case 'icon':
case 'onLoad':
break;
// Boolean attributes
case 'inline':
case 'hFlip':
case 'vFlip':
customisations[key] =
value === true || value === 'true' || value === 1;
break;
// Flip as string: 'horizontal,vertical'
case 'flip':
if (typeof value === 'string') {
flipFromString(customisations, value);
}
break;
// Alignment as string
case 'align':
if (typeof value === 'string') {
alignmentFromString(customisations, value);
}
break;
// Color: copy to style
case 'color':
style += 'color: ' + value + ';';
break;
// Rotation as string
case 'rotate':
if (typeof value === 'string') {
customisations[key] = rotateFromString(value);
} else if (typeof value === 'number') {
customisations[key] = value;
}
break;
// Ignore other properties
}
}
// Generate icon
const item = iconToSVG(icon, customisations);
// Counter for ids based on "id" property to render icons consistently on server and client
let localCounter = 0;
const id = props.id;
// Create body
const body = replaceIDs(
item.body,
id ? () => id + '-' + localCounter++ : 'iconify-ember-'
);
// Add inline
if (item.inline) {
style += 'vertical-align: -0.125em;';
}
return {
...item.attributes,
style: style === '' ? void 0 : style,
className,
body,
};
};

View File

@ -0,0 +1,16 @@
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"target": "ES2019",
"module": "ESNext",
"declaration": true,
"sourceMap": false,
"strict": false,
"moduleResolution": "node",
"esModuleInterop": true,
"importsNotUsedAsValues": "error",
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true
}
}