From c399917589f4f72a6e2ff3302f1dcc099d8f7200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Mutte?= Date: Tue, 18 Jul 2023 18:49:31 -0300 Subject: [PATCH 1/3] feat(icons): implement `svg` icons new structure with types (#182) Co-authored-by: Felipe Fialho --- .gitignore | 1 + package.json | 3 +- packages/core/src/components/alert/alert.tsx | 4 +- .../alert/stories/alert.core.stories.tsx | 6 +- .../alert/stories/alert.react.stories.tsx | 6 +- .../core/src/components/chip/chip.spec.ts | 6 +- packages/core/src/components/chip/chip.tsx | 4 +- .../chip/stories/chip.core.stories.tsx | 2 +- .../chip/stories/chip.react.stories.tsx | 2 +- .../core/src/components/icon/icon.spec.ts | 2 +- packages/core/src/components/icon/icon.tsx | 7 ++- .../core/src/components/input/input.spec.ts | 6 +- packages/core/src/components/input/input.tsx | 4 +- .../input/stories/input.core.stories.tsx | 2 +- .../input/stories/input.react.stories.tsx | 2 +- .../core/src/components/select/select.spec.ts | 6 +- .../core/src/components/select/select.tsx | 5 +- .../select/stories/select.core.stories.tsx | 2 +- .../select/stories/select.react.stories.tsx | 2 +- .../stories/textarea.core.stories.tsx | 2 +- .../stories/textarea.react.stories.tsx | 2 +- .../src/components/textarea/textarea.spec.ts | 6 +- .../core/src/components/textarea/textarea.tsx | 4 +- packages/icons/package.json | 4 +- packages/icons/scripts/build.ts | 61 ++++++++----------- packages/icons/scripts/generate-types.ts | 9 +++ packages/icons/scripts/helpers.ts | 38 +++++++++--- .../svg/{ => custom}/professional-plus.svg | 0 packages/icons/svg/heart-outline.svg | 1 - packages/icons/svg/heart.svg | 1 - packages/icons/svg/home-outline.svg | 1 - packages/icons/svg/home.svg | 1 - .../svg/mdi/account-multiple-outline.svg | 1 + packages/icons/svg/mdi/account-multiple.svg | 1 + packages/icons/svg/mdi/alert.svg | 1 + packages/icons/svg/mdi/check.svg | 1 + packages/icons/svg/mdi/close-outline.svg | 1 + packages/icons/svg/mdi/close.svg | 1 + packages/icons/svg/mdi/eye-off.svg | 1 + packages/icons/svg/mdi/eye.svg | 1 + packages/icons/svg/mdi/heart-outline.svg | 1 + packages/icons/svg/mdi/heart.svg | 1 + packages/icons/svg/mdi/home-outline.svg | 1 + packages/icons/svg/mdi/home.svg | 1 + packages/icons/svg/mdi/magnify.svg | 1 + 45 files changed, 129 insertions(+), 86 deletions(-) create mode 100644 packages/icons/scripts/generate-types.ts rename packages/icons/svg/{ => custom}/professional-plus.svg (100%) delete mode 100644 packages/icons/svg/heart-outline.svg delete mode 100644 packages/icons/svg/heart.svg delete mode 100644 packages/icons/svg/home-outline.svg delete mode 100644 packages/icons/svg/home.svg create mode 100644 packages/icons/svg/mdi/account-multiple-outline.svg create mode 100644 packages/icons/svg/mdi/account-multiple.svg create mode 100644 packages/icons/svg/mdi/alert.svg create mode 100644 packages/icons/svg/mdi/check.svg create mode 100644 packages/icons/svg/mdi/close-outline.svg create mode 100644 packages/icons/svg/mdi/close.svg create mode 100644 packages/icons/svg/mdi/eye-off.svg create mode 100644 packages/icons/svg/mdi/eye.svg create mode 100644 packages/icons/svg/mdi/heart-outline.svg create mode 100644 packages/icons/svg/mdi/heart.svg create mode 100644 packages/icons/svg/mdi/home-outline.svg create mode 100644 packages/icons/svg/mdi/home.svg create mode 100644 packages/icons/svg/mdi/magnify.svg diff --git a/.gitignore b/.gitignore index 493c3b89e..c1fb67a2d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ packages/tokens/index.ts packages/core/react packages/core/vue packages/core/core.css +packages/core/src/icons.d.ts storybook-static dist tmp diff --git a/package.json b/package.json index c96020c2a..65cbf9f5b 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,13 @@ "utils/*" ], "scripts": { - "core:build": "npx nx build @juntossomosmais/atomium && npm run react:build", + "core:build": "npm run icons:generate-types && npx nx build @juntossomosmais/atomium && npm run react:build", "docs:build": "npx nx build @atomium/docs && npx nx build @atomium/docs-react", "docs-react:start": "npx nx run @atomium/docs-react:start", "lint:pre-commit": "eslint --resolve-plugins-relative-to . -c ./.eslintrc.json $(git diff --cached --name-only --diff-filter=AM | grep -E \"(.js$|.ts$)\") --cache --cache-location node_modules/.cache/eslint", "lint:styles": "stylelint '**/*.scss'", "icons:build": "npx nx build @juntossomosmais/atomium-icons", + "icons:generate-types": "cd packages/icons && npm run generate:types", "postinstall": "npx husky install & npx nx build @juntossomosmais/atomium:prebuild && npm run icons:build && npm run core:build && npm run tokens:build", "pre-commit": "lint-staged", "prepare": "husky install", diff --git a/packages/core/src/components/alert/alert.tsx b/packages/core/src/components/alert/alert.tsx index edd16c92c..eb3e811a1 100644 --- a/packages/core/src/components/alert/alert.tsx +++ b/packages/core/src/components/alert/alert.tsx @@ -1,5 +1,7 @@ import { Component, Event, EventEmitter, Host, Prop, h } from '@stencil/core' +import { IconProps } from '../../icons' + @Component({ tag: 'atom-alert', styleUrl: 'alert.scss', @@ -8,7 +10,7 @@ import { Component, Event, EventEmitter, Host, Prop, h } from '@stencil/core' export class AtomAlert { @Prop() color?: 'info' | 'success' | 'warning' | 'danger' | 'neutral' = 'neutral' - @Prop() icon?: string + @Prop() icon?: IconProps @Prop() messageTitle?: string @Prop() messageText?: string @Prop() actionText?: string diff --git a/packages/core/src/components/alert/stories/alert.core.stories.tsx b/packages/core/src/components/alert/stories/alert.core.stories.tsx index 6c256baee..7ef4aa4b5 100644 --- a/packages/core/src/components/alert/stories/alert.core.stories.tsx +++ b/packages/core/src/components/alert/stories/alert.core.stories.tsx @@ -35,7 +35,7 @@ export const Info: StoryObj = { args: { ...AlertComponentArgs, color: 'info', - icon: 'people', + icon: 'account-multiple', }, } @@ -53,7 +53,7 @@ export const Warning: StoryObj = { args: { ...AlertComponentArgs, color: 'warning', - icon: 'warning', + icon: 'alert', }, } @@ -62,6 +62,6 @@ export const Danger: StoryObj = { args: { ...AlertComponentArgs, color: 'danger', - icon: 'people', + icon: 'account-multiple', }, } diff --git a/packages/core/src/components/alert/stories/alert.react.stories.tsx b/packages/core/src/components/alert/stories/alert.react.stories.tsx index e2d13c607..d8ff06f5a 100644 --- a/packages/core/src/components/alert/stories/alert.react.stories.tsx +++ b/packages/core/src/components/alert/stories/alert.react.stories.tsx @@ -35,7 +35,7 @@ export const Info: StoryObj = { args: { ...AlertComponentArgs, color: 'info', - icon: 'people', + icon: 'account-multiple', }, } @@ -53,7 +53,7 @@ export const Warning: StoryObj = { args: { ...AlertComponentArgs, color: 'warning', - icon: 'warning', + icon: 'alert', }, } @@ -62,6 +62,6 @@ export const Danger: StoryObj = { args: { ...AlertComponentArgs, color: 'danger', - icon: 'people', + icon: 'account-multiple', }, } diff --git a/packages/core/src/components/chip/chip.spec.ts b/packages/core/src/components/chip/chip.spec.ts index 6ea29c1d3..ce31af0d0 100644 --- a/packages/core/src/components/chip/chip.spec.ts +++ b/packages/core/src/components/chip/chip.spec.ts @@ -46,16 +46,16 @@ describe('AtomChip', () => { it('should add icon when icon prop is set', async () => { const page = await newSpecPage({ components: [AtomChip], - html: ``, + html: ``, }) await page.waitForChanges() expect(page.root).toEqualHtml(` - + - + diff --git a/packages/core/src/components/chip/chip.tsx b/packages/core/src/components/chip/chip.tsx index afccd2b0f..7f8a361cd 100644 --- a/packages/core/src/components/chip/chip.tsx +++ b/packages/core/src/components/chip/chip.tsx @@ -1,5 +1,7 @@ import { Component, Event, EventEmitter, Prop, h } from '@stencil/core' +import { IconProps } from '../../icons' + @Component({ tag: 'atom-chip', styleUrl: 'chip.scss', @@ -10,7 +12,7 @@ export class AtomChip { @Prop() activated = false @Prop() outline = false @Prop() mode: 'ios' | 'md' = 'md' - @Prop() icon?: string + @Prop() icon?: IconProps @Prop() close = false @Event() atomClick: EventEmitter diff --git a/packages/core/src/components/chip/stories/chip.core.stories.tsx b/packages/core/src/components/chip/stories/chip.core.stories.tsx index 07459f150..d2a6555a4 100644 --- a/packages/core/src/components/chip/stories/chip.core.stories.tsx +++ b/packages/core/src/components/chip/stories/chip.core.stories.tsx @@ -52,7 +52,7 @@ export const WithIcon: StoryObj = { render: (args) => createChip(args), args: { ...ChipComponentArgs, - icon: 'checkmark', + icon: 'check', }, } diff --git a/packages/core/src/components/chip/stories/chip.react.stories.tsx b/packages/core/src/components/chip/stories/chip.react.stories.tsx index c877fd701..44f3a89e3 100644 --- a/packages/core/src/components/chip/stories/chip.react.stories.tsx +++ b/packages/core/src/components/chip/stories/chip.react.stories.tsx @@ -52,7 +52,7 @@ export const WithIcon: StoryObj = { render: (args) => createChip(args), args: { ...ChipComponentArgs, - icon: 'checkmark', + icon: 'check', }, } diff --git a/packages/core/src/components/icon/icon.spec.ts b/packages/core/src/components/icon/icon.spec.ts index aa29adf6f..87b173282 100644 --- a/packages/core/src/components/icon/icon.spec.ts +++ b/packages/core/src/components/icon/icon.spec.ts @@ -2,7 +2,7 @@ import { newSpecPage } from '@stencil/core/testing' import { AtomIcon } from './icon' -const URL_MOCK = 'https://unpkg.com/ionicons@7.1.0/dist/ionicons/svg' +const URL_MOCK = 'https://d2kfdqa8kiizgt.cloudfront.net/atomium/icons' describe('atom-icon', () => { it('should render ion-icon element', async () => { diff --git a/packages/core/src/components/icon/icon.tsx b/packages/core/src/components/icon/icon.tsx index 15606101f..71c3ffa1a 100644 --- a/packages/core/src/components/icon/icon.tsx +++ b/packages/core/src/components/icon/icon.tsx @@ -1,7 +1,10 @@ import { Color } from '@ionic/core' import { Component, Host, Prop, h } from '@stencil/core' -const CDN_URL = 'https://unpkg.com/ionicons@7.1.0/dist/ionicons/svg' +import { IconProps } from '../../icons' + +// @note: this is a temporary solution using sandbox until we have a proper CDN for our icons +const CDN_URL = 'https://d2kfdqa8kiizgt.cloudfront.net/atomium/icons' @Component({ tag: 'atom-icon', @@ -10,7 +13,7 @@ const CDN_URL = 'https://unpkg.com/ionicons@7.1.0/dist/ionicons/svg' }) export class AtomIcon { @Prop() color?: Color - @Prop() icon?: string + @Prop() icon?: IconProps @Prop() size?: 'small' | 'large' render(): JSX.Element { diff --git a/packages/core/src/components/input/input.spec.ts b/packages/core/src/components/input/input.spec.ts index 2a2204a46..0c8875322 100644 --- a/packages/core/src/components/input/input.spec.ts +++ b/packages/core/src/components/input/input.spec.ts @@ -41,15 +41,15 @@ describe('AtomInput', () => { const page = await newSpecPage({ components: [AtomInput], html: ` - + `, }) expect(page.root).toEqualHtml(` - + - + `) diff --git a/packages/core/src/components/input/input.tsx b/packages/core/src/components/input/input.tsx index 66099d8f1..0f2d970a4 100644 --- a/packages/core/src/components/input/input.tsx +++ b/packages/core/src/components/input/input.tsx @@ -11,6 +11,8 @@ import { h, } from '@stencil/core' +import { IconProps } from '../../icons' + @Component({ tag: 'atom-input', styleUrl: 'input.scss', @@ -43,7 +45,7 @@ export class AtomInput { @Prop() fill: 'solid' | 'outline' = 'solid' @Prop() hasError = false @Prop() helperText?: string - @Prop() icon?: string + @Prop() icon?: IconProps @Prop() inputmode?: | 'none' | 'text' diff --git a/packages/core/src/components/input/stories/input.core.stories.tsx b/packages/core/src/components/input/stories/input.core.stories.tsx index 97e40d57f..5fda6bfb6 100644 --- a/packages/core/src/components/input/stories/input.core.stories.tsx +++ b/packages/core/src/components/input/stories/input.core.stories.tsx @@ -59,7 +59,7 @@ export const InputIcon: StoryObj = { render: (args) => createInput(args), args: { ...InputComponentArgs, - icon: 'search', + icon: 'magnify', }, } diff --git a/packages/core/src/components/input/stories/input.react.stories.tsx b/packages/core/src/components/input/stories/input.react.stories.tsx index 6c4754db4..e0de15c49 100644 --- a/packages/core/src/components/input/stories/input.react.stories.tsx +++ b/packages/core/src/components/input/stories/input.react.stories.tsx @@ -58,7 +58,7 @@ export const InputIcon: StoryObj = { render: (args) => createInput(args), args: { ...InputComponentArgs, - icon: 'search', + icon: 'magnify', }, } diff --git a/packages/core/src/components/select/select.spec.ts b/packages/core/src/components/select/select.spec.ts index f557860ac..92734077d 100644 --- a/packages/core/src/components/select/select.spec.ts +++ b/packages/core/src/components/select/select.spec.ts @@ -64,7 +64,7 @@ describe('AtomSelect', () => { const page = await newSpecPage({ components: [AtomSelect], html: ` - + `, }) @@ -72,14 +72,14 @@ describe('AtomSelect', () => { await page.waitForChanges() expect(page.root).toEqualHtml(` - + apple banana orange - + `) diff --git a/packages/core/src/components/select/select.tsx b/packages/core/src/components/select/select.tsx index 28acffb9a..23b8e4973 100644 --- a/packages/core/src/components/select/select.tsx +++ b/packages/core/src/components/select/select.tsx @@ -1,6 +1,5 @@ import { Mode } from '@ionic/core' import { JSX as IonTypes } from '@ionic/core/dist/types/components' - import { Component, Element, @@ -11,6 +10,8 @@ import { h, } from '@stencil/core' +import { IconProps } from '../../icons' + @Component({ tag: 'atom-select', styleUrl: 'select.scss', @@ -24,7 +25,7 @@ export class AtomSelect { @Prop() errorText?: string @Prop() fill: 'solid' | 'outline' = 'solid' @Prop() helperText?: string - @Prop() icon?: string + @Prop() icon?: IconProps @Prop() label?: string @Prop() mode: Mode = 'md' @Prop() multiple?: boolean diff --git a/packages/core/src/components/select/stories/select.core.stories.tsx b/packages/core/src/components/select/stories/select.core.stories.tsx index 14e3d9a7b..12ed0a311 100644 --- a/packages/core/src/components/select/stories/select.core.stories.tsx +++ b/packages/core/src/components/select/stories/select.core.stories.tsx @@ -63,7 +63,7 @@ export const SelectIcon: StoryObj = { render: (args) => createSelect(args), args: { ...SelectComponentArgs, - icon: 'people', + icon: 'account-multiple', }, } diff --git a/packages/core/src/components/select/stories/select.react.stories.tsx b/packages/core/src/components/select/stories/select.react.stories.tsx index 63864eff0..204b5e12d 100644 --- a/packages/core/src/components/select/stories/select.react.stories.tsx +++ b/packages/core/src/components/select/stories/select.react.stories.tsx @@ -52,7 +52,7 @@ export const SelectIcon: StoryObj = { render: (args) => createSelect(args), args: { ...SelectComponentArgs, - icon: 'people', + icon: 'account-multiple', }, } diff --git a/packages/core/src/components/textarea/stories/textarea.core.stories.tsx b/packages/core/src/components/textarea/stories/textarea.core.stories.tsx index 8ed19b4f3..23628faa3 100644 --- a/packages/core/src/components/textarea/stories/textarea.core.stories.tsx +++ b/packages/core/src/components/textarea/stories/textarea.core.stories.tsx @@ -51,7 +51,7 @@ export const TextareaIcon: StoryObj = { render: (args) => createTextarea(args), args: { ...TextareaComponentArgs, - icon: 'people', + icon: 'account-multiple', }, } diff --git a/packages/core/src/components/textarea/stories/textarea.react.stories.tsx b/packages/core/src/components/textarea/stories/textarea.react.stories.tsx index 007a3e145..73085d6b8 100644 --- a/packages/core/src/components/textarea/stories/textarea.react.stories.tsx +++ b/packages/core/src/components/textarea/stories/textarea.react.stories.tsx @@ -50,7 +50,7 @@ export const TextareaIcon: StoryObj = { render: (args) => createTextarea(args), args: { ...TextareaComponentArgs, - icon: 'people', + icon: 'account-multiple', }, } diff --git a/packages/core/src/components/textarea/textarea.spec.ts b/packages/core/src/components/textarea/textarea.spec.ts index bbafd8bc8..10a4d3723 100644 --- a/packages/core/src/components/textarea/textarea.spec.ts +++ b/packages/core/src/components/textarea/textarea.spec.ts @@ -41,15 +41,15 @@ describe('AtomTextarea', () => { const page = await newSpecPage({ components: [AtomTextarea], html: ` - + `, }) expect(page.root).toEqualHtml(` - + - + `) diff --git a/packages/core/src/components/textarea/textarea.tsx b/packages/core/src/components/textarea/textarea.tsx index 1ae585a3a..c5f733b95 100644 --- a/packages/core/src/components/textarea/textarea.tsx +++ b/packages/core/src/components/textarea/textarea.tsx @@ -11,6 +11,8 @@ import { h, } from '@stencil/core' +import { IconProps } from '../../icons' + @Component({ tag: 'atom-textarea', styleUrl: 'textarea.scss', @@ -44,7 +46,7 @@ export class AtomTextarea { @Prop() fill: 'solid' | 'outline' = 'solid' @Prop() hasError = false @Prop() helperText?: string - @Prop() icon?: string + @Prop() icon?: IconProps @Prop() inputmode?: | 'none' | 'text' diff --git a/packages/icons/package.json b/packages/icons/package.json index 141422d0c..b0964a330 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -7,6 +7,8 @@ "dist/" ], "scripts": { - "build": "tsc && node dist/scripts/build.js" + "build": "tsc && node dist/scripts/build.js && npm run generate:types", + "generate:types": "node dist/scripts/generate-types.js && npm run copy", + "copy": "npx copyfiles --flat ./dist/icons.d.ts ../core/src" } } diff --git a/packages/icons/scripts/build.ts b/packages/icons/scripts/build.ts index bed589989..b6baed17d 100644 --- a/packages/icons/scripts/build.ts +++ b/packages/icons/scripts/build.ts @@ -1,48 +1,35 @@ import path from 'path' import { optimize } from 'svgo' -import { - getCurrentDirPath, - readSvg, - readSvgDirectory, - writeSvgFile, - writeTypeDefinitionFile, -} from './helpers.js' - -const ICONS_DIR = path.resolve(getCurrentDirPath(), '../../svg') -const DIST_DIR = path.resolve(getCurrentDirPath(), '../svg') +import { readSvg, readSvgDirectories, writeSvgFile } from './helpers.js' + +function optimizeSvg(path: string, svg: string) { + const config = [ + { + name: 'preset-default', + params: { + overrides: { + convertShapeToPath: false, + mergePaths: false, + removeViewBox: false, + }, + }, + }, + ] + const optimizedSvg = optimize(svg, { path, plugins: config }) + return optimizedSvg.data +} function build() { - const svgFiles = readSvgDirectory(ICONS_DIR) + const files = readSvgDirectories() console.log(`Optimizing SVGs...`) - - for (const svgFile of svgFiles) { - const pathFile = path.join(ICONS_DIR, svgFile) - const content = readSvg(pathFile) - - const optimizedFile = optimize(content, { - path: pathFile, - plugins: [ - { - name: 'preset-default', - params: { - overrides: { - convertShapeToPath: false, - mergePaths: false, - removeViewBox: false, - }, - }, - }, - ], - }).data - - writeSvgFile(DIST_DIR, svgFile, optimizedFile) + for (const file of files) { + const basename = path.basename(file) + const content = readSvg(file) + const optimizedFile = optimizeSvg(file, content) + writeSvgFile(basename, optimizedFile) } - - console.log(`Generating types...`) - - writeTypeDefinitionFile(svgFiles) } build() diff --git a/packages/icons/scripts/generate-types.ts b/packages/icons/scripts/generate-types.ts new file mode 100644 index 000000000..a982b285d --- /dev/null +++ b/packages/icons/scripts/generate-types.ts @@ -0,0 +1,9 @@ +import { readSvgDirectories, writeTypeDefinitionFile } from './helpers.js' + +function generateTypes() { + console.log(`Generating types...`) + const files = readSvgDirectories() + writeTypeDefinitionFile(files) +} + +generateTypes() diff --git a/packages/icons/scripts/helpers.ts b/packages/icons/scripts/helpers.ts index 06f16784f..597b1eea5 100644 --- a/packages/icons/scripts/helpers.ts +++ b/packages/icons/scripts/helpers.ts @@ -5,17 +5,39 @@ import { fileURLToPath } from 'url' export const getCurrentDirPath = (currentUrl = import.meta.url) => path.dirname(fileURLToPath(currentUrl)) +const ICONS_DIR = path.resolve(getCurrentDirPath(), '../../svg') +const DIST_DIR = path.resolve(getCurrentDirPath(), '../svg') + export const readSvg = (path: string) => fs.readFileSync(path, 'utf-8') -export const readSvgDirectory = (directory: string, fileExtension = '.svg') => - fs - .readdirSync(directory) - .filter((file) => path.extname(file) === fileExtension) +export const readSvgDirectories = ( + directory = ICONS_DIR, + fileExtension = '.svg' +) => { + const allSvgFiles: string[] = [] + + const folders = fs.readdirSync(directory).filter((folder) => { + return fs.lstatSync(path.join(directory, folder)).isDirectory() + }) + + for (const folder of folders) { + const folderPath = path.join(directory, folder) + const files = fs.readdirSync(folderPath) + + for (const file of files) { + if (path.extname(file) !== fileExtension) continue + const filePath = path.join(folderPath, file) + allSvgFiles.push(filePath) + } + } + + return allSvgFiles +} export const writeSvgFile = ( - outputDirectory: string, fileName: string, - content: string + content: string, + outputDirectory = DIST_DIR ) => { if (!fs.existsSync(outputDirectory)) { fs.mkdirSync(outputDirectory) @@ -33,6 +55,6 @@ export const writeTypeDefinitionFile = ( outputPath = getCurrentDirPath() ) => { const types = svgFiles.map((file) => `'${path.basename(file, '.svg')}'`) - const typeDef = `export type IconProps = ${types.join(' | ')};\n` - fs.writeFileSync(path.join(outputPath, '..', 'index.d.ts'), typeDef) + const typeDef = `export type IconProps = ${types.join('\n | ')};` + fs.writeFileSync(path.join(outputPath, '..', 'icons.d.ts'), typeDef) } diff --git a/packages/icons/svg/professional-plus.svg b/packages/icons/svg/custom/professional-plus.svg similarity index 100% rename from packages/icons/svg/professional-plus.svg rename to packages/icons/svg/custom/professional-plus.svg diff --git a/packages/icons/svg/heart-outline.svg b/packages/icons/svg/heart-outline.svg deleted file mode 100644 index d48547f1f..000000000 --- a/packages/icons/svg/heart-outline.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/icons/svg/heart.svg b/packages/icons/svg/heart.svg deleted file mode 100644 index a4b8a217c..000000000 --- a/packages/icons/svg/heart.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/icons/svg/home-outline.svg b/packages/icons/svg/home-outline.svg deleted file mode 100644 index 7c09f9a1e..000000000 --- a/packages/icons/svg/home-outline.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/icons/svg/home.svg b/packages/icons/svg/home.svg deleted file mode 100644 index 607061316..000000000 --- a/packages/icons/svg/home.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/icons/svg/mdi/account-multiple-outline.svg b/packages/icons/svg/mdi/account-multiple-outline.svg new file mode 100644 index 000000000..cc780de9c --- /dev/null +++ b/packages/icons/svg/mdi/account-multiple-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/account-multiple.svg b/packages/icons/svg/mdi/account-multiple.svg new file mode 100644 index 000000000..17e3a2b04 --- /dev/null +++ b/packages/icons/svg/mdi/account-multiple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/alert.svg b/packages/icons/svg/mdi/alert.svg new file mode 100644 index 000000000..114aea1fb --- /dev/null +++ b/packages/icons/svg/mdi/alert.svg @@ -0,0 +1 @@ + diff --git a/packages/icons/svg/mdi/check.svg b/packages/icons/svg/mdi/check.svg new file mode 100644 index 000000000..066aed300 --- /dev/null +++ b/packages/icons/svg/mdi/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/close-outline.svg b/packages/icons/svg/mdi/close-outline.svg new file mode 100644 index 000000000..255653ec0 --- /dev/null +++ b/packages/icons/svg/mdi/close-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/close.svg b/packages/icons/svg/mdi/close.svg new file mode 100644 index 000000000..64fc924e0 --- /dev/null +++ b/packages/icons/svg/mdi/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/eye-off.svg b/packages/icons/svg/mdi/eye-off.svg new file mode 100644 index 000000000..25536563d --- /dev/null +++ b/packages/icons/svg/mdi/eye-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/eye.svg b/packages/icons/svg/mdi/eye.svg new file mode 100644 index 000000000..915c953c8 --- /dev/null +++ b/packages/icons/svg/mdi/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/heart-outline.svg b/packages/icons/svg/mdi/heart-outline.svg new file mode 100644 index 000000000..91475fdb5 --- /dev/null +++ b/packages/icons/svg/mdi/heart-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/heart.svg b/packages/icons/svg/mdi/heart.svg new file mode 100644 index 000000000..551a3572b --- /dev/null +++ b/packages/icons/svg/mdi/heart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/home-outline.svg b/packages/icons/svg/mdi/home-outline.svg new file mode 100644 index 000000000..a22a78aab --- /dev/null +++ b/packages/icons/svg/mdi/home-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/home.svg b/packages/icons/svg/mdi/home.svg new file mode 100644 index 000000000..0cf7c6055 --- /dev/null +++ b/packages/icons/svg/mdi/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/svg/mdi/magnify.svg b/packages/icons/svg/mdi/magnify.svg new file mode 100644 index 000000000..45e15c5a1 --- /dev/null +++ b/packages/icons/svg/mdi/magnify.svg @@ -0,0 +1 @@ + \ No newline at end of file From 2ca49a0cf7f518a23c1393e0541a0034e0835874 Mon Sep 17 00:00:00 2001 From: Denilson Date: Wed, 19 Jul 2023 12:49:30 -0300 Subject: [PATCH 2/3] feat(breadcrumb): create new component (#163) Co-authored-by: felipefialho --- ...b-component-event-undocumented.stories.mdx | 17 ++++ packages/core/src/components/alert/alert.scss | 2 +- .../src/components/breadcrumb/breadcrumb.scss | 60 +++++++++++++ .../components/breadcrumb/breadcrumb.spec.ts | 90 +++++++++++++++++++ .../src/components/breadcrumb/breadcrumb.tsx | 50 +++++++++++ .../breadcrumb/stories/breadcrumb.args.ts | 25 ++++++ .../stories/breadcrumb.core.stories.tsx | 45 ++++++++++ .../stories/breadcrumb.react.stories.tsx | 37 ++++++++ packages/icons/svg/mdi/arrow-right.svg | 1 + packages/icons/svg/mdi/west.svg | 1 + 10 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 apps/docs/stories/architecture-decision-records/0009-why-use-onclick-event-on-breadcrumb-component-event-undocumented.stories.mdx create mode 100644 packages/core/src/components/breadcrumb/breadcrumb.scss create mode 100644 packages/core/src/components/breadcrumb/breadcrumb.spec.ts create mode 100644 packages/core/src/components/breadcrumb/breadcrumb.tsx create mode 100644 packages/core/src/components/breadcrumb/stories/breadcrumb.args.ts create mode 100644 packages/core/src/components/breadcrumb/stories/breadcrumb.core.stories.tsx create mode 100644 packages/core/src/components/breadcrumb/stories/breadcrumb.react.stories.tsx create mode 100644 packages/icons/svg/mdi/arrow-right.svg create mode 100644 packages/icons/svg/mdi/west.svg diff --git a/apps/docs/stories/architecture-decision-records/0009-why-use-onclick-event-on-breadcrumb-component-event-undocumented.stories.mdx b/apps/docs/stories/architecture-decision-records/0009-why-use-onclick-event-on-breadcrumb-component-event-undocumented.stories.mdx new file mode 100644 index 000000000..c2ac33c96 --- /dev/null +++ b/apps/docs/stories/architecture-decision-records/0009-why-use-onclick-event-on-breadcrumb-component-event-undocumented.stories.mdx @@ -0,0 +1,17 @@ +import { Meta } from '@storybook/addon-docs' + + + +# Why use `onClick` event on breadcrumb component even undocumented? + +🗓️ 2023-07 · ✍️ [@denilsonrp](https://github.com/denilsonrp) + +## Context + +In the [breadcrumb component's pull request](https://github.com/juntossomosmais/atomium/pull/163) a [doubt arose about the correct functioning of the `onClick` event](https://github.com/juntossomosmais/atomium/pull/163#discussion_r1250986555), as this event isn't documented in [ion-breadcrumb docs](https://ionicframework.com/docs/api/breadcrumb#events). + +## Decision + +We ran some tests on Atomium's breadcrumb component in order to ensure the correct firing of the event and even though the `onClick` event isn't documented in the events section of the [ion-breadcrumb docs](https://ionicframework.com/docs/api/breadcrumb#events), the tests were successful and the event fired correctly. + +Based on these tests, we can assume that, even without event documentation, it's possible to use it. The idea of ​​exposing this decision is to serve as a reference in possible similar scenarios in the future. diff --git a/packages/core/src/components/alert/alert.scss b/packages/core/src/components/alert/alert.scss index 054509d0e..43b30e229 100644 --- a/packages/core/src/components/alert/alert.scss +++ b/packages/core/src/components/alert/alert.scss @@ -7,8 +7,8 @@ } .atom-alert { - border-radius: var(--border-radius); border: 1px solid transparent; + border-radius: var(--border-radius); font: var(--text-body-medium); letter-spacing: var(--text-body-medium-letter); padding: var(--spacing-base); diff --git a/packages/core/src/components/breadcrumb/breadcrumb.scss b/packages/core/src/components/breadcrumb/breadcrumb.scss new file mode 100644 index 000000000..60bce3839 --- /dev/null +++ b/packages/core/src/components/breadcrumb/breadcrumb.scss @@ -0,0 +1,60 @@ +@import '~@atomium/scss-utils/index'; + +.atom-breadcrumbs { + display: none; + + @include above(medium) { + display: flex; + } +} + +.atom-breadcrumb { + --color: var(--color-brand-secondary-regular); + --color-active: var(--color-neutral-regular); + font: var(--text-body-small); + letter-spacing: var(--text-body-small-letter); + + &:not(:last-of-type) { + &::part(native) { + cursor: pointer; + + &:hover { + text-decoration: underline; + } + } + + .atom-breadcrumb__text { + max-width: 100px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + &::part(native) { + padding: 0; + } + + &::part(separator) { + color: var(--color-neutral-regular); + margin: 0 var(--spacing-xxsmall); + } +} + +.atom-button__back { + align-items: center; + background-color: transparent; + border: 0; + color: var(--color-brand-secondary-regular); + cursor: pointer; + display: flex; + font: var(--text-link-small); + gap: var(--spacing-xsmall); + letter-spacing: var(--text-link-small-letter); + padding: 0; + text-decoration: underline; + + @include above(medium) { + display: none; + } +} diff --git a/packages/core/src/components/breadcrumb/breadcrumb.spec.ts b/packages/core/src/components/breadcrumb/breadcrumb.spec.ts new file mode 100644 index 000000000..370469f67 --- /dev/null +++ b/packages/core/src/components/breadcrumb/breadcrumb.spec.ts @@ -0,0 +1,90 @@ +import { newSpecPage } from '@stencil/core/testing' + +import { AtomBreadcrumb } from './breadcrumb' + +const breadcrumbItemsMock = [ + { + text: 'First level', + title: 'Go to first level', + redirect: () => console.log('/first'), + }, + { + text: 'Intermediary level', + title: 'Go to intermediary level', + redirect: () => console.log('/intermediary'), + }, + { + text: 'Current level', + title: 'This is the current level', + }, +] + +describe('atom-breadcrumb', () => { + it('should render breadcrumb items and mobile back button correctly', async () => { + const page = await newSpecPage({ + components: [AtomBreadcrumb], + html: ``, + }) + + page.rootInstance.items = breadcrumbItemsMock + + await page.waitForChanges() + + expect(page.root).toEqualHtml(` + + + + + + + First level + + + + + + Intermediary level + + + + + + Current level + + + + + + + `) + }) + + it('should not render mobile back button when only one breadcrumb item is sent as prop', async () => { + const page = await newSpecPage({ + components: [AtomBreadcrumb], + html: ``, + }) + + page.rootInstance.items = [breadcrumbItemsMock[0]] + + await page.waitForChanges() + + expect(page.root).toEqualHtml(` + + + + + + First level + + + + + + + `) + }) +}) diff --git a/packages/core/src/components/breadcrumb/breadcrumb.tsx b/packages/core/src/components/breadcrumb/breadcrumb.tsx new file mode 100644 index 000000000..85c2fe1ed --- /dev/null +++ b/packages/core/src/components/breadcrumb/breadcrumb.tsx @@ -0,0 +1,50 @@ +import { Component, h, Host, Prop } from '@stencil/core' + +type BreadcrumbItemProp = { + redirect?: (event: MouseEvent) => void + text: string + title: string +} + +@Component({ + tag: 'atom-breadcrumb', + styleUrl: 'breadcrumb.scss', + shadow: true, +}) +export class AtomBreadcrumb { + @Prop({ mutable: true }) items: BreadcrumbItemProp[] = [] + + render() { + const prevItem = this.items[this.items.length - 2] + + return ( + + {this.items.length > 1 && ( + + )} + + + {this.items.map((item) => ( + + + {item.text} + + + + ))} + + + ) + } +} diff --git a/packages/core/src/components/breadcrumb/stories/breadcrumb.args.ts b/packages/core/src/components/breadcrumb/stories/breadcrumb.args.ts new file mode 100644 index 000000000..e94512111 --- /dev/null +++ b/packages/core/src/components/breadcrumb/stories/breadcrumb.args.ts @@ -0,0 +1,25 @@ +import { Category } from '@atomium/storybook-utils/enums/table' + +export const BreadcrumbStoryArgs = { + decorators: [], + parameters: { + actions: { + handles: [], + }, + docs: { + description: { + component: + 'Breadcrumbs are navigation items that are used to indicate where a user is on site. Read the [Ionic documentation](https://ionicframework.com/docs/api/breadcrumbs) for more information about this component.', + }, + }, + }, + argTypes: { + items: { + description: + 'This is the list of items that will be displayed in the breadcrumb. Items must have `title` and `text` and optionally a `redirect` function when clicking on the item.', + table: { + category: Category.PROPERTIES, + }, + }, + }, +} diff --git a/packages/core/src/components/breadcrumb/stories/breadcrumb.core.stories.tsx b/packages/core/src/components/breadcrumb/stories/breadcrumb.core.stories.tsx new file mode 100644 index 000000000..b8f0d3380 --- /dev/null +++ b/packages/core/src/components/breadcrumb/stories/breadcrumb.core.stories.tsx @@ -0,0 +1,45 @@ +import { Meta, StoryObj } from '@storybook/web-components' + +import { html } from 'lit' + +import { BreadcrumbStoryArgs } from './breadcrumb.args' + +export default { + title: 'Components/Breadcrumb', + ...BreadcrumbStoryArgs, +} as Meta + +const createBreadcrumb = () => { + return html` + + + + ` +} + +export const Default: StoryObj = { + render: () => createBreadcrumb(), +} diff --git a/packages/core/src/components/breadcrumb/stories/breadcrumb.react.stories.tsx b/packages/core/src/components/breadcrumb/stories/breadcrumb.react.stories.tsx new file mode 100644 index 000000000..262551576 --- /dev/null +++ b/packages/core/src/components/breadcrumb/stories/breadcrumb.react.stories.tsx @@ -0,0 +1,37 @@ +import { Meta, StoryObj } from '@storybook/react' +import React from 'react' + +import { AtomBreadcrumb } from '@juntossomosmais/atomium/react' + +import { BreadcrumbStoryArgs } from './breadcrumb.args' + +export default { + title: 'Components/Breadcrumb', + ...BreadcrumbStoryArgs, +} as Meta + +const createBreadcrumb = (args) => ( + +) + +export const Default: StoryObj = { + render: (args) => createBreadcrumb(args), + args: { + items: [ + { + text: 'First level', + title: 'Go to first level', + redirect: () => console.log('/first'), + }, + { + text: 'Intermediary level', + title: 'Go to intermediary level', + redirect: () => console.log('/intermediary'), + }, + { + text: 'Current level', + title: 'This is the current level', + }, + ], + }, +} diff --git a/packages/icons/svg/mdi/arrow-right.svg b/packages/icons/svg/mdi/arrow-right.svg new file mode 100644 index 000000000..cb91467f0 --- /dev/null +++ b/packages/icons/svg/mdi/arrow-right.svg @@ -0,0 +1 @@ + diff --git a/packages/icons/svg/mdi/west.svg b/packages/icons/svg/mdi/west.svg new file mode 100644 index 000000000..2633b747e --- /dev/null +++ b/packages/icons/svg/mdi/west.svg @@ -0,0 +1 @@ + From 051b52eaed7573119e751f0e98571808bb222372 Mon Sep 17 00:00:00 2001 From: felipefialho Date: Wed, 19 Jul 2023 14:27:47 -0300 Subject: [PATCH 3/3] chore: remove husky to postinstall --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 65cbf9f5b..a257bbf3a 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "lint:styles": "stylelint '**/*.scss'", "icons:build": "npx nx build @juntossomosmais/atomium-icons", "icons:generate-types": "cd packages/icons && npm run generate:types", - "postinstall": "npx husky install & npx nx build @juntossomosmais/atomium:prebuild && npm run icons:build && npm run core:build && npm run tokens:build", + "postinstall": "npx nx build @juntossomosmais/atomium:prebuild && npm run icons:build && npm run core:build && npm run tokens:build", "pre-commit": "lint-staged", "prepare": "husky install", "react:build": "cd packages/react && npm run build",