我有一个 ui 组件:
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { MatRippleModule } from '@angular/material/core';
import { TranslocoModule } from '@ngneat/transloco';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
/**
* Todo - Add description
* Todo - Add a basic button and use them in dialogs, now we use outline buttons without hover shadow
* Also remove no-shadow class
* https://material.angular.io/components/button/overview
*
* form: for when the button is of type submit and it's outside of the form tag. Add an id to the form with the same name
*
* @description
* This component is used to render a button.
*s
* @example
* <vetfysio-button
* [label]="'Button label'"
* [disabled]="false"
* (action)="action()">
* </vetfysio-button>
*/
@Component({
selector: 'vh-button',
templateUrl: './button.component.html',
styleUrls: ['./button.component.scss'],
standalone: true,
imports: [MatRippleModule, CommonModule, TranslocoModule, FontAwesomeModule],
})
export class ButtonComponent {
@Input() label!: string;
@Input() disabled?: boolean;
@Input() color: 'basic' | 'primary' | 'secondary' | 'warning' | 'dark' =
'basic';
@Input() size: 'extra-small' | 'small' | 'base' | 'large' | 'extra-large' =
'base';
@Input() type: string = 'button';
@Input() rounded: boolean = false;
@Input() outline: boolean = false;
@Input() prefixIcon?: IconProp;
@Input() suffixIcon?: IconProp;
@Input() shadow: boolean = true;
@Input() cdkFocusInitial: boolean = false;
@Input() form?: string;
@Output() action = new EventEmitter<void>();
}
button.component.stories.ts:
import {
Meta,
StoryObj,
moduleMetadata,
argsToTemplate,
} from '@storybook/angular';
import { provideHttpClient } from '@angular/common/http';
import { within } from '@storybook/testing-library';
import { expect } from '@storybook/jest';
import { applicationConfig } from '@storybook/angular';
import { provideTransloco } from '@ngneat/transloco';
import { TranslocoHttpLoader, translocoConf } from '@vh-components/transloco';
import { ButtonComponent } from './button.component';
import {
FaIconLibrary,
FontAwesomeModule,
} from '@fortawesome/angular-fontawesome';
import { APP_INITIALIZER, importProvidersFrom } from '@angular/core';
import { faCoffee } from '@fortawesome/free-solid-svg-icons';
const meta: Meta<ButtonComponent> = {
component: ButtonComponent,
title: 'Design system/Buttons/Button',
tags: ['autodocs'],
decorators: [
moduleMetadata({
imports: [FontAwesomeModule],
providers: [
{
provide: APP_INITIALIZER,
useFactory: (iconLibrary: FaIconLibrary) => async () => {
// Add any icons needed here:
iconLibrary.addIcons(faCoffee);
},
// When using a factory provider you need to explicitly specify its dependencies.
deps: [FaIconLibrary],
multi: true,
},
],
}),
applicationConfig({
providers: [
provideHttpClient(),
provideTransloco({
config: translocoConf,
loader: TranslocoHttpLoader,
}),
// importProvidersFrom(TranslocoSharedModule), // TODO Why does this not work?
],
}),
],
render: (args: ButtonComponent) => ({
props: {
...args,
},
template: `
<vh-button ${argsToTemplate(args)}></vh-button>
`,
}),
};
export default meta;
type Story = StoryObj<ButtonComponent>;
export const Default: Story = {
args: {
label: 'text1',
disabled: false,
color: 'primary',
prefixIcon: 'coffee',
},
argTypes: {
color: {
control: {
type: 'select',
},
options: ['basic', 'primary', 'secondary', 'warning', 'dark'],
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(canvas.getByText(/button works!/gi)).toBeTruthy();
},
};
export const disabled: Story = {
args: {
...Default.args,
disabled: true,
},
};
但是 fontawesome 在故事书中不起作用。
它正在我的角度应用程序中工作:
import { Component } from '@angular/core';
import { FaConfig, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { faCoffee } from '@fortawesome/free-solid-svg-icons';
import { NxWelcomeComponent } from './nx-welcome.component';
@Component({
standalone: true,
imports: [NxWelcomeComponent],
selector: 'vh-components-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
title = 'vh-components';
constructor(library: FaIconLibrary, faConfig: FaConfig) {
faConfig.fixedWidth = true;
library.addIcons(faCoffee);
}
}
Package.json:
{
"name": "@vh-components/source",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"start": "nx serve",
"build": "nx build",
"test": "nx test",
"storybook": "nx run vh-components:storybook"
},
"private": true,
"dependencies": {
"@angular/animations": "~16.2.0",
"@angular/cdk": "^16.2.12",
"@angular/common": "~16.2.0",
"@angular/compiler": "~16.2.0",
"@angular/core": "~16.2.0",
"@angular/forms": "~16.2.0",
"@angular/material": "^16.2.12",
"@angular/platform-browser": "~16.2.0",
"@angular/platform-browser-dynamic": "~16.2.0",
"@angular/router": "~16.2.0",
"@fortawesome/angular-fontawesome": "^0.13.0",
"@fortawesome/fontawesome-svg-core": "^6.5.0",
"@fortawesome/free-solid-svg-icons": "^6.5.0",
"@ngneat/transloco": "^6.0.0",
"@nx/angular": "17.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.13.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "~16.2.0",
"@angular-devkit/core": "~16.2.0",
"@angular-devkit/schematics": "~16.2.0",
"@angular-eslint/eslint-plugin": "~16.0.0",
"@angular-eslint/eslint-plugin-template": "~16.0.0",
"@angular-eslint/template-parser": "~16.0.0",
"@angular/cli": "~16.2.0",
"@angular/compiler-cli": "~16.2.0",
"@angular/language-service": "~16.2.0",
"@nx/eslint": "17.0.3",
"@nx/eslint-plugin": "17.0.3",
"@nx/jest": "17.0.3",
"@nx/js": "17.0.3",
"@nx/storybook": "17.0.3",
"@nx/web": "17.0.3",
"@nx/workspace": "17.0.3",
"@schematics/angular": "~16.2.0",
"@storybook/addon-essentials": "^7.5.1",
"@storybook/addon-interactions": "^7.5.1",
"@storybook/addon-storysource": "^7.5.1",
"@storybook/angular": "^7.5.1",
"@storybook/core-server": "^7.5.1",
"@storybook/jest": "~0.1.0",
"@storybook/test-runner": "^0.13.0",
"@storybook/testing-library": "~0.2.0",
"@swc-node/register": "~1.6.7",
"@swc/core": "~1.3.85",
"@tailwindcss/typography": "^0.5.10",
"@types/jest": "^29.4.0",
"@types/node": "16.11.7",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"autoprefixer": "^10.4.0",
"eslint": "~8.46.0",
"eslint-config-prettier": "^9.0.0",
"jest": "^29.4.1",
"jest-environment-jsdom": "^29.4.1",
"jest-preset-angular": "~13.1.0",
"jsonc-eslint-parser": "^2.1.0",
"ng-packagr": "~16.2.0",
"nx": "17.0.3",
"postcss": "^8.4.5",
"postcss-import": "~14.1.0",
"postcss-preset-env": "~7.5.0",
"postcss-url": "~10.1.3",
"prettier": "^2.6.2",
"storybook-addon-pseudo-states": "^2.1.2",
"tailwindcss": "^3.3.5",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
"typescript": "~5.1.3"
}
}
项目.json
{
"name": "vh-components",
"$schema": "node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"prefix": "vh-components",
"sourceRoot": "./src",
"tags": [],
"targets": {
"build": {
"executor": "@angular-devkit/build-angular:browser",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/vh-components",
"index": "./src/index.html",
"main": "./src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "./tsconfig.app.json",
"assets": ["./src/favicon.ico", "./src/assets"],
"styles": ["./src/styles.scss"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"executor": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "vh-components:build:production"
},
"development": {
"browserTarget": "vh-components:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"executor": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "vh-components:build"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["./src/**/*.ts", "./src/**/*.html"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectName}"],
"options": {
"jestConfig": "jest.config.app.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"storybook": {
"executor": "@storybook/angular:start-storybook",
"options": {
"port": 4400,
"configDir": "./.storybook",
"browserTarget": "vh-components:build",
"compodoc": false,
"assets": [
"src/favicon.ico",
"src/assets"
]
},
"configurations": {
"ci": {
"quiet": true
}
}
},
"build-storybook": {
"executor": "@storybook/angular:build-storybook",
"outputs": ["{options.outputDir}"],
"options": {
"outputDir": "dist/storybook/vh-components",
"configDir": "./.storybook",
"browserTarget": "vh-components:build",
"compodoc": false,
"assets": [
"src/favicon.ico",
"src/assets"
]
},
"configurations": {
"ci": {
"quiet": true
}
}
},
"test-storybook": {
"executor": "nx:run-commands",
"options": {
"command": "test-storybook -c ./.storybook --url=http://localhost:4400"
}
},
"static-storybook": {
"executor": "@nx/web:file-server",
"options": {
"buildTarget": "vh-components:build-storybook",
"staticFilePath": "dist/storybook/vh-components"
},
"configurations": {
"ci": {
"buildTarget": "vh-components:build-storybook:ci"
}
}
}
}
}
尝试对您的故事文件进行以下更改。设置 Angular 模块时,您需要导入独立组件。与在另一个组件中使用该组件的方式相同。
import {
Meta,
StoryObj,
moduleMetadata,
argsToTemplate,
} from '@storybook/angular';
import { provideHttpClient } from '@angular/common/http';
import { within } from '@storybook/testing-library';
import { expect } from '@storybook/jest';
import { applicationConfig } from '@storybook/angular';
import { provideTransloco } from '@ngneat/transloco';
import { TranslocoHttpLoader, translocoConf } from '@vh-components/transloco';
import { ButtonComponent } from './button.component';
import {
FaIconLibrary,
FontAwesomeModule,
} from '@fortawesome/angular-fontawesome';
import { APP_INITIALIZER, importProvidersFrom } from '@angular/core';
import { faCoffee } from '@fortawesome/free-solid-svg-icons';
const meta: Meta<ButtonComponent> = {
component: ButtonComponent,
title: 'Design system/Buttons/Button',
tags: ['autodocs'],
decorators: [
moduleMetadata({
imports: [ButtonComponent], // <== Here
providers: [
{
provide: APP_INITIALIZER,
useFactory: (iconLibrary: FaIconLibrary) => async () => {
// Add any icons needed here:
iconLibrary.addIcons(faCoffee);
},
// When using a factory provider you need to explicitly specify its dependencies.
deps: [FaIconLibrary],
multi: true,
},
],
}),
applicationConfig({
providers: [
provideHttpClient(),
provideTransloco({
config: translocoConf,
loader: TranslocoHttpLoader,
}),
// importProvidersFrom(TranslocoSharedModule), // TODO Why does this not work?
],
}),
],
render: (args: ButtonComponent) => ({
props: {
...args,
},
template: `
<vh-button ${argsToTemplate(args)}></vh-button>
`,
}),
};
export default meta;
type Story = StoryObj<ButtonComponent>;
export const Default: Story = {
args: {
label: 'text1',
disabled: false,
color: 'primary',
prefixIcon: 'coffee',
},
argTypes: {
color: {
control: {
type: 'select',
},
options: ['basic', 'primary', 'secondary', 'warning', 'dark'],
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(canvas.getByText(/button works!/gi)).toBeTruthy();
},
};
export const disabled: Story = {
args: {
...Default.args,
disabled: true,
},
};