@@ -419,6 +429,24 @@ InlineSearchSingle.args = {
size: 'md',
disabled: false,
};
+InlineSearchSingle.play = async ( { canvasElement } ) => {
+ const canvas = within( canvasElement );
+ const trigger = await canvas.findByRole( 'combobox' );
+ await userEvent.click( trigger );
+
+ const input = await canvas.findByPlaceholderText( 'Search colors...' );
+ await userEvent.type( input, 'pi' );
+
+ const listbox = await screen.findByRole( 'listbox' );
+ expect( listbox ).toHaveTextContent( 'Pink' );
+ expect( listbox ).not.toHaveTextContent( 'Red' );
+
+ const pinkOption = await screen.findByRole( 'option', { name: 'Pink' } );
+ await userEvent.click( pinkOption );
+
+ expect( screen.queryByRole( 'listbox' ) ).toBeNull();
+ expect( input ).toHaveValue( 'Pink' );
+};
export const InlineSearchMulti: Story = ( { size, disabled } ) => (
@@ -491,6 +519,31 @@ InlineSearchMulti.play = async ( { canvasElement } ) => {
await userEvent.keyboard( '{Backspace}' );
expect( canvas.queryByText( 'Orange' ) ).toBeNull();
expect( canvas.queryByText( 'Red' ) ).not.toBeNull();
+
+ // Re-open if closed after Backspace
+ if ( ! screen.queryByRole( 'listbox' ) ) {
+ await userEvent.click( triggerWrapper );
+ }
+ await userEvent.clear( input );
+
+ // Case-insensitive filter
+ await userEvent.type( input, 'R' );
+ const listboxR = await screen.findByRole( 'listbox' );
+ expect( listboxR ).toHaveTextContent( 'Red' );
+ expect( listboxR ).toHaveTextContent( 'Orange' );
+
+ // Empty query restores all options
+ await userEvent.clear( input );
+ const listboxAll = await screen.findByRole( 'listbox' );
+ expect( listboxAll ).toHaveTextContent( 'Cyan' );
+
+ // No-results state
+ await userEvent.type( input, 'zzz' );
+ expect( screen.queryAllByRole( 'option' ) ).toHaveLength( 0 );
+
+ // Escape closes the dropdown
+ await userEvent.keyboard( '{Escape}' );
+ expect( screen.queryByRole( 'listbox' ) ).toBeNull();
};
const GroupedSelectTemplate: Story = ( {
From 2098698ce2f4ab75409cd03269e0a1e8bd85b409 Mon Sep 17 00:00:00 2001
From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com>
Date: Tue, 28 Apr 2026 22:16:36 +0600
Subject: [PATCH 6/6] Update changelog.txt
---
.claude/settings.json | 50 +-
.github/workflows/claude-code-review.yml | 88 +-
.github/workflows/claude.yml | 100 +-
.github/workflows/publish-public-build.yml | 112 +-
.github/workflows/publish.yml | 56 +-
.gitignore | 45 +-
.storybook/main.ts | 152 +-
CLAUDE.md | 166 +-
README.md | 678 +-
changelog.txt | 443 +-
package-lock.json | 46214 ++++++++--------
skills-lock.json | 100 +-
src/components/bar-chart/bar-chart.tsx | 570 +-
src/components/select/readme.md | 428 +-
src/components/select/select-atom.stories.tsx | 1274 +-
src/components/select/select-types.ts | 360 +-
src/components/select/select.tsx | 2750 +-
src/components/textarea/textarea.stories.tsx | 124 +-
src/components/textarea/textarea.tsx | 222 +-
tailwind.config.js | 13 +-
20 files changed, 26975 insertions(+), 26970 deletions(-)
diff --git a/.claude/settings.json b/.claude/settings.json
index 877d9b9a..b869c896 100644
--- a/.claude/settings.json
+++ b/.claude/settings.json
@@ -1,25 +1,25 @@
-{
- "attribution": {
- "commit": "",
- "pr": ""
- },
- "permissions": {
- "allow": [
- "Bash(npm run *)",
- "Bash(npm install *)",
- "Bash(npm view *)",
- "Bash(npx tsc *)",
- "Bash(npx eslint *)",
- "Bash(npx stylelint *)",
- "Bash(npx prettier *)",
- "Bash(git status)",
- "Bash(grep *)",
- "Bash(find * -name *)",
- "Bash(ls *)"
- ]
- },
- "statusLine": {
- "type": "command",
- "command": "bash \"/Users/jaieds/.claude/plugins/cache/caveman/caveman/63e797cd753b/hooks/caveman-statusline.sh\""
- }
-}
+{
+ "attribution": {
+ "commit": "",
+ "pr": ""
+ },
+ "permissions": {
+ "allow": [
+ "Bash(npm run *)",
+ "Bash(npm install *)",
+ "Bash(npm view *)",
+ "Bash(npx tsc *)",
+ "Bash(npx eslint *)",
+ "Bash(npx stylelint *)",
+ "Bash(npx prettier *)",
+ "Bash(git status)",
+ "Bash(grep *)",
+ "Bash(find * -name *)",
+ "Bash(ls *)"
+ ]
+ },
+ "statusLine": {
+ "type": "command",
+ "command": "bash \"/Users/jaieds/.claude/plugins/cache/caveman/caveman/63e797cd753b/hooks/caveman-statusline.sh\""
+ }
+}
diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml
index b5e8cfd4..800eeadd 100644
--- a/.github/workflows/claude-code-review.yml
+++ b/.github/workflows/claude-code-review.yml
@@ -1,44 +1,44 @@
-name: Claude Code Review
-
-on:
- pull_request:
- types: [opened, synchronize, ready_for_review, reopened]
- # Optional: Only run on specific file changes
- # paths:
- # - "src/**/*.ts"
- # - "src/**/*.tsx"
- # - "src/**/*.js"
- # - "src/**/*.jsx"
-
-jobs:
- claude-review:
- # Optional: Filter by PR author
- # if: |
- # github.event.pull_request.user.login == 'external-contributor' ||
- # github.event.pull_request.user.login == 'new-developer' ||
- # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
-
- runs-on: ubuntu-latest
- permissions:
- contents: read
- pull-requests: read
- issues: read
- id-token: write
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
- with:
- fetch-depth: 1
-
- - name: Run Claude Code Review
- id: claude-review
- uses: anthropics/claude-code-action@v1
- with:
- claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
- plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
- plugins: 'code-review@claude-code-plugins'
- prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
- # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
- # or https://code.claude.com/docs/en/cli-reference for available options
-
+name: Claude Code Review
+
+on:
+ pull_request:
+ types: [opened, synchronize, ready_for_review, reopened]
+ # Optional: Only run on specific file changes
+ # paths:
+ # - "src/**/*.ts"
+ # - "src/**/*.tsx"
+ # - "src/**/*.js"
+ # - "src/**/*.jsx"
+
+jobs:
+ claude-review:
+ # Optional: Filter by PR author
+ # if: |
+ # github.event.pull_request.user.login == 'external-contributor' ||
+ # github.event.pull_request.user.login == 'new-developer' ||
+ # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
+
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: read
+ id-token: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Run Claude Code Review
+ id: claude-review
+ uses: anthropics/claude-code-action@v1
+ with:
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
+ plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
+ plugins: 'code-review@claude-code-plugins'
+ prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
+ # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
+ # or https://code.claude.com/docs/en/cli-reference for available options
+
diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml
index d300267f..8233826b 100644
--- a/.github/workflows/claude.yml
+++ b/.github/workflows/claude.yml
@@ -1,50 +1,50 @@
-name: Claude Code
-
-on:
- issue_comment:
- types: [created]
- pull_request_review_comment:
- types: [created]
- issues:
- types: [opened, assigned]
- pull_request_review:
- types: [submitted]
-
-jobs:
- claude:
- if: |
- (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
- (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
- (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
- (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
- runs-on: ubuntu-latest
- permissions:
- contents: read
- pull-requests: read
- issues: read
- id-token: write
- actions: read # Required for Claude to read CI results on PRs
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
- with:
- fetch-depth: 1
-
- - name: Run Claude Code
- id: claude
- uses: anthropics/claude-code-action@v1
- with:
- claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
-
- # This is an optional setting that allows Claude to read CI results on PRs
- additional_permissions: |
- actions: read
-
- # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
- # prompt: 'Update the pull request description to include a summary of changes.'
-
- # Optional: Add claude_args to customize behavior and configuration
- # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
- # or https://code.claude.com/docs/en/cli-reference for available options
- # claude_args: '--allowed-tools Bash(gh pr:*)'
-
+name: Claude Code
+
+on:
+ issue_comment:
+ types: [created]
+ pull_request_review_comment:
+ types: [created]
+ issues:
+ types: [opened, assigned]
+ pull_request_review:
+ types: [submitted]
+
+jobs:
+ claude:
+ if: |
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
+ (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
+ (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
+ (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: read
+ id-token: write
+ actions: read # Required for Claude to read CI results on PRs
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Run Claude Code
+ id: claude
+ uses: anthropics/claude-code-action@v1
+ with:
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
+
+ # This is an optional setting that allows Claude to read CI results on PRs
+ additional_permissions: |
+ actions: read
+
+ # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
+ # prompt: 'Update the pull request description to include a summary of changes.'
+
+ # Optional: Add claude_args to customize behavior and configuration
+ # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
+ # or https://code.claude.com/docs/en/cli-reference for available options
+ # claude_args: '--allowed-tools Bash(gh pr:*)'
+
diff --git a/.github/workflows/publish-public-build.yml b/.github/workflows/publish-public-build.yml
index daef2f54..0c74e290 100644
--- a/.github/workflows/publish-public-build.yml
+++ b/.github/workflows/publish-public-build.yml
@@ -1,56 +1,56 @@
-name: Publish Public Build
-
-on:
- push:
- branches:
- - master
-
-jobs:
- publish-build:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
-
- - uses: actions/setup-node@v4
- with:
- node-version: '18'
-
- # Build the library
- - name: Install and Build
- run: |
- npm ci
- npm run build
-
- # Push to public mirror repo
- - name: Push Build to Public Mirror
- env:
- FORCE_UI_TOKEN: ${{ secrets.FORCE_UI_TOKEN }}
- run: |
- # Clone public mirror repo
- git clone https://x-access-token:${{ secrets.FORCE_UI_TOKEN }}@github.com/brainstormforce/bsf-admin-ui.git build-repo
-
- cd build-repo
-
- # Clear old dist
- rm -rf dist
-
- # Copy new build
- cp -r ../dist ./
-
- # Update version in package.json
- VERSION=$(node -p "require('../package.json').version")
- node -e "
- const pkg = require('./package.json');
- pkg.version = process.argv[1];
- require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2));
- " "$VERSION"
-
- # Commit and tag
- git config user.name github-actions
- git config user.email github-actions@github.com
- git add dist package.json
- git commit -m "Release v$VERSION - build artifacts only"
- git tag v$VERSION
- git push origin master
- git push origin v$VERSION
+name: Publish Public Build
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ publish-build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '18'
+
+ # Build the library
+ - name: Install and Build
+ run: |
+ npm ci
+ npm run build
+
+ # Push to public mirror repo
+ - name: Push Build to Public Mirror
+ env:
+ FORCE_UI_TOKEN: ${{ secrets.FORCE_UI_TOKEN }}
+ run: |
+ # Clone public mirror repo
+ git clone https://x-access-token:${{ secrets.FORCE_UI_TOKEN }}@github.com/brainstormforce/bsf-admin-ui.git build-repo
+
+ cd build-repo
+
+ # Clear old dist
+ rm -rf dist
+
+ # Copy new build
+ cp -r ../dist ./
+
+ # Update version in package.json
+ VERSION=$(node -p "require('../package.json').version")
+ node -e "
+ const pkg = require('./package.json');
+ pkg.version = process.argv[1];
+ require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2));
+ " "$VERSION"
+
+ # Commit and tag
+ git config user.name github-actions
+ git config user.email github-actions@github.com
+ git add dist package.json
+ git commit -m "Release v$VERSION - build artifacts only"
+ git tag v$VERSION
+ git push origin master
+ git push origin v$VERSION
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index e287f670..3572b159 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,28 +1,28 @@
-name: Publish Package
-
-on:
- push:
- branches:
- - master
-
-jobs:
- publish:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - uses: actions/setup-node@v4
- with:
- node-version: '18'
- registry-url: 'https://npm.pkg.github.com'
- scope: '@brainstormforce'
-
- - run: npm ci
- - run: npm run build
-
- - run: npm publish
- env:
- NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+name: Publish Package
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '18'
+ registry-url: 'https://npm.pkg.github.com'
+ scope: '@brainstormforce'
+
+ - run: npm ci
+ - run: npm run build
+
+ - run: npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index bee12538..e64a179f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,22 +1,23 @@
-node_modules
-.claude/settings.local.json
-dist/*
-.DS_Store
-.cursor
-.vscode
-.npmrc
-*storybook.log
-storybook-static/*
-*.zip
-/test-results/
-/playwright-report/
-/blob-report/
-/playwright/.cache/
-tsconfig.app.tsbuildinfo
-tsconfig.node.tsbuildinfo
-*.app.tsbuildinfo
-*.node.tsbuildinfo
-tsconfig.app.tsbuildinfo
-.agents/skills
-.kiro
-.continue
\ No newline at end of file
+node_modules
+.claude/settings.local.json
+dist/*
+.DS_Store
+.cursor
+.vscode
+.npmrc
+*storybook.log
+storybook-static/*
+*.zip
+/test-results/
+/playwright-report/
+/blob-report/
+/playwright/.cache/
+tsconfig.app.tsbuildinfo
+tsconfig.node.tsbuildinfo
+*.app.tsbuildinfo
+*.node.tsbuildinfo
+tsconfig.app.tsbuildinfo
+.agents/skills
+.kiro
+.continue
+config.bat
diff --git a/.storybook/main.ts b/.storybook/main.ts
index d6e28d58..8f12c045 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -1,76 +1,76 @@
-// This file has been automatically migrated to valid ESM format by Storybook.
-import { fileURLToPath } from "node:url";
-import type { StorybookConfig } from '@storybook/react-vite';
-import path, { dirname } from 'path';
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = dirname(__filename);
-
-/** @type { import('@storybook/react-webpack5').StorybookConfig } */
-const config: StorybookConfig = {
- stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
- addons: [
- '@storybook/addon-onboarding',
- '@storybook/addon-links',
- '@chromatic-com/storybook',
- '@storybook/addon-a11y',
- '@storybook/addon-docs',
- '@storybook/addon-mcp',
- '@storybook/addon-vitest'
- ],
- framework: {
- name: '@storybook/react-vite',
- options: {
- builder: {
- viteConfigPath: path.resolve(__dirname, '..', 'vite.config.ts'),
- },
- },
- },
- core: {
- builder: '@storybook/builder-vite',
- },
- viteFinal: async (config) => {
- // Merge custom configuration into the default config
- const { mergeConfig } = await import('vite');
-
- // Remove the dts plugin from the default config.
- config.plugins = [
- ...(config.plugins ?? []).filter((plugin) => {
- return (
- (plugin as typeof plugin & Record
).name !==
- 'vite:dts'
- );
- }),
- ];
-
- return mergeConfig(config, {
- optimizeDeps: {
- ...config?.optimizeDeps,
- },
- resolve: {
- ...config.resolve,
- alias: {
- ...config.resolve?.alias,
- // 👇 Internal modules
- '@/icons': path.resolve(
- __dirname,
- '..',
- 'src/ui/icons.jsx'
- ),
- '@/utilities': path.resolve(
- __dirname,
- '..',
- 'src/utilities'
- ),
- '@/components': path.resolve(
- __dirname,
- '..',
- 'src/components'
- ),
- '@': path.resolve(__dirname, '..', 'src'),
- },
- },
- });
- },
-};
-export default config;
+// This file has been automatically migrated to valid ESM format by Storybook.
+import { fileURLToPath } from "node:url";
+import type { StorybookConfig } from '@storybook/react-vite';
+import path, { dirname } from 'path';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+/** @type { import('@storybook/react-webpack5').StorybookConfig } */
+const config: StorybookConfig = {
+ stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
+ addons: [
+ '@storybook/addon-onboarding',
+ '@storybook/addon-links',
+ '@chromatic-com/storybook',
+ '@storybook/addon-a11y',
+ '@storybook/addon-docs',
+ '@storybook/addon-mcp',
+ '@storybook/addon-vitest'
+ ],
+ framework: {
+ name: '@storybook/react-vite',
+ options: {
+ builder: {
+ viteConfigPath: path.resolve(__dirname, '..', 'vite.config.ts'),
+ },
+ },
+ },
+ core: {
+ builder: '@storybook/builder-vite',
+ },
+ viteFinal: async (config) => {
+ // Merge custom configuration into the default config
+ const { mergeConfig } = await import('vite');
+
+ // Remove the dts plugin from the default config.
+ config.plugins = [
+ ...(config.plugins ?? []).filter((plugin) => {
+ return (
+ (plugin as typeof plugin & Record).name !==
+ 'vite:dts'
+ );
+ }),
+ ];
+
+ return mergeConfig(config, {
+ optimizeDeps: {
+ ...config?.optimizeDeps,
+ },
+ resolve: {
+ ...config.resolve,
+ alias: {
+ ...config.resolve?.alias,
+ // 👇 Internal modules
+ '@/icons': path.resolve(
+ __dirname,
+ '..',
+ 'src/ui/icons.jsx'
+ ),
+ '@/utilities': path.resolve(
+ __dirname,
+ '..',
+ 'src/utilities'
+ ),
+ '@/components': path.resolve(
+ __dirname,
+ '..',
+ 'src/components'
+ ),
+ '@': path.resolve(__dirname, '..', 'src'),
+ },
+ },
+ });
+ },
+};
+export default config;
diff --git a/CLAUDE.md b/CLAUDE.md
index 71ae79fb..61205be5 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,84 +1,84 @@
-# force-ui
-
-React component library for BSF projects. Publishes to GitHub Package Registry as `@bsf/force-ui`.
-
-## Stack
-
-- **React 18** + **TypeScript** — component authoring
-- **Vite** — build (CJS + ESM outputs)
-- **Tailwind CSS 3** — styling via `cn()` utility
-- **Storybook 10** — component dev + visual regression (Chromatic)
-- **Vitest** — unit/interaction tests (Storybook play functions)
-- **ESLint + Prettier + Stylelint** — linting
-
-## Commands
-
-```bash
-npm run build # production build
-npm run start # build in watch mode
-npm run storybook # dev server at :6006
-npm run test # vitest (storybook project)
-npm run test:watch # vitest in watch mode
-npm run lint:js-fix # eslint + prettier fix
-npm run lint:css-fix # stylelint fix
-npx tsc --noEmit # type-check only
-```
-
-## Component Conventions
-
-Each component lives at `src/components/{name}/`:
-```
-{name}.tsx # component implementation
-{name}.stories.tsx # Storybook stories
-index.ts # named exports
-readme.md # usage docs
-```
-
-### Authoring pattern
-
-```tsx
-import { forwardRef } from 'react';
-import { cn } from '@/utilities/functions';
-
-export interface FooProps {
- /** JSDoc for every prop — Storybook renders these as docs */
- variant?: 'primary' | 'secondary';
- className?: string;
-}
-
-const Foo = forwardRef(
- ({ variant = 'primary', className, ...props }, ref) => {
- return (
-
- );
- }
-);
-Foo.displayName = 'Foo';
-export default Foo;
-```
-
-- Always `forwardRef` + `displayName`
-- Export props interface with component
-- `cn()` from `@/utilities/functions` for class merging
-- Path alias `@/` → `src/`
-- Props interface JSDoc required — Storybook autodocs reads them
-
-## Exports
-
-New components go in `src/components/index.ts` and `src/index.ts`.
-
-## Testing
-
-Tests via Storybook `play` functions using `@storybook/test`. Run: `npm run test`. Add `play` to stories for interaction coverage.
-
-## Current Focus
-
-_Update this section with current sprint/task context._
-
-## Gotchas
-
-- `peerDependencies` for `react`/`react-dom` — consumers supply; don't bundle
-- Storybook on `:6006`; `test-storybook` needs Storybook running first
-- Chromatic upload needs `CHROMATIC_PROJECT_TOKEN` env var
-- GitHub Package Registry — `npm publish` needs `NPM_TOKEN` with `write:packages` scope
+# force-ui
+
+React component library for BSF projects. Publishes to GitHub Package Registry as `@bsf/force-ui`.
+
+## Stack
+
+- **React 18** + **TypeScript** — component authoring
+- **Vite** — build (CJS + ESM outputs)
+- **Tailwind CSS 3** — styling via `cn()` utility
+- **Storybook 10** — component dev + visual regression (Chromatic)
+- **Vitest** — unit/interaction tests (Storybook play functions)
+- **ESLint + Prettier + Stylelint** — linting
+
+## Commands
+
+```bash
+npm run build # production build
+npm run start # build in watch mode
+npm run storybook # dev server at :6006
+npm run test # vitest (storybook project)
+npm run test:watch # vitest in watch mode
+npm run lint:js-fix # eslint + prettier fix
+npm run lint:css-fix # stylelint fix
+npx tsc --noEmit # type-check only
+```
+
+## Component Conventions
+
+Each component lives at `src/components/{name}/`:
+```
+{name}.tsx # component implementation
+{name}.stories.tsx # Storybook stories
+index.ts # named exports
+readme.md # usage docs
+```
+
+### Authoring pattern
+
+```tsx
+import { forwardRef } from 'react';
+import { cn } from '@/utilities/functions';
+
+export interface FooProps {
+ /** JSDoc for every prop — Storybook renders these as docs */
+ variant?: 'primary' | 'secondary';
+ className?: string;
+}
+
+const Foo = forwardRef(
+ ({ variant = 'primary', className, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+Foo.displayName = 'Foo';
+export default Foo;
+```
+
+- Always `forwardRef` + `displayName`
+- Export props interface with component
+- `cn()` from `@/utilities/functions` for class merging
+- Path alias `@/` → `src/`
+- Props interface JSDoc required — Storybook autodocs reads them
+
+## Exports
+
+New components go in `src/components/index.ts` and `src/index.ts`.
+
+## Testing
+
+Tests via Storybook `play` functions using `@storybook/test`. Run: `npm run test`. Add `play` to stories for interaction coverage.
+
+## Current Focus
+
+_Update this section with current sprint/task context._
+
+## Gotchas
+
+- `peerDependencies` for `react`/`react-dom` — consumers supply; don't bundle
+- Storybook on `:6006`; `test-storybook` needs Storybook running first
+- Chromatic upload needs `CHROMATIC_PROJECT_TOKEN` env var
+- GitHub Package Registry — `npm publish` needs `NPM_TOKEN` with `write:packages` scope
- Add `.claude/settings.local.json` to local `.gitignore` for personal settings
\ No newline at end of file
diff --git a/README.md b/README.md
index a06c1cc6..158ae011 100644
--- a/README.md
+++ b/README.md
@@ -1,339 +1,339 @@
-## Getting Started - Development Repo
-
-Learn how to use @bsf/force-ui components to quickly and easily create elegant and flexible pages using Tailwind CSS.
-
-@bsf/force-ui is working with Tailwind CSS classes and you need to have Tailwind CSS installed on your project - Tailwind CSS Installation.
-
-
-
-1. Install `@bsf/force-ui`.
-
-Force UI library can be installed using npm package manager. Since this library is still in it's alpha phase, we need to use the staging branch.
-
-Using Force UI as a dependency in package.json -
-
-```json
-"dependencies": {
- "@bsf/force-ui": "git+https://github.com/brainstormforce/force-ui#1.7.11"
-}
-```
-
-And run the following command to install the package -
-
-
-```bash
-npm install
-```
-
-Or you can directly run the following command to install the package -
-
-```bash
-npm i -S @bsf/force-ui@git+https://github.com/brainstormforce/force-ui.git#1.7.11
-```
-
-
-
-2. Once you install @bsf/force-ui you need to wrap your tailwind css configurations with the `withTW()` function coming from @bsf/force-ui/withTW.
-
-```js
-const withTW = require( '@bsf/force-ui/withTW' );
-
-module.exports = withTW( {
- content: [ './src/**/*.{js, jsx}' ],
- theme: {
- extend: {
- colors: {
- 'button-primary': '#6B21A8',
- 'button-primary-hover': '#7E22CE',
- 'brand-800': '#6B21A8',
- 'brand-50': '#FAF5FF',
- 'border-interactive': '#6B21A8',
- focus: '#9333EA',
- 'focus-border': '#D8B4FE',
- 'toggle-on': '#6B21A8',
- 'toggle-on-border': '#C084FC',
- 'toggle-on-hover': '#A855F7',
- },
- fontSize: {
- xxs: '0.6875rem', // 11px
- },
- lineHeight: {
- 2.6: '0.6875rem', // 11px
- },
- boxShadow: {
- 'content-wrapper':
- '0px 1px 1px 0px #0000000F, 0px 1px 2px 0px #0000001A',
- },
- },
- },
- plugins: [],
- corePlugins: {
- preflight: false,
- },
- important: '.surerank-styles',
-} );
-```
-
-
-
-3. @bsf/force-ui comes with a default tailwind theme settings that set's the default theme/styles for components or to provide your own theme/styles to your components. You can override these give below variables in your tailwind.config.js file.
-
-```jsx
-theme: {
- extend: {
- colors: {
- // brand
- 'brand-background-50': '#EFF6FF',
- 'brand-background-hover-100': '#DBEAFE',
- 'brand-200': '#BFDBFE',
- 'brand-border-300': '#93C5FD',
- 'brand-400': '#60A5FA',
- 'brand-500': '#3B82F6',
- 'brand-primary-600': '#2563EB',
- 'brand-hover-700': '#1D4ED8',
- 'brand-800': '#1E40AF',
- 'brand-900': '#1E3A8A',
- 'brand-text-950': '#172554',
- // background
- 'background-primary': '#FFFFFF',
- 'background-secondary': '#F3F4F6',
- 'background-inverse': '#111827',
- 'background-brand': '#2563EB',
- 'background-important': '#DC2626',
- // field
- 'field-primary-background': '#F9FAFB',
- 'field-secondary-background': '#FFFFFF',
- 'field-primary-hover': '#F3F4F6',
- 'field-secondary-hover': '#F3F4F6',
- 'field-dropzone-background': '#FFFFFF',
- 'field-border': '#E5E7EB',
- 'field-dropzone-background-hover': '#F9FAFB',
- 'field-dropzone-color': '#2563EB',
- 'field-label': '#111827',
- 'field-input': '#111827',
- 'field-helper': '#9CA3AF',
- 'field-background-disabled': '#F9FAFB',
- 'field-color-disabled': '#D1D5DB',
- 'field-placeholder': '#6B7280',
- 'field-border-disabled': '#F3F4F6',
- 'field-color-error': '#DC2626',
- 'field-border-error': '#FECACA',
- 'field-background-error': '#FEF2F2',
- 'field-required': '#DC2626',
- // border
- 'border-interactive': '#2563EB',
- 'border-subtle': '#E5E7EB',
- 'border-strong': '#6B7280',
- 'border-inverse': '#374151',
- 'border-disabled': '#E5E7EB',
- 'border-muted': '#E5E7EB',
- 'border-error': '#DC2626',
- 'border-transparent-subtle': '#37415114',
- 'border-white': '#FFFFFF',
- // text
- 'text-primary': '#111827',
- 'text-secondary': '#4B5563',
- 'text-tertiary': '#9CA3AF',
- 'text-on-color': '#FFFFFF',
- 'text-error': '#DC2626',
- 'text-error-inverse': '#F87171',
- 'text-inverse': '#FFFFFF',
- 'text-disabled': '#D1D5DB',
- 'text-on-button-disabled': '#9CA3AF',
- // link
- 'link-primary': '#2563EB',
- 'link-primary-hover': '#1D4ED8',
- 'link-inverse': '#38BDF8',
- 'link-visited': '#7C3AED',
- 'link-visited-inverse': '#A78BFA',
- 'link-inverse-hover': '#7DD3FC',
- // icon
- 'icon-primary': '#111827',
- 'icon-secondary': '#4B5563',
- 'icon-on-color': '#FFFFFF',
- 'icon-inverse': '#FFFFFF',
- 'icon-interactive': '#2563EB',
- 'icon-on-color-disabled': '#9CA3AF',
- 'icon-disabled': '#D1D5DB',
- // support
- 'support-error': '#DC2626',
- 'support-success': '#16A34A',
- 'support-warning': '#EAB308',
- 'support-info': '#0284C7',
- 'support-error-inverse': '#F87171',
- 'support-success-inverse': '#4ADE80',
- 'support-warning-inverse': '#FDE047',
- 'support-info-inverse': '#38BDF8',
- // button
- 'button-primary': '#2563EB',
- 'button-primary-hover': '#1D4ED8',
- 'button-secondary': '#1F2937',
- 'button-secondary-hover': '#374151',
- 'button-tertiary': '#FFFFFF',
- 'button-tertiary-hover': '#F9FAFB',
- 'button-danger': '#DC2626',
- 'button-danger-secondary': '#DC2626',
- 'button-danger-hover': '#B91C1C',
- 'button-disabled': '#F3F4F6',
- 'button-tertiary-border': '#E5E7EB',
- 'button-tertiary-color': '#111827',
- // focus
- focus: '#2563EB',
- 'focus-inset': '#FFFFFF',
- 'focus-inverse': '#38BDF8',
- 'focus-inverse-inset': '#111827',
- 'focus-error': '#DC2626',
- 'focus-border': '#BFDBFE',
- 'focus-error-border': '#FECACA',
- // misc
- 'misc-highlight': '#BFDBFE',
- 'misc-overlay': '#11182780',
- 'misc-skeleton-background': '#F3F4F6',
- 'misc-skeleton-element': '#D1D5DB',
- 'misc-popup-button-hover': '#1118270D',
- 'misc-tab-item-hover': '#E5E7EB',
- 'misc-dropdown-hover': '#F3F4F6',
- 'misc-loader-base': '#1118270D',
- 'misc-loader-color': '#2563EB',
- 'misc-progress-background': '#E5E7EB',
- // badge
- 'badge-background-gray': '#F9FAFB',
- 'badge-color-gray': '#1F2937',
- 'badge-hover-gray': '#F3F4F6',
- 'badge-border-gray': '#E5E7EB',
- 'badge-background-red': '#FEF2F2',
- 'badge-color-red': '#B91C1C',
- 'badge-hover-red': '#FEE2E2',
- 'badge-border-red': '#FECACA',
- 'badge-background-yellow': '#FEFCE8',
- 'badge-color-yellow': '#A16207',
- 'badge-hover-yellow': '#FEF9C3',
- 'badge-border-yellow': '#FEF08A',
- 'badge-hover-green': '#DCFCE7',
- 'badge-border-green': '#BBF7D0',
- 'badge-background-green': '#F0FDF4',
- 'badge-color-green': '#15803D',
- 'badge-background-sky': '#F0F9FF',
- 'badge-color-sky': '#0369A1',
- 'badge-hover-sky': '#E0F2FE',
- 'badge-border-sky': '#BAE6FD',
- 'badge-background-disabled': '#F3F4F6',
- 'badge-color-disabled': '#D1D5DB',
- 'badge-hover-disabled': '#F3F4F6',
- 'badge-border-disabled': '#E5E7EB',
- 'badge-background-important': '#DC2626',
- // alert
- 'alert-background-neutral': '#FFFFFF',
- 'alert-border-neutral': '#E5E7EB',
- 'alert-background-danger': '#FEF2F2',
- 'alert-border-danger': '#FECACA',
- 'alert-background-warning': '#FEFCE8',
- 'alert-border-warning': '#FEF08A',
- 'alert-background-green': '#F0FDF4',
- 'alert-border-green': '#BBF7D0',
- 'alert-background-info': '#F0F9FF',
- 'alert-border-info': '#BAE6FD',
- // tab
- 'tab-background': '#F3F4F6',
- 'tab-border': '#E5E7EB',
- // tooltip
- 'tooltip-background-light': '#FFFFFF',
- 'tooltip-background-dark': '#111827',
- // toggle
- 'toggle-off': '#E5E7EB',
- 'toggle-on': '#2563EB',
- 'toggle-dial-background': '#FFFFFF',
- 'toggle-off-hover': '#D1D5DB',
- 'toggle-off-border': '#D1D5DB',
- 'toggle-on-hover': '#3B82F6',
- 'toggle-on-border': '#60A5FA',
- 'toggle-off-disabled': '#F3F4F6',
- },
- width: {
- '1/7': '14.2857143%',
- '1/8': '12.5%',
- '1/9': '11.1111111%',
- '1/10': '10%',
- '1/11': '9.0909091%',
- '1/12': '8.3333333%',
- },
- boxShadow: {
- 'soft-shadow-sm':
- '0px 6px 32px -12px rgba(149, 160, 178, 0.12)',
- 'soft-shadow': '0px 8px 32px -12px rgba(149, 160, 178, 0.16)',
- 'soft-shadow-md':
- '0px 10px 32px -12px rgba(149, 160, 178, 0.2)',
- 'soft-shadow-lg':
- '0px 12px 32px -12px rgba(149, 160, 178, 0.24)',
- 'soft-shadow-xl':
- '0px 16px 32px -12px rgba(149, 160, 178, 0.32)',
- 'soft-shadow-2xl':
- '0px 24px 64px -12px rgba(149, 160, 178, 0.32)',
- 'soft-shadow-inner': '0px 1px 1px 0px rgba(0, 0, 0, 0.05)',
- },
- fontSize: {
- tiny: '0.625rem',
- },
- spacing: {
- 120: '30rem', // 480px
- 95: '23.75rem', // 380px
- 141.5: '35.375rem', // 566px
- 188: '47rem', // 752px
- },
- zIndex: {
- 999999: '999999',
- },
- },
-}
-
-```
-
-
-
-4. Great 🥳, now you're ready to use @bsf/force-ui.
-
-```jsx
-import { Button } from "@bsf/force-ui";
-
-export default function Example() {
- return ;
-}
-```
-
-
-
-## MCP Setup
-
-Force UI provides an MCP server that gives AI assistants accurate component usage context correct props, patterns, and examples. So you get reliable implementations without guesswork.
-
-```bash
-npx mcp-add --type http --url "https://brainstormforce.github.io/force-ui/mcp" --scope project # use `global` instead of `project` for making it accessible globally
-```
-
-When prompted, use the following configuration:
-
-| Prompt | Value |
-| --- | --- |
-| **What is the server name?** | `force-ui-mcp` |
-| **HTTP headers? (comma-separated Key=value, or leave empty)** | Leave empty |
-| **Which clients should be configured?** | Select your preferred AI client(s). Ex. Claude |
-| **claude code OAuth client ID? (leave empty if not needed)** | Leave empty |
-
-
-
-Now you are ready to use Force-UI MCP in your project.
-
-
-
-## @bsf/force-ui Documentation
-
-Visit https://github.com/brainstormforce/force-ui/wiki for full documentation.
-
-
-## Contributing
-
-Contributions are always welcome!
-
-See `CONTRIBUTING.md` for ways to get started.
-
-Please adhere to this project's `CODE_OF_CONDUCT.md`.
+## Getting Started - Development Repo
+
+Learn how to use @bsf/force-ui components to quickly and easily create elegant and flexible pages using Tailwind CSS.
+
+@bsf/force-ui is working with Tailwind CSS classes and you need to have Tailwind CSS installed on your project - Tailwind CSS Installation.
+
+
+
+1. Install `@bsf/force-ui`.
+
+Force UI library can be installed using npm package manager. Since this library is still in it's alpha phase, we need to use the staging branch.
+
+Using Force UI as a dependency in package.json -
+
+```json
+"dependencies": {
+ "@bsf/force-ui": "git+https://github.com/brainstormforce/force-ui#1.7.11"
+}
+```
+
+And run the following command to install the package -
+
+
+```bash
+npm install
+```
+
+Or you can directly run the following command to install the package -
+
+```bash
+npm i -S @bsf/force-ui@git+https://github.com/brainstormforce/force-ui.git#1.7.11
+```
+
+
+
+2. Once you install @bsf/force-ui you need to wrap your tailwind css configurations with the `withTW()` function coming from @bsf/force-ui/withTW.
+
+```js
+const withTW = require( '@bsf/force-ui/withTW' );
+
+module.exports = withTW( {
+ content: [ './src/**/*.{js, jsx}' ],
+ theme: {
+ extend: {
+ colors: {
+ 'button-primary': '#6B21A8',
+ 'button-primary-hover': '#7E22CE',
+ 'brand-800': '#6B21A8',
+ 'brand-50': '#FAF5FF',
+ 'border-interactive': '#6B21A8',
+ focus: '#9333EA',
+ 'focus-border': '#D8B4FE',
+ 'toggle-on': '#6B21A8',
+ 'toggle-on-border': '#C084FC',
+ 'toggle-on-hover': '#A855F7',
+ },
+ fontSize: {
+ xxs: '0.6875rem', // 11px
+ },
+ lineHeight: {
+ 2.6: '0.6875rem', // 11px
+ },
+ boxShadow: {
+ 'content-wrapper':
+ '0px 1px 1px 0px #0000000F, 0px 1px 2px 0px #0000001A',
+ },
+ },
+ },
+ plugins: [],
+ corePlugins: {
+ preflight: false,
+ },
+ important: '.surerank-styles',
+} );
+```
+
+
+
+3. @bsf/force-ui comes with a default tailwind theme settings that set's the default theme/styles for components or to provide your own theme/styles to your components. You can override these give below variables in your tailwind.config.js file.
+
+```jsx
+theme: {
+ extend: {
+ colors: {
+ // brand
+ 'brand-background-50': '#EFF6FF',
+ 'brand-background-hover-100': '#DBEAFE',
+ 'brand-200': '#BFDBFE',
+ 'brand-border-300': '#93C5FD',
+ 'brand-400': '#60A5FA',
+ 'brand-500': '#3B82F6',
+ 'brand-primary-600': '#2563EB',
+ 'brand-hover-700': '#1D4ED8',
+ 'brand-800': '#1E40AF',
+ 'brand-900': '#1E3A8A',
+ 'brand-text-950': '#172554',
+ // background
+ 'background-primary': '#FFFFFF',
+ 'background-secondary': '#F3F4F6',
+ 'background-inverse': '#111827',
+ 'background-brand': '#2563EB',
+ 'background-important': '#DC2626',
+ // field
+ 'field-primary-background': '#F9FAFB',
+ 'field-secondary-background': '#FFFFFF',
+ 'field-primary-hover': '#F3F4F6',
+ 'field-secondary-hover': '#F3F4F6',
+ 'field-dropzone-background': '#FFFFFF',
+ 'field-border': '#E5E7EB',
+ 'field-dropzone-background-hover': '#F9FAFB',
+ 'field-dropzone-color': '#2563EB',
+ 'field-label': '#111827',
+ 'field-input': '#111827',
+ 'field-helper': '#9CA3AF',
+ 'field-background-disabled': '#F9FAFB',
+ 'field-color-disabled': '#D1D5DB',
+ 'field-placeholder': '#6B7280',
+ 'field-border-disabled': '#F3F4F6',
+ 'field-color-error': '#DC2626',
+ 'field-border-error': '#FECACA',
+ 'field-background-error': '#FEF2F2',
+ 'field-required': '#DC2626',
+ // border
+ 'border-interactive': '#2563EB',
+ 'border-subtle': '#E5E7EB',
+ 'border-strong': '#6B7280',
+ 'border-inverse': '#374151',
+ 'border-disabled': '#E5E7EB',
+ 'border-muted': '#E5E7EB',
+ 'border-error': '#DC2626',
+ 'border-transparent-subtle': '#37415114',
+ 'border-white': '#FFFFFF',
+ // text
+ 'text-primary': '#111827',
+ 'text-secondary': '#4B5563',
+ 'text-tertiary': '#9CA3AF',
+ 'text-on-color': '#FFFFFF',
+ 'text-error': '#DC2626',
+ 'text-error-inverse': '#F87171',
+ 'text-inverse': '#FFFFFF',
+ 'text-disabled': '#D1D5DB',
+ 'text-on-button-disabled': '#9CA3AF',
+ // link
+ 'link-primary': '#2563EB',
+ 'link-primary-hover': '#1D4ED8',
+ 'link-inverse': '#38BDF8',
+ 'link-visited': '#7C3AED',
+ 'link-visited-inverse': '#A78BFA',
+ 'link-inverse-hover': '#7DD3FC',
+ // icon
+ 'icon-primary': '#111827',
+ 'icon-secondary': '#4B5563',
+ 'icon-on-color': '#FFFFFF',
+ 'icon-inverse': '#FFFFFF',
+ 'icon-interactive': '#2563EB',
+ 'icon-on-color-disabled': '#9CA3AF',
+ 'icon-disabled': '#D1D5DB',
+ // support
+ 'support-error': '#DC2626',
+ 'support-success': '#16A34A',
+ 'support-warning': '#EAB308',
+ 'support-info': '#0284C7',
+ 'support-error-inverse': '#F87171',
+ 'support-success-inverse': '#4ADE80',
+ 'support-warning-inverse': '#FDE047',
+ 'support-info-inverse': '#38BDF8',
+ // button
+ 'button-primary': '#2563EB',
+ 'button-primary-hover': '#1D4ED8',
+ 'button-secondary': '#1F2937',
+ 'button-secondary-hover': '#374151',
+ 'button-tertiary': '#FFFFFF',
+ 'button-tertiary-hover': '#F9FAFB',
+ 'button-danger': '#DC2626',
+ 'button-danger-secondary': '#DC2626',
+ 'button-danger-hover': '#B91C1C',
+ 'button-disabled': '#F3F4F6',
+ 'button-tertiary-border': '#E5E7EB',
+ 'button-tertiary-color': '#111827',
+ // focus
+ focus: '#2563EB',
+ 'focus-inset': '#FFFFFF',
+ 'focus-inverse': '#38BDF8',
+ 'focus-inverse-inset': '#111827',
+ 'focus-error': '#DC2626',
+ 'focus-border': '#BFDBFE',
+ 'focus-error-border': '#FECACA',
+ // misc
+ 'misc-highlight': '#BFDBFE',
+ 'misc-overlay': '#11182780',
+ 'misc-skeleton-background': '#F3F4F6',
+ 'misc-skeleton-element': '#D1D5DB',
+ 'misc-popup-button-hover': '#1118270D',
+ 'misc-tab-item-hover': '#E5E7EB',
+ 'misc-dropdown-hover': '#F3F4F6',
+ 'misc-loader-base': '#1118270D',
+ 'misc-loader-color': '#2563EB',
+ 'misc-progress-background': '#E5E7EB',
+ // badge
+ 'badge-background-gray': '#F9FAFB',
+ 'badge-color-gray': '#1F2937',
+ 'badge-hover-gray': '#F3F4F6',
+ 'badge-border-gray': '#E5E7EB',
+ 'badge-background-red': '#FEF2F2',
+ 'badge-color-red': '#B91C1C',
+ 'badge-hover-red': '#FEE2E2',
+ 'badge-border-red': '#FECACA',
+ 'badge-background-yellow': '#FEFCE8',
+ 'badge-color-yellow': '#A16207',
+ 'badge-hover-yellow': '#FEF9C3',
+ 'badge-border-yellow': '#FEF08A',
+ 'badge-hover-green': '#DCFCE7',
+ 'badge-border-green': '#BBF7D0',
+ 'badge-background-green': '#F0FDF4',
+ 'badge-color-green': '#15803D',
+ 'badge-background-sky': '#F0F9FF',
+ 'badge-color-sky': '#0369A1',
+ 'badge-hover-sky': '#E0F2FE',
+ 'badge-border-sky': '#BAE6FD',
+ 'badge-background-disabled': '#F3F4F6',
+ 'badge-color-disabled': '#D1D5DB',
+ 'badge-hover-disabled': '#F3F4F6',
+ 'badge-border-disabled': '#E5E7EB',
+ 'badge-background-important': '#DC2626',
+ // alert
+ 'alert-background-neutral': '#FFFFFF',
+ 'alert-border-neutral': '#E5E7EB',
+ 'alert-background-danger': '#FEF2F2',
+ 'alert-border-danger': '#FECACA',
+ 'alert-background-warning': '#FEFCE8',
+ 'alert-border-warning': '#FEF08A',
+ 'alert-background-green': '#F0FDF4',
+ 'alert-border-green': '#BBF7D0',
+ 'alert-background-info': '#F0F9FF',
+ 'alert-border-info': '#BAE6FD',
+ // tab
+ 'tab-background': '#F3F4F6',
+ 'tab-border': '#E5E7EB',
+ // tooltip
+ 'tooltip-background-light': '#FFFFFF',
+ 'tooltip-background-dark': '#111827',
+ // toggle
+ 'toggle-off': '#E5E7EB',
+ 'toggle-on': '#2563EB',
+ 'toggle-dial-background': '#FFFFFF',
+ 'toggle-off-hover': '#D1D5DB',
+ 'toggle-off-border': '#D1D5DB',
+ 'toggle-on-hover': '#3B82F6',
+ 'toggle-on-border': '#60A5FA',
+ 'toggle-off-disabled': '#F3F4F6',
+ },
+ width: {
+ '1/7': '14.2857143%',
+ '1/8': '12.5%',
+ '1/9': '11.1111111%',
+ '1/10': '10%',
+ '1/11': '9.0909091%',
+ '1/12': '8.3333333%',
+ },
+ boxShadow: {
+ 'soft-shadow-sm':
+ '0px 6px 32px -12px rgba(149, 160, 178, 0.12)',
+ 'soft-shadow': '0px 8px 32px -12px rgba(149, 160, 178, 0.16)',
+ 'soft-shadow-md':
+ '0px 10px 32px -12px rgba(149, 160, 178, 0.2)',
+ 'soft-shadow-lg':
+ '0px 12px 32px -12px rgba(149, 160, 178, 0.24)',
+ 'soft-shadow-xl':
+ '0px 16px 32px -12px rgba(149, 160, 178, 0.32)',
+ 'soft-shadow-2xl':
+ '0px 24px 64px -12px rgba(149, 160, 178, 0.32)',
+ 'soft-shadow-inner': '0px 1px 1px 0px rgba(0, 0, 0, 0.05)',
+ },
+ fontSize: {
+ tiny: '0.625rem',
+ },
+ spacing: {
+ 120: '30rem', // 480px
+ 95: '23.75rem', // 380px
+ 141.5: '35.375rem', // 566px
+ 188: '47rem', // 752px
+ },
+ zIndex: {
+ 999999: '999999',
+ },
+ },
+}
+
+```
+
+
+
+4. Great 🥳, now you're ready to use @bsf/force-ui.
+
+```jsx
+import { Button } from "@bsf/force-ui";
+
+export default function Example() {
+ return ;
+}
+```
+
+
+
+## MCP Setup
+
+Force UI provides an MCP server that gives AI assistants accurate component usage context correct props, patterns, and examples. So you get reliable implementations without guesswork.
+
+```bash
+npx mcp-add --type http --url "https://brainstormforce.github.io/force-ui/mcp" --scope project # use `global` instead of `project` for making it accessible globally
+```
+
+When prompted, use the following configuration:
+
+| Prompt | Value |
+| --- | --- |
+| **What is the server name?** | `force-ui-mcp` |
+| **HTTP headers? (comma-separated Key=value, or leave empty)** | Leave empty |
+| **Which clients should be configured?** | Select your preferred AI client(s). Ex. Claude |
+| **claude code OAuth client ID? (leave empty if not needed)** | Leave empty |
+
+
+
+Now you are ready to use Force-UI MCP in your project.
+
+
+
+## @bsf/force-ui Documentation
+
+Visit https://github.com/brainstormforce/force-ui/wiki for full documentation.
+
+
+## Contributing
+
+Contributions are always welcome!
+
+See `CONTRIBUTING.md` for ways to get started.
+
+Please adhere to this project's `CODE_OF_CONDUCT.md`.
diff --git a/changelog.txt b/changelog.txt
index 279c4b11..ccd5ef6c 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,220 +1,223 @@
-Version 1.7.11 - 8th April, 2026
-- New: Added Storybook MCP compatibility support for smoother integration with MCP-based tooling and workflows.
-- Improvement: Atom - Alert: Added `role="alert"` and improved focus-visible ring on the close button.
-- Improvement: Atom - Badge: Converted closable element to a semantic `