├── .babelrc ├── .devcontainer └── devcontainer.json ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yaml │ └── feature-request.yaml ├── dependabot.yml └── workflows │ ├── codeql.yml │ └── deploy-storybook.yml ├── .gitignore ├── .npmrc ├── .storybook ├── main.js ├── manager-head.html ├── manager.js ├── preview-body.html ├── preview-head.html ├── preview.js ├── theme.js ├── tsconfig.json ├── typings.d.ts └── utils.ts ├── .vscode ├── extensions.json ├── launch.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── projects └── showcase │ ├── karma.conf.js │ ├── src │ ├── app │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── theme.service.spec.ts │ │ └── theme.service.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── material-theme.scss │ ├── polyfills.ts │ ├── styles.scss │ └── test.ts │ ├── tsconfig.app.json │ └── tsconfig.spec.json ├── public └── favicon.ico ├── stories ├── assets │ ├── arrow-next.svg │ ├── arrow-next_disabled.svg │ ├── arrow-previous.svg │ ├── arrow-previous_disabled.svg │ ├── code-brackets.svg │ ├── colors.svg │ ├── comments.svg │ ├── diamond.svg │ ├── direction.svg │ ├── flow.svg │ ├── image.png │ ├── logo.png │ ├── open_in_new.png │ ├── plugin.svg │ ├── repo.svg │ └── stackalt.svg ├── components │ ├── badge │ │ └── badge.argtype.ts │ ├── form-field │ │ ├── form-field-argtype.ts │ │ ├── form-field.mdx │ │ └── form-field.stories.ts │ ├── icon.mdx │ ├── icon.stories.ts │ ├── introduction.mdx │ ├── progress-bar │ │ ├── progress-bar.argtype.ts │ │ ├── progress-bar.mdx │ │ └── progress-bar.stories.ts │ ├── progress-spinner │ │ ├── progress-spinner.argtype.ts │ │ ├── progress-spinner.mdx │ │ └── progress-spinner.stories.ts │ └── table │ │ ├── table.argtype.ts │ │ ├── table.mdx │ │ └── table.stories.ts ├── introduction.mdx ├── theming-preview.jsx ├── theming-settings.jsx ├── theming.mdx └── usecases │ ├── authentication │ └── change-password │ │ ├── change-password.component.ts │ │ └── change-password.stories.ts │ ├── dialog │ ├── confirmation-dialog.component.ts │ └── confirmation-dialog.stories.ts │ ├── introduction.mdx │ ├── navigation │ ├── collapsible-vertical-navigation │ │ ├── collapsible-vertical-navigation.component.ts │ │ └── collapsible-vertical-navigation.stories.ts │ ├── fab-bottom-navigation │ │ ├── fab-bottom-navigation.component.ts │ │ └── fab-bottom-navigation.stories.ts │ └── fab-icon-menu │ │ ├── fab-icon-menu.component.ts │ │ └── fab-icon-menu.stories.ts │ ├── progress-indicators │ └── toolbar-loader.stories.ts │ └── settings │ ├── generic-settings.component.ts │ ├── generic-settings.stories.ts │ ├── wifi-settings.component.ts │ └── wifi-settings.stories.ts └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react", "@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/devcontainers/universal:2", 3 | "features": { 4 | "ghcr.io/devcontainers/features/node:1": {}, 5 | "ghcr.io/devcontainers-contrib/features/angular-cli:1": {} 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.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 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a bug in Angular Material Storybook project 3 | labels: 4 | - bug 5 | 6 | body: 7 | - type: dropdown 8 | id: is-regression 9 | attributes: 10 | label: Is this a regression? 11 | options: 12 | - 'Yes' 13 | - 'No' 14 | validations: 15 | required: true 16 | 17 | - type: textarea 18 | id: description 19 | attributes: 20 | label: Description 21 | validations: 22 | required: true 23 | 24 | - type: input 25 | id: reproduction 26 | attributes: 27 | label: Please provide a link to a minimal reproduction of the bug 28 | 29 | - type: textarea 30 | id: exception-or-error 31 | attributes: 32 | label: Please provide the exception or error you saw 33 | render: true 34 | 35 | - type: textarea 36 | id: environment 37 | attributes: 38 | label: Please provide the environment you discovered this bug in 39 | render: true 40 | 41 | - type: textarea 42 | id: other 43 | attributes: 44 | label: Anything else? 45 | 46 | - type: dropdown 47 | id: contribute 48 | attributes: 49 | label: Do you want to create a pull request? 50 | options: 51 | - 'Yes' 52 | - 'No' 53 | validations: 54 | required: true 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yaml: -------------------------------------------------------------------------------- 1 | name: 'Feature Request' 2 | description: Suggest a feature for Angular Material Storybook project 3 | 4 | body: 5 | 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | validations: 11 | required: true 12 | 13 | - type: textarea 14 | id: proposed-solution 15 | attributes: 16 | label: Proposed solution 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | id: alternatives-considered 22 | attributes: 23 | label: Alternatives considered 24 | 25 | - type: dropdown 26 | id: contribute 27 | attributes: 28 | label: Do you want to create a pull request? 29 | options: 30 | - 'Yes' 31 | - 'No' 32 | validations: 33 | required: true 34 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" # Location of package manifests 5 | schedule: 6 | interval: "weekly" 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '27 12 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /.github/workflows/deploy-storybook.yml: -------------------------------------------------------------------------------- 1 | name: Publish Storybook 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: actions/setup-node@v3 20 | with: 21 | node-version: "16" 22 | - name: Build Storybook 23 | run: | 24 | npm install 25 | npx ng run showcase:build-storybook 26 | - name: Upload artifact 27 | uses: actions/upload-pages-artifact@v1 28 | with: 29 | path: ./storybook-static 30 | # Deployment job 31 | deploy: 32 | environment: 33 | name: github-pages 34 | url: ${{ steps.deployment.outputs.page_url }} 35 | runs-on: ubuntu-latest 36 | needs: build 37 | steps: 38 | - name: Deploy to GitHub Pages 39 | id: deployment 40 | uses: actions/deploy-pages@v1 41 | -------------------------------------------------------------------------------- /.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 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | 44 | # Storybook 45 | documentation.json 46 | storybook-static 47 | build-storybook.log 48 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "stories": ["../stories/**/*.mdx", "../stories/**/*.stories.@(js|jsx|ts|tsx)"], 3 | "addons": ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions", "storybook-addon-rtl", "storybook-addon-pseudo-states", "@storybook/addon-a11y"], 4 | "framework": { 5 | name: "@storybook/angular", 6 | options: {} 7 | }, 8 | "staticDirs": ['../public', { 9 | from: "../stories/assets", 10 | to: "/static/assets" 11 | }], 12 | "features": { 13 | "interactionsDebugger": true 14 | }, 15 | "core": {}, 16 | // "docs": { 17 | // // You can change this value to `false` to remove all automaitcally generated Docs Pages 18 | // // We recommend instead to use them, and remove the "Overview" pages. 19 | // // But there might be some features/content missing, so you be the judge. 20 | // // For more information take a look here: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#docs-page 21 | // "docsPage": "automatic", 22 | // }, 23 | docs: { 24 | autodocs: true 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /.storybook/manager-head.html: -------------------------------------------------------------------------------- 1 | 2 | 15 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from "@storybook/manager-api"; 2 | import theme from "./theme"; 3 | 4 | addons.setConfig({ 5 | theme: theme, 6 | }); 7 | -------------------------------------------------------------------------------- /.storybook/preview-body.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | 209 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import {setCompodocJson} from "@storybook/addon-docs/angular"; 2 | import docJson from "../documentation.json"; 3 | import { initializeRTL } from 'storybook-addon-rtl'; 4 | import { componentWrapperDecorator } from '@storybook/angular'; 5 | 6 | setCompodocJson(docJson); 7 | initializeRTL(); 8 | 9 | export const parameters = { 10 | actions: {argTypesRegex: "^on[A-Z].*"}, 11 | controls: { 12 | matchers: { 13 | color: /(background|color)$/i, 14 | date: /Date$/, 15 | }, 16 | }, 17 | viewMode: 'story', 18 | docs: {inlineStories: true}, 19 | direction: 'ltr', 20 | layout: 'fullscreen', 21 | backgrounds: { disable: true } 22 | } 23 | 24 | export const decorators = [ 25 | componentWrapperDecorator((story) => `
${story}
`), 26 | ]; 27 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import { create } from '@storybook/theming'; 2 | import CoverImage from '../stories/assets/logo.png'; 3 | 4 | export default create({ 5 | base: 'light', 6 | brandTitle: 'Angular Material Storybook', 7 | brandUrl: 'https://github.com/geromegrignon/angular-material-storybook', 8 | brandImage: CoverImage, 9 | brandTarget: '_self', 10 | 11 | barSelectedColor: 'rgba(0,68,85,1)', 12 | colorSecondary: 'rgba(0,68,85,1)', 13 | }); 14 | -------------------------------------------------------------------------------- /.storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "allowSyntheticDefaultImports": true, 5 | "types": [ 6 | "node", 7 | "jest", 8 | "testing-library__jest-dom", 9 | ], 10 | }, 11 | "exclude": [ 12 | "../src/test.ts", 13 | "../src/**/*.spec.ts", 14 | "../projects/**/*.spec.ts" 15 | ], 16 | "include": [ 17 | "../src/**/*", 18 | "../projects/**/*", 19 | "../stories/**/*" 20 | ], 21 | "files": [ 22 | "./typings.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.storybook/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md' { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /.storybook/utils.ts: -------------------------------------------------------------------------------- 1 | export const defaultUsecasesParameters = { 2 | options: { 3 | showPanel: false 4 | }, 5 | previewTabs: { 6 | 'storybook/docs/panel': { 7 | hidden: true 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | gerome.grignon.lp2@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Welcome on this project! 4 | These guidelines will help you to contribute. 5 | 6 | 7 | ## Contribution opportunities 8 | 9 | ### Add components examples 10 | 11 | The components part of the project showcases sample examples of Angular Material components in isolation. 12 | Some components or valuables examples might be missing as you are reading this. 13 | 14 | #### Add a missing component 15 | 16 | Create a folder matching the component name and using kebab-case format in the `stories/components` folder. 17 | For example a foldernamed `radio-button` for the Radio button component. 18 | 19 | Create a `.argtype.ts` file in this new folder. 20 | It'll define argtypes for the component for the ArgTable and Controls features. 21 | 22 | Create a `.stories.mdx` file in the same folder. 23 | It'll provide an overview of the component : 24 | - quick introduction 25 | - how to add it in an Angular application 26 | - link towards the official documentation 27 | - showcase stories 28 | 29 | Create a `.stories.ts` for stories. 30 | 31 | #### Add stories 32 | 33 | 34 | ### Add component use cases 35 | 36 | Showcase Angular Material working together in a real world situation. 37 | The limit is the sky but 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Gerome Grignon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Material Storybook 2 | 3 | This project is a collection of Angular Components showcased in isolation and in action with Storybook. 4 | 5 | ## Run the project locally 6 | 7 | Install dependancies 8 | ``` 9 | npm install 10 | ``` 11 | 12 | Run Storybook 13 | ``` 14 | ng run showcase:storybook 15 | ``` 16 | 17 | ## Contribute 18 | 19 | > Guidances in progress 20 | 21 | You can contribute by adding **Components** and **Usecases** 22 | 23 | ## Known bugs 24 | 25 | #### Canvas 26 | > error triggered by using `` 27 | [GitHub issue](https://github.com/storybookjs/storybook/issues/17269) 28 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "showcase": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "projects/showcase", 14 | "sourceRoot": "projects/showcase/src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/showcase", 21 | "index": "projects/showcase/src/index.html", 22 | "main": "projects/showcase/src/main.ts", 23 | "polyfills": "projects/showcase/src/polyfills.ts", 24 | "tsConfig": "projects/showcase/tsconfig.app.json", 25 | "inlineStyleLanguage": "scss", 26 | "assets": [ 27 | "projects/showcase/src/favicon.ico", 28 | "projects/showcase/src/assets" 29 | ], 30 | "styles": [ 31 | "projects/showcase/src/styles.scss" 32 | ], 33 | "scripts": [], 34 | "allowedCommonJsDependencies": [ 35 | "tinycolor2" 36 | ] 37 | }, 38 | "configurations": { 39 | "production": { 40 | "budgets": [ 41 | { 42 | "type": "initial", 43 | "maximumWarning": "500kb", 44 | "maximumError": "1mb" 45 | }, 46 | { 47 | "type": "anyComponentStyle", 48 | "maximumWarning": "2kb", 49 | "maximumError": "4kb" 50 | } 51 | ], 52 | "fileReplacements": [ 53 | { 54 | "replace": "projects/showcase/src/environments/environment.ts", 55 | "with": "projects/showcase/src/environments/environment.prod.ts" 56 | } 57 | ], 58 | "outputHashing": "all" 59 | }, 60 | "development": { 61 | "buildOptimizer": false, 62 | "optimization": false, 63 | "vendorChunk": true, 64 | "extractLicenses": false, 65 | "sourceMap": true, 66 | "namedChunks": true 67 | } 68 | }, 69 | "defaultConfiguration": "production" 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "configurations": { 74 | "production": { 75 | "browserTarget": "showcase:build:production" 76 | }, 77 | "development": { 78 | "browserTarget": "showcase:build:development" 79 | } 80 | }, 81 | "defaultConfiguration": "development" 82 | }, 83 | "extract-i18n": { 84 | "builder": "@angular-devkit/build-angular:extract-i18n", 85 | "options": { 86 | "browserTarget": "showcase:build" 87 | } 88 | }, 89 | "test": { 90 | "builder": "@angular-devkit/build-angular:karma", 91 | "options": { 92 | "main": "projects/showcase/src/test.ts", 93 | "polyfills": "projects/showcase/src/polyfills.ts", 94 | "tsConfig": "projects/showcase/tsconfig.spec.json", 95 | "karmaConfig": "projects/showcase/karma.conf.js", 96 | "inlineStyleLanguage": "scss", 97 | "assets": [ 98 | "projects/showcase/src/assets" 99 | ], 100 | "styles": [ 101 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 102 | "projects/showcase/src/styles.scss" 103 | ], 104 | "scripts": [] 105 | } 106 | }, 107 | "storybook": { 108 | "builder": "@storybook/angular:start-storybook", 109 | "options": { 110 | "browserTarget": "showcase:build", 111 | "port": 6006 112 | } 113 | }, 114 | "build-storybook": { 115 | "builder": "@storybook/angular:build-storybook", 116 | "options": { 117 | "browserTarget": "showcase:build" 118 | } 119 | } 120 | } 121 | } 122 | }, 123 | "cli": { 124 | "analytics": "5e49e647-b64f-4051-b56c-774f5b25b1b9" 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-material-storybook", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test", 10 | "docs:json": "compodoc -p ./tsconfig.json -e json -d .", 11 | "storybook": "npm run docs:json && storybook dev -p 6006", 12 | "build-storybook": "npm run docs:json && storybook build", 13 | "chromatic": "npx chromatic --project-token=2475ac9ed750" 14 | }, 15 | "private": true, 16 | "dependencies": { 17 | "@angular/animations": "^15.2.0", 18 | "@angular/cdk": "^15.2.0", 19 | "@angular/common": "^15.2.0", 20 | "@angular/compiler": "^15.2.0", 21 | "@angular/core": "^15.2.0", 22 | "@angular/forms": "^15.2.0", 23 | "@angular/material": "^15.2.0", 24 | "@angular/platform-browser": "^15.2.0", 25 | "@angular/platform-browser-dynamic": "^15.2.0", 26 | "@angular/router": "^15.2.0", 27 | "rxjs": "~7.5.7", 28 | "tinycolor2": "^1.4.2", 29 | "tslib": "^2.4.1", 30 | "zone.js": "~0.12.0" 31 | }, 32 | "devDependencies": { 33 | "@angular-devkit/build-angular": "^15.2.0", 34 | "@angular/cli": "~15.2.0", 35 | "@angular/compiler-cli": "^15.2.0", 36 | "@babel/core": "^7.21.0", 37 | "@babel/plugin-syntax-jsx": "^7.18.6", 38 | "@babel/preset-env": "^7.20.2", 39 | "@babel/preset-react": "^7.18.6", 40 | "@compodoc/compodoc": "^1.1.19", 41 | "@storybook/addon-a11y": "^7.0.0-beta.55", 42 | "@storybook/addon-actions": "^7.0.0-beta.55", 43 | "@storybook/addon-docs": "^7.0.0-beta.55", 44 | "@storybook/addon-essentials": "^7.0.0-beta.55", 45 | "@storybook/addon-interactions": "^7.0.0-beta.55", 46 | "@storybook/addon-links": "^7.0.0-beta.55", 47 | "@storybook/angular": "^7.0.0-beta.55", 48 | "@storybook/jest": "^0.0.11-next.0", 49 | "@storybook/manager-api": "^7.0.0-beta.55", 50 | "@storybook/testing-library": "^0.0.14-next.1", 51 | "@storybook/theming": "^7.0.0-beta.55", 52 | "@types/jasmine": "~4.3.0", 53 | "@types/tinycolor2": "^1.4.3", 54 | "babel-loader": "^9.1.0", 55 | "chromatic": "^6.14.0", 56 | "jasmine-core": "~4.5.0", 57 | "karma": "~6.4.1", 58 | "karma-chrome-launcher": "~3.1.0", 59 | "karma-coverage": "~2.2.0", 60 | "karma-jasmine": "~5.1.0", 61 | "karma-jasmine-html-reporter": "~2.0.0", 62 | "react": "^18.2.0", 63 | "react-dom": "^18.2.0", 64 | "storybook": "^7.0.0-beta.55", 65 | "storybook-addon-pseudo-states": "^2.0.0-next.0", 66 | "storybook-addon-rtl": "^0.4.4", 67 | "typescript": "~4.8.4" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /projects/showcase/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'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, '../../coverage/showcase'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /projects/showcase/src/app/app.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/projects/showcase/src/app/app.component.html -------------------------------------------------------------------------------- /projects/showcase/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/projects/showcase/src/app/app.component.scss -------------------------------------------------------------------------------- /projects/showcase/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import {ThemeService} from "./theme.service"; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.scss'] 8 | }) 9 | export class AppComponent { 10 | constructor(private readonly themeService: ThemeService) { 11 | themeService.saveIndigoPreset(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /projects/showcase/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppComponent } from './app.component'; 5 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | imports: [ 12 | BrowserModule, 13 | BrowserAnimationsModule 14 | ], 15 | providers: [], 16 | bootstrap: [AppComponent] 17 | }) 18 | export class AppModule { } 19 | -------------------------------------------------------------------------------- /projects/showcase/src/app/theme.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ThemeService } from './theme.service'; 4 | 5 | describe('ThemeService', () => { 6 | let service: ThemeService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(ThemeService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /projects/showcase/src/app/theme.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import * as tinycolor from "tinycolor2"; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class ThemeService { 8 | 9 | constructor() { } 10 | 11 | saveLightPrimaryColor = (color: string) => { 12 | const primaryColorPalette = this.computeColors(color); 13 | this.updateTheme(primaryColorPalette, 'primary', 'light'); 14 | } 15 | 16 | saveLightAccentColor(color: string) { 17 | const accentColorPalette = this.computeColors(color); 18 | this.updateTheme(accentColorPalette, 'accent', 'light'); 19 | } 20 | 21 | saveLightWarnColor(color: string) { 22 | const warnColorPalette = this.computeColors(color); 23 | this.updateTheme(warnColorPalette, 'warn', 'light'); 24 | } 25 | 26 | saveDarkPrimaryColor(color: string) { 27 | const primaryColorPalette = this.computeColors(color); 28 | this.updateTheme(primaryColorPalette, 'primary', 'dark'); 29 | } 30 | 31 | saveDarkAccentColor(color: string) { 32 | const accentColorPalette = this.computeColors(color); 33 | this.updateTheme(accentColorPalette, 'accent', 'dark'); 34 | } 35 | 36 | saveDarktWarnColor(color: string) { 37 | const warnColorPalette = this.computeColors(color); 38 | this.updateTheme(warnColorPalette, 'warn', 'dark'); 39 | } 40 | 41 | saveIndigoPreset() { 42 | this.saveLightPrimaryColor('#3f51b5'); 43 | this.saveLightAccentColor('#ff4081'); 44 | this.saveLightWarnColor('#f44336'); 45 | } 46 | 47 | saveDeepPurplePreset() { 48 | this.saveLightPrimaryColor('#673ab7'); 49 | this.saveLightAccentColor('#ffd740'); 50 | this.saveLightWarnColor('#f44336'); 51 | } 52 | 53 | savePinkPreset() { 54 | this.saveLightPrimaryColor('#e91e63'); 55 | this.saveLightAccentColor('#607d8b'); 56 | this.saveLightWarnColor('#f44336'); 57 | } 58 | 59 | savePurplePreset() { 60 | this.saveLightPrimaryColor('#9c27b0'); 61 | this.saveLightAccentColor('#69f0ae'); 62 | this.saveLightWarnColor('#f44336'); 63 | } 64 | 65 | toggleDarkTheme() { 66 | document.documentElement.classList.toggle('dark-theme'); 67 | } 68 | 69 | updateTheme(colors: any[], theme: any, mode: any) { 70 | colors.forEach(color => { 71 | document.body.style.setProperty( 72 | `--${mode}-theme-${theme}-${color.name}`, 73 | color.hex 74 | ); 75 | document.body.style.setProperty( 76 | `--${mode}-theme-${theme}-contrast-${color.name}`, 77 | color.darkContrast ? 'black' : 'white' 78 | ); 79 | }); 80 | } 81 | 82 | computeColors(hex: any) { 83 | return [ 84 | this.getColorObject(tinycolor(hex).lighten(52), '50'), 85 | this.getColorObject(tinycolor(hex).lighten(37), '100'), 86 | this.getColorObject(tinycolor(hex).lighten(26), '200'), 87 | this.getColorObject(tinycolor(hex).lighten(12), '300'), 88 | this.getColorObject(tinycolor(hex).lighten(6), '400'), 89 | this.getColorObject(tinycolor(hex), '500'), 90 | this.getColorObject(tinycolor(hex).darken(6), '600'), 91 | this.getColorObject(tinycolor(hex).darken(12), '700'), 92 | this.getColorObject(tinycolor(hex).darken(18), '800'), 93 | this.getColorObject(tinycolor(hex).darken(24), '900'), 94 | this.getColorObject(tinycolor(hex).lighten(50).saturate(30), 'A100'), 95 | this.getColorObject(tinycolor(hex).lighten(30).saturate(30), 'A200'), 96 | this.getColorObject(tinycolor(hex).lighten(10).saturate(15), 'A400'), 97 | this.getColorObject(tinycolor(hex).lighten(5).saturate(5), 'A700') 98 | ]; 99 | } 100 | 101 | getColorObject(value: any, name: any) { 102 | const c = tinycolor(value); 103 | return { 104 | name: name, 105 | hex: c.toHexString(), 106 | darkContrast: c.isLight() 107 | }; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /projects/showcase/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/projects/showcase/src/assets/.gitkeep -------------------------------------------------------------------------------- /projects/showcase/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /projects/showcase/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` 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/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /projects/showcase/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/projects/showcase/src/favicon.ico -------------------------------------------------------------------------------- /projects/showcase/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Showcase 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /projects/showcase/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 | -------------------------------------------------------------------------------- /projects/showcase/src/material-theme.scss: -------------------------------------------------------------------------------- 1 | @use '@angular/material' as mat; 2 | @import '@angular/material/theming'; 3 | 4 | // Light theme 5 | 6 | $light-theme-primary: ( 7 | 50 : var(--light-theme-primary-50, #8ae7ff), 8 | 100 : var(--light-theme-primary-100, #3ed8ff), 9 | 200 : var(--light-theme-primary-200, #06ccff), 10 | 300 : var(--light-theme-primary-300, #0097bd), 11 | 400 : var(--light-theme-primary-400, #007e9f), 12 | 500 : var(--light-theme-primary-500, #006680), 13 | 600 : var(--light-theme-primary-600, #004e61), 14 | 700 : var(--light-theme-primary-700, #003543), 15 | 800 : var(--light-theme-primary-800, #001d24), 16 | 900 : var(--light-theme-primary-900, #000406), 17 | A100 : var(--light-theme-primary-A100, #80e5ff), 18 | A200 : var(--light-theme-primary-A200, #1ad0ff), 19 | A400 : var(--light-theme-primary-A400, #008fb3), 20 | A700 : var(--light-theme-primary-A700, #007a99), 21 | contrast: ( 22 | 50: var(--light-theme-primary-contrast-50, black), 23 | 100: var(--light-theme-primary-contrast-100, black), 24 | 200: var(--light-theme-primary-contrast-200, black), 25 | 300: var(--light-theme-primary-contrast-300, white), 26 | 400: var(--light-theme-primary-contrast-400, white), 27 | 500: var(--light-theme-primary-contrast-500, white), 28 | 600: var(--light-theme-primary-contrast-600, white), 29 | 700: var(--light-theme-primary-contrast-700, white), 30 | 800: var(--light-theme-primary-contrast-800, white), 31 | 900: var(--light-theme-primary-contrast-900, white), 32 | A100: var(--light-theme-primary-contrast-A100, black), 33 | A200: var(--light-theme-primary-contrast-A200, black), 34 | A400: var(--light-theme-primary-contrast-A400, white), 35 | A700: var(--light-theme-primary-contrast-A700, white), 36 | ) 37 | ); 38 | 39 | $light-theme-accent: ( 40 | 50 : var(--light-theme-accent-50, #ffffff), 41 | 100 : var(--light-theme-accent-100, #fef2e6), 42 | 200 : var(--light-theme-accent-200, #fbd6b0), 43 | 300 : var(--light-theme-accent-300, #f8b26c), 44 | 400 : var(--light-theme-accent-400, #f6a34f), 45 | 500 : var(--light-theme-accent-500, #f59432), 46 | 600 : var(--light-theme-accent-600, #f48515), 47 | 700 : var(--light-theme-accent-700, #df750b), 48 | 800 : var(--light-theme-accent-800, #c26609), 49 | 900 : var(--light-theme-accent-900, #a55708), 50 | A100 : var(--light-theme-accent-A100, #ffffff), 51 | A200 : var(--light-theme-accent-A200, #ffe0c1), 52 | A400 : var(--light-theme-accent-A400, #ffad5b), 53 | A700 : var(--light-theme-accent-A700, #fba146), 54 | contrast: ( 55 | 50: var(--light-theme-accent-contrast-50, black), 56 | 100: var(--light-theme-accent-contrast-100, black), 57 | 200: var(--light-theme-accent-contrast-200, black), 58 | 300: var(--light-theme-accent-contrast-300, black), 59 | 400: var(--light-theme-accent-contrast-400, black), 60 | 500: var(--light-theme-accent-contrast-500, black), 61 | 600: var(--light-theme-accent-contrast-60, black), 62 | 700: var(--light-theme-accent-contrast-700, black), 63 | 800: var(--light-theme-accent-contrast-800, white), 64 | 900: var(--light-theme-accent-contrast-900, white), 65 | A100: var(--light-theme-accent-contrast-A100, black), 66 | A200: var(--light-theme-accent-contrast-A200, black), 67 | A400: var(--light-theme-accent-contrast-A400, black), 68 | A700: var(--light-theme-accent-contrast-A700, black), 69 | ) 70 | ); 71 | 72 | $light-theme-warn: ( 73 | 50 : var(--light-theme-warn-50, #ffffff), 74 | 100 : var(--light-theme-warn-100, #feeae9), 75 | 200 : var(--light-theme-warn-200, #fbb9b4), 76 | 300 : var(--light-theme-warn-300, #f77970), 77 | 400 : var(--light-theme-warn-400, #f65e53), 78 | 500 : var(--light-theme-warn-500, #f44336), 79 | 600 : var(--light-theme-warn-600, #f22819), 80 | 700 : var(--light-theme-warn-700, #e11b0c), 81 | 800 : var(--light-theme-warn-800, #c3170b), 82 | 900 : var(--light-theme-warn-900, #a61409), 83 | A100 : var(--light-theme-warn-A100, #ffffff), 84 | A200 : var(--light-theme-warn-A200, #ffc8c4), 85 | A400 : var(--light-theme-warn-A400, #ff695e), 86 | A700 : var(--light-theme-warn-A700, #fa564a), 87 | contrast: ( 88 | 50: var(--light-theme-warn-contrast-50, rgba(black, 0.87)), 89 | 100: var(--light-theme-warn-contrast-100, rgba(black, 0.87)), 90 | 200: var(--light-theme-warn-contrast-200, rgba(black, 0.87)), 91 | 300: var(--light-theme-warn-contrast-300, rgba(black, 0.87)), 92 | 400: var(--light-theme-warn-contrast-400, rgba(black, 0.87)), 93 | 500: var(--light-theme-warn-contrast-500, white), 94 | 600: var(--light-theme-warn-contrast-600, white), 95 | 700: var(--light-theme-warn-contrast-700, white), 96 | 800: var(--light-theme-warn-contrast-800, white), 97 | 900: var(--light-theme-warn-contrast-900, white), 98 | A100: var(--light-theme-warn-contrast-A100, rgba(black, 0.87)), 99 | A200: var(--light-theme-warn-contrast-A200, rgba(black, 0.87)), 100 | A400: var(--light-theme-warn-contrast-A400, rgba(black, 0.87)), 101 | A700: var(--light-theme-warn-contrast-A700, rgba(black, 0.87)), 102 | ) 103 | ); 104 | 105 | // Dark theme 106 | 107 | $dark-theme-primary: ( 108 | 50 : var(--dark-theme-primary-50, #8ae7ff), 109 | 100 : var(--dark-theme-primary-100, #3ed8ff), 110 | 200 : var(--dark-theme-primary-200, #06ccff), 111 | 300 : var(--dark-theme-primary-300, #0097bd), 112 | 400 : var(--dark-theme-primary-400, #007e9f), 113 | 500 : var(--dark-theme-primary-500, #006680), 114 | 600 : var(--dark-theme-primary-600, #004e61), 115 | 700 : var(--dark-theme-primary-700, #003543), 116 | 800 : var(--dark-theme-primary-800, #001d24), 117 | 900 : var(--dark-theme-primary-900, #000406), 118 | A100 : var(--dark-theme-primary-A100, #80e5ff), 119 | A200 : var(--dark-theme-primary-A200, #1ad0ff), 120 | A400 : var(--dark-theme-primary-A400, #008fb3), 121 | A700 : var(--dark-theme-primary-A700, #007a99), 122 | contrast: ( 123 | 50: var(--dark-theme-primary-contrast-50, black), 124 | 100: var(--dark-theme-primary-contrast-100, black), 125 | 200: var(--dark-theme-primary-contrast-200, black), 126 | 300: var(--dark-theme-primary-contrast-300, white), 127 | 400: var(--dark-theme-primary-contrast-400, white), 128 | 500: var(--dark-theme-primary-contrast-500, white), 129 | 600: var(--dark-theme-primary-contrast-600, white), 130 | 700: var(--dark-theme-primary-contrast-700, white), 131 | 800: var(--dark-theme-primary-contrast-800, white), 132 | 900: var(--dark-theme-primary-contrast-900, white), 133 | A100: var(--dark-theme-primary-contrast-A100, black), 134 | A200: var(--dark-theme-primary-contrast-A200, black), 135 | A400: var(--dark-theme-primary-contrast-A400, white), 136 | A700: var(--dark-theme-primary-contrast-A700, white), 137 | ) 138 | ); 139 | 140 | $dark-theme-accent: ( 141 | 50 : var(--dark-theme-accent-50, #ffffff), 142 | 100 : var(--dark-theme-accent-100, #fef2e6), 143 | 200 : var(--dark-theme-accent-200, #fbd6b0), 144 | 300 : var(--dark-theme-accent-300, #f8b26c), 145 | 400 : var(--dark-theme-accent-400, #f6a34f), 146 | 500 : var(--dark-theme-accent-500, #f59432), 147 | 600 : var(--dark-theme-accent-600, #f48515), 148 | 700 : var(--dark-theme-accent-700, #df750b), 149 | 800 : var(--dark-theme-accent-800, #c26609), 150 | 900 : var(--dark-theme-accent-900, #a55708), 151 | A100 : var(--dark-theme-accent-A100, #ffffff), 152 | A200 : var(--dark-theme-accent-A200, #ffe0c1), 153 | A400 : var(--dark-theme-accent-A400, #ffad5b), 154 | A700 : var(--dark-theme-accent-A700, #fba146), 155 | contrast: ( 156 | 50: var(--dark-theme-accent-contrast-50, black), 157 | 100: var(--dark-theme-accent-contrast-100, black), 158 | 200: var(--dark-theme-accent-contrast-200, black), 159 | 300: var(--dark-theme-accent-contrast-300, black), 160 | 400: var(--dark-theme-accent-contrast-400, black), 161 | 500: var(--dark-theme-accent-contrast-500, black), 162 | 600: var(--dark-theme-accent-contrast-60, black), 163 | 700: var(--dark-theme-accent-contrast-700, black), 164 | 800: var(--dark-theme-accent-contrast-800, white), 165 | 900: var(--dark-theme-accent-contrast-900, white), 166 | A100: var(--dark-theme-accent-contrast-A100, black), 167 | A200: var(--dark-theme-accent-contrast-A200, black), 168 | A400: var(--dark-theme-accent-contrast-A400, black), 169 | A700: var(--dark-theme-accent-contrast-A700, black), 170 | ) 171 | ); 172 | 173 | $dark-theme-warn: ( 174 | 50 : var(--dark-theme-warn-50, #ffffff), 175 | 100 : var(--dark-theme-warn-100, #feeae9), 176 | 200 : var(--dark-theme-warn-200, #fbb9b4), 177 | 300 : var(--dark-theme-warn-300, #f77970), 178 | 400 : var(--dark-theme-warn-400, #f65e53), 179 | 500 : var(--dark-theme-warn-500, #f44336), 180 | 600 : var(--dark-theme-warn-600, #f22819), 181 | 700 : var(--dark-theme-warn-700, #e11b0c), 182 | 800 : var(--dark-theme-warn-800, #c3170b), 183 | 900 : var(--dark-theme-warn-900, #a61409), 184 | A100 : var(--dark-theme-warn-A100, #ffffff), 185 | A200 : var(--dark-theme-warn-A200, #ffc8c4), 186 | A400 : var(--dark-theme-warn-A400, #ff695e), 187 | A700 : var(--dark-theme-warn-A700, #fa564a), 188 | contrast: ( 189 | 50: var(--dark-theme-warn-contrast-50, rgba(black, 0.87)), 190 | 100: var(--dark-theme-warn-contrast-100, rgba(black, 0.87)), 191 | 200: var(--dark-theme-warn-contrast-200, rgba(black, 0.87)), 192 | 300: var(--dark-theme-warn-contrast-300, rgba(black, 0.87)), 193 | 400: var(--dark-theme-warn-contrast-400, rgba(black, 0.87)), 194 | 500: var(--dark-theme-warn-contrast-500, white), 195 | 600: var(--dark-theme-warn-contrast-600, white), 196 | 700: var(--dark-theme-warn-contrast-700, white), 197 | 800: var(--dark-theme-warn-contrast-800, white), 198 | 900: var(--dark-theme-warn-contrast-900, white), 199 | A100: var(--dark-theme-warn-contrast-A100, rgba(black, 0.87)), 200 | A200: var(--dark-theme-warn-contrast-A200, rgba(black, 0.87)), 201 | A400: var(--dark-theme-warn-contrast-A400, rgba(black, 0.87)), 202 | A700: var(--dark-theme-warn-contrast-A700, rgba(black, 0.87)), 203 | ) 204 | ); 205 | /* 206 | $dynamic-light-theme-background: ( 207 | status-bar: map_get(mat.$grey-palette, 300), 208 | app-bar: map_get(mat.$grey-palette, 100), 209 | background: map_get(mat.$grey-palette, 50), 210 | hover: rgba(black, 0.04), 211 | card: white, 212 | dialog: white, 213 | disabled-button: rgba(black, 0.12), 214 | raised-button: white, 215 | focused-button: $dark-focused, 216 | selected-button: map_get(mat.$grey-palette, 300), 217 | selected-disabled-button: map_get(mat.$grey-palette, 400), 218 | disabled-button-toggle: map_get(mat.$grey-palette, 200), 219 | unselected-chip: map_get(mat.$grey-palette, 300), 220 | disabled-list-option: map_get(mat.$grey-palette, 200), 221 | ); 222 | 223 | $dynamic-light-theme-foreground: ( 224 | base: black, 225 | divider: $dark-dividers, 226 | dividers: $dark-dividers, 227 | disabled: $dark-disabled-text, 228 | disabled-button: rgba(black, 0.26), 229 | disabled-text: $dark-disabled-text, 230 | elevation: black, 231 | hint-text: $dark-disabled-text, 232 | secondary-text: $dark-secondary-text, 233 | icon: rgba(black, 0.54), 234 | icons: rgba(black, 0.54), 235 | text: rgba(black, 0.87), 236 | slider-min: rgba(black, 0.87), 237 | slider-off: rgba(black, 0.26), 238 | slider-off-active: rgba(black, 0.38), 239 | ); 240 | 241 | 242 | 243 | $dynamic-app-theme: ( 244 | primary: mat.define-palette($dynamic-theme-primary), 245 | accent: mat.define-palette($dynamic-theme-accent), 246 | warn: mat.define-palette($dynamic-theme-warn), 247 | is-dark: false, 248 | foreground: $dynamic-light-theme-foreground, 249 | background: $dynamic-light-theme-background 250 | ); 251 | 252 | */ 253 | $dynamic-typography: mat.define-typography-config( 254 | $font-family: 'Roboto, "Helvetica Neue", sans-serif', 255 | $headline-1: mat.define-typography-level(112px, 112px, 300, $letter-spacing: -0.05em), 256 | $headline-2: mat.define-typography-level(56px, 56px, 400, $letter-spacing: -0.02em), 257 | $headline-3: mat.define-typography-level(45px, 48px, 400, $letter-spacing: -0.005em), 258 | $headline-4: mat.define-typography-level(34px, 40px, 400), 259 | $headline-5: mat.define-typography-level(24px, 32px, 400), 260 | $headline-6: mat.define-typography-level(20px, 32px, 500), 261 | $subtitle-1: mat.define-typography-level(16px, 28px, 400), 262 | $body-1: mat.define-typography-level(15px, 24px, 400), 263 | $subtitle-2: mat.define-typography-level(14px, 24px, 500), 264 | $body-2: mat.define-typography-level(14px, 20px, 400), 265 | $caption: mat.define-typography-level(12px, 20px, 400), 266 | $button: mat.define-typography-level(14px, 14px, 500), 267 | ); 268 | -------------------------------------------------------------------------------- /projects/showcase/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 recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /projects/showcase/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | @use '@angular/material' as mat; 3 | @import './material-theme'; 4 | 5 | @include mat.all-component-typographies(); 6 | @include mat.core(); 7 | 8 | $light-primary: mat.define-palette($light-theme-primary); 9 | $light-accent: mat.define-palette($light-theme-accent); 10 | $light-warn: mat.define-palette($light-theme-warn); 11 | 12 | $light-theme: mat.define-light-theme(( 13 | color: ( 14 | primary: $light-primary, 15 | accent: $light-accent, 16 | warn: $light-warn, 17 | ) 18 | )); 19 | 20 | $dark-primary: mat.define-palette($dark-theme-primary); 21 | $dark-accent: mat.define-palette($dark-theme-accent); 22 | $dark-warn: mat.define-palette($dark-theme-warn); 23 | 24 | $dark-theme: mat.define-dark-theme(( 25 | color: ( 26 | primary: $dark-primary, 27 | accent: $dark-accent, 28 | warn: $dark-warn, 29 | ) 30 | )); 31 | 32 | @include mat.core-theme($light-theme); 33 | @include mat.all-component-themes($light-theme); 34 | 35 | html, body { height: 100%; } 36 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 37 | 38 | .dark-theme { 39 | @include mat.core-color($dark-theme); 40 | @include mat.all-component-colors($dark-theme); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /projects/showcase/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/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | // First, initialize the Angular testing environment. 11 | getTestBed().initTestEnvironment( 12 | BrowserDynamicTestingModule, 13 | platformBrowserDynamicTesting(), 14 | ); 15 | -------------------------------------------------------------------------------- /projects/showcase/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 | // "**/*.stories.*" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/showcase/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../../out-tsc/spec", 6 | "types": [ 7 | "jasmine" 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 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/public/favicon.ico -------------------------------------------------------------------------------- /stories/assets/arrow-next.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stories/assets/arrow-next_disabled.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stories/assets/arrow-previous.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stories/assets/arrow-previous_disabled.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stories/assets/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /stories/assets/colors.svg: -------------------------------------------------------------------------------- 1 | illustration/colors -------------------------------------------------------------------------------- /stories/assets/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /stories/assets/diamond.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stories/assets/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /stories/assets/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /stories/assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/stories/assets/image.png -------------------------------------------------------------------------------- /stories/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/stories/assets/logo.png -------------------------------------------------------------------------------- /stories/assets/open_in_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-sanctuary/angular-material-storybook/bca464f8403b1bd0d85560c6ed8e93c547931a0b/stories/assets/open_in_new.png -------------------------------------------------------------------------------- /stories/assets/plugin.svg: -------------------------------------------------------------------------------- 1 | illustration/plugin -------------------------------------------------------------------------------- /stories/assets/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /stories/assets/stackalt.svg: -------------------------------------------------------------------------------- 1 | illustration/stackalt -------------------------------------------------------------------------------- /stories/components/badge/badge.argtype.ts: -------------------------------------------------------------------------------- 1 | export const badgeArgtypes = { 2 | matBadge: { 3 | description: 'The content for the badge', 4 | defaultValue: '3', 5 | table: { 6 | type: { summary: 'text' }, 7 | defaultValue: { summary: '3' }, 8 | }, 9 | control: { 10 | type: 'text' 11 | } 12 | }, 13 | matBadgeDescription: { 14 | description: 'Message used to describe the decorated element via aria-describedby', 15 | defaultValue: '', 16 | control: { 17 | type: 'text' 18 | } 19 | }, 20 | matBadgeDisabled: { 21 | description: 'Whether the component is disabled', 22 | defaultValue: false, 23 | table: { 24 | type: { summary: 'boolean' }, 25 | defaultValue: { summary: false }, 26 | }, 27 | control: { 28 | type: 'boolean' 29 | } 30 | }, 31 | matBadgeHidden: { 32 | description: 'Whether the badge is hidden', 33 | defaultValue: false, 34 | table: { 35 | type: { summary: 'boolean' }, 36 | defaultValue: { summary: false }, 37 | }, 38 | control: { 39 | type: 'boolean' 40 | } 41 | }, 42 | matBadgeOverlap: { 43 | description: 'Whether the badge should overlap its contents or not', 44 | defaultValue: true, 45 | table: { 46 | type: { summary: 'boolean' }, 47 | defaultValue: { summary: true }, 48 | }, 49 | control: { 50 | type: 'boolean' 51 | } 52 | }, 53 | matBadgePosition: { 54 | description: 'Position the badge should reside', 55 | control: 'select', 56 | defaultValue: 'above after', 57 | table: { 58 | defaultValue: { summary: 'above after' }, 59 | }, 60 | options: [ 61 | 'before', 62 | 'after', 63 | 'above', 64 | 'below', 65 | 'above after', 66 | 'above before', 67 | 'below before', 68 | 'below after', 69 | ] 70 | }, 71 | matBadgeSize: { 72 | description: 'Size of the badge', 73 | defaultValue: 'medium', 74 | table: { 75 | defaultValue: { summary: 'medium' }, 76 | }, 77 | control: 'select', 78 | options: [ 79 | 'small', 80 | 'medium', 81 | 'large' 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /stories/components/form-field/form-field-argtype.ts: -------------------------------------------------------------------------------- 1 | export const formFieldArgtypes = { 2 | appearance: { 3 | description: 'The form field appearance style', 4 | control: 'select', 5 | defaultValue: 'standard', 6 | table: { 7 | defaultValue: { summary: 'standard' }, 8 | }, 9 | options: [ 10 | 'legacy', 11 | 'standard', 12 | 'fill', 13 | 'outline', 14 | ] 15 | }, 16 | color: { 17 | description: 'Theme color palette', 18 | control: 'select', 19 | defaultValue: 'primary', 20 | table: { 21 | defaultValue: { summary: 'primary' }, 22 | }, 23 | options: [ 24 | 'primary', 25 | 'accent', 26 | 'warn', 27 | ] 28 | }, 29 | floatLabel: { 30 | description: 'Whether the label should always float, never float or float as the user types', 31 | control: 'select', 32 | defaultValue: 'primary', 33 | table: { 34 | defaultValue: { summary: 'primary' }, 35 | }, 36 | options: [ 37 | 'always', 38 | 'never', 39 | 'auto', 40 | ] 41 | }, 42 | hideRequiredMarker: { 43 | description: 'Whether the required marker should be hidden', 44 | defaultValue: false, 45 | table: { 46 | type: { summary: 'boolean' }, 47 | defaultValue: { summary: false }, 48 | }, 49 | control: { 50 | type: 'boolean' 51 | } 52 | }, 53 | hintLabel: { 54 | description: 'Text for the form field hint', 55 | defaultValue: '', 56 | table: { 57 | type: { summary: 'text' }, 58 | defaultValue: { summary: '' }, 59 | }, 60 | control: { 61 | type: 'text' 62 | } 63 | }, 64 | alignHint: { 65 | description: 'Whether to align the hint label at the start or end of the line', 66 | control: 'select', 67 | defaultValue: 'start', 68 | table: { 69 | defaultValue: { summary: 'start' }, 70 | }, 71 | options: [ 72 | 'start', 73 | 'end', 74 | ] 75 | }, 76 | } 77 | -------------------------------------------------------------------------------- /stories/components/form-field/form-field.mdx: -------------------------------------------------------------------------------- 1 | import {Story} from '@storybook/blocks'; 2 | import LinkTo from '@storybook/addon-links/react'; 3 | 4 | import linkImage from '../../assets/open_in_new.png' 5 | import * as ComponentStories from './form-field.stories'; 6 | 7 | # Form field 8 | 9 | > *mat-form-field* is a component used to wrap several Angular Material components and apply common Text field styles such as the underline, floating label, and hint messages. 10 | 11 |
12 | 13 | ## Installation 14 | 15 | `import {MatFormFieldModule} from '@angular/material/form-field';` 16 | 17 | [Official documentation](https://material.angular.io/components/form-field/overview) 18 | 19 |
20 | 21 | ## Basic usage 22 | 23 |
24 |
25 | 26 |
27 |
28 |
Basic usage
29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | ## State 41 | 42 |
43 |
44 |
45 | 46 |
47 |
48 |
49 |
Inactive
50 | 51 | 52 | 53 |
54 | 55 |
56 | 57 |
58 |
59 |
Filled
60 | 61 | 62 | 63 |
64 | 65 |
66 | 67 |
68 |
69 |
Hover
70 | 71 | 72 | 73 |
74 | 75 |
76 | 77 |
78 |
79 |
Focused
80 | 81 | 82 | 83 |
84 | 85 |
86 | 87 |
88 |
89 |
Disabled
90 | 91 | 92 | 93 |
94 | 95 |
96 | 97 |
98 |
99 |
Error
100 | 101 | 102 | 103 |
104 | 105 |
106 |
107 | 108 | 109 |
110 |
111 |
112 | 113 | 114 | ## Appearance 115 | 116 | > supports 4 different appearance variants. 117 | 118 | Official 119 | documentation 120 | 121 |
122 |
123 |
124 | 125 |
126 |
127 |
128 |
Legacy
129 | 130 | 131 | 132 |
133 | 134 |
135 | 136 |
137 |
138 |
Standard
139 | 140 | 141 | 142 |
143 | 144 |
145 | 146 |
147 |
148 |
Fill
149 | 150 | 151 | 152 |
153 | 154 |
155 | 156 |
157 |
158 |
Outline
159 | 160 | 161 | 162 |
163 | 164 |
165 |
166 | 167 |
168 |
169 |
170 | 171 | ## Hints 172 | 173 | > Hint labels are additional descriptive text that appears below the form field's underline. 174 | 175 | Official 176 | documentation 177 | 178 |
179 |
180 |
181 | 182 |
183 |
184 |
185 |
Left hint
186 | 187 | 188 | 189 |
190 | 191 |
192 | 193 |
194 |
195 |
Right hint
196 | 197 | 198 | 199 |
200 | 201 |
202 | 203 |
204 |
205 |
Double hints
206 | 207 | 208 | 209 |
210 | 211 |
212 |
213 | 214 |
215 |
216 |
217 | 218 | ## Prefix and suffix 219 | 220 | > Custom content can be included before and after the input tag, as a prefix or suffix. 221 | 222 | Official 223 | documentation 224 | 225 |
226 |
227 |
228 | 229 |
230 |
231 |
232 |
Prefix
233 | 234 | 235 | 236 |
237 | 238 |
239 | 240 |
241 |
242 |
Suffix
243 | 244 | 245 | 246 |
247 | 248 |
249 | 250 |
251 |
252 |
Prefix and suffix
253 | 254 | 255 | 256 |
257 | 258 |
259 |
260 | 261 |
262 |
263 |
264 | 265 | ## Error message 266 | 267 | > Error messages can be shown under the form field underline. 268 | 269 | Official 270 | documentation 271 | 272 |
273 |
274 |
275 | 276 |
277 |
278 |
Error message
279 | 280 | 281 | 282 |
283 | 284 |
285 | -------------------------------------------------------------------------------- /stories/components/form-field/form-field.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { MatFormFieldModule } from '@angular/material/form-field'; 3 | import { MatInputModule } from '@angular/material/input'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | import { formFieldArgtypes } from './form-field-argtype'; 6 | import { MatSelectModule } from '@angular/material/select'; 7 | import { MatIconModule } from '@angular/material/icon'; 8 | import { MatButtonModule } from '@angular/material/button'; 9 | import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; 10 | import { userEvent, within } from '@storybook/testing-library'; 11 | import { expect } from '@storybook/jest'; 12 | 13 | export default { 14 | title: 'components/Form field', 15 | tags: ['docsPage'], 16 | decorators: [ 17 | moduleMetadata({ 18 | imports: [ 19 | BrowserAnimationsModule, 20 | MatFormFieldModule, 21 | MatInputModule, 22 | MatSelectModule, 23 | MatIconModule, 24 | MatButtonModule, 25 | ReactiveFormsModule, 26 | FormsModule, 27 | ], 28 | }), 29 | ], 30 | parameters: { 31 | controls: { 32 | expanded: true, 33 | }, 34 | }, 35 | argTypes: formFieldArgtypes, 36 | } as Meta; 37 | 38 | export const AAWithBasicUsage: StoryObj = { 39 | render: (args) => ({ 40 | props: args, 41 | template: ` 42 | 43 | Password 44 | 45 | 46 | `, 47 | }), 48 | // Added an example of how to use the play function 49 | // For more information, see https://storybook.js.org/docs/angular/writing-tests/interaction-testing 50 | play: async ({ canvasElement }) => { 51 | const canvas = within(canvasElement); 52 | await userEvent.type(canvas.getByLabelText('Password'), 'email@provider.com'); 53 | await expect(canvas.getByLabelText('Password')).toHaveValue('email@provider.com'); 54 | }, 55 | name: 'basic usage', 56 | parameters: { 57 | controls: { 58 | exclude: ['alignHint'], 59 | }, 60 | }, 61 | }; 62 | 63 | export const WithStateFilled: StoryObj = { 64 | render: (args) => ({ 65 | props: args, 66 | template: ` 67 | 68 | Password 69 | 70 | 71 | `, 72 | }), 73 | name: 'with state (filled)', 74 | parameters: { 75 | controls: { 76 | exclude: ['alignHint'], 77 | }, 78 | }, 79 | }; 80 | 81 | export const WithStateDisabled: StoryObj = { 82 | render: (args) => ({ 83 | props: args, 84 | template: ` 85 | 86 | Password 87 | 88 | 89 | `, 90 | }), 91 | name: 'with state (disabled)', 92 | parameters: { 93 | controls: { 94 | exclude: ['alignHint'], 95 | }, 96 | }, 97 | }; 98 | 99 | export const WithStateFocused: StoryObj = { 100 | render: (args) => ({ 101 | props: args, 102 | template: ` 103 | 104 | Password 1 105 | 106 | 107 | `, 108 | }), 109 | name: 'with state (focused)', 110 | parameters: { 111 | controls: { 112 | exclude: ['alignHint'], 113 | }, 114 | }, 115 | }; 116 | 117 | export const WithStateHover: StoryObj = { 118 | render: (args) => ({ 119 | props: args, 120 | template: ` 121 | 122 | Password 123 | 124 | 125 | `, 126 | }), 127 | name: 'with state (hover)', 128 | parameters: { 129 | controls: { 130 | exclude: ['alignHint'], 131 | }, 132 | pseudo: { 133 | hover: true, 134 | }, 135 | }, 136 | }; 137 | 138 | export const WithAppearanceLegacy: StoryObj = { 139 | render: (args) => ({ 140 | props: { 141 | ...args, 142 | appearance: 'legacy', 143 | }, 144 | template: ` 145 | 146 | Password 147 | 148 | 149 | `, 150 | }), 151 | name: 'with appearance (legacy)', 152 | parameters: { 153 | controls: { 154 | exclude: ['alignHint'], 155 | }, 156 | }, 157 | }; 158 | 159 | export const WithAppearanceStandard: StoryObj = { 160 | render: (args) => ({ 161 | props: { 162 | ...args, 163 | appearance: 'standard', 164 | }, 165 | template: ` 166 | 167 | Password 168 | 169 | 170 | `, 171 | }), 172 | name: 'with appearance (standard)', 173 | parameters: { 174 | controls: { 175 | exclude: ['alignHint'], 176 | }, 177 | }, 178 | }; 179 | 180 | export const WithAppearanceFill: StoryObj = { 181 | render: (args) => ({ 182 | props: { 183 | ...args, 184 | appearance: 'fill', 185 | }, 186 | template: ` 187 | 188 | Password 189 | 190 | 191 | `, 192 | }), 193 | name: 'with appearance (fill)', 194 | parameters: { 195 | controls: { 196 | exclude: ['alignHint'], 197 | }, 198 | }, 199 | }; 200 | 201 | export const WithAppearanceOutline: StoryObj = { 202 | render: (args) => ({ 203 | props: { 204 | ...args, 205 | appearance: 'outline', 206 | }, 207 | template: ` 208 | 209 | Password 210 | 211 | 212 | `, 213 | }), 214 | name: 'with appearance (outline)', 215 | parameters: { 216 | controls: { 217 | exclude: ['alignHint'], 218 | }, 219 | }, 220 | }; 221 | 222 | export const WithStartHint: StoryObj = { 223 | render: (args) => ({ 224 | props: args, 225 | template: ` 226 | 227 | Password 228 | 229 | at least 8 characters 230 | 231 | `, 232 | }), 233 | name: 'with hint (start)', 234 | }; 235 | 236 | export const WithEndHint: StoryObj = { 237 | render: (args) => ({ 238 | props: args, 239 | template: ` 240 | 241 | Contributions 242 | 243 | Components 244 | Use cases 245 | 246 | Choose an option ^ 247 | 248 | `, 249 | }), 250 | name: 'with hint (end)', 251 | }; 252 | 253 | export const WithDoubleHints: StoryObj = { 254 | render: (args) => ({ 255 | props: args, 256 | template: ` 257 | 258 | Username 259 | 260 | Max 10 characters 261 | {{input.value.length || 0}}/10 262 | 263 | `, 264 | }), 265 | name: 'with hint (double)', 266 | }; 267 | 268 | export const WithPrefix: StoryObj = { 269 | render: (args) => ({ 270 | props: { 271 | ...args, 272 | hide: true, 273 | }, 274 | template: ` 275 | 276 | Password 277 | 278 | key 279 | 280 | `, 281 | }), 282 | name: 'with prefix', 283 | parameters: { 284 | controls: { 285 | exclude: ['alignHint'], 286 | }, 287 | }, 288 | }; 289 | 290 | export const WithSuffix: StoryObj = { 291 | render: (args) => ({ 292 | props: { 293 | ...args, 294 | hide: true, 295 | }, 296 | template: ` 297 | 298 | Password 299 | 300 | 303 | 304 | `, 305 | }), 306 | name: 'with suffix', 307 | parameters: { 308 | controls: { 309 | exclude: ['alignHint'], 310 | }, 311 | }, 312 | }; 313 | 314 | export const WithPrefixAndSuffix: StoryObj = { 315 | render: (args) => ({ 316 | props: { 317 | ...args, 318 | hide: true, 319 | }, 320 | template: ` 321 | 335 | 336 | Amount 337 | 338 | 339 | .00 340 | 341 | `, 342 | }), 343 | name: 'with prefix and suffix', 344 | parameters: { 345 | controls: { 346 | exclude: ['alignHint'], 347 | }, 348 | }, 349 | }; 350 | 351 | const control = new FormControl('', Validators.required); 352 | control.markAsTouched(); 353 | 354 | export const WithErrorMessage: StoryObj = { 355 | render: (args) => ({ 356 | props: { 357 | ...args, 358 | control: control, 359 | }, 360 | template: ` 361 | 362 | Password 363 | 364 | This field is required 365 | 366 | `, 367 | }), 368 | name: 'with error message', 369 | parameters: { 370 | controls: { 371 | exclude: ['alignHint'], 372 | }, 373 | }, 374 | }; 375 | -------------------------------------------------------------------------------- /stories/components/icon.mdx: -------------------------------------------------------------------------------- 1 | 2 | import { Story } from '@storybook/blocks'; 3 | import * as ComponentStories from './icon.stories'; 4 | 5 | # Icon 6 | 7 | > *mat-icon* makes it easier to use vector-based icons in your app. This directive supports both icon fonts and SVG icons, but not bitmap-based formats (png, jpg, etc.). 8 | 9 |
10 | 11 | ## Installation 12 | 13 | `import {MatIconModule} from '@angular/material/icon';` 14 | 15 | [Official documentation](https://material.angular.io/components/icon/overview) 16 | 17 |
18 | 19 | ## Example 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /stories/components/icon.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { MatIconModule } from '@angular/material/icon'; 3 | import { MatBadgeModule } from '@angular/material/badge'; 4 | import { MatButtonModule } from '@angular/material/button'; 5 | import { badgeArgtypes } from './badge/badge.argtype'; 6 | 7 | export default { 8 | title: 'Components/Icon', 9 | decorators: [ 10 | moduleMetadata({ 11 | imports: [MatIconModule, MatBadgeModule, MatButtonModule], 12 | }), 13 | ], 14 | parameters: { 15 | options: { 16 | controls: { 17 | disable: true, 18 | }, 19 | }, 20 | }, 21 | } as Meta; 22 | 23 | export const BasicUsage: StoryObj = { 24 | render: (args) => ({ 25 | props: args, 26 | template: ` 27 | 28 | more_vert 29 | home 30 | menu 31 | favorite 32 | open_in_new 33 | `, 34 | }), 35 | name: 'basic usage', 36 | }; 37 | 38 | export const WithBadge: StoryObj = { 39 | render: (args) => ({ 40 | props: args, 41 | template: ` 42 | 43 | more_vert 44 | home 45 | menu 46 | favorite 47 | open_in_new 48 | `, 49 | }), 50 | name: 'with badge', 51 | parameters: { 52 | controls: { 53 | expanded: true, 54 | }, 55 | }, 56 | argTypes: { 57 | ...badgeArgtypes, 58 | }, 59 | }; 60 | 61 | export const WithButtons: StoryObj = { 62 | render: (args) => ({ 63 | props: args, 64 | template: ` 65 | 66 | 67 | 68 | 69 | 70 | 71 | `, 72 | }), 73 | name: 'with buttons', 74 | }; 75 | 76 | export const WithFloatingActionButtons: StoryObj = { 77 | render: (args) => ({ 78 | props: args, 79 | template: ` 80 | 81 | 82 | 83 | 84 | 85 | 86 | `, 87 | }), 88 | name: 'with floating action buttons', 89 | }; 90 | 91 | export const WithMiniFloatingActionButtons: StoryObj = { 92 | render: (args) => ({ 93 | props: args, 94 | template: ` 95 | 96 | 97 | 98 | 99 | 100 | 101 | `, 102 | }), 103 | name: 'with mini floating action buttons', 104 | }; 105 | -------------------------------------------------------------------------------- /stories/components/introduction.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs'; 2 | import LinkTo from '@storybook/addon-links/react'; 3 | 4 | 5 | 6 | 83 | 84 | # Angular Material Components 85 | 86 | > Basic examples of Angular Material components in isolation. 87 | 88 |
Components
89 | 90 |
91 | 96 | 97 | Form field 98 | Wraps input fields so they are displayed consistently. 99 | 100 | 101 | 102 | 107 | 108 | Icon 109 | Renders a specific icon. 110 | 111 | 112 | 113 | 118 | 119 | Progress bar 120 | A linear progress indicator. 121 | 122 | 123 | 124 | 129 | 130 | Progress spinner 131 | A circular progress indicator. 132 | 133 | 134 | 135 | 140 | 141 | Table 142 | A configurable component for displaying tabular data. 143 | 144 | 145 |
146 | -------------------------------------------------------------------------------- /stories/components/progress-bar/progress-bar.argtype.ts: -------------------------------------------------------------------------------- 1 | export const progressBarArgtypes = { 2 | bufferValue: { 3 | description: 'Buffer value of the progress bar', 4 | defaultValue: 0, 5 | table: { 6 | type: { summary: 'range' }, 7 | defaultValue: { summary: 0 }, 8 | }, 9 | control: { 10 | type: 'range', 11 | min: 0, 12 | max: 100, 13 | step: 1 14 | } 15 | }, 16 | color: { 17 | description: 'Theme color palette', 18 | control: 'select', 19 | defaultValue: 'primary', 20 | table: { 21 | defaultValue: { summary: 'primary' }, 22 | }, 23 | options: [ 24 | 'primary', 25 | 'accent', 26 | 'warn', 27 | ] 28 | }, 29 | mode: { 30 | description: 'Mode of the progress bar', 31 | control: 'select', 32 | defaultValue: 'indeterminate', 33 | table: { 34 | defaultValue: { summary: 'indeterminate' }, 35 | }, 36 | options: [ 37 | 'determinate', 38 | 'indeterminate', 39 | 'buffer', 40 | 'query' 41 | ] 42 | }, 43 | value: { 44 | description: 'Value of the progress bar', 45 | defaultValue: 0, 46 | table: { 47 | type: { summary: 'range' }, 48 | defaultValue: { summary: 0 }, 49 | }, 50 | control: { 51 | type: 'range', 52 | min: 0, 53 | max: 100, 54 | step: 1 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /stories/components/progress-bar/progress-bar.mdx: -------------------------------------------------------------------------------- 1 | import { Story } from '@storybook/blocks'; 2 | import * as ComponentStories from './progress-bar.stories'; 3 | 4 | 5 | # Progress bar 6 | 7 | > *mat-progress-bar* is a horizontal progress-bar for indicating progress and activity. 8 | 9 |
10 | 11 | ## Installation 12 | 13 | `import {MatProgressBarModule} from '@angular/material/progress-bar';` 14 | 15 | [Official documentation](https://material.angular.io/components/progress-bar/overview) 16 | 17 |
18 | 19 | ## Example 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /stories/components/progress-bar/progress-bar.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { MatProgressBarModule } from '@angular/material/progress-bar'; 3 | import { progressBarArgtypes } from './progress-bar.argtype'; 4 | 5 | export default { 6 | title: 'components/Progress bar', 7 | decorators: [ 8 | moduleMetadata({ 9 | imports: [MatProgressBarModule], 10 | }), 11 | ], 12 | argTypes: progressBarArgtypes, 13 | parameters: { 14 | controls: { 15 | expanded: true, 16 | exclude: ['mode'], 17 | }, 18 | }, 19 | } as Meta; 20 | 21 | export const WithBasicUsage: StoryObj = { 22 | render: (args) => ({ 23 | props: args, 24 | template: ` 25 | 31 | 32 | 33 | 34 | 35 | `, 36 | }), 37 | name: 'basic usage', 38 | }; 39 | -------------------------------------------------------------------------------- /stories/components/progress-spinner/progress-spinner.argtype.ts: -------------------------------------------------------------------------------- 1 | export const progressSpinnerArgtypes = { 2 | color: { 3 | description: 'Theme color palette', 4 | control: 'select', 5 | defaultValue: 'primary', 6 | table: { 7 | defaultValue: { summary: 'primary' }, 8 | }, 9 | options: [ 10 | 'primary', 11 | 'accent', 12 | 'warn', 13 | ] 14 | }, 15 | diameter: { 16 | description: 'The diameter of the progress spinner (will set width and height of svg)', 17 | defaultValue: 100, 18 | table: { 19 | type: { summary: 'number' }, 20 | defaultValue: { summary: 100 }, 21 | }, 22 | control: { 23 | type: 'number' 24 | } 25 | }, 26 | mode: { 27 | description: 'Mode of the progress circle', 28 | control: 'select', 29 | defaultValue: 'indeterminate', 30 | table: { 31 | defaultValue: { summary: 'indeterminate' }, 32 | }, 33 | options: [ 34 | 'determinate', 35 | 'indeterminate', 36 | 'buffer', 37 | 'query' 38 | ] 39 | }, 40 | strokeWidth: { 41 | description: 'Stroke width of the progress spinner', 42 | defaultValue: 5, 43 | table: { 44 | type: { summary: 'number' }, 45 | defaultValue: { summary: 5 }, 46 | }, 47 | control: { 48 | type: 'number' 49 | } 50 | }, 51 | value: { 52 | description: 'Value of the progress circle', 53 | defaultValue: 70, 54 | table: { 55 | type: { summary: 'range' }, 56 | defaultValue: { summary: 70 }, 57 | }, 58 | control: { 59 | type: 'range', 60 | min: 0, 61 | max: 100, 62 | step: 1 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /stories/components/progress-spinner/progress-spinner.mdx: -------------------------------------------------------------------------------- 1 | import { Story } from '@storybook/blocks'; 2 | import * as ComponentStories from './progress-spinner.stories'; 3 | 4 | 5 | # Progress spinner 6 | 7 | > *mat-progress-spinner* and *mat-spinner* are a circular indicators of progress and activity. 8 | 9 |
10 | 11 | ## Installation 12 | 13 | `import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';` 14 | 15 | [Official documentation](https://material.angular.io/components/progress-spinner/overview) 16 | 17 |
18 | 19 | ## Example 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /stories/components/progress-spinner/progress-spinner.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { progressSpinnerArgtypes } from './progress-spinner.argtype'; 3 | import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; 4 | export default { 5 | title: 'components/Progress spinner', 6 | decorators: [ 7 | moduleMetadata({ 8 | imports: [MatProgressSpinnerModule], 9 | }), 10 | ], 11 | argTypes: progressSpinnerArgtypes, 12 | parameters: { 13 | controls: { 14 | expanded: true, 15 | exclude: ['mode'], 16 | }, 17 | }, 18 | } as Meta; 19 | 20 | export const WithBasicUsage: StoryObj = { 21 | render: (args) => ({ 22 | props: args, 23 | template: ` 24 | 29 | 30 | 31 | `, 32 | }), 33 | name: 'basic usage', 34 | }; 35 | -------------------------------------------------------------------------------- /stories/components/table/table.argtype.ts: -------------------------------------------------------------------------------- 1 | export const tableArgtypes = {}; 2 | -------------------------------------------------------------------------------- /stories/components/table/table.mdx: -------------------------------------------------------------------------------- 1 | import { Story } from '@storybook/blocks'; 2 | import * as ComponentStories from './table.stories'; 3 | 4 | # Table 5 | 6 | > The *mat-table* provides a Material Design styled data-table that can be used to display rows of data. 7 | 8 |
9 | 10 | ## Installation 11 | 12 | `import {MatTableModule} from '@angular/material/table';` 13 | 14 | [Official documentation](https://material.angular.io/components/table/overview) 15 | 16 |
17 | 18 | ## Example 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /stories/components/table/table.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { MatTableModule } from '@angular/material/table'; 3 | export default { 4 | title: 'Components/Table', 5 | decorators: [ 6 | moduleMetadata({ 7 | imports: [MatTableModule], 8 | }), 9 | ], 10 | parameters: { 11 | layout: 'fullscreen', 12 | controls: { 13 | expanded: true, 14 | }, 15 | }, 16 | } as Meta; 17 | export const WithBasicUsage: StoryObj = { 18 | render: (args) => ({ 19 | props: { 20 | ...args, 21 | displayedColumns: ['position', 'name', 'weight', 'symbol'], 22 | dataSource: [ 23 | { 24 | position: 1, 25 | name: 'Hydrogen', 26 | weight: 1.0079, 27 | symbol: 'H', 28 | }, 29 | { 30 | position: 2, 31 | name: 'Helium', 32 | weight: 4.0026, 33 | symbol: 'He', 34 | }, 35 | { 36 | position: 3, 37 | name: 'Lithium', 38 | weight: 6.941, 39 | symbol: 'Li', 40 | }, 41 | { 42 | position: 4, 43 | name: 'Beryllium', 44 | weight: 9.0122, 45 | symbol: 'Be', 46 | }, 47 | { 48 | position: 5, 49 | name: 'Boron', 50 | weight: 10.811, 51 | symbol: 'B', 52 | }, 53 | { 54 | position: 6, 55 | name: 'Carbon', 56 | weight: 12.0107, 57 | symbol: 'C', 58 | }, 59 | { 60 | position: 7, 61 | name: 'Nitrogen', 62 | weight: 14.0067, 63 | symbol: 'N', 64 | }, 65 | { 66 | position: 8, 67 | name: 'Oxygen', 68 | weight: 15.9994, 69 | symbol: 'O', 70 | }, 71 | { 72 | position: 9, 73 | name: 'Fluorine', 74 | weight: 18.9984, 75 | symbol: 'F', 76 | }, 77 | { 78 | position: 10, 79 | name: 'Neon', 80 | weight: 20.1797, 81 | symbol: 'Ne', 82 | }, 83 | ], 84 | }, 85 | template: ` 86 | 91 | 92 | 93 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
No. {{element.position}} Name {{element.name}} Weight {{element.weight}} Symbol {{element.symbol}}
123 | `, 124 | }), 125 | name: 'basic usage', 126 | }; 127 | -------------------------------------------------------------------------------- /stories/introduction.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/blocks' 2 | import LinkTo from '@storybook/addon-links/react'; 3 | 4 | import Code from './assets/code-brackets.svg'; 5 | import Colors from './assets/colors.svg'; 6 | import Comments from './assets/comments.svg'; 7 | import Plugin from './assets/plugin.svg'; 8 | import Repo from './assets/repo.svg'; 9 | import StackAlt from './assets/stackalt.svg'; 10 | 11 | 12 | 13 | 14 | 15 | 92 | 93 | # Welcome to Angular Material Storybook 94 | 95 | > Material Design components for Angular in action. 96 | 97 |
Configure
98 | 99 |
100 | 101 | colors 102 | 103 | Theming 104 | How to dynamically change the theme palette of your UI. 105 | 106 | 107 |
108 | 109 |
Discover
110 | 111 |
112 | 113 | code 114 | 115 | Components 116 | Basic examples of Angular Material components in isolation. 117 | 118 | 119 | 120 | comments 121 | 122 | Usecases 123 | Discover real-world use cases. 124 | 125 | 126 |
127 | 128 |
About this project
129 | 130 | 146 | 147 |
Learn
148 | 173 | -------------------------------------------------------------------------------- /stories/theming-preview.jsx: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import { Story } from "@storybook/blocks"; 3 | import ArrowPrevious from './assets/arrow-previous.svg'; 4 | import ArrowPreviousDisabled from './assets/arrow-previous_disabled.svg'; 5 | import ArrowNext from './assets/arrow-next.svg'; 6 | import ArrowNextDisabled from './assets/arrow-next_disabled.svg'; 7 | 8 | export default function ThemingPreview(props) { 9 | const [activeStory, setActiveStory] = useState(props.stories[0]); 10 | 11 | const displayPreviousPreview = () => { 12 | let currentIndex = props.stories.findIndex(item => item.id === activeStory.id); 13 | setActiveStory(props.stories[--currentIndex]); 14 | } 15 | 16 | const displayNextPreview = () => { 17 | let currentIndex = props.stories.findIndex(item => item.id === activeStory.id); 18 | setActiveStory(props.stories[++currentIndex]); 19 | } 20 | 21 | return ( 22 |
23 |
24 | 27 | {activeStory.name} 28 | 31 |
32 | 33 | 34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /stories/theming-settings.jsx: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import * as tinycolor from "tinycolor2"; 3 | import Diamond from './assets/diamond.svg'; 4 | 5 | export default function ThemingSettings() { 6 | const [lightPrimaryColor, setLightPrimaryColor] = useState(window.getComputedStyle(document.documentElement).getPropertyValue('--light-theme-primary-500') || '#006680'); 7 | const [lightAccentColor, setLightAccentColor] = useState(window.getComputedStyle(document.documentElement).getPropertyValue('--light-theme-accent-500') || '#F59432'); 8 | const [lightWarnColor, setLightWarnColor] = useState(window.getComputedStyle(document.documentElement).getPropertyValue('--light-theme-warn-500') || '#f44336'); 9 | 10 | const [lightPrimaryPalette, setLightPrimaryPalette] = useState(computeColors('#006680')); 11 | const [lightAccentPalette, setLightAccentPalette] = useState(computeColors('#F59432')); 12 | const [lightWarnPalette, setLightWarnPalette] = useState(computeColors('#f44336')); 13 | 14 | const [darkPrimaryColor, setDarkPrimaryColor] = useState(window.getComputedStyle(document.documentElement).getPropertyValue('--dark-theme-primary-500') || '#006680'); 15 | const [darkAccentColor, setDarkAccentColor] = useState(window.getComputedStyle(document.documentElement).getPropertyValue('--dark-theme-accent-500') || '#F59432'); 16 | const [darkWarnColor, setDarkWarnColor] = useState(window.getComputedStyle(document.documentElement).getPropertyValue('--dark-theme-warn-500') || '#f44336'); 17 | 18 | const [darkPrimaryPalette, setDarkPrimaryPalette] = useState(computeColors('#006680')); 19 | const [darkAccentPalette, setDarkAccentPalette] = useState(computeColors('#F59432')); 20 | const [darkWarnPalette, setDarkWarnPalette] = useState(computeColors('#f44336')); 21 | 22 | const [darkMode, setDarkMode] = useState(document.documentElement.classList.contains('dark-theme')); 23 | 24 | const saveLightPrimaryColor = (e) => { 25 | const primaryColor = e.target?.value || e; 26 | setLightPrimaryColor(primaryColor); 27 | const primaryColorPalette = computeColors(primaryColor); 28 | setLightPrimaryPalette(primaryColorPalette); 29 | updateTheme(primaryColorPalette, 'primary', 'light'); 30 | } 31 | 32 | const saveLightAccentColor = (e) => { 33 | const accentColor = e.target?.value || e; 34 | setLightAccentColor(accentColor); 35 | const accentColorPalette = computeColors(accentColor); 36 | setLightAccentPalette(accentColorPalette); 37 | updateTheme(accentColorPalette, 'accent', 'light'); 38 | } 39 | 40 | const saveLightWarnColor = (e) => { 41 | const warnColor = e.target?.value || e; 42 | setLightWarnColor(warnColor); 43 | const warnColorPalette = computeColors(warnColor); 44 | setLightWarnPalette(warnColorPalette); 45 | updateTheme(warnColorPalette, 'warn', 'light'); 46 | } 47 | 48 | const saveDarkPrimaryColor = (e) => { 49 | const primaryColor = e.target?.value || e; 50 | setDarkPrimaryColor(primaryColor); 51 | const primaryColorPalette = computeColors(primaryColor); 52 | setDarkPrimaryPalette(primaryColorPalette); 53 | updateTheme(primaryColorPalette, 'primary', 'dark'); 54 | } 55 | 56 | const saveDarkAccentColor = (e) => { 57 | const accentColor = e.target?.value || e; 58 | setDarkAccentColor(accentColor); 59 | const accentColorPalette = computeColors(accentColor); 60 | setDarkAccentPalette(accentColorPalette); 61 | updateTheme(accentColorPalette, 'accent', 'dark'); 62 | } 63 | 64 | const saveDarkWarnColor = (e) => { 65 | const warnColor = e.target?.value || e; 66 | setDarkWarnColor(warnColor); 67 | const warnColorPalette = computeColors(warnColor); 68 | setDarkWarnPalette(warnColorPalette); 69 | updateTheme(warnColorPalette, 'warn', 'dark'); 70 | } 71 | 72 | const saveIndigoPreset = () => { 73 | saveLightPrimaryColor('#3f51b5'); 74 | setLightPrimaryColor('#3f51b5'); 75 | saveLightAccentColor('#ff4081'); 76 | setLightAccentColor('#ff4081'); 77 | saveLightWarnColor('#f44336'); 78 | setLightWarnColor('#f44336'); 79 | } 80 | 81 | const saveDeepPurplePreset = () => { 82 | saveLightPrimaryColor('#673ab7'); 83 | setLightPrimaryColor('#673ab7'); 84 | saveLightAccentColor('#ffd740'); 85 | setLightAccentColor('#ffd740'); 86 | saveLightWarnColor('#f44336'); 87 | setLightWarnColor('#f44336'); 88 | } 89 | 90 | const savePinkPreset = () => { 91 | saveLightPrimaryColor('#e91e63'); 92 | setLightPrimaryColor('#e91e63'); 93 | saveLightAccentColor('#607d8b'); 94 | setLightAccentColor('#607d8b'); 95 | saveLightWarnColor('#f44336'); 96 | setLightWarnColor('#f44336'); 97 | } 98 | 99 | const savePurplePreset = () => { 100 | saveLightPrimaryColor('#9c27b0'); 101 | setLightPrimaryColor('#9c27b0'); 102 | saveLightAccentColor('#69f0ae'); 103 | setLightAccentColor('#69f0ae'); 104 | saveLightWarnColor('#f44336'); 105 | setLightWarnColor('#f44336'); 106 | } 107 | 108 | const toggleDarkTheme = (mode) => { 109 | const newMode = mode ?? !darkMode; 110 | if(newMode) { 111 | document.documentElement.classList.add('dark-theme'); 112 | } else { 113 | document.documentElement.classList.remove('dark-theme'); 114 | } 115 | setDarkMode(newMode); 116 | } 117 | 118 | return ( 119 | <> 120 |
121 | 122 | 123 |
124 | 125 | 129 |
130 |
131 | 132 | 134 |
135 |
    136 | {lightPrimaryPalette.map(color => 137 |
  • 138 | 139 | {color.name} 140 |
  • 141 | )} 142 |
143 |
144 | 145 | 147 |
148 |
    149 | {lightAccentPalette.map(color => 150 |
  • 151 | 152 | {color.name} 153 |
  • 154 | )} 155 |
156 |
157 | 158 | 160 |
161 |
    162 | {lightWarnPalette.map(color => 163 |
  • 164 | 165 | {color.name} 166 |
  • 167 | )} 168 |
169 |
170 | 171 |
172 |
173 | 174 | 176 |
177 |
    178 | {darkPrimaryPalette.map(color => 179 |
  • 180 | 181 | {color.name} 182 |
  • 183 | )} 184 |
185 |
186 | 187 | 189 |
190 |
    191 | {darkAccentPalette.map(color => 192 |
  • 193 | 194 | {color.name} 195 |
  • 196 | )} 197 |
198 |
199 | 200 | 202 |
203 |
    204 | {darkWarnPalette.map(color => 205 |
  • 206 | 207 | {color.name} 208 |
  • 209 | )} 210 |
211 |
212 | 213 |
214 | 215 |

Presets

216 | 217 |
218 | 223 | 224 | 229 | 230 | 235 | 236 | 241 |
242 | 243 | ); 244 | } 245 | 246 | function updateTheme(colors, theme, mode) { 247 | colors.forEach(color => { 248 | document.body.style.setProperty( 249 | `--${mode}-theme-${theme}-${color.name}`, 250 | color.hex 251 | ); 252 | document.body.style.setProperty( 253 | `--${mode}-theme-${theme}-contrast-${color.name}`, 254 | color.darkContrast ? 'black' : 'white' 255 | ); 256 | }); 257 | } 258 | 259 | function computeColors(hex) { 260 | return [ 261 | getColorObject(tinycolor(hex).lighten(52), '50'), 262 | getColorObject(tinycolor(hex).lighten(37), '100'), 263 | getColorObject(tinycolor(hex).lighten(26), '200'), 264 | getColorObject(tinycolor(hex).lighten(12), '300'), 265 | getColorObject(tinycolor(hex).lighten(6), '400'), 266 | getColorObject(tinycolor(hex), '500'), 267 | getColorObject(tinycolor(hex).darken(6), '600'), 268 | getColorObject(tinycolor(hex).darken(12), '700'), 269 | getColorObject(tinycolor(hex).darken(18), '800'), 270 | getColorObject(tinycolor(hex).darken(24), '900'), 271 | getColorObject(tinycolor(hex).lighten(50).saturate(30), 'A100'), 272 | getColorObject(tinycolor(hex).lighten(30).saturate(30), 'A200'), 273 | getColorObject(tinycolor(hex).lighten(10).saturate(15), 'A400'), 274 | getColorObject(tinycolor(hex).lighten(5).saturate(5), 'A700') 275 | ]; 276 | } 277 | 278 | function getColorObject(value, name) { 279 | const c = tinycolor(value); 280 | return { 281 | name: name, 282 | hex: c.toHexString(), 283 | darkContrast: c.isLight() 284 | }; 285 | } 286 | -------------------------------------------------------------------------------- /stories/theming.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/blocks' 2 | 3 | import ThemingSettings from "./theming-settings"; 4 | import ThemingPreview from "./theming-preview"; 5 | 6 | 7 | 8 |
9 |
10 | 28 |
29 |
30 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /stories/usecases/authentication/change-password/change-password.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {MatFormFieldModule} from "@angular/material/form-field"; 3 | import {MatButtonModule} from "@angular/material/button"; 4 | import {MatInputModule} from "@angular/material/input"; 5 | import {MatIconModule} from "@angular/material/icon"; 6 | 7 | @Component({ 8 | template: ` 9 |
10 |

CHANGE PASSWORD

11 | 12 | Current password 13 | 14 | 15 | 16 | 17 | New password 18 | 19 | 22 | 23 | 24 | 25 | Confirm new password 26 | 27 | 30 | 31 | 32 | 33 | 34 |
35 | `, 36 | styles: [ 37 | ':host {display: flex; justify-content: center; height: 100%; width: 100%}', 38 | '.form-container {display: flex; flex-direction: column; justify-content: center;}', 39 | '.change-password__save-button {margin-block-start: 1rem; margin-block-end: 1rem}', 40 | '.change-password__cancel-button {margin-block-end: 1rem}', 41 | '.change-password__title {margin-block-end: 3rem}' 42 | ], 43 | standalone: true, 44 | imports: [ 45 | MatButtonModule, 46 | MatIconModule, 47 | MatFormFieldModule, 48 | MatInputModule, 49 | ] 50 | }) 51 | export class ChangePasswordComponent { 52 | constructor() { 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /stories/usecases/authentication/change-password/change-password.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { ChangePasswordComponent } from './change-password.component'; 3 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 4 | import { defaultUsecasesParameters } from '../../../../.storybook/utils'; 5 | 6 | export default { 7 | title: 'usecases/authentication/change password', 8 | component: ChangePasswordComponent, 9 | parameters: { 10 | ...defaultUsecasesParameters, 11 | }, 12 | decorators: [ 13 | moduleMetadata({ 14 | imports: [BrowserAnimationsModule], 15 | }), 16 | ], 17 | } as Meta; 18 | 19 | export const ChangePassword: StoryObj = { 20 | render: (args) => ({ 21 | props: args, 22 | }), 23 | name: 'change password', 24 | }; 25 | -------------------------------------------------------------------------------- /stories/usecases/dialog/confirmation-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, ViewEncapsulation} from "@angular/core"; 2 | import {MatDialog, MatDialogModule} from "@angular/material/dialog"; 3 | import {MatIconModule} from "@angular/material/icon"; 4 | import {MatButtonModule} from "@angular/material/button"; 5 | 6 | @Component({ 7 | template: ` 8 |
9 | 10 |
11 | `, 12 | styles: [ 13 | 'section {display: flex; justify-content: center; align-items: center; height: 100%}', 14 | '.dialog-border mat-dialog-container {border-radius: 20px; border: 5px solid green} ' 15 | ], 16 | standalone: true, 17 | imports: [ 18 | MatDialogModule, 19 | MatButtonModule 20 | ], 21 | encapsulation: ViewEncapsulation.None 22 | }) 23 | export class ConfirmationDialogComponent { 24 | constructor(private readonly dialog: MatDialog) {} 25 | 26 | openDialog(): void { 27 | this.dialog.open(ConfirmationDialogDialogComponent, { 28 | width: '250px', 29 | autoFocus: false, 30 | panelClass: 'dialog-border' 31 | }); 32 | } 33 | } 34 | 35 | @Component({ 36 | template: ` 37 | check_circle 38 |

Your order has been created successfully!

39 | 40 | `, 41 | styles: [ 42 | ':host {display: flex; justify-content: center; align-items: center; flex-direction: column}', 43 | 'h3 {text-align: center}', 44 | 'mat-icon {color: green; height: 6rem; width: 6rem; font-size: 6rem}' 45 | ], 46 | standalone: true, 47 | imports: [ 48 | MatIconModule, 49 | MatButtonModule, 50 | MatDialogModule 51 | ] 52 | }) 53 | class ConfirmationDialogDialogComponent { 54 | } 55 | -------------------------------------------------------------------------------- /stories/usecases/dialog/confirmation-dialog.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { ConfirmationDialogComponent } from './confirmation-dialog.component'; 3 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 4 | import { defaultUsecasesParameters } from '../../../.storybook/utils'; 5 | 6 | export default { 7 | title: 'Usecases/Dialog', 8 | component: ConfirmationDialogComponent, 9 | decorators: [ 10 | moduleMetadata({ 11 | imports: [BrowserAnimationsModule], 12 | }), 13 | ], 14 | parameters: { 15 | ...defaultUsecasesParameters, 16 | }, 17 | } as Meta; 18 | 19 | export const Template: StoryObj = { 20 | render: (args) => ({ 21 | props: args, 22 | }), 23 | name: 'success (custom css)', 24 | }; 25 | -------------------------------------------------------------------------------- /stories/usecases/introduction.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs'; 2 | 3 | 4 | 5 | 82 | 83 | # Angular Material usecases 84 | 85 | > Discover real-world use cases. 86 | 87 |
Components
88 | 89 | 108 | -------------------------------------------------------------------------------- /stories/usecases/navigation/collapsible-vertical-navigation/collapsible-vertical-navigation.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {MatIconModule} from "@angular/material/icon"; 3 | import {MatListModule} from "@angular/material/list"; 4 | import {MatSidenavModule} from "@angular/material/sidenav"; 5 | import {MatBadgeModule} from "@angular/material/badge"; 6 | import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; 7 | 8 | @Component({ 9 | selector: 'app-fab-bottom-navigation', 10 | template: ` 11 | 12 | 13 | 14 | 15 | account_circle 16 | Profile 17 | 18 | 19 | notifications 20 | Notifications 21 | 22 | 23 | home 24 | Dashboard 25 | 26 | 27 | shopping_cart 28 | Cart 29 | 30 | 31 | stars 32 | Wish list 33 | 34 | 35 | settings 36 | Settings 37 | 38 | 39 | 40 | Main content 41 | `, 42 | styles:[ 43 | 'mat-drawer-container {height: 100%; width: 100%;}', 44 | 'a[matLine] {max-width: 0;transition-property: max-width;transition-duration: 0.3s;}', 45 | 'mat-nav-list:hover a[matLine] {max-width: 1000px;}', 46 | '::ng-deep .mat-list-text {padding-left: 0 !important;transition-property: padding-left;transition-duration: 0.4s;}', 47 | 'mat-nav-list:hover ::ng-deep .mat-list-text {padding-left: 16px !important;}' 48 | ], 49 | standalone: true, 50 | imports: [ 51 | BrowserAnimationsModule, 52 | MatListModule, 53 | MatSidenavModule, 54 | MatIconModule, 55 | MatBadgeModule, 56 | ] 57 | }) 58 | export class CollapsibleVerticalNavigationComponent { 59 | } 60 | -------------------------------------------------------------------------------- /stories/usecases/navigation/collapsible-vertical-navigation/collapsible-vertical-navigation.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, StoryObj } from '@storybook/angular'; 2 | import { defaultUsecasesParameters } from '../../../../.storybook/utils'; 3 | import { CollapsibleVerticalNavigationComponent } from './collapsible-vertical-navigation.component'; 4 | 5 | export default { 6 | title: 'Usecases/Navigation', 7 | component: CollapsibleVerticalNavigationComponent, 8 | parameters: { 9 | ...defaultUsecasesParameters, 10 | viewport: { 11 | defaultViewport: 'mobile1', 12 | }, 13 | }, 14 | } as Meta; 15 | 16 | export const CollapsibleVerticalNavigation: StoryObj = { 17 | render: (args) => ({ 18 | props: args, 19 | }), 20 | name: 'collapsible vertical navigation', 21 | }; 22 | -------------------------------------------------------------------------------- /stories/usecases/navigation/fab-bottom-navigation/fab-bottom-navigation.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {MatToolbarModule} from "@angular/material/toolbar"; 3 | import {MatIconModule} from "@angular/material/icon"; 4 | import {MatButtonModule} from "@angular/material/button"; 5 | 6 | @Component({ 7 | selector: 'app-fab-bottom-navigation', 8 | template: ` 9 | 10 |
11 | 12 | home 13 | 14 | 15 | favorite_outline 16 | 17 |
18 |
19 | 20 | login 21 | 22 | 23 | settings 24 | 25 |
26 | 29 |
`, 30 | styles:[ 31 | ':host {height: 100vh; margin: 0;}', 32 | 'mat-toolbar {position: absolute;bottom: 0;display: flex;justify-content: space-between;}', 33 | 'section {width: 40%;display: flex;justify-content: space-around;}', 34 | 'a[mat-icon-button]:not([color]) {color: darkslategrey;}', 35 | 'button[mat-fab] {position: absolute;margin-left: auto;margin-right: auto;left: 0;right: 0;text-align: center;bottom: 30px;}' 36 | ], 37 | standalone: true, 38 | imports: [MatToolbarModule, MatIconModule, MatButtonModule] 39 | }) 40 | export class FabBottomNavigationComponent { 41 | } 42 | -------------------------------------------------------------------------------- /stories/usecases/navigation/fab-bottom-navigation/fab-bottom-navigation.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, StoryObj } from '@storybook/angular'; 2 | import { FabBottomNavigationComponent } from './fab-bottom-navigation.component'; 3 | import { defaultUsecasesParameters } from '../../../../.storybook/utils'; 4 | 5 | export default { 6 | title: 'Usecases/Navigation', 7 | component: FabBottomNavigationComponent, 8 | parameters: { 9 | ...defaultUsecasesParameters, 10 | viewport: { 11 | defaultViewport: 'mobile1', 12 | }, 13 | }, 14 | } as Meta; 15 | 16 | export const Template: StoryObj = { 17 | render: (args) => ({ 18 | props: args, 19 | }), 20 | name: 'bottom navigation 1', 21 | }; 22 | -------------------------------------------------------------------------------- /stories/usecases/navigation/fab-icon-menu/fab-icon-menu.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {MatButtonModule} from "@angular/material/button"; 3 | import {MatIconModule} from "@angular/material/icon"; 4 | import {OverlayModule} from "@angular/cdk/overlay"; 5 | 6 | @Component({ 7 | selector: 'app-fab-icon-menu', 8 | template: ` 9 | 13 | 18 |
    19 |
  • 20 | 23 |
  • 24 |
  • 25 | 28 |
  • 29 |
  • 30 | 33 |
  • 34 |
  • 35 | 38 |
  • 39 |
40 |
41 | , 42 | `, 43 | styles: [ 44 | ':host {height: 100vh; margin: 0;}', 45 | '.fab-menu-btn {position: absolute;right: 1rem; bottom: 1rem;}', 46 | '.fab-menu-list {list-style-type: none; padding:0; margin: 0;}', 47 | '.fab-menu-list li {margin-block-end: 0.5rem;}', 48 | '.fab-menu-list li button {background: white;}', 49 | ], 50 | standalone: true, 51 | imports: [ 52 | MatButtonModule, 53 | MatIconModule, 54 | OverlayModule 55 | ] 56 | }) 57 | export class FabIconMenuComponent { 58 | isOpen = false; 59 | } 60 | -------------------------------------------------------------------------------- /stories/usecases/navigation/fab-icon-menu/fab-icon-menu.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, StoryObj } from '@storybook/angular'; 2 | import { defaultUsecasesParameters } from '../../../../.storybook/utils'; 3 | import { FabIconMenuComponent } from './fab-icon-menu.component'; 4 | 5 | export default { 6 | title: 'Usecases/Navigation', 7 | component: FabIconMenuComponent, 8 | parameters: { 9 | ...defaultUsecasesParameters, 10 | viewport: { 11 | defaultViewport: 'mobile1', 12 | }, 13 | }, 14 | } as Meta; 15 | 16 | export const Fab: StoryObj = { 17 | render: (args) => ({ 18 | props: args, 19 | }), 20 | name: 'fab menu (with icons)', 21 | }; 22 | -------------------------------------------------------------------------------- /stories/usecases/progress-indicators/toolbar-loader.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; 2 | import { MatToolbarModule } from '@angular/material/toolbar'; 3 | import { MatProgressBarModule } from '@angular/material/progress-bar'; 4 | import { MatButtonModule } from '@angular/material/button'; 5 | import { MatIconModule } from '@angular/material/icon'; 6 | import { progressBarArgtypes } from '../../components/progress-bar/progress-bar.argtype'; 7 | import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; 8 | import { progressSpinnerArgtypes } from '../../components/progress-spinner/progress-spinner.argtype'; 9 | import { MatBadgeModule } from '@angular/material/badge'; 10 | import { defaultUsecasesParameters } from '../../../.storybook/utils'; 11 | 12 | export default { 13 | title: 'usecases/Progress indicators', 14 | decorators: [ 15 | moduleMetadata({ 16 | imports: [ 17 | MatToolbarModule, 18 | MatProgressBarModule, 19 | MatProgressSpinnerModule, 20 | MatButtonModule, 21 | MatIconModule, 22 | MatBadgeModule, 23 | ], 24 | }), 25 | ], 26 | argTypes: progressBarArgtypes, 27 | parameters: { 28 | ...defaultUsecasesParameters, 29 | }, 30 | } as Meta; 31 | 32 | export const Toolbar: StoryObj = { 33 | render: (args) => ({ 34 | props: args, 35 | template: ` 36 | 42 | 43 | 46 | 49 | 50 | `, 51 | }), 52 | name: 'toolbar', 53 | }; 54 | 55 | export const Fullscreen: StoryObj = { 56 | render: (args) => ({ 57 | props: args, 58 | template: ` 59 | 77 |
78 |
79 | 80 |

Getting your files

81 |
82 |
83 | 84 |

Getting your files

85 |
86 |
87 | `, 88 | }), 89 | name: 'fullscreen', 90 | argTypes: { 91 | ...progressSpinnerArgtypes, 92 | ...progressBarArgtypes, 93 | }, 94 | }; 95 | -------------------------------------------------------------------------------- /stories/usecases/settings/generic-settings.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {MatDividerModule} from "@angular/material/divider"; 3 | import {MatRadioModule} from "@angular/material/radio"; 4 | import {MatIconModule} from "@angular/material/icon"; 5 | import {MatSlideToggleModule} from "@angular/material/slide-toggle"; 6 | import {CommonModule} from "@angular/common"; 7 | import {MatButtonModule} from "@angular/material/button"; 8 | import {FormsModule} from "@angular/forms"; 9 | import {MatToolbarModule} from "@angular/material/toolbar"; 10 | 11 | @Component({ 12 | template: ` 13 | 14 | settings 15 | SETTINGS 16 | 17 |
18 |

DIRECT MESSAGES

19 | 20 | 21 | from all users 22 | 23 | 24 | from my friends 25 | 26 | 27 | no direct messages 28 | 29 | 30 |
31 | 32 |

PREFERENCES

33 |
    34 |
  • 35 |
    36 | notifications 37 | NOTIFICATIONS 38 |
    39 | 40 |
  • 41 |
  • 42 |
    43 | dark_mode 44 | DARK MODE 45 |
    46 | 47 |
  • 48 |
49 |
50 | 51 |

SECURITY

52 | 53 |
54 | `, 55 | styles: [ 56 | ` 57 | :host { 58 | display: flex; 59 | flex-direction: column; 60 | } 61 | .settings-header__icon { 62 | margin-inline-end: 1rem; 63 | } 64 | 65 | .settings__main-container { 66 | display: flex; 67 | flex-direction: column; 68 | padding: 1rem; 69 | } 70 | 71 | 72 | .settings__messages-group { 73 | display: flex; 74 | flex-direction: column; 75 | } 76 | 77 | .settings__messages-field + .settings__messages-field { 78 | margin-block-start: 0.5rem; 79 | } 80 | 81 | .settings__preferences-list { 82 | list-style-type: none; 83 | margin: 0; 84 | padding: 0; 85 | } 86 | 87 | .settings__prefences-item { 88 | display: flex; 89 | justify-content: space-between; 90 | } 91 | 92 | .settings__prefences-item + .settings__prefences-item { 93 | margin-block-start: 0.5rem; 94 | } 95 | 96 | .settings__prefences-item-title { 97 | display: flex; 98 | align-items: center; 99 | } 100 | 101 | @media (min-width: 800px) { 102 | :host { 103 | align-items: center; 104 | } 105 | .settings__main-container { 106 | max-width: 400px; 107 | width: calc(100% - 2rem); 108 | } 109 | } 110 | ` 111 | ], 112 | standalone: true, 113 | imports: [ 114 | CommonModule, 115 | MatDividerModule, 116 | MatSlideToggleModule, 117 | MatIconModule, 118 | MatRadioModule, 119 | FormsModule, 120 | MatToolbarModule, 121 | MatButtonModule 122 | ] 123 | }) 124 | export class GenericSettingsComponent { 125 | constructor() { 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /stories/usecases/settings/generic-settings.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, StoryObj } from '@storybook/angular'; 2 | import { GenericSettingsComponent } from './generic-settings.component'; 3 | import { defaultUsecasesParameters } from '../../../.storybook/utils'; 4 | 5 | export default { 6 | title: 'usecases/Settings', 7 | component: GenericSettingsComponent, 8 | parameters: { 9 | ...defaultUsecasesParameters, 10 | }, 11 | } as Meta; 12 | 13 | export const Generic: StoryObj = { 14 | render: (args) => ({ 15 | props: args, 16 | }), 17 | name: 'generic', 18 | }; 19 | -------------------------------------------------------------------------------- /stories/usecases/settings/wifi-settings.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {MatToolbarModule} from "@angular/material/toolbar"; 3 | import {MatIconModule} from "@angular/material/icon"; 4 | import {MatSlideToggleModule} from "@angular/material/slide-toggle"; 5 | import {MatListModule} from "@angular/material/list"; 6 | import {MatDividerModule} from "@angular/material/divider"; 7 | import {MatButtonModule} from "@angular/material/button"; 8 | 9 | @Component({ 10 | template: ` 11 | 12 | arrow_back 13 | Wi-Fi 14 | 15 | 16 | Activate Wi-Fi 17 | 18 | 19 |
20 | 21 | 28 | 29 | 30 | 31 | 32 | 37 | 38 | 39 | 44 | 45 | 46 | 51 | 52 |
53 | `, 54 | styles: [ 55 | ` 56 | .wifi-header__back-button { 57 | margin-inline-end: 1rem; 58 | } 59 | 60 | .wifi-toolbar__activate { 61 | display: flex; 62 | align-items: center; 63 | justify-content: space-between; 64 | } 65 | 66 | .wifi__activated { 67 | color: green; 68 | } 69 | ` 70 | ], 71 | standalone: true, 72 | imports: [ 73 | MatToolbarModule, 74 | MatIconModule, 75 | MatSlideToggleModule, 76 | MatListModule, 77 | MatDividerModule, 78 | MatButtonModule 79 | ] 80 | }) 81 | export class WifiSettingsComponent { 82 | constructor() { 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /stories/usecases/settings/wifi-settings.stories.ts: -------------------------------------------------------------------------------- 1 | import { Meta, StoryObj } from '@storybook/angular'; 2 | import { WifiSettingsComponent } from './wifi-settings.component'; 3 | import { defaultUsecasesParameters } from '../../../.storybook/utils'; 4 | 5 | export default { 6 | title: 'usecases/Settings', 7 | component: WifiSettingsComponent, 8 | parameters: { 9 | ...defaultUsecasesParameters, 10 | }, 11 | } as Meta; 12 | 13 | export const Wifi: StoryObj = { 14 | render: (args) => ({ 15 | props: args, 16 | }), 17 | name: 'Wi-Fi', 18 | }; 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "es2020", 21 | "lib": [ 22 | "es2020", 23 | "dom" 24 | ], 25 | "useDefineForClassFields": false 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | --------------------------------------------------------------------------------