From 0d0950454a71c46ed16f8a3991c00fbb84e2a4da Mon Sep 17 00:00:00 2001 From: auraofdivinity Date: Fri, 10 Oct 2025 14:05:08 +0530 Subject: [PATCH 1/8] feat(storybooks): init storybooks --- .gitignore | 3 + .vscode/extensions.json | 4 +- nx.json | 32 +++-- package.json | 23 +++- packages/react/.storybook/main.ts | 25 ++++ packages/react/.storybook/preview.tsx | 41 +++++++ packages/react/package.json | 4 +- .../primitives/Checkbox/Checkbox.stories.tsx | 112 ++++++++++++++++++ packages/react/tsconfig.json | 3 + packages/react/tsconfig.lib.json | 6 +- packages/react/tsconfig.storybook.json | 32 +++++ tsconfig.json | 9 +- 12 files changed, 274 insertions(+), 20 deletions(-) create mode 100644 packages/react/.storybook/main.ts create mode 100644 packages/react/.storybook/preview.tsx create mode 100644 packages/react/src/components/primitives/Checkbox/Checkbox.stories.tsx create mode 100644 packages/react/tsconfig.storybook.json diff --git a/.gitignore b/.gitignore index 6e06d3ee..b9987ae2 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ Thumbs.db # Experimental Samples # NOTE to Developers: Please use this samples folder for experimental code only and do not commit. samples/__experimental__/ + + +storybook-static \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 91feb169..71f5e856 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,3 @@ { - "recommendations": [ - "nrwl.angular-console" - ] + "recommendations": ["nrwl.angular-console", "esbenp.prettier-vscode"] } diff --git a/nx.json b/nx.json index f5c24760..d0aeb1ff 100644 --- a/nx.json +++ b/nx.json @@ -1,26 +1,32 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", "namedInputs": { - "default": [ - "{projectRoot}/**/*", - "sharedGlobals" - ], + "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ - "default" + "default", + "!{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)", + "!{projectRoot}/.storybook/**/*", + "!{projectRoot}/tsconfig.storybook.json" ], "sharedGlobals": [] }, "targetDefaults": { "build": { - "dependsOn": [ - "^build" - ] + "dependsOn": ["^build"] }, "typecheck": { - "dependsOn": [ - "^build" - ] + "dependsOn": ["^build"] } }, - "plugins": [] -} \ No newline at end of file + "plugins": [ + { + "plugin": "@nx/storybook/plugin", + "options": { + "serveStorybookTargetName": "storybook", + "buildStorybookTargetName": "build-storybook", + "testStorybookTargetName": "test-storybook", + "staticStorybookTargetName": "static-storybook" + } + } + ] +} diff --git a/package.json b/package.json index a10805b9..c8bde9eb 100644 --- a/package.json +++ b/package.json @@ -31,12 +31,33 @@ "devDependencies": { "@changesets/changelog-github": "^0.5.1", "@changesets/cli": "^2.29.4", + "@nx/js": "20.8.2", + "@nx/react": "^20.8.2", + "@nx/storybook": "^20.8.2", + "@nx/vite": "20.8.2", + "@nx/web": "20.8.2", + "@storybook/addon-a11y": "^8.6.14", + "@storybook/addon-docs": "^8.6.14", + "@storybook/addon-essentials": "^8.6.14", + "@storybook/addon-interactions": "^8.6.14", + "@storybook/addon-viewport": "^8.6.14", + "@storybook/core-server": "^8.6.14", + "@storybook/react": "^8.6.14", + "@storybook/react-vite": "^8.6.14", + "@storybook/test": "^8.6.14", + "@swc-node/register": "~1.9.1", + "@swc/core": "~1.5.7", + "@swc/helpers": "~0.5.11", "@wso2/eslint-plugin": "catalog:", "@wso2/prettier-config": "catalog:", "eslint": "8.57.0", "nx": "20.8.1", "prettier": "^2.6.2", - "typescript": "~5.7.2" + "storybook": "^8.6.14", + "ts-node": "^10.9.2", + "tslib": "^2.3.0", + "typescript": "~5.7.2", + "vite": "^5.4.20" }, "publishConfig": { "access": "restricted" diff --git a/packages/react/.storybook/main.ts b/packages/react/.storybook/main.ts new file mode 100644 index 00000000..9ea90b51 --- /dev/null +++ b/packages/react/.storybook/main.ts @@ -0,0 +1,25 @@ +import type {StorybookConfig} from '@storybook/react-vite'; + +import {nxViteTsPaths} from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; +import {mergeConfig} from 'vite'; +import react from '@vitejs/plugin-react'; + +const config: StorybookConfig = { + stories: ['../src/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'], + addons: ['@storybook/addon-essentials'], + framework: { + name: '@storybook/react-vite', + options: {}, + }, + + viteFinal: async config => + mergeConfig(config, { + plugins: [react(), nxViteTsPaths()], + }), +}; + +export default config; + +// To customize your Vite configuration you can use the viteFinal field. +// Check https://storybook.js.org/docs/react/builders/vite#configuration +// and https://nx.dev/recipes/storybook/custom-builder-configs diff --git a/packages/react/.storybook/preview.tsx b/packages/react/.storybook/preview.tsx new file mode 100644 index 00000000..5f4130f4 --- /dev/null +++ b/packages/react/.storybook/preview.tsx @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Preview} from '@storybook/react'; +import ThemeProvider from '../src/contexts/Theme/ThemeProvider'; + +const preview: Preview = { + parameters: { + actions: {argTypesRegex: '^on[A-Z].*'}, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, + decorators: [ + Story => ( + + + + ), + ], +}; + +export default preview; diff --git a/packages/react/package.json b/packages/react/package.json index 5eb3be03..15da2181 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -38,7 +38,9 @@ "lint": "eslint . --ext .js,.jsx,.ts,.tsx,.cjs,.mjs", "test": "vitest", "test:browser": "vitest --workspace=vitest.workspace.ts", - "typecheck": "tsc -p tsconfig.lib.json" + "typecheck": "tsc -p tsconfig.lib.json", + "storybook": "storybook dev -p 6006 -c ./.storybook", + "build-storybook": "storybook build -c ./.storybook -o ../../dist/storybook/asgardeo-react" }, "devDependencies": { "@testing-library/dom": "^10.4.0", diff --git a/packages/react/src/components/primitives/Checkbox/Checkbox.stories.tsx b/packages/react/src/components/primitives/Checkbox/Checkbox.stories.tsx new file mode 100644 index 00000000..2834a801 --- /dev/null +++ b/packages/react/src/components/primitives/Checkbox/Checkbox.stories.tsx @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import Checkbox from './Checkbox'; + +const meta: Meta = { + title: 'Components/Primitives/Checkbox', + component: Checkbox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + label: { + control: 'text', + description: 'Label text to display next to the checkbox', + }, + error: { + control: 'text', + description: 'Error message to display below the checkbox', + }, + required: { + control: 'boolean', + description: 'Whether the field is required', + }, + helperText: { + control: 'text', + description: 'Helper text to display below the checkbox', + }, + disabled: { + control: 'boolean', + description: 'Whether the checkbox is disabled', + }, + checked: { + control: 'boolean', + description: 'Whether the checkbox is checked', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + label: 'Accept terms and conditions', + }, +}; + +export const Checked: Story = { + args: { + label: 'Subscribe to newsletter', + checked: true, + }, +}; + +export const Required: Story = { + args: { + label: 'I agree to the privacy policy', + required: true, + }, +}; + +export const WithHelperText: Story = { + args: { + label: 'Enable notifications', + helperText: 'You will receive email notifications about important updates', + }, +}; + +export const WithError: Story = { + args: { + label: 'Accept terms and conditions', + error: 'You must accept the terms and conditions to continue', + required: true, + }, +}; + +export const Disabled: Story = { + args: { + label: 'This option is not available', + disabled: true, + }, +}; + +export const DisabledChecked: Story = { + args: { + label: 'This option is pre-selected', + disabled: true, + checked: true, + }, +}; + +export const WithoutLabel: Story = { + args: {}, +}; diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json index 59084d66..4f82b7a9 100644 --- a/packages/react/tsconfig.json +++ b/packages/react/tsconfig.json @@ -31,6 +31,9 @@ }, { "path": "./tsconfig.spec.json" + }, + { + "path": "./tsconfig.storybook.json" } ] } diff --git a/packages/react/tsconfig.lib.json b/packages/react/tsconfig.lib.json index 8d37e00d..f5428765 100644 --- a/packages/react/tsconfig.lib.json +++ b/packages/react/tsconfig.lib.json @@ -14,7 +14,11 @@ "**/*.spec.js", "**/*.test.js", "**/*.spec.jsx", - "**/*.test.jsx" + "**/*.test.jsx", + "**/*.stories.ts", + "**/*.stories.js", + "**/*.stories.jsx", + "**/*.stories.tsx" ], "include": ["src/**/*.js", "src/**/*.ts", "src/**/*.jsx", "src/**/*.tsx", "types/**/*.d.ts"] } diff --git a/packages/react/tsconfig.storybook.json b/packages/react/tsconfig.storybook.json new file mode 100644 index 00000000..88a45468 --- /dev/null +++ b/packages/react/tsconfig.storybook.json @@ -0,0 +1,32 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "emitDecoratorMetadata": true, + "outDir": "" + }, + "exclude": [ + "src/**/*.spec.ts", + "src/**/*.test.ts", + "src/**/*.spec.js", + "src/**/*.test.js", + "src/**/*.spec.tsx", + "src/**/*.test.tsx", + "src/**/*.spec.jsx", + "src/**/*.test.js" + ], + "include": [ + "src/**/*.stories.ts", + "src/**/*.stories.js", + "src/**/*.stories.jsx", + "src/**/*.stories.tsx", + "src/**/*.stories.mdx", + ".storybook/*.js", + ".storybook/*.ts", + ".storybook/preview.tsx" + ], + "files": [ + "../../node_modules/@nx/react/typings/styled-jsx.d.ts", + "../../node_modules/@nx/react/typings/cssmodule.d.ts", + "../../node_modules/@nx/react/typings/image.d.ts" + ] +} diff --git a/tsconfig.json b/tsconfig.json index dc121f19..35fcc4f1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,14 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "@asgardeo/react": ["packages/react/src/index.ts"], + "@asgardeo/react": ["packages/react/src/index.ts"] + }, + "skipLibCheck": true + }, + "ts-node": { + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node10" } } } From 74f3033fc24b6073eea6aa7c4add5ac21e805168 Mon Sep 17 00:00:00 2001 From: auraofdivinity Date: Sat, 11 Oct 2025 01:58:22 +0530 Subject: [PATCH 2/8] feat(storybook): add accessibility addon --- packages/react/.storybook/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/.storybook/main.ts b/packages/react/.storybook/main.ts index 9ea90b51..c149cdd3 100644 --- a/packages/react/.storybook/main.ts +++ b/packages/react/.storybook/main.ts @@ -6,7 +6,7 @@ import react from '@vitejs/plugin-react'; const config: StorybookConfig = { stories: ['../src/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'], - addons: ['@storybook/addon-essentials'], + addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'], framework: { name: '@storybook/react-vite', options: {}, From ed10cd88f01286b50cd58965d2044e671e2e9e9b Mon Sep 17 00:00:00 2001 From: auraofdivinity Date: Sat, 11 Oct 2025 09:58:48 +0530 Subject: [PATCH 3/8] feat(i18n): integrate I18nProvider and add locale selection in Storybook --- packages/react/.storybook/preview.tsx | 45 ++++- .../SignOutButton/SignOutButton.stories.tsx | 170 ++++++++++++++++++ .../react/src/contexts/I18n/I18nProvider.tsx | 7 + 3 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx diff --git a/packages/react/.storybook/preview.tsx b/packages/react/.storybook/preview.tsx index 5f4130f4..3dc6b3a4 100644 --- a/packages/react/.storybook/preview.tsx +++ b/packages/react/.storybook/preview.tsx @@ -18,6 +18,27 @@ import type {Preview} from '@storybook/react'; import ThemeProvider from '../src/contexts/Theme/ThemeProvider'; +import I18nProvider from '../src/contexts/I18n/I18nProvider'; +import {en_US, fr_FR, hi_IN, si_LK} from '@asgardeo/i18n'; + +export const globalTypes = { + locale: { + name: 'Locale', + description: 'Internationalization locale', + toolbar: { + title: 'Locale', + icon: 'globe', + items: [ + {value: 'en-US', title: 'English'}, + {value: 'fr-FR', title: 'French'}, + {value: 'hi-IN', title: 'Hindi'}, + {value: 'si-LK', title: 'Sinhala'}, + ], + showName: true, + dynamicTitle: true, + }, + }, +}; const preview: Preview = { parameters: { @@ -30,11 +51,25 @@ const preview: Preview = { }, }, decorators: [ - Story => ( - - - - ), + (Story, context) => { + const locale = context.globals['locale']; + + // Create custom bundles that include all available languages for Storybook + const storybookBundles = { + 'en-US': en_US, + 'fr-FR': fr_FR, + 'hi-IN': hi_IN, + 'si-LK': si_LK, + }; + + return ( + + + + + + ); + }, ], }; diff --git a/packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx b/packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx new file mode 100644 index 00000000..a27a758a --- /dev/null +++ b/packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx @@ -0,0 +1,170 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import SignOutButton from './SignOutButton'; +import useI18n from '../../../contexts/I18n/useI18n'; + +const meta: Meta = { + title: 'Components/Actions/SignOutButton', + component: SignOutButton, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + children: { + control: 'text', + description: + 'Custom text to display on the button. If not provided, uses translation key "elements.buttons.signOut"', + }, + onClick: { + action: 'clicked', + description: 'Callback function called after successful sign out', + }, + className: { + control: 'text', + description: 'Additional CSS classes to apply to the button', + }, + style: { + control: 'object', + description: 'Inline styles to apply to the button', + }, + disabled: { + control: 'boolean', + description: 'Whether the button is disabled', + }, + preferences: { + control: 'object', + description: 'Component-level preferences including i18n bundles for custom translations', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +/** + * Default SignOutButton using the translation system. + * The button text will change based on the locale selected in the Storybook toolbar. + * - English: "Sign Out" + * - French: "Se déconnecter" + * - Hindi: "साइन आउट" + * - Sinhala: "ඉවත් වෙන්න" + */ +export const Default: Story = { + render: args => { + const {t} = useI18n(); + const signOutText = t('elements.buttons.signOut'); + return {signOutText}; + }, + args: {}, +}; + +/** + * SignOutButton with custom text. + * This overrides the translation system and displays the custom text regardless of locale. + */ +export const WithCustomText: Story = { + args: { + children: 'Sign Out', + }, +}; + +/** + * SignOutButton using render props pattern. + * This demonstrates the advanced usage where you can access the signOut function and loading state. + */ +export const WithRenderProps: Story = { + render: args => { + const {t} = useI18n(); + const signOutText = t('elements.buttons.signOut'); + const loadingText = t('messages.loading'); + + return ( + ( + + )} + /> + ); + }, + args: {}, +}; + +/** + * SignOutButton with custom styling. + * Demonstrates how to apply custom CSS classes and inline styles. + */ +export const WithCustomStyling: Story = { + render: args => { + const {t} = useI18n(); + const signOutText = t('elements.buttons.signOut'); + + return ( + + {signOutText} + + ); + }, + args: {}, +}; + +/** + * Disabled SignOutButton. + * Shows the button in a disabled state. + */ +export const Disabled: Story = { + render: args => { + const {t} = useI18n(); + const signOutText = t('elements.buttons.signOut'); + + return ( + + {signOutText} + + ); + }, + args: {}, +}; diff --git a/packages/react/src/contexts/I18n/I18nProvider.tsx b/packages/react/src/contexts/I18n/I18nProvider.tsx index 23ea0a83..4e74da89 100644 --- a/packages/react/src/contexts/I18n/I18nProvider.tsx +++ b/packages/react/src/contexts/I18n/I18nProvider.tsx @@ -134,6 +134,13 @@ const I18nProvider: FC> = ({ storeLanguage(currentLanguage); }, [currentLanguage]); + // Sync language with preferences when they change (e.g., Storybook toolbar) + useEffect(() => { + if (preferences?.language && preferences.language !== currentLanguage) { + setCurrentLanguage(preferences.language); + } + }, [preferences?.language, currentLanguage]); + // Translation function const t = useCallback( (key: string, params?: Record): string => { From 39724093afe9a2af6c3cfa0ee04837c76380863d Mon Sep 17 00:00:00 2001 From: auraofdivinity Date: Sat, 11 Oct 2025 10:13:40 +0530 Subject: [PATCH 4/8] feat(storybooks): add actions (SignInButton, SignUpButton, SignOutButton) stories. --- .../SignInButton/SignInButton.stories.tsx | 252 ++++++++++++++++++ .../SignOutButton/SignOutButton.stories.tsx | 47 +++- .../SignUpButton/SignUpButton.stories.tsx | 224 ++++++++++++++++ 3 files changed, 510 insertions(+), 13 deletions(-) create mode 100644 packages/react/src/components/actions/SignInButton/SignInButton.stories.tsx create mode 100644 packages/react/src/components/actions/SignUpButton/SignUpButton.stories.tsx diff --git a/packages/react/src/components/actions/SignInButton/SignInButton.stories.tsx b/packages/react/src/components/actions/SignInButton/SignInButton.stories.tsx new file mode 100644 index 00000000..a14194fe --- /dev/null +++ b/packages/react/src/components/actions/SignInButton/SignInButton.stories.tsx @@ -0,0 +1,252 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import SignInButton from './SignInButton'; +import useI18n from '../../../contexts/I18n/useI18n'; + +const meta: Meta = { + title: 'Components/Actions/SignInButton', + component: SignInButton, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + children: { + control: 'text', + description: + 'Custom text to display on the button. If not provided, uses translation key "elements.buttons.signIn"', + }, + onClick: { + action: 'clicked', + description: 'Callback function called after successful sign in', + }, + className: { + control: 'text', + description: 'Additional CSS classes to apply to the button', + }, + style: { + control: 'object', + description: 'Inline styles to apply to the button', + }, + disabled: { + control: 'boolean', + description: 'Whether the button is disabled', + }, + preferences: { + control: 'object', + description: 'Component-level preferences including i18n bundles for custom translations', + }, + signInOptions: { + control: 'object', + description: 'Additional parameters to pass to the authorize request', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +/** + * Default SignInButton with automatic translation support. + * The button text will change based on the locale selected in the Storybook toolbar. + */ +export const Default: Story = { + render: args => { + const {t} = useI18n(); + const signInText = t('elements.buttons.signIn'); + + return {signInText}; + }, + args: {}, +}; + +/** + * SignInButton with custom text that overrides the translation system. + * This demonstrates how to provide custom text regardless of the current locale. + */ +export const WithCustomText: Story = { + args: { + children: 'Sign In', + }, +}; + +/** + * SignInButton using the render props pattern. + * This demonstrates advanced usage where you can access the signIn function and loading state. + */ +export const WithRenderProps: Story = { + render: args => { + const {t} = useI18n(); + const signInText = t('elements.buttons.signIn'); + const loadingText = t('messages.loading'); + + return ( + ( + + )} + /> + ); + }, + args: {}, +}; + +/** + * SignInButton with custom styling applied via className and inline styles. + * This demonstrates how to customize the button's appearance. + */ +export const WithCustomStyling: Story = { + render: args => { + const {t} = useI18n(); + const signInText = t('elements.buttons.signIn'); + + return ( + + {signInText} + + ); + }, + args: {}, +}; + +/** + * SignInButton in a disabled state. + * This demonstrates the button's disabled appearance and behavior. + */ +export const Disabled: Story = { + render: args => { + const {t} = useI18n(); + const signInText = t('elements.buttons.signIn'); + + return ( + + {signInText} + + ); + }, + args: {}, +}; + +/** + * SignInButton with a custom onClick handler. + * This demonstrates how to handle the click event and perform additional actions after sign in. + */ +export const WithOnClickHandler: Story = { + render: args => { + const {t} = useI18n(); + const signInText = t('elements.buttons.signIn'); + + return ( + { + console.log('Sign in completed!', event); + alert('You have been signed in successfully!'); + }} + > + {signInText} + + ); + }, + args: {}, +}; + +/** + * SignInButton with custom sign-in options. + * This demonstrates how to pass additional parameters to the authorize request. + */ +export const WithSignInOptions: Story = { + render: args => { + const {t} = useI18n(); + const signInText = t('elements.buttons.signIn'); + + return ( + + {signInText} + + ); + }, + args: {}, +}; + +/** + * SignInButton with component-level i18n preferences. + * This demonstrates how to override translations at the component level. + */ +export const WithCustomTranslations: Story = { + render: args => { + return ( + + ); + }, + args: {}, +}; diff --git a/packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx b/packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx index a27a758a..0ed67d31 100644 --- a/packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx +++ b/packages/react/src/components/actions/SignOutButton/SignOutButton.stories.tsx @@ -60,25 +60,22 @@ export default meta; type Story = StoryObj; /** - * Default SignOutButton using the translation system. + * Default SignOutButton with automatic translation support. * The button text will change based on the locale selected in the Storybook toolbar. - * - English: "Sign Out" - * - French: "Se déconnecter" - * - Hindi: "साइन आउट" - * - Sinhala: "ඉවත් වෙන්න" */ export const Default: Story = { render: args => { const {t} = useI18n(); const signOutText = t('elements.buttons.signOut'); + return {signOutText}; }, args: {}, }; /** - * SignOutButton with custom text. - * This overrides the translation system and displays the custom text regardless of locale. + * SignOutButton with custom text that overrides the translation system. + * This demonstrates how to provide custom text regardless of the current locale. */ export const WithCustomText: Story = { args: { @@ -87,8 +84,8 @@ export const WithCustomText: Story = { }; /** - * SignOutButton using render props pattern. - * This demonstrates the advanced usage where you can access the signOut function and loading state. + * SignOutButton using the render props pattern. + * This demonstrates advanced usage where you can access the signOut function and loading state. */ export const WithRenderProps: Story = { render: args => { @@ -122,8 +119,8 @@ export const WithRenderProps: Story = { }; /** - * SignOutButton with custom styling. - * Demonstrates how to apply custom CSS classes and inline styles. + * SignOutButton with custom styling applied via className and inline styles. + * This demonstrates how to customize the button's appearance. */ export const WithCustomStyling: Story = { render: args => { @@ -152,8 +149,8 @@ export const WithCustomStyling: Story = { }; /** - * Disabled SignOutButton. - * Shows the button in a disabled state. + * SignOutButton in a disabled state. + * This demonstrates the button's disabled appearance and behavior. */ export const Disabled: Story = { render: args => { @@ -168,3 +165,27 @@ export const Disabled: Story = { }, args: {}, }; + +/** + * SignOutButton with a custom onClick handler. + * This demonstrates how to handle the click event and perform additional actions after sign out. + */ +export const WithOnClickHandler: Story = { + render: args => { + const {t} = useI18n(); + const signOutText = t('elements.buttons.signOut'); + + return ( + { + console.log('Sign out completed!', event); + alert('You have been signed out successfully!'); + }} + > + {signOutText} + + ); + }, + args: {}, +}; diff --git a/packages/react/src/components/actions/SignUpButton/SignUpButton.stories.tsx b/packages/react/src/components/actions/SignUpButton/SignUpButton.stories.tsx new file mode 100644 index 00000000..ff5a3837 --- /dev/null +++ b/packages/react/src/components/actions/SignUpButton/SignUpButton.stories.tsx @@ -0,0 +1,224 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import SignUpButton from './SignUpButton'; +import useI18n from '../../../contexts/I18n/useI18n'; + +const meta: Meta = { + title: 'Components/Actions/SignUpButton', + component: SignUpButton, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + children: { + control: 'text', + description: + 'Custom text to display on the button. If not provided, uses translation key "elements.buttons.signUp"', + }, + onClick: { + action: 'clicked', + description: 'Callback function called after successful sign up', + }, + className: { + control: 'text', + description: 'Additional CSS classes to apply to the button', + }, + style: { + control: 'object', + description: 'Inline styles to apply to the button', + }, + disabled: { + control: 'boolean', + description: 'Whether the button is disabled', + }, + preferences: { + control: 'object', + description: 'Component-level preferences including i18n bundles for custom translations', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +/** + * Default SignUpButton with automatic translation support. + * The button text will change based on the locale selected in the Storybook toolbar. + */ +export const Default: Story = { + render: args => { + const {t} = useI18n(); + const signUpText = t('elements.buttons.signUp'); + + return {signUpText}; + }, + args: {}, +}; + +/** + * SignUpButton with custom text that overrides the translation system. + * This demonstrates how to provide custom text regardless of the current locale. + */ +export const WithCustomText: Story = { + args: { + children: 'Create Account', + }, +}; + +/** + * SignUpButton using the render props pattern. + * This demonstrates advanced usage where you can access the signUp function and loading state. + */ +export const WithRenderProps: Story = { + render: args => { + const {t} = useI18n(); + const signUpText = t('elements.buttons.signUp'); + const loadingText = t('messages.loading'); + + return ( + ( + + )} + /> + ); + }, + args: {}, +}; + +/** + * SignUpButton with custom styling applied via className and inline styles. + * This demonstrates how to customize the button's appearance. + */ +export const WithCustomStyling: Story = { + render: args => { + const {t} = useI18n(); + const signUpText = t('elements.buttons.signUp'); + + return ( + + {signUpText} + + ); + }, + args: {}, +}; + +/** + * SignUpButton in a disabled state. + * This demonstrates the button's disabled appearance and behavior. + */ +export const Disabled: Story = { + render: args => { + const {t} = useI18n(); + const signUpText = t('elements.buttons.signUp'); + + return ( + + {signUpText} + + ); + }, + args: {}, +}; + +/** + * SignUpButton with a custom onClick handler. + * This demonstrates how to handle the click event and perform additional actions after sign up. + */ +export const WithOnClickHandler: Story = { + render: args => { + const {t} = useI18n(); + const signUpText = t('elements.buttons.signUp'); + + return ( + { + console.log('Sign up completed!', event); + alert('Account created successfully!'); + }} + > + {signUpText} + + ); + }, + args: {}, +}; + +/** + * SignUpButton with component-level i18n preferences. + * This demonstrates how to override translations at the component level. + */ +export const WithCustomTranslations: Story = { + render: args => { + return ( + + ); + }, + args: {}, +}; From 8b2f7dc1b4beb8e5203458bda58b643c521e7ae1 Mon Sep 17 00:00:00 2001 From: auraofdivinity Date: Sun, 12 Oct 2025 01:40:11 +0530 Subject: [PATCH 5/8] chore: update React and related dependencies to version 19.2.0 across multiple packages for consistency & storybook requirements. --- packages/nextjs/package.json | 2 +- packages/react-router/package.json | 2 +- packages/react/package.json | 4 ++-- samples/teamspace-react/package.json | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 3f83bd43..bc44aa61 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -64,7 +64,7 @@ "eslint": "8.57.0", "next": "^15.3.2", "prettier": "^2.6.2", - "react": "^19.1.0", + "react": "^19.2.0", "rimraf": "^6.0.1", "typescript": "~5.7.2", "vitest": "^3.1.3" diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 1bc26cb6..bf091c8a 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -51,7 +51,7 @@ "esbuild": "^0.25.9", "eslint": "8.57.0", "prettier": "^2.6.2", - "react": "^19.1.0", + "react": "^19.2.0", "react-router": "^7.6.3", "rimraf": "^6.0.1", "typescript": "~5.7.2", diff --git a/packages/react/package.json b/packages/react/package.json index 15da2181..1747f66c 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -53,7 +53,7 @@ "eslint": "8.57.0", "playwright": "^1.52.0", "prettier": "^2.6.2", - "react": "^19.1.0", + "react": "^19.2.0", "rimraf": "^6.0.1", "typescript": "~5.7.2", "vitest": "^3.1.3", @@ -70,7 +70,7 @@ "@floating-ui/react": "^0.27.12", "@types/react-dom": "^19.1.5", "esbuild": "^0.25.9", - "react-dom": "^19.1.0", + "react-dom": "^19.2.0", "tslib": "^2.8.1" }, "publishConfig": { diff --git a/samples/teamspace-react/package.json b/samples/teamspace-react/package.json index b41f3c80..5bc12da3 100644 --- a/samples/teamspace-react/package.json +++ b/samples/teamspace-react/package.json @@ -20,8 +20,8 @@ "clsx": "^2.1.1", "dompurify": "^3.2.7", "lucide-react": "^0.294.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "react-router": "^7.6.3", "tailwind-merge": "^3.3.0" }, From e81260fef77f822c3a012a074641e351f8a27a33 Mon Sep 17 00:00:00 2001 From: auraofdivinity Date: Sun, 12 Oct 2025 02:06:58 +0530 Subject: [PATCH 6/8] feat(storybooks): add primitive component stories --- .../primitives/Alert/Alert.stories.tsx | 206 ++++++ .../primitives/Avatar/Avatar.stories.tsx | 292 +++++++++ .../primitives/Button/Button.stories.tsx | 238 +++++++ .../primitives/Card/Card.stories.tsx | 306 +++++++++ .../DatePicker/DatePicker.stories.tsx | 226 +++++++ .../primitives/Dialog/Dialog.stories.tsx | 373 +++++++++++ .../primitives/Divider/Divider.stories.tsx | 283 ++++++++ .../FormControl/FormControl.stories.tsx | 366 +++++++++++ .../primitives/Icons/Icons.stories.tsx | 618 ++++++++++++++++++ .../components/primitives/Icons/Settings.tsx | 57 ++ .../src/components/primitives/Icons/index.ts | 5 + .../InputLabel/InputLabel.stories.tsx | 317 +++++++++ .../KeyValueInput/KeyValueInput.stories.tsx | 371 +++++++++++ .../primitives/Logo/Logo.stories.tsx | 316 +++++++++ .../MultiInput/MultiInput.stories.tsx | 410 ++++++++++++ .../primitives/OtpField/OtpField.stories.tsx | 358 ++++++++++ .../PasswordField/PasswordField.stories.tsx | 269 ++++++++ .../primitives/Select/Select.stories.tsx | 222 +++++++ .../primitives/Spinner/Spinner.stories.tsx | 179 +++++ .../TextField/TextField.stories.tsx | 227 +++++++ .../Typography/Typography.stories.tsx | 331 ++++++++++ 21 files changed, 5970 insertions(+) create mode 100644 packages/react/src/components/primitives/Alert/Alert.stories.tsx create mode 100644 packages/react/src/components/primitives/Avatar/Avatar.stories.tsx create mode 100644 packages/react/src/components/primitives/Button/Button.stories.tsx create mode 100644 packages/react/src/components/primitives/Card/Card.stories.tsx create mode 100644 packages/react/src/components/primitives/DatePicker/DatePicker.stories.tsx create mode 100644 packages/react/src/components/primitives/Dialog/Dialog.stories.tsx create mode 100644 packages/react/src/components/primitives/Divider/Divider.stories.tsx create mode 100644 packages/react/src/components/primitives/FormControl/FormControl.stories.tsx create mode 100644 packages/react/src/components/primitives/Icons/Icons.stories.tsx create mode 100644 packages/react/src/components/primitives/InputLabel/InputLabel.stories.tsx create mode 100644 packages/react/src/components/primitives/KeyValueInput/KeyValueInput.stories.tsx create mode 100644 packages/react/src/components/primitives/Logo/Logo.stories.tsx create mode 100644 packages/react/src/components/primitives/MultiInput/MultiInput.stories.tsx create mode 100644 packages/react/src/components/primitives/OtpField/OtpField.stories.tsx create mode 100644 packages/react/src/components/primitives/PasswordField/PasswordField.stories.tsx create mode 100644 packages/react/src/components/primitives/Select/Select.stories.tsx create mode 100644 packages/react/src/components/primitives/Spinner/Spinner.stories.tsx create mode 100644 packages/react/src/components/primitives/TextField/TextField.stories.tsx create mode 100644 packages/react/src/components/primitives/Typography/Typography.stories.tsx diff --git a/packages/react/src/components/primitives/Alert/Alert.stories.tsx b/packages/react/src/components/primitives/Alert/Alert.stories.tsx new file mode 100644 index 00000000..f5ae33d9 --- /dev/null +++ b/packages/react/src/components/primitives/Alert/Alert.stories.tsx @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import Alert from './Alert'; + +const meta: Meta = { + title: 'Components/Primitives/Alert', + component: Alert, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + variant: { + control: 'select', + options: ['success', 'error', 'warning', 'info'], + description: 'The visual variant of the alert that determines color scheme and icon', + }, + showIcon: { + control: 'boolean', + description: 'Whether to show the default icon for the variant', + }, + children: { + control: 'text', + description: 'Alert content', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'This is a default info alert.', + }, +}; + +export const Success: Story = { + args: { + variant: 'success', + children: 'Your changes have been saved successfully!', + }, +}; + +export const Error: Story = { + args: { + variant: 'error', + children: 'Something went wrong. Please try again.', + }, +}; + +export const Warning: Story = { + args: { + variant: 'warning', + children: 'Please review your information before proceeding.', + }, +}; + +export const Info: Story = { + args: { + variant: 'info', + children: 'Here is some helpful information for you.', + }, +}; + +export const WithoutIcon: Story = { + args: { + variant: 'success', + showIcon: false, + children: 'Success message without icon.', + }, +}; + +export const WithTitle: Story = { + args: { + variant: 'success', + children: ( + <> + Success! + Your changes have been saved successfully. + + ), + }, +}; + +export const WithDescription: Story = { + args: { + variant: 'info', + children: ( + <> + Information + + This is additional information that provides more context about the alert. + + + ), + }, +}; + +export const ComplexContent: Story = { + args: { + variant: 'warning', + children: ( + <> + Account Verification Required + + Please verify your email address to continue using your account. Check your inbox for a verification link. + + + ), + }, +}; + +export const LongContent: Story = { + args: { + variant: 'error', + children: ( + <> + Multiple Errors Detected + + The following errors were found in your submission: +
    +
  • Email address is required
  • +
  • Password must be at least 8 characters
  • +
  • Phone number format is invalid
  • +
+ Please correct these errors and try again. +
+ + ), + }, +}; + +export const AllVariants: Story = { + render: () => ( +
+ + Success + Operation completed successfully. + + + Error + An error occurred during the operation. + + + Warning + Please review before proceeding. + + + Information + Here is some helpful information. + +
+ ), +}; + +export const WithoutIcons: Story = { + render: () => ( +
+ + Success + Operation completed successfully. + + + Error + An error occurred during the operation. + + + Warning + Please review before proceeding. + + + Information + Here is some helpful information. + +
+ ), +}; + +export const SimpleTextOnly: Story = { + render: () => ( +
+ Simple success message + Simple error message + Simple warning message + Simple info message +
+ ), +}; diff --git a/packages/react/src/components/primitives/Avatar/Avatar.stories.tsx b/packages/react/src/components/primitives/Avatar/Avatar.stories.tsx new file mode 100644 index 00000000..b0823735 --- /dev/null +++ b/packages/react/src/components/primitives/Avatar/Avatar.stories.tsx @@ -0,0 +1,292 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import Avatar from './Avatar'; + +const meta: Meta = { + title: 'Components/Primitives/Avatar', + component: Avatar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + name: { + control: 'text', + description: 'The name to use for generating initials when no image is provided', + }, + imageUrl: { + control: 'text', + description: 'The URL of the avatar image', + }, + size: { + control: 'number', + description: 'The size of the avatar in pixels', + }, + variant: { + control: 'select', + options: ['circular', 'square'], + description: 'The variant of the avatar shape', + }, + background: { + control: 'select', + options: ['random', 'none'], + description: 'Background generation strategy', + }, + isLoading: { + control: 'boolean', + description: 'Loading state of the avatar', + }, + alt: { + control: 'text', + description: 'Alternative text for the avatar image', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; + +export const WithName: Story = { + args: { + name: 'John Doe', + }, +}; + +export const WithInitials: Story = { + args: { + name: 'Jane Smith', + }, +}; + +export const WithImage: Story = { + args: { + name: 'John Doe', + imageUrl: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face', + }, +}; + +export const Small: Story = { + args: { + name: 'John Doe', + size: 32, + }, +}; + +export const Medium: Story = { + args: { + name: 'John Doe', + size: 64, + }, +}; + +export const Large: Story = { + args: { + name: 'John Doe', + size: 96, + }, +}; + +export const ExtraLarge: Story = { + args: { + name: 'John Doe', + size: 128, + }, +}; + +export const Square: Story = { + args: { + name: 'John Doe', + variant: 'square', + }, +}; + +export const Circular: Story = { + args: { + name: 'John Doe', + variant: 'circular', + }, +}; + +export const NoBackground: Story = { + args: { + name: 'John Doe', + background: 'none', + }, +}; + +export const Loading: Story = { + args: { + isLoading: true, + }, +}; + +export const LoadingWithSize: Story = { + args: { + isLoading: true, + size: 96, + }, +}; + +export const WithCustomAlt: Story = { + args: { + name: 'John Doe', + imageUrl: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face', + alt: 'Profile picture of John Doe', + }, +}; + +export const AllSizes: Story = { + render: () => ( +
+
+ +
24px
+
+
+ +
32px
+
+
+ +
48px
+
+
+ +
64px
+
+
+ +
96px
+
+
+ +
128px
+
+
+ ), +}; + +export const AllVariants: Story = { + render: () => ( +
+
+ +
Circular
+
+
+ +
Square
+
+
+ ), +}; + +export const DifferentNames: Story = { + render: () => ( +
+
+ +
Alice Johnson
+
+
+ +
Bob Smith
+
+
+ +
Charlie Brown
+
+
+ +
Diana Prince
+
+
+ +
Eve Wilson
+
+
+ ), +}; + +export const WithImages: Story = { + render: () => ( +
+
+ +
John Doe
+
+
+ +
Jane Smith
+
+
+ +
Bob Johnson
+
+
+ ), +}; + +export const LoadingStates: Story = { + render: () => ( +
+
+ +
Small Loading
+
+
+ +
Medium Loading
+
+
+ +
Large Loading
+
+
+ ), +}; + +export const BackgroundVariations: Story = { + render: () => ( +
+
+ +
Random Background
+
+
+ +
No Background
+
+
+ ), +}; diff --git a/packages/react/src/components/primitives/Button/Button.stories.tsx b/packages/react/src/components/primitives/Button/Button.stories.tsx new file mode 100644 index 00000000..aa6e7651 --- /dev/null +++ b/packages/react/src/components/primitives/Button/Button.stories.tsx @@ -0,0 +1,238 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import Button from './Button'; +import {Check, Plus, Settings} from '../Icons'; + +const meta: Meta = { + title: 'Components/Primitives/Button', + component: Button, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + children: { + control: 'text', + description: 'Button text content', + }, + color: { + control: 'select', + options: ['primary', 'secondary', 'tertiary'], + description: 'The button color that determines the color scheme', + }, + variant: { + control: 'select', + options: ['solid', 'outline', 'text', 'icon'], + description: 'The button variant that determines the visual style', + }, + size: { + control: 'select', + options: ['small', 'medium', 'large'], + description: 'The size of the button', + }, + fullWidth: { + control: 'boolean', + description: 'Whether the button should take the full width of its container', + }, + loading: { + control: 'boolean', + description: 'Whether the button is in a loading state', + }, + disabled: { + control: 'boolean', + description: 'Whether the button is disabled', + }, + shape: { + control: 'select', + options: ['square', 'round'], + description: 'The shape of the button', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Button', + }, +}; + +export const Primary: Story = { + args: { + children: 'Primary Button', + color: 'primary', + variant: 'solid', + }, +}; + +export const Secondary: Story = { + args: { + children: 'Secondary Button', + color: 'secondary', + variant: 'solid', + }, +}; + +export const Tertiary: Story = { + args: { + children: 'Tertiary Button', + color: 'tertiary', + variant: 'solid', + }, +}; + +export const Outline: Story = { + args: { + children: 'Outline Button', + variant: 'outline', + }, +}; + +export const Text: Story = { + args: { + children: 'Text Button', + variant: 'text', + }, +}; + +export const Small: Story = { + args: { + children: 'Small Button', + size: 'small', + }, +}; + +export const Large: Story = { + args: { + children: 'Large Button', + size: 'large', + }, +}; + +export const FullWidth: Story = { + args: { + children: 'Full Width Button', + fullWidth: true, + }, + parameters: { + layout: 'padded', + }, +}; + +export const Loading: Story = { + args: { + children: 'Loading Button', + loading: true, + }, +}; + +export const Disabled: Story = { + args: { + children: 'Disabled Button', + disabled: true, + }, +}; + +export const WithStartIcon: Story = { + args: { + children: 'Save', + startIcon: , + }, +}; + +export const WithEndIcon: Story = { + args: { + children: 'Continue', + endIcon: , + }, +}; + +export const WithBothIcons: Story = { + args: { + children: 'Save and Continue', + startIcon: , + endIcon: , + }, +}; + +export const IconButton: Story = { + args: { + variant: 'icon', + children: , + }, +}; + +export const Round: Story = { + args: { + children: 'Round Button', + shape: 'round', + }, +}; + +export const RoundIcon: Story = { + args: { + variant: 'icon', + shape: 'round', + children: , + }, +}; + +export const LoadingWithIcon: Story = { + args: { + children: 'Saving', + startIcon: , + loading: true, + }, +}; + +export const AllVariants: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +export const AllSizes: Story = { + render: () => ( +
+ + + +
+ ), +}; + +export const AllColors: Story = { + render: () => ( +
+ + + +
+ ), +}; diff --git a/packages/react/src/components/primitives/Card/Card.stories.tsx b/packages/react/src/components/primitives/Card/Card.stories.tsx new file mode 100644 index 00000000..78d1f7b7 --- /dev/null +++ b/packages/react/src/components/primitives/Card/Card.stories.tsx @@ -0,0 +1,306 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import Card from './Card'; +import Button from '../Button/Button'; +import Typography from '../Typography/Typography'; + +const meta: Meta = { + title: 'Components/Primitives/Card', + component: Card, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + variant: { + control: 'select', + options: ['default', 'outlined', 'elevated'], + description: 'The visual variant of the card', + }, + clickable: { + control: 'boolean', + description: 'Whether the card should be clickable (shows hover effects)', + }, + children: { + control: 'text', + description: 'Card content', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Simple card content', + }, +}; + +export const Outlined: Story = { + args: { + variant: 'outlined', + children: 'Outlined card content', + }, +}; + +export const Elevated: Story = { + args: { + variant: 'elevated', + children: 'Elevated card content', + }, +}; + +export const Clickable: Story = { + args: { + clickable: true, + children: 'Clickable card content', + }, +}; + +export const WithHeader: Story = { + args: { + children: ( + <> + + Card Title + This is a card description + + + This is the main content of the card. + + + ), + }, +}; + +export const WithFooter: Story = { + args: { + children: ( + <> + + This is the main content of the card. + + + + + + + ), + }, +}; + +export const Complete: Story = { + args: { + variant: 'elevated', + children: ( + <> + + Complete Card + This is a complete card example with all components + + + + + + + This is the main content area of the card. It can contain any type of content including text, images, forms, + or other components. + + + Additional content can be added here to demonstrate the card's flexibility. + + + + + + + + ), + }, +}; + +export const ProductCard: Story = { + args: { + variant: 'outlined', + clickable: true, + children: ( + <> + +
+
+ Product Image +
+
+ Product Name + Product description goes here + + $99.99 + +
+ + + + + ), + }, +}; + +export const UserProfileCard: Story = { + args: { + variant: 'elevated', + children: ( + <> + +
+
+ JD +
+
+ John Doe + Software Engineer +
+
+
+ + + Experienced software engineer with expertise in React, TypeScript, and modern web development practices. + + + + + + + + ), + }, +}; + +export const AllVariants: Story = { + render: () => ( +
+ + + Default Card + This is a default card variant. + + + + + Outlined Card + This is an outlined card variant. + + + + + Elevated Card + This is an elevated card variant. + + +
+ ), +}; + +export const AllTitleLevels: Story = { + render: () => ( +
+ + + Heading Level 1 + This card uses heading level 1. + + + + + Heading Level 2 + This card uses heading level 2. + + + + + Heading Level 3 + This card uses heading level 3. + + + + + Heading Level 4 + This card uses heading level 4. + + + + + Heading Level 5 + This card uses heading level 5. + + + + + Heading Level 6 + This card uses heading level 6. + + +
+ ), +}; + +export const ClickableVariants: Story = { + render: () => ( +
+ + + Clickable Default + Hover to see the effect. + + + + + Clickable Outlined + Hover to see the effect. + + + + + Clickable Elevated + Hover to see the effect. + + +
+ ), +}; diff --git a/packages/react/src/components/primitives/DatePicker/DatePicker.stories.tsx b/packages/react/src/components/primitives/DatePicker/DatePicker.stories.tsx new file mode 100644 index 00000000..ebda10d7 --- /dev/null +++ b/packages/react/src/components/primitives/DatePicker/DatePicker.stories.tsx @@ -0,0 +1,226 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import DatePicker from './DatePicker'; + +const meta: Meta = { + title: 'Components/Primitives/DatePicker', + component: DatePicker, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + label: { + control: 'text', + description: 'Label text to display above the input', + }, + placeholder: { + control: 'text', + description: 'Placeholder text for the input', + }, + value: { + control: 'text', + description: 'The value of the input', + }, + min: { + control: 'text', + description: 'Minimum date allowed', + }, + max: { + control: 'text', + description: 'Maximum date allowed', + }, + error: { + control: 'text', + description: 'Error message to display below the input', + }, + helperText: { + control: 'text', + description: 'Helper text to display below the input', + }, + required: { + control: 'boolean', + description: 'Whether the field is required', + }, + disabled: { + control: 'boolean', + description: 'Whether the field is disabled', + }, + dateFormat: { + control: 'text', + description: 'Custom date format for the regex pattern', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; + +export const WithLabel: Story = { + args: { + label: 'Select Date', + }, +}; + +export const Required: Story = { + args: { + label: 'Birth Date', + required: true, + }, +}; + +export const WithHelperText: Story = { + args: { + label: 'Event Date', + helperText: 'Select the date for your event', + }, +}; + +export const WithError: Story = { + args: { + label: 'Due Date', + error: 'Please select a valid date', + required: true, + }, +}; + +export const Disabled: Story = { + args: { + label: 'Disabled Date', + disabled: true, + }, +}; + +export const WithMinDate: Story = { + args: { + label: 'Future Date', + min: '2024-01-01', + helperText: 'Select a date from 2024 onwards', + }, +}; + +export const WithMaxDate: Story = { + args: { + label: 'Past Date', + max: '2023-12-31', + helperText: 'Select a date before 2024', + }, +}; + +export const WithDateRange: Story = { + args: { + label: 'Date Range', + min: '2024-01-01', + max: '2024-12-31', + helperText: 'Select a date within 2024', + }, +}; + +export const WithDefaultValue: Story = { + args: { + label: 'Default Date', + defaultValue: '2024-06-15', + }, +}; + +export const CustomDateFormat: Story = { + args: { + label: 'Custom Format', + dateFormat: 'dd/MM/yyyy', + helperText: 'Date format: dd/MM/yyyy', + }, +}; + +export const AllStates: Story = { + render: () => ( +
+ + + + + +
+ ), +}; + +export const FormExample: Story = { + render: () => ( +
+

Event Registration

+ + + +
+ ), +}; + +export const BookingForm: Story = { + render: () => ( +
+

Hotel Booking

+ + + +
+ ), +}; + +export const DateConstraints: Story = { + render: () => ( +
+
+

Future Dates Only

+ +
+
+

Past Dates Only

+ +
+
+

Date Range

+ +
+
+ ), +}; diff --git a/packages/react/src/components/primitives/Dialog/Dialog.stories.tsx b/packages/react/src/components/primitives/Dialog/Dialog.stories.tsx new file mode 100644 index 00000000..90ca9c62 --- /dev/null +++ b/packages/react/src/components/primitives/Dialog/Dialog.stories.tsx @@ -0,0 +1,373 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type {Meta, StoryObj} from '@storybook/react'; +import {useState} from 'react'; +import Dialog from './Dialog'; +import Button from '../Button/Button'; +import Typography from '../Typography/Typography'; + +const meta: Meta = { + title: 'Components/Primitives/Dialog', + component: Dialog, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + initialOpen: { + control: 'boolean', + description: 'Whether the dialog is initially open', + }, + open: { + control: 'boolean', + description: 'Whether the dialog is open (controlled)', + }, + onOpenChange: { + action: 'openChanged', + description: 'Callback when the open state changes', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + Dialog Title + This is a basic dialog with a title and description. +
+ + + + + + +
+
+
+ ), +}; + +export const ConfirmationDialog: Story = { + render: () => ( + + + + + + Delete Item + + Are you sure you want to delete this item? This action cannot be undone. + +
+ + + + + + +
+
+
+ ), +}; + +export const FormDialog: Story = { + render: () => ( + + + + + + Add New Item + Fill out the form below to add a new item to your list. +
+
+ + +
+
+ +