{"v":0,"components":{"ui-components-accordion":{"id":"ui-components-accordion","name":"Accordion","path":"./src/stories/ui-components/Accordion.stories.tsx","stories":[{"id":"ui-components-accordion--basic","name":"Basic","snippet":"const Basic = () => (\n  <div>\n    <Accordion>\n      <AccordionSummary>\n        <Typography>Accordion 1</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse\n          malesuada lacus ex, sit amet blandit leo lobortis eget.\n        </Typography>\n      </AccordionDetails>\n    </Accordion>\n    <Accordion>\n      <AccordionSummary>\n        <Typography>Accordion 2</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          Donec placerat, lectus sed mattis semper, neque lectus feugiat\n          lectus, varius pulvinar diam eros in elit.\n        </Typography>\n      </AccordionDetails>\n    </Accordion>\n    <Accordion>\n      <AccordionSummary>\n        <Typography>Accordion 3</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer\n          sit amet egestas eros, vitae egestas augue.\n        </Typography>\n      </AccordionDetails>\n    </Accordion>\n  </div>\n);","description":"Basic accordion with summary and details."},{"id":"ui-components-accordion--expanded-by-default","name":"Expanded By Default","snippet":"const ExpandedByDefault = () => (\n  <div>\n    <Accordion defaultExpanded>\n      <AccordionSummary>\n        <Typography>Expanded by default</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          This accordion is expanded by default. Lorem ipsum dolor sit amet,\n          consectetur adipiscing elit.\n        </Typography>\n      </AccordionDetails>\n    </Accordion>\n    <Accordion>\n      <AccordionSummary>\n        <Typography>Collapsed</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.\n        </Typography>\n      </AccordionDetails>\n    </Accordion>\n  </div>\n);","description":"Accordion expanded by default using the `defaultExpanded` prop."},{"id":"ui-components-accordion--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <div>\n    <Accordion>\n      <AccordionSummary>\n        <Typography>Enabled accordion</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n        </Typography>\n      </AccordionDetails>\n    </Accordion>\n    <Accordion disabled>\n      <AccordionSummary>\n        <Typography>Disabled accordion</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>This content is not reachable.</Typography>\n      </AccordionDetails>\n    </Accordion>\n  </div>\n);","description":"A disabled accordion cannot be expanded or collapsed by the user."},{"id":"ui-components-accordion--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [expanded, setExpanded] = useState<string | false>(false);\n\n  const handleChange =\n    (panel: string) => (_event: React.SyntheticEvent, isExpanded: boolean) => {\n      setExpanded(isExpanded ? panel : false);\n    };\n\n  return (\n    <div>\n      <Accordion expanded={expanded === 'panel1'} onChange={handleChange('panel1')}>\n        <AccordionSummary>\n          <Typography sx={{ width: '33%', flexShrink: 0 }}>General settings</Typography>\n          <Typography sx={{ color: 'text.secondary' }}>I am an accordion</Typography>\n        </AccordionSummary>\n        <AccordionDetails>\n          <Typography>\n            Nulla facilisi. Phasellus sollicitudin nulla et quam mattis\n            feugiat. Aliquam eget maximus est, id dignissim quam.\n          </Typography>\n        </AccordionDetails>\n      </Accordion>\n      <Accordion expanded={expanded === 'panel2'} onChange={handleChange('panel2')}>\n        <AccordionSummary>\n          <Typography sx={{ width: '33%', flexShrink: 0 }}>Users</Typography>\n          <Typography sx={{ color: 'text.secondary' }}>\n            You are currently not an owner\n          </Typography>\n        </AccordionSummary>\n        <AccordionDetails>\n          <Typography>\n            Donec placerat, lectus sed mattis semper, neque lectus feugiat\n            lectus, varius pulvinar diam eros in elit.\n          </Typography>\n        </AccordionDetails>\n      </Accordion>\n      <Accordion expanded={expanded === 'panel3'} onChange={handleChange('panel3')}>\n        <AccordionSummary>\n          <Typography sx={{ width: '33%', flexShrink: 0 }}>Advanced settings</Typography>\n          <Typography sx={{ color: 'text.secondary' }}>\n            Filtering has been entirely disabled\n          </Typography>\n        </AccordionSummary>\n        <AccordionDetails>\n          <Typography>\n            Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer\n            sit amet egestas eros, vitae egestas augue.\n          </Typography>\n        </AccordionDetails>\n      </Accordion>\n    </div>\n  );\n};","description":"Controlled accordion where expand/collapse state is managed by React state."},{"id":"ui-components-accordion--with-actions","name":"With Actions","snippet":"const WithActions = () => (\n  <div>\n    <Accordion>\n      <AccordionSummary>\n        <Typography>Accordion with actions</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse\n          malesuada lacus ex, sit amet blandit leo lobortis eget.\n        </Typography>\n      </AccordionDetails>\n      <AccordionActions>\n        <Button size=\"small\">Cancel</Button>\n        <Button size=\"small\" variant=\"contained\">\n          Agree\n        </Button>\n      </AccordionActions>\n    </Accordion>\n  </div>\n);","description":"Accordion with action buttons using the `AccordionActions` component."},{"id":"ui-components-accordion--custom-transition","name":"Custom Transition","snippet":"const CustomTransition = () => {\n  const [expanded, setExpanded] = useState(false);\n\n  return (\n    <div>\n      <Accordion\n        expanded={expanded}\n        onChange={(_event, isExpanded) => setExpanded(isExpanded)}\n        slots={{ transition: Fade as any }}\n        slotProps={{ transition: { timeout: 400 } }}\n        sx={[\n          !expanded && {\n            '& .MuiAccordion-region': { height: 0 },\n            '& .MuiAccordionDetails-root': { display: 'none' },\n          },\n        ]}\n      >\n        <AccordionSummary>\n          <Typography>Custom transition using Fade</Typography>\n        </AccordionSummary>\n        <AccordionDetails>\n          <Typography>\n            Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n            Suspendisse malesuada lacus ex, sit amet blandit leo lobortis\n            eget.\n          </Typography>\n        </AccordionDetails>\n      </Accordion>\n      <Accordion>\n        <AccordionSummary>\n          <Typography>Default transition using Collapse</Typography>\n        </AccordionSummary>\n        <AccordionDetails>\n          <Typography>\n            Donec placerat, lectus sed mattis semper, neque lectus feugiat\n            lectus, varius pulvinar diam eros in elit.\n          </Typography>\n        </AccordionDetails>\n      </Accordion>\n    </div>\n  );\n};","description":"Custom transition using Fade instead of the default Collapse."},{"id":"ui-components-accordion--only-one-expanded","name":"Only One Expanded","snippet":"const OnlyOneExpanded = () => {\n  const [expanded, setExpanded] = useState<string | false>('panel1');\n\n  const handleChange =\n    (panel: string) => (_event: React.SyntheticEvent, newExpanded: boolean) => {\n      setExpanded(newExpanded ? panel : false);\n    };\n\n  return (\n    <div>\n      {['panel1', 'panel2', 'panel3'].map((panel, index) => (\n        <Accordion\n          key={panel}\n          expanded={expanded === panel}\n          onChange={handleChange(panel)}\n          disableGutters\n          elevation={0}\n          square\n          sx={{\n            border: '1px solid',\n            borderColor: 'divider',\n            '&:not(:last-child)': { borderBottom: 0 },\n            '&::before': { display: 'none' },\n          }}\n        >\n          <AccordionSummary>\n            <Typography>Collapsible Group Item #{index + 1}</Typography>\n          </AccordionSummary>\n          <AccordionDetails>\n            <Typography>\n              Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n              Suspendisse malesuada lacus ex, sit amet blandit leo lobortis\n              eget.\n            </Typography>\n          </AccordionDetails>\n        </Accordion>\n      ))}\n    </div>\n  );\n};","description":"Only one accordion can be expanded at a time, with visual customization."},{"id":"ui-components-accordion--square","name":"Square","snippet":"const Square = () => (\n  <div>\n    <Accordion square>\n      <AccordionSummary>\n        <Typography>Square Accordion</Typography>\n      </AccordionSummary>\n      <AccordionDetails>\n        <Typography>\n          This accordion has square corners instead of the default rounded\n          ones.\n        </Typography>\n      </AccordionDetails>\n    </Accordion>\n  </div>\n);","description":"Square accordion without rounded corners."}],"import":"import {\n    Accordion,\n    AccordionActions,\n    AccordionDetails,\n    AccordionSummary,\n    Button,\n    Typography,\n} from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Accordion","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Accordion/Accordion.tsx","actualName":"Accordion","exportName":"Accordion","composes":["Omit"]},"docs":{"ui-components-accordion--docs":{"id":"ui-components-accordion--docs","name":"Docs","path":"./src/stories/ui-components/Accordion.mdx","title":"UI Components/Accordion","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AccordionStories from './Accordion.stories';\nimport { Accordion } from '../../components/Accordion';\n\n<Meta of={AccordionStories} />\n\n# Accordion\n\n## Overview\n\n`Accordion` is the Signal Design System wrapper around MUI `Accordion`. It is a thin `forwardRef` pass-through with no custom logic. It lets users show and hide sections of related content on a page.\n\n```tsx\nimport {\n  Accordion,\n  AccordionSummary,\n  AccordionDetails,\n  AccordionActions,\n  Typography,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n`AccordionSummary`, `AccordionDetails`, and `AccordionActions` are MUI re-exports from the design system package — not Signal wrappers. Import them from `@exotel-npm-dev/signal-design-system` alongside `Accordion`.\n\n**When to use**\n\n- Grouping related optional or secondary content into collapsible sections\n- Reducing visual clutter on dense settings or configuration pages\n- Showing supplementary detail that agents can expand on demand\n\n**When not to use**\n\n- Switching between peer views where only one panel is visible at a time → use `Tabs`\n- Off-canvas or overlay content → use `Drawer` or `Dialog`\n- Sequential step-by-step workflows → use `Stepper`\n- Critical information that must always be visible → render directly or use `Card`\n- Navigation to another route → use `Link` or app navigation\n\n## Anatomy\n\nSignal does not provide `AccordionItem`, `AccordionTrigger`, `AccordionContent`, or `AccordionHeader`. Use MUI composition:\n\n```\nAccordion                    ← Signal wrapper\n├── AccordionSummary         ← MUI header/trigger (required)\n├── AccordionDetails         ← MUI content panel (required)\n└── AccordionActions         ← MUI optional footer\n```\n\nMultiple sibling `<Accordion>` elements form a group. There is no parent `AccordionGroup` component.\n\nCanonical structure:\n\n```tsx\n<Accordion>\n  <AccordionSummary>\n    <Typography>Section title</Typography>\n  </AccordionSummary>\n  <AccordionDetails>\n    <Typography>Panel content</Typography>\n  </AccordionDetails>\n  {/* optional */}\n  <AccordionActions>\n    <Button size=\"small\">Cancel</Button>\n    <Button size=\"small\" variant=\"contained\">Agree</Button>\n  </AccordionActions>\n</Accordion>\n```\n\n## Props\n\n`AccordionProps` extends MUI `AccordionProps` (minus `ref`). All MUI props pass through via spread.\n\n### Props documented in stories argTypes\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `defaultExpanded` | `boolean` | `false` | Expands the panel on mount in uncontrolled mode | Use for the most important section that should be visible initially. Only one panel per group should use this unless using controlled state. |\n| `disabled` | `boolean` | `false` | Prevents expand/collapse interaction | Use when the section is unavailable. Content in `AccordionDetails` is not reachable. |\n| `disableGutters` | `boolean` | `true` | Removes expanded margin in accordion sets | Default `true` so stacked panels stay flush with divider separators. Set `false` only if you need MUI's expanded spacing. |\n| `square` | `boolean` | `false` | Disables rounded corners | Use for flush groups or when matching rectangular layout containers. |\n| `expanded` | `boolean` | — | Controlled expand state | Pair with `onChange`. Required for controlled and single-expand patterns. |\n\n### Props used in stories (not in argTypes)\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `onChange` | `(event: SyntheticEvent, expanded: boolean) => void` | Fires when expand state changes | Required for controlled mode and `OnlyOneExpanded` pattern. |\n| `elevation` | `number` | Shadow depth | `OnlyOneExpanded` uses `elevation={0}` for flat groups. |\n| `slots.transition` | Component | Custom expand animation | `CustomTransition` uses `Fade` instead of default `Collapse`. |\n| `slotProps.transition` | `object` | Transition configuration | e.g. `{ timeout: 400 }` in `CustomTransition`. |\n| `sx` | `SxProps` | Style overrides | Used for borders, subtitle layout, and collapsed-region hiding. |\n\nAdditional standard MUI `AccordionProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Accordion} />\n\n## Variants\n\nSignal defines no custom `variant` prop. Styling options evidenced in stories:\n\n| Style | Props | Story |\n|-------|-------|-------|\n| Default stacked set | `disableGutters` (default `true`), `elevation` (default `0`) | `Basic` |\n| Square corners | `square` | `Square` |\n| Flush bordered group | `disableGutters`, `elevation={0}`, `square`, border `sx` | `OnlyOneExpanded` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Collapsed | Default | Content in `AccordionDetails` is hidden |\n| Expanded | `defaultExpanded` or `expanded={true}` | Content visible; summary shows expanded indicator |\n| Disabled | `disabled={true}` | Non-interactive; content not reachable |\n| Hover / Focus / Pressed | Automatic | Styled by MUI defaults; no separate Signal stories |\n\n<Canvas of={AccordionStories.Disabled} />\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Independent panels | Multiple sibling `<Accordion>` elements; each manages own state | `Basic` |\n| Default open | `defaultExpanded` on one panel | `ExpandedByDefault` |\n| Controlled panel | `expanded` + `onChange` per panel | `Controlled` |\n| Only one expanded | App state tracks active panel ID; `expanded={activeId === panel}` | `OnlyOneExpanded` |\n| Footer actions | `AccordionActions` with `Button` children | `WithActions` |\n| Custom transition | `slots={{ transition: Fade }}` + `slotProps` + conditional `sx` | `CustomTransition` |\n\n**Not built-in:** There is no `type=\"single\"` or built-in single-expand prop. Exclusive expand is a composition pattern implemented via controlled state in `OnlyOneExpanded`.\n\n`MuiAccordion` theme defaults: `disableGutters: true` and `elevation: 0` so stacked panels stay flush; expanded panels keep the `::before` divider between siblings (no 16px expanded margin).\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-accordion--basic`\n\nThree independent accordions, each with `AccordionSummary` and `AccordionDetails`.\n\n**Recommended usage:** Default composition for unrelated collapsible sections on the same page.\n\n<Canvas of={AccordionStories.Basic} />\n\n### ExpandedByDefault\n\n**Story ID:** `ui-components-accordion--expanded-by-default`\n\nFirst panel uses `defaultExpanded`; second panel is collapsed.\n\n**Recommended usage:** When one section should be visible on initial page load.\n\n### Disabled\n\n**Story ID:** `ui-components-accordion--disabled`\n\nEnabled accordion alongside `disabled` accordion.\n\n**Recommended usage:** Reference for non-interactive panel appearance and behavior.\n\n### Controlled\n\n**Story ID:** `ui-components-accordion--controlled`\n\nThree panels with `expanded` and `onChange` driven by React state. Summary includes primary label and secondary subtitle `Typography`.\n\n**Recommended usage:** When expand state must sync with app logic or URL state. Two-line summary layout pattern.\n\n<Canvas of={AccordionStories.Controlled} />\n\n### WithActions\n\n**Story ID:** `ui-components-accordion--with-actions`\n\nPanel with `AccordionActions` containing `Cancel` and `Agree` buttons.\n\n**Recommended usage:** Panel-scoped actions such as inline agreement or confirmation within a section.\n\n<Canvas of={AccordionStories.WithActions} />\n\n### CustomTransition\n\n**Story ID:** `ui-components-accordion--custom-transition`\n\nControlled accordion using `Fade` transition via `slots` and `slotProps` instead of default `Collapse`.\n\n**Recommended usage:** Custom animation when default collapse transition is insufficient.\n\n### OnlyOneExpanded\n\n**Story ID:** `ui-components-accordion--only-one-expanded`\n\nThree panels in a flush bordered group. Controlled state ensures only one panel is expanded at a time. Uses `disableGutters`, `elevation={0}`, `square`, and border `sx`.\n\n**Recommended usage:** Mutually exclusive sections such as settings categories.\n\n<Canvas of={AccordionStories.OnlyOneExpanded} />\n\n### Square\n\n**Story ID:** `ui-components-accordion--square`\n\nSingle accordion with `square` prop.\n\n**Recommended usage:** Square-corner styling without full flush-group treatment.\n\n## Accessibility\n\n- `AccordionSummary` renders an interactive header (button) with `aria-expanded` reflecting panel state.\n- `AccordionDetails` content is associated with its summary via MUI region/id linkage.\n- Keyboard: Enter and Space toggle expand/collapse on the summary (MUI default).\n- Focus: summary receives focus; MUI `:focus-visible` ring applies.\n- `disabled` removes interactivity and sets appropriate disabled ARIA state.\n- No custom ARIA logic in the Signal wrapper; standard MUI `aria-*` props pass through via `{...props}`.\n- Screen readers announce expanded/collapsed state via `aria-expanded` on the summary button.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Group related optional or secondary content into collapsible sections.\n- Use clear, scannable summary labels via `Typography` in `AccordionSummary`.\n- Use the `OnlyOneExpanded` controlled pattern when panels are mutually exclusive.\n- Apply `defaultExpanded` to at most one section in an uncontrolled group.\n- Use `AccordionActions` for actions scoped to a single panel, not page-level CTAs.\n- Use controlled mode (`expanded` + `onChange`) when expand state must sync with app logic.\n- Import all accordion parts from `@exotel-npm-dev/signal-design-system`, not `@mui/material` directly.\n\n## Anti-patterns\n\n- Hiding critical required information in collapsed panels by default.\n- Nesting accordions inside accordions (not demonstrated in stories; increases accessibility complexity).\n- Using accordion for sequential step-by-step workflows — use `Stepper`.\n- Using accordion for switching between peer views — use `Tabs`.\n- Using accordion for off-canvas navigation — use `Drawer`.\n- Inventing `AccordionItem`, `AccordionTrigger`, or `AccordionContent` APIs — they do not exist in Signal.\n- Assuming a built-in single-expand prop — implement via controlled state (`OnlyOneExpanded`).\n- Importing `@mui/material/Accordion` directly in consumer apps.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `Accordion`\n\n- Collapsible sections of related content on the same page\n- Optional or secondary detail agents can expand on demand\n- Settings or configuration grouped into scannable sections\n- Supplementary content that reduces clutter when collapsed\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Switch between peer views (one visible at a time) | `Tabs` |\n| Off-canvas or overlay panel | `Drawer` or `Dialog` / `StructuredDialog` |\n| Static grouped content always visible | `Card` or plain layout |\n| Short content that should not hide | Render directly (no accordion) |\n| Sequential wizard or multi-step flow | `Stepper` |\n| Navigation to URL or route | `Link` or app navigation |\n\n### Recommended content types\n\n- Settings sections (general, users, advanced)\n- FAQ or help supplementary detail\n- Optional configuration fields\n- Inline agreement or confirmation within a section (`AccordionActions`)\n\n### Recommended content length\n\n- Summary: short label (1–5 words) via `Typography` in `AccordionSummary`\n- Details: moderate content; avoid very long scrollable panels inside a single accordion\n- For lengthy forms, prefer `Drawer` or dedicated page over deep accordion nesting\n\n### Preferred composition patterns\n\n```tsx\n// Basic — story: Basic\n<Accordion>\n  <AccordionSummary>\n    <Typography>Section title</Typography>\n  </AccordionSummary>\n  <AccordionDetails>\n    <Typography>Panel content</Typography>\n  </AccordionDetails>\n</Accordion>\n\n// Controlled with subtitle — story: Controlled\n<Accordion expanded={expanded === 'panel1'} onChange={handleChange('panel1')}>\n  <AccordionSummary>\n    <Typography sx={{ width: '33%', flexShrink: 0 }}>General settings</Typography>\n    <Typography sx={{ color: 'text.secondary' }}>Subtitle text</Typography>\n  </AccordionSummary>\n  <AccordionDetails>\n    <Typography>Content</Typography>\n  </AccordionDetails>\n</Accordion>\n\n// Single-expand flush group — story: OnlyOneExpanded\n<Accordion\n  expanded={expanded === 'panel1'}\n  onChange={handleChange('panel1')}\n  disableGutters\n  elevation={0}\n  square\n  sx={{ border: '1px solid', borderColor: 'divider', '&:not(:last-child)': { borderBottom: 0 }, '&::before': { display: 'none' } }}\n>\n  <AccordionSummary><Typography>Collapsible Group Item #1</Typography></AccordionSummary>\n  <AccordionDetails><Typography>Content</Typography></AccordionDetails>\n</Accordion>\n\n// With actions — story: WithActions\n<AccordionActions>\n  <Button size=\"small\">Cancel</Button>\n  <Button size=\"small\" variant=\"contained\">Agree</Button>\n</AccordionActions>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default composition | `Basic` (`ui-components-accordion--basic`) |\n| Initially expanded panel | `ExpandedByDefault` |\n| Controlled expand state | `Controlled` |\n| Mutually exclusive panels | `OnlyOneExpanded` |\n| Panel footer actions | `WithActions` |\n| Disabled panel | `Disabled` |\n| Square corners | `Square` |\n| Custom animation | `CustomTransition` |\n\n### Common mistakes to avoid\n\n- Inventing `AccordionItem`, `AccordionTrigger`, `AccordionContent`, or `AccordionHeader` — use `AccordionSummary` and `AccordionDetails`.\n- Assuming built-in single-expand — use controlled state pattern from `OnlyOneExpanded`.\n- Omitting `AccordionSummary` or `AccordionDetails` — both are required for a functional panel.\n- Using `Collapsible` — component does not exist in Signal.\n- Using `Accordion` for tab-like view switching — use `Tabs`.\n- Omitting `ExotelThemeProvider` in app setup.\n\n### Composition guidance\n\n- Place sibling `<Accordion>` elements in a containing `div` or layout component.\n- For exclusive expand, track active panel ID in state and pass `expanded={activeId === panelId}` to each accordion.\n- Put page-level primary actions outside accordions; use `AccordionActions` only for panel-scoped actions.\n- Use `defaultExpanded` on one panel OR controlled state — not both on the same panel.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `AccordionSummary` | MUI header/trigger (re-export) |\n| `AccordionDetails` | MUI content panel (re-export) |\n| `AccordionActions` | MUI optional footer (re-export) |\n| `Typography` | Summary and details text |\n| `Button` | Actions in `AccordionActions` |\n| `Tabs` | Alternative for view switching |\n| `Card` | Alternative for always-visible grouped content |\n| `Drawer` | Alternative for overlay panels |\n| `Dialog` / `StructuredDialog` | Alternative for modal content |\n| `Stepper` | Alternative for sequential flows |\n\n`Collapsible` and `Section` do not exist as components in the Signal Design System.\n"}}},"ui-components-alert":{"id":"ui-components-alert","name":"Alert","path":"./src/stories/ui-components/Alert.stories.tsx","stories":[{"id":"ui-components-alert--success","name":"Success","snippet":"const Success = () => <Alert severity=\"success\">This is a success alert!</Alert>;","description":"Success alert"},{"id":"ui-components-alert--error","name":"Error","snippet":"const Error = () => <Alert severity=\"error\">This is an error alert!</Alert>;","description":"Error alert"},{"id":"ui-components-alert--warning","name":"Warning","snippet":"const Warning = () => <Alert severity=\"warning\">This is a warning alert!</Alert>;","description":"Warning alert"},{"id":"ui-components-alert--info","name":"Info","snippet":"const Info = () => <Alert severity=\"info\">This is an info alert!</Alert>;","description":"Info alert"},{"id":"ui-components-alert--variants","name":"Variants","snippet":"const Variants = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '400px' }}>\n    <Alert severity=\"success\" variant=\"standard\">Standard variant</Alert>\n    <Alert severity=\"success\" variant=\"filled\">Filled variant</Alert>\n    <Alert severity=\"success\" variant=\"outlined\">Outlined variant</Alert>\n  </div>\n);","description":"Different variants"},{"id":"ui-components-alert--dismissible","name":"Dismissible","snippet":"const Dismissible = () => {\n  const [open, setOpen] = React.useState(true);\n  if (!open) return <button onClick={() => setOpen(true)}>Show Alert</button>;\n  return (\n    <Alert severity=\"info\" onClose={() => setOpen(false)}>\n      This alert can be dismissed\n    </Alert>\n  );\n};","description":"Dismissible alert"},{"id":"ui-components-alert--with-action","name":"With Action","snippet":"const WithAction = () => (\n  <Alert\n    severity=\"warning\"\n    action={\n      <IconButton size=\"small\" onClick={() => {}}>\n        <Icon name=\"x\" size=\"sm\" />\n      </IconButton>\n    }\n  >\n    This alert has a custom action button\n  </Alert>\n);","description":"Alert with action"},{"id":"ui-components-alert--interactive","name":"Interactive","snippet":"const Interactive = () => <Alert severity=\"success\" variant=\"standard\">This is an alert message</Alert>;","description":"Interactive alert with all controls"}],"import":"import { Alert, Icon, IconButton } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Alert","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Alert/Alert.tsx","actualName":"Alert","exportName":"Alert","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-alert--docs":{"id":"ui-components-alert--docs","name":"Docs","path":"./src/stories/ui-components/Alert.mdx","title":"UI Components/Alert","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AlertStories from './Alert.stories';\nimport { Alert } from '../../components/Alert';\n\n<Meta of={AlertStories} />\n\n# Alert\n\n## Overview\n\n`Alert` is the Signal Design System wrapper around MUI `Alert`. It is a thin `forwardRef` pass-through with no custom logic. It displays important, persistent messages inline within a page or view.\n\n```tsx\nimport { Alert } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Inline feedback that should remain visible until dismissed or resolved\n- Form validation summaries, configuration warnings, or status messages within a page section\n- Contextual messages tied to a specific area of the UI (not global transient toasts)\n\n**When not to use**\n\n- Brief, auto-dismissing global notifications → use `Snackbar` (typically wrapping `Alert` as its child)\n- Blocking confirmation or destructive actions → use `Dialog` or `StructuredDialog`\n- Small status indicators on icons or avatars → use `Badge`\n- Long-form help or supplementary detail → use `Accordion` or inline `Typography`\n- Navigation or routing → use `Link`\n\n## Anatomy\n\nSignal does not provide `AlertTitle` or `AlertDescription` subcomponents. Use MUI composition:\n\n```\nAlert                        ← Signal wrapper\n├── (optional) Typography    ← title or emphasized line (MUI re-export)\n└── children                 ← message body (text or Typography)\n```\n\nOptional slots:\n\n- `action` — trailing control (e.g. `IconButton` for dismiss or secondary action)\n- `onClose` — built-in dismiss button when provided\n\nCanonical structure:\n\n```tsx\n<Alert severity=\"success\" variant=\"standard\">\n  Operation completed successfully.\n</Alert>\n```\n\nWith dismiss:\n\n```tsx\n<Alert severity=\"info\" onClose={handleClose}>\n  This alert can be dismissed\n</Alert>\n```\n\n## Props\n\n`AlertProps` extends MUI `AlertProps` (minus `ref`). All MUI props pass through via spread.\n\n### Props documented in stories argTypes\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `severity` | `'error' \\| 'warning' \\| 'info' \\| 'success'` | `'success'` | Semantic color and icon | Match message intent: `error` for failures, `warning` for caution, `info` for neutral context, `success` for confirmation |\n| `variant` | `'standard' \\| 'filled' \\| 'outlined'` | `'standard'` | Visual style | `standard` for default inline; `filled` for higher emphasis; `outlined` for subtle bordered look |\n| `onClose` | `(event: SyntheticEvent) => void` | — | Shows built-in close button and fires on dismiss | Use when the user can dismiss the message; pair with local state (`Dismissible` story) |\n| `children` | `ReactNode` | — | Alert message content | Keep concise; use `Typography` for multi-line or titled messages |\n\n### Props used in stories (not in argTypes)\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `action` | `ReactNode` | Trailing slot for custom controls | `WithAction` uses `IconButton` + `Icon` for a custom dismiss or action control |\n\nAdditional standard MUI `AlertProps` pass through (e.g. `icon`, `iconMapping`, `sx`, `role`). See the generated table below for the full API.\n\n<ArgTypes of={Alert} />\n\n## Variants\n\n| Variant | Description | Story |\n|---------|-------------|-------|\n| `standard` | Tonal background via `resolveTonalColor` (light: solid; dark: alpha 32%) | `Variants`, `Success`, `Error`, `Warning`, `Info` |\n| `filled` | Solid semantic background | `Variants` |\n| `outlined` | Border with transparent/light background | `Variants` |\n\nSignal defines no custom variant beyond MUI's three options. **`standard`** uses `MuiAlert` theme overrides with `resolveTonalColor` for background — **light:** solid `palette.tonal`; **dark:** `alpha(palette.main, 32%)`. Text and icon colors remain MUI defaults.\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Visible (default) | Render `<Alert>` | Inline in document flow |\n| Dismissible | `onClose` callback | Renders MUI close button; parent controls visibility (`Dismissible`) |\n| With custom action | `action` prop | Custom trailing control (`WithAction`) |\n| Hidden | Conditional render in parent | `Dismissible` unmounts alert when closed |\n\nSeverity states (semantic, not interactive):\n\n| Severity | Use for | Story |\n|----------|---------|-------|\n| `success` | Completed actions, positive outcomes | `Success` |\n| `error` | Failures, blocking issues | `Error` |\n| `warning` | Caution, reversible risk | `Warning` |\n| `info` | Neutral context, tips | `Info` |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Static inline message | Render with `severity` + `children` | `Success`, `Error`, `Warning`, `Info` |\n| Variant comparison | `variant` prop | `Variants` |\n| User-dismissible | `onClose` + parent `open` state | `Dismissible` |\n| Custom trailing action | `action` slot | `WithAction` |\n| Interactive controls | Storybook argTypes | `Interactive` |\n\n`Alert` is not a toast container. It does not auto-hide, anchor to viewport corners, or manage `open` state — that is `Snackbar`'s role. In Signal stories, `Snackbar` wraps `Alert` as its child for transient notifications.\n\n## Stories\n\n### Success\n\n**Story ID:** `ui-components-alert--success`\n\nSuccess severity with default `standard` variant.\n\n**Recommended usage:** Confirming a completed operation inline on the page.\n\n<Canvas of={AlertStories.Success} />\n\n### Error\n\n**Story ID:** `ui-components-alert--error`\n\nError severity alert.\n\n**Recommended usage:** Reporting failures or validation errors that need attention.\n\n<Canvas of={AlertStories.Error} />\n\n### Warning\n\n**Story ID:** `ui-components-alert--warning`\n\nWarning severity alert.\n\n**Recommended usage:** Cautionary messages about reversible or pending issues.\n\n<Canvas of={AlertStories.Warning} />\n\n### Info\n\n**Story ID:** `ui-components-alert--info`\n\nInfo severity alert.\n\n**Recommended usage:** Neutral contextual information or tips.\n\n<Canvas of={AlertStories.Info} />\n\n### Variants\n\n**Story ID:** `ui-components-alert--variants`\n\nThree `success` alerts demonstrating `standard`, `filled`, and `outlined` variants.\n\n**Recommended usage:** Choose visual weight appropriate to page density and emphasis needs.\n\n<Canvas of={AlertStories.Variants} />\n\n### Dismissible\n\n**Story ID:** `ui-components-alert--dismissible`\n\n`info` alert with `onClose` handler; parent state controls visibility. Re-open via button when dismissed.\n\n**Recommended usage:** Non-critical messages the user can dismiss after reading.\n\n<Canvas of={AlertStories.Dismissible} />\n\n### WithAction\n\n**Story ID:** `ui-components-alert--with-action`\n\n`warning` alert with custom `action` slot containing `IconButton` and `Icon`.\n\n**Recommended usage:** Custom trailing control when the built-in `onClose` button is insufficient.\n\n<Canvas of={AlertStories.WithAction} />\n\n### Interactive\n\n**Story ID:** `ui-components-alert--interactive`\n\nPlayground story with Storybook controls for `severity`, `variant`, and `children`.\n\n**Recommended usage:** Explore prop combinations during development.\n\n## Content guidelines\n\nRules for writing alert messages in Exotel products. Content is set via `children` (and optionally a `Typography` title).\n\n### Message structure\n\n| Element | Guidance |\n|---------|----------|\n| Body (`children`) | One clear sentence stating what happened or what the user should know |\n| Title (optional) | Short emphasized line via `Typography` with `fontWeight=\"bold\"` or `variant=\"label1\"` — use when the body needs context |\n| Action label | If using `action`, use an icon with accessible `aria-label` (e.g. dismiss) |\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Lead with outcome | State what happened first: \"Campaign saved\" not \"We have saved your campaign\" |\n| Be specific | Name the object: \"3 contacts failed to import\" not \"Import failed\" |\n| Actionable errors | Tell the user what to do next: \"Check the phone number format and try again\" |\n| Concise | One to two sentences; avoid paragraphs |\n| Match severity | `error` = something failed; `warning` = caution; `info` = neutral; `success` = confirmed completion |\n| No blame | Describe the issue, not the user: \"Invalid email format\" not \"You entered an invalid email\" |\n\n### Severity and tone\n\n| Severity | Tone | Example |\n|----------|------|---------|\n| `success` | Confident, brief | \"Channel configuration saved.\" |\n| `error` | Direct, actionable | \"Unable to save changes. Check required fields and try again.\" |\n| `warning` | Cautionary, specific | \"This action will remove 12 contacts from the list.\" |\n| `info` | Neutral, helpful | \"Changes take effect after the next sync.\" |\n\n### Do and don't\n\n| Do | Don't |\n|----|-------|\n| \"3 campaigns failed to export. Download the error report.\" | \"Error!\" (no context) |\n| \"Connection restored. Pending messages will send shortly.\" | \"Something went wrong. Please contact support.\" (when fixable inline) |\n| Use `onClose` for dismissible non-critical info | Auto-dismiss inline alerts (use `Snackbar` instead) |\n| Pair `error` severity with specific next steps | Use `error` for neutral information |\n\n### Guidance for AI-generated content\n\n- Choose `severity` from message intent, not visual preference.\n- Keep `children` to 1–2 sentences; never generate placeholder lorem ipsum.\n- For errors, include what failed and a suggested user action when known.\n- Do not invent a `title` prop — use `Typography` as a child if a title line is needed.\n- Prefer `onClose` for dismissible alerts; use `action` only when a custom control is required.\n- Do not use `Alert` for toast-style transient messages — wrap in `Snackbar` with `autoHideDuration`.\n\n## Accessibility\n\n- Renders with `role=\"alert\"` by default (MUI), so screen readers announce the message when it appears.\n- Severity icons are decorative; MUI provides appropriate `aria-hidden` on icons.\n- `onClose` renders a close button with an accessible label (MUI default close text).\n- Custom `action` controls must include their own accessible names (`aria-label` on `IconButton`).\n- Keyboard: close button is focusable and activatable via Enter/Space (MUI default).\n- No custom ARIA logic in the Signal wrapper; standard MUI `aria-*` props pass through via `{...props}`.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best practices\n\n- Place alerts near the content they relate to (form top, section header, affected panel).\n- Match `severity` to message intent; do not use `error` for informational content.\n- Use `onClose` when the message is dismissible; control visibility with parent state.\n- For transient global feedback, compose `Snackbar` + `Alert` (see `Snackbar` stories).\n- Keep messages short and actionable; link to detail pages for lengthy explanations.\n- Use `variant=\"outlined\"` or `variant=\"standard\"` in dense layouts; reserve `filled` for high emphasis.\n- Import from `@exotel-npm-dev/signal-design-system`, not `@mui/material` directly.\n\n## Anti-patterns\n\n- Using `Alert` for auto-dismissing toast notifications — use `Snackbar`.\n- Using `Alert` for modal confirmations — use `Dialog` or `StructuredDialog`.\n- Stacking many simultaneous inline alerts without hierarchy — consolidate or use `Snackbar`.\n- Using `success` severity for warnings or errors.\n- Inventing a `title` or `description` prop — use `children` and optional `Typography`.\n- Hardcoding hex colors instead of `severity` semantic colors.\n- Omitting `ExotelThemeProvider` in app setup.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `Alert`\n\n- Inline, persistent feedback within a page section\n- Form-level validation or status messages\n- Contextual warnings tied to a specific UI area\n- Child content inside `Snackbar` for styled toast messages\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Auto-dismissing global notification | `Snackbar` (with `Alert` child) |\n| Blocking confirmation or destructive action | `Dialog` / `StructuredDialog` |\n| Small count or status on an icon/avatar | `Badge` |\n| Expandable supplementary detail | `Accordion` |\n| Hover-only supplementary text | `Tooltip` |\n| Rich interactive popover content | `Popover` |\n| Page-level promotional banner (persistent) | Custom layout with `Alert` or dedicated banner pattern |\n\n### Prop selection guidance\n\n| Use case | Recommended props |\n|----------|-------------------|\n| Default inline success | `severity=\"success\"`, `variant=\"standard\"` |\n| High-emphasis error | `severity=\"error\"`, `variant=\"filled\"` |\n| Subtle info in dense UI | `severity=\"info\"`, `variant=\"outlined\"` |\n| User can dismiss | `onClose={handler}` + parent visibility state |\n| Custom trailing control | `action={<IconButton ...>}` |\n\n### Preferred composition patterns\n\n```tsx\n// Inline success — story: Success\n<Alert severity=\"success\">This is a success alert!</Alert>\n\n// Severity set — stories: Error, Warning, Info\n<Alert severity=\"error\">This is an error alert!</Alert>\n\n// Variants — story: Variants\n<Alert severity=\"success\" variant=\"filled\">Filled variant</Alert>\n\n// Dismissible — story: Dismissible\n<Alert severity=\"info\" onClose={() => setOpen(false)}>\n  This alert can be dismissed\n</Alert>\n\n// Custom action — story: WithAction\n<Alert\n  severity=\"warning\"\n  action={\n    <IconButton size=\"small\" aria-label=\"Dismiss\" onClick={handleDismiss}>\n      <Icon name=\"x\" size=\"sm\" />\n    </IconButton>\n  }\n>\n  This alert has a custom action button\n</Alert>\n\n// Toast pattern — see Snackbar stories\n<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>\n  <Alert severity=\"success\" onClose={handleClose}>\n    This is a success message!\n  </Alert>\n</Snackbar>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default success message | `Success` (`ui-components-alert--success`) |\n| Error message | `Error` |\n| Warning message | `Warning` |\n| Info message | `Info` |\n| Compare visual variants | `Variants` |\n| Dismissible alert | `Dismissible` |\n| Custom action slot | `WithAction` |\n| Prop playground | `Interactive` |\n\n### Common mistakes to avoid\n\n- Using `Alert` alone for toast behavior — wrap in `Snackbar` with `open` and `autoHideDuration`.\n- Inventing `title` or `description` props — use `children` and `Typography`.\n- Choosing `filled` variant everywhere — increases visual noise in dense pages.\n- Omitting parent state for dismissible alerts — `onClose` only fires the callback; parent must hide the alert.\n- Using `Alert` for modal dialogs — use `Dialog` / `StructuredDialog`.\n- Forgetting `aria-label` on custom `action` icon buttons.\n\n### Composition guidance\n\n- Place one primary alert per form or section; avoid alert stacking.\n- Combine with `Snackbar` for transient feedback; keep `Alert` inline for persistent context.\n- Use `IconButton` + `Icon` in `action` for icon-only controls (see `WithAction`).\n- Do not nest `Alert` inside `Alert`.\n- Pair form validation alerts with `FormField` / `EnhancedTextField` error states at the field level.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Snackbar` | Container for transient toast notifications; typically wraps `Alert` |\n| `Dialog` / `StructuredDialog` | Blocking modal for confirmations |\n| `Typography` | Optional title or formatted message text |\n| `IconButton` | Custom `action` slot control |\n| `Icon` | Icon inside `action` (`WithAction` story) |\n| `Badge` | Small status indicator on icons/avatars |\n| `Tooltip` | Hover-only supplementary text |\n| `FormField` | Field-level validation alongside form alerts |\n"}}},"ui-components-appbar":{"id":"ui-components-appbar","name":"AppBar","path":"./src/stories/ui-components/AppBar.stories.tsx","stories":[{"id":"ui-components-appbar--with-logo-url","name":"Logo as URL","snippet":"const WithLogoUrl = () => <AppBar\n    brandLogo={EXOTEL_LOGO_URL}\n    brandLogoAlt=\"Exotel\"\n    appLauncherType=\"sectioned\"\n    appLauncherProducts={DEFAULT_PRODUCTS}\n    onNotificationClick={() => console.log('notification clicked')} />;"},{"id":"ui-components-appbar--with-logo-node","name":"Logo as React node","snippet":"const WithLogoNode = () => <AppBar\n    brandLogo={(<svg width=\"96\" height=\"24\" viewBox=\"0 0 96 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-label=\"Exotel\">\n      <rect width=\"96\" height=\"24\" rx=\"4\" fill=\"#0F3460\" />\n      <text x=\"8\" y=\"17\" fontFamily=\"sans-serif\" fontSize=\"13\" fontWeight=\"700\" fill=\"white\">exotel</text>\n    </svg>)}\n    appLauncherType=\"default\"\n    appLauncherProducts={DEFAULT_PRODUCTS}\n    onNotificationClick={() => console.log('notification clicked')} />;"},{"id":"ui-components-appbar--default-layout","name":"AppLauncher — default layout","snippet":"const DefaultLayout = () => <AppBar\n    brandLogo={EXOTEL_LOGO_URL}\n    brandLogoAlt=\"Exotel\"\n    appLauncherType=\"default\"\n    appLauncherProducts={DEFAULT_PRODUCTS}\n    onNotificationClick={() => console.log('notification clicked')} />;"},{"id":"ui-components-appbar--sectioned-layout","name":"AppLauncher — sectioned layout","snippet":"const SectionedLayout = () => <AppBar\n    brandLogo={EXOTEL_LOGO_URL}\n    brandLogoAlt=\"Exotel\"\n    appLauncherType=\"sectioned\"\n    appLauncherProducts={DEFAULT_PRODUCTS}\n    onNotificationClick={() => console.log('notification clicked')} />;"},{"id":"ui-components-appbar--without-app-launcher","name":"Without AppLauncher","snippet":"const WithoutAppLauncher = () => <AppBar\n    brandLogo={EXOTEL_LOGO_URL}\n    brandLogoAlt=\"Exotel\"\n    onNotificationClick={() => console.log('notification clicked')} />;"}],"import":"import { AppBar, Icon } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"AppBar","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/AppBar/AppBar.tsx","actualName":"AppBar","exportName":"AppBar","props":{"appLauncherType":{"required":false,"tsType":{"name":"union","raw":"'default' | 'sectioned'","elements":[{"name":"literal","value":"'default'"},{"name":"literal","value":"'sectioned'"}]},"description":"Layout mode for the AppLauncher. Omit `appLauncherProducts` to hide the launcher entirely.","defaultValue":{"value":"'default'","computed":false}},"appLauncherProducts":{"required":false,"tsType":{"name":"Array","elements":[{"name":"Product"}],"raw":"Product[]"},"description":"Product list rendered inside the AppLauncher. Required to show the launcher."},"appLauncherIconName":{"required":false,"tsType":{"name":"unknown"},"description":"Icon for the AppLauncher trigger button."},"avatarName":{"required":true,"tsType":{"name":"string"},"description":"Full name used to derive initials and avatar background colour."},"avatarSize":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"Size of the avatar trigger. @default 'small'"},"avatarMenuGroups":{"required":true,"tsType":{"name":"Array","elements":[{"name":"AvatarMenuGroup"}],"raw":"AvatarMenuGroup[]"},"description":"Grouped menu items rendered inside the AvatarMenu popup."},"avatarFooterInfo":{"required":true,"tsType":{"name":"Array","elements":[{"name":"AvatarMenuFooterInfo"}],"raw":"AvatarMenuFooterInfo[]"},"description":"Static info rows displayed in the AvatarMenu footer (e.g. last login, version)."},"avatarSelectedTheme":{"required":true,"tsType":{"name":"union","raw":"'light' | 'dark' | 'system'","elements":[{"name":"literal","value":"'light'"},{"name":"literal","value":"'dark'"},{"name":"literal","value":"'system'"}]},"description":"Currently active theme mode — highlights the selected option in the Theme submenu."},"onAvatarThemeChange":{"required":true,"tsType":{"name":"signature","type":"function","raw":"(mode: ThemeMode) => void","signature":{"arguments":[{"type":{"name":"union","raw":"'light' | 'dark' | 'system'","elements":[{"name":"literal","value":"'light'"},{"name":"literal","value":"'dark'"},{"name":"literal","value":"'system'"}]},"name":"mode"}],"return":{"name":"void"}}},"description":"Called when the user picks a theme option in the Theme submenu."},"onAvatarLogout":{"required":true,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":"Called when the Logout row is clicked."},"brandLogo":{"required":true,"tsType":{"name":"union","raw":"string | React.ReactNode","elements":[{"name":"string"},{"name":"ReactReactNode","raw":"React.ReactNode"}]},"description":"Brand logo — either a URL string (renders as <img>) or a React node\n(renders as-is, e.g. an inline <svg>)."},"brandLogoAlt":{"required":false,"tsType":{"name":"string"},"description":"Alt text used when brandLogo is a URL string.","defaultValue":{"value":"'Brand logo'","computed":false}},"brandLogoStyle":{"required":false,"tsType":{"name":"ReactCSSProperties","raw":"React.CSSProperties"},"description":"Style applied to the brand logo container."},"onNotificationClick":{"required":false,"tsType":{"name":"ReactMouseEventHandler","raw":"React.MouseEventHandler<HTMLButtonElement>","elements":[{"name":"HTMLButtonElement"}]},"description":"Called when the notification bell is clicked."}},"composes":["Omit"]},"docs":{"ui-components-appbar--docs":{"id":"ui-components-appbar--docs","name":"Docs","path":"./src/stories/ui-components/AppBar.mdx","title":"UI Components/AppBar","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AppBarStories from './AppBar.stories';\nimport { AppBar } from '../../components/AppBar';\n\n<Meta of={AppBarStories} />\n\n# AppBar\n\n## Overview\n\n`AppBar` is a composed Signal header bar that combines `AppLauncher`, brand logo, notification bell, and `AvatarMenu`. It wraps MUI `AppBar` with Exotel-specific styling (`surface.elevation1` background, no shadow or border) and a fixed toolbar layout.\n\n> **UX Constitution:** See **Application Layout → App Bar** (persistent top chrome; no page-level forms in the bar).\n\n```tsx\nimport { AppBar } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Top-level application shell header across Exotel products\n- Pages that need product switching, brand identity, notifications entry point, and user menu in one bar\n\n**When not to use**\n\n- In-page section headers → use `PageHeader`\n- Side navigation panels → use `Navigation` or `Drawer`\n- Dialog or drawer headers → use `Dialog` / `StructuredDialog` or `Drawer` title areas\n- Standalone product launcher without full header → use `AppLauncher` directly\n\n## Content guidelines\n\n### Brand logo\n\n| `brandLogo` type | Rule |\n|------------------|------|\n| URL string | Always set meaningful `brandLogoAlt` (e.g. `'Exotel'`) |\n| React node (SVG) | Include `aria-label` on the SVG or wrapper for screen readers |\n| Dimensions | Default URL logo renders at 96×24; override with `brandLogoStyle` if needed |\n\n### Notification and user areas\n\n- Notification bell has a fixed `aria-label=\"Notifications\"` — host implements panel/drawer content in `onNotificationClick`.\n- User display name and menu content come from `avatarMenuProps.avatarName` and `menuGroups` — see **AvatarMenu** content guidelines.\n\n## Anatomy\n\n```\nAppBar                           ← Signal composed wrapper\n├── Toolbar\n│   ├── Left section\n│   │   ├── AppLauncher          ← via appLauncherProps\n│   │   └── brandLogo            ← URL string or React node\n│   └── Right section\n│       ├── IconButton (bell)    ← onNotificationClick\n│       └── AvatarMenu           ← via avatarMenuProps\n```\n\n`AppBar` does not accept arbitrary toolbar children. Layout is fixed; host supplies data via `appLauncherProps` and `avatarMenuProps`.\n\n## Props\n\n`AppBarProps` extends MUI `AppBarProps` (minus `ref`) with required composed slots.\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `appLauncherProps` | `AppLauncherProps` | — (required) | Props forwarded to `AppLauncher` | Provide `type`, `products`, and optional `iconName` |\n| `avatarMenuProps` | `AvatarMenuProps` | — (required) | Props forwarded to `AvatarMenu` | Provide user name, menu groups, theme controls, logout |\n| `brandLogo` | `string \\| ReactNode` | — (required) | Brand mark — URL renders `<img>`, node renders as-is | Use URL for production logos; React node for inline SVG |\n| `brandLogoAlt` | `string` | `'Brand logo'` | Alt text when `brandLogo` is a URL string | Set to brand name (e.g. `'Exotel'`) |\n| `brandLogoStyle` | `CSSProperties` | — | Style on logo `<img>` container | Override default `96×24` dimensions when needed |\n| `onNotificationClick` | `MouseEventHandler` | — | Notification bell click handler | Host owns notification panel/drawer behavior |\n\n### Inherited MUI props\n\n`position` defaults to `'static'` in the implementation. Additional MUI `AppBarProps` pass through via `{...rest}`.\n\n<ArgTypes of={AppBar} />\n\n## Variants\n\n`AppBar` has no `variant` prop. Visual differences come from `appLauncherProps.type`:\n\n| Layout | `appLauncherProps.type` | Story |\n|--------|-------------------------|-------|\n| Flat product list | `'default'` | `DefaultLayout`, `WithLogoNode` |\n| Sectioned product list | `'sectioned'` | `SectionedLayout`, `WithLogoUrl` |\n\nBrand logo presentation:\n\n| Style | `brandLogo` type | Story |\n|-------|------------------|-------|\n| Image URL | `string` | `WithLogoUrl`, `DefaultLayout`, `SectionedLayout` |\n| Inline SVG / React node | `ReactNode` | `WithLogoNode` |\n\n## States\n\n| State | Notes |\n|-------|-------|\n| Default | Static bar with elevation surface background |\n| Notification click | Host handles via `onNotificationClick` — no built-in panel |\n| App launcher open | Managed internally by `AppLauncher` |\n| Avatar menu open | Managed internally by `AvatarMenu` |\n\n## Behavior\n\n- `position` is set to `'static'` in the implementation (not `fixed` or `sticky`).\n- Left section: `AppLauncher` + brand logo with `flexGrow: 1`.\n- Right section: notification `IconButton` (`aria-label=\"Notifications\"`) + `AvatarMenu`.\n- Logo URL renders at `96×24` via `Box` `component=\"img\"`.\n- `AppLauncher` and `AvatarMenu` are host-data-driven; `AppBar` does not fetch products or user data.\n\n## Stories\n\n### Logo as URL\n\n**Story ID:** `ui-components-app-bar--logo-as-url`\n\n`brandLogo` as Exotel SVG URL; `appLauncherProps.type: 'sectioned'`.\n\n**Recommended usage:** Production header with hosted logo asset.\n\n<Canvas of={AppBarStories.WithLogoUrl} />\n\n### Logo as React node\n\n**Story ID:** `ui-components-app-bar--logo-as-react-node`\n\n`brandLogo` as inline SVG React node; `appLauncherProps.type: 'default'`.\n\n**Recommended usage:** Custom or dynamically rendered brand marks.\n\n<Canvas of={AppBarStories.WithLogoNode} />\n\n### AppLauncher — default layout\n\n**Story ID:** `ui-components-app-bar--app-launcher-default-layout`\n\nFlat product list in launcher.\n\n<Canvas of={AppBarStories.DefaultLayout} />\n\n### AppLauncher — sectioned layout\n\n**Story ID:** `ui-components-app-bar--app-launcher-sectioned-layout`\n\nSectioned product list with subheaders in launcher.\n\n<Canvas of={AppBarStories.SectionedLayout} />\n\n## Accessibility\n\n- Notification bell uses `aria-label=\"Notifications\"` on `IconButton`.\n- `AppLauncher` trigger uses `aria-label=\"Open app launcher\"`, `aria-expanded`, `aria-haspopup` (implemented in `AppLauncher`).\n- `AvatarMenu` provides its own accessibility behavior (see `AvatarMenu` docs).\n- Brand logo as URL uses `brandLogoAlt` for image alt text; inline SVG nodes need their own `aria-label` (see `WithLogoNode` story).\n- Keyboard support for launcher and avatar menu is delegated to child components.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best practices\n\n- Provide complete `appLauncherProps.products` from host/backend with `id`, `name`, `icon`, `section`, `order`, and `onProductClick`.\n- Provide `avatarMenuProps` with user display name, menu groups, theme mode, and logout handler.\n- Use URL `brandLogo` with meaningful `brandLogoAlt` in production.\n- Handle `onNotificationClick` to open the host's notification experience.\n- Use `sectioned` launcher layout when products are grouped (home, products, recommended, explore).\n- Wrap the app in `ExotelThemeProvider`.\n\n## Anti-patterns\n\n- Expecting to inject custom toolbar children — layout is fixed.\n- Omitting required `appLauncherProps` or `avatarMenuProps`.\n- Using `AppBar` for in-page section titles — use `PageHeader`.\n- Hardcoding notification UI inside `AppBar` — handle in host via `onNotificationClick`.\n- Importing MUI `AppBar` directly when the composed Exotel header is needed.\n\n## Guidance for AI Agents\n\n**Read UX Constitution first** (Application Layout → App Bar).\n\n### When to choose `AppBar`\n\n- Full application top header with product switcher, logo, notifications, and user menu\n- Exotel product shell consistent with Storybook examples\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Page title and actions only | `PageHeader` |\n| Side navigation | `Navigation`, `NavigationDrawer`, or `Drawer` |\n| Product switcher only | `AppLauncher` |\n| User menu only | `AvatarMenu` |\n| Modal header | `Dialog` / `StructuredDialog` |\n\n### Prop selection guidance\n\n| Use case | Recommended setup |\n|----------|-------------------|\n| Production Exotel header | URL `brandLogo` + `type: 'sectioned'` + full `products` list |\n| Simpler product list | `type: 'default'` |\n| Custom logo rendering | `brandLogo` as React node with `aria-label` |\n\n### Preferred composition pattern\n\n```tsx\n<AppBar\n  brandLogo=\"https://example.com/logo.svg\"\n  brandLogoAlt=\"Exotel\"\n  appLauncherProps={{\n    type: 'sectioned',\n    products: products, // host-owned Product[]\n  }}\n  avatarMenuProps={{\n    avatarName: 'Anjali Srivastava',\n    menuGroups: menuGroups,\n    footerInfo: footerInfo,\n    selectedTheme: 'system',\n    onThemeChange: handleThemeChange,\n    onLogout: handleLogout,\n  }}\n  onNotificationClick={() => openNotifications()}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| URL logo + sectioned launcher | `WithLogoUrl` |\n| Inline SVG logo | `WithLogoNode` |\n| Default launcher layout | `DefaultLayout` |\n| Sectioned launcher layout | `SectionedLayout` |\n\n### Common mistakes to avoid\n\n- Inventing toolbar slot props — only `appLauncherProps`, `avatarMenuProps`, `brandLogo`, and `onNotificationClick` are supported.\n- Omitting `onProductClick` on each `Product` in `appLauncherProps.products`.\n- Using `position=\"fixed\"` without testing layout impact — implementation defaults to `static`.\n- Forgetting `brandLogoAlt` when using a URL logo.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `AppLauncher` | Left-side product switcher (required via props) |\n| `AvatarMenu` | Right-side user menu (required via props) |\n| `IconButton` | Notification bell trigger |\n| `Icon` | Bell icon (`bell-ringing`) |\n| `PageHeader` | In-page title/actions alternative |\n| `Navigation` | Side nav alternative/complement |\n| `Drawer` | Off-canvas panels |\n"}}},"ui-components-applauncher":{"id":"ui-components-applauncher","name":"AppLauncher","path":"./src/stories/ui-components/AppLauncher.stories.tsx","stories":[{"id":"ui-components-applauncher--default-mode","name":"Default Mode","snippet":"const DefaultMode = () => <AppLauncher type=\"default\" products={DEFAULT_PRODUCTS} />;"},{"id":"ui-components-applauncher--sectioned-mode","name":"Sectioned Mode","snippet":"const SectionedMode = () => <AppLauncher type=\"sectioned\" products={DEFAULT_PRODUCTS} />;"}],"import":"import { AppLauncher, Icon } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"AppLauncher","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/AppLauncher/AppLauncher.tsx","actualName":"AppLauncher","exportName":"AppLauncher","props":{"type":{"required":true,"tsType":{"name":"union","raw":"'default' | 'sectioned'","elements":[{"name":"literal","value":"'default'"},{"name":"literal","value":"'sectioned'"}]},"description":"Layout: flat list (default) or sectioned with subheaders."},"products":{"required":true,"tsType":{"name":"Array","elements":[{"name":"Product"}],"raw":"Product[]"},"description":"Product list from host. Order/section/icon/trial fully owned by host."},"iconName":{"required":false,"tsType":{"name":"unknown"},"description":"Icon name for the launcher trigger button. Passed from parent.","defaultValue":{"value":"'squares-four'","computed":false}}}},"docs":{"ui-components-applauncher--docs":{"id":"ui-components-applauncher--docs","name":"Docs","path":"./src/stories/ui-components/AppLauncher.mdx","title":"UI Components/AppLauncher","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AppLauncherStories from './AppLauncher.stories';\nimport { AppLauncher } from '../../components/AppLauncher';\n\n<Meta of={AppLauncherStories} />\n\n# AppLauncher\n\n## Overview\n\n`AppLauncher` is a pure render-only product switcher. It renders an `IconButton` trigger and a `Popover` listing host-provided products. The host owns all product data, ordering, sections, trial flags, and click/navigation behavior.\n\n```tsx\nimport { AppLauncher, Icon } from '@exotel-npm-dev/signal-design-system';\nimport type { Product } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Multi-product Exotel shell where users switch between applications\n- Standalone product picker (also composed inside `AppBar`)\n\n**When not to use**\n\n- Full application header with logo and user menu → use `AppBar`\n- Arbitrary menu lists → use `Menu`\n- Navigation within a single product → use `Navigation` or `NavigationDrawer`\n- Rich interactive panel content → use `Popover` or `Drawer` directly\n\n## Content guidelines\n\n### Product names\n\n| Principle | Rule | Example |\n|-----------|------|---------|\n| Official names | Use product marketing names | Enterprise Contact Centre, Voicebot |\n| Concise in popover | Full names OK in launcher list | Chatbot, Campaigns, Engage |\n| Trial indicator | Use `isTrial: true`, not \"(Trial)\" in name | Shows `TRIAL` chip automatically |\n| Section keys | Meaningful grouping labels for sectioned mode | `home`, `products`, `recommended`, `explore` |\n\nSection subheaders in sectioned layout render the raw `section` string uppercased via typography — use consistent section keys from backend/config.\n\n## Anatomy\n\n```\nAppLauncher\n├── IconButton (trigger)       ← iconName, aria-expanded\n└── Popover\n    └── ProductItem rows       ← per product in products[]\n        ├── icon\n        ├── name\n        └── optional TRIAL Chip\n```\n\n`ProductItem` is exported for advanced use but is rendered internally by layout strategies.\n\n## Props\n\n### AppLauncherProps\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `type` | `'default' \\| 'sectioned'` | — (required) | Layout mode | `'default'` for flat list; `'sectioned'` for grouped subheaders |\n| `products` | `Product[]` | — (required) | Host-owned product list | Each product needs `id`, `name`, `icon`, `section`, `onProductClick` |\n| `iconName` | `IconName` | `'squares-four'` | Trigger button icon | Override only when design requires a different icon |\n\n### Product shape\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `id` | `string` | yes | Unique product identifier |\n| `name` | `string` | yes | Display name |\n| `icon` | `ReactNode` | yes | Product icon (typically `<Icon name=\"...\" />`) |\n| `section` | `string` | yes | Grouping key (`'home'`, `'products'`, `'recommended'`, `'explore'`, etc.) |\n| `onProductClick` | `() => void` | yes | Host click handler (navigation, routing) |\n| `isTrial` | `boolean` | no | Shows `TRIAL` chip via `theme.palette.appLauncher.trialChip` |\n| `iconBgColor` | `string` | no | Background behind product icon |\n| `order` | `number` | no | Sort order within section |\n\n<ArgTypes of={AppLauncher} />\n\n## Variants\n\n| `type` | Description | Story |\n|--------|-------------|-------|\n| `'default'` | Flat scrollable product list | `DefaultMode` |\n| `'sectioned'` | Products grouped with section subheaders | `SectionedMode` |\n\nPopover dimensions are fixed in implementation: width `330px`, max height `360px`.\n\n## States\n\n| State | Behavior |\n|-------|----------|\n| Closed | Only trigger `IconButton` visible |\n| Open | `Popover` anchored below-right of trigger; `aria-expanded={true}` |\n| Trial product | `ProductItem` shows `TRIAL` chip when `isTrial: true` |\n\n## Behavior\n\n- Trigger opens `Popover` on click; closes on `Escape` (keydown handler on popover).\n- `anchorOrigin`: bottom-right; `transformOrigin`: top-right.\n- No built-in routing — `onProductClick` on each `Product` is the only activation callback.\n- Layout content is computed via `layoutStrategies[type]`.\n- Default trigger icon is `squares-four`.\n\n## Stories\n\n### DefaultMode\n\n**Story ID:** `ui-components-app-launcher--default-mode`\n\nFlat list of products with default trigger icon.\n\n**Recommended usage:** Simpler product catalog without section headers.\n\n<Canvas of={AppLauncherStories.DefaultMode} />\n\n### SectionedMode\n\n**Story ID:** `ui-components-app-launcher--sectioned-mode`\n\nProducts grouped by `section` with subheaders (home, products, recommended, explore).\n\n**Recommended usage:** Multi-group product catalogs matching Exotel shell patterns.\n\n<Canvas of={AppLauncherStories.SectionedMode} />\n\n## Accessibility\n\n- Trigger: `aria-label=\"Open app launcher\"`, `aria-expanded`, `aria-haspopup=\"true\"`.\n- `ProductItem`: `role=\"button\"`, `tabIndex={0}`, `aria-label={product.name}`; Enter and Space activate.\n- Escape closes the popover.\n- Focus-visible outline on trigger (`primary.main`, 2px).\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best practices\n\n- Provide `onProductClick` on every `Product` for host-controlled navigation.\n- Use `section` and `order` consistently for sectioned layout.\n- Pass `<Icon name=\"...\" size=\"md\" />` for product icons (as in stories).\n- Set `isTrial: true` only for trial products; styling uses theme `appLauncher.trialChip`.\n- Use `type: 'sectioned'` when products span multiple categories.\n- Compose inside `AppBar` for full application header.\n\n## Anti-patterns\n\n- Expecting built-in routing or URL handling — host must implement `onProductClick`.\n- Empty `products` array — renders an empty popover.\n- Using `AppLauncher` for arbitrary action menus — use `Menu`.\n- Inventing layout types beyond `'default'` and `'sectioned'`.\n- Omitting `section` on products when using sectioned layout.\n\n## Guidance for AI Agents\n\n### When to choose `AppLauncher`\n\n- Product/application switcher in Exotel multi-product shell\n- Host has a product list with icons, names, and click handlers\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Full header with logo, notifications, user menu | `AppBar` |\n| In-app navigation links | `Navigation` / `NavigationDrawer` |\n| Contextual action list | `Menu` |\n| User account/settings menu | `AvatarMenu` |\n| Generic anchored panel | `Popover` |\n\n### Prop selection guidance\n\n| Use case | Recommended props |\n|----------|-------------------|\n| Standard Exotel shell | `type: 'sectioned'`, full `products` with sections |\n| Simple product list | `type: 'default'` |\n| Trial products | `isTrial: true` on relevant `Product` entries |\n\n### Preferred composition pattern\n\n```tsx\nconst products: Product[] = [\n  {\n    id: 'ecc',\n    name: 'Enterprise Contact Centre',\n    icon: <Icon name=\"headset\" size=\"md\" />,\n    section: 'products',\n    order: 0,\n    onProductClick: () => navigate('/ecc'),\n  },\n  {\n    id: 'voicebot',\n    name: 'Voicebot',\n    icon: <Icon name=\"phone\" size=\"md\" />,\n    section: 'products',\n    isTrial: true,\n    order: 1,\n    onProductClick: () => navigate('/voicebot'),\n  },\n];\n\n<AppLauncher type=\"sectioned\" products={products} />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Flat product list | `DefaultMode` |\n| Sectioned product list | `SectionedMode` |\n\n### Common mistakes to avoid\n\n- Inventing an `onProductClick` at the `AppLauncher` level — it lives on each `Product`.\n- Omitting `icon` ReactNode on products.\n- Using invalid `IconName` values for `iconName` — must be from `Icon` registry.\n- Assuming `AppLauncher` includes brand logo or user menu — use `AppBar` for that.\n\n### Composition guidance\n\n- Inside `AppBar`: pass via `appLauncherProps={{ type, products, iconName }}`.\n- Product icons should use Signal `Icon` component at `size=\"md\"`.\n- Group products with meaningful `section` strings for sectioned mode.\n- Do not nest `AppLauncher` inside another `Popover`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `AppBar` | Composes `AppLauncher` in application header |\n| `ProductItem` | Presentational row (internal/exported) |\n| `Popover` | Container for product list |\n| `IconButton` | Launcher trigger |\n| `Icon` | Trigger and product icons |\n| `Chip` | `TRIAL` badge on trial products |\n| `AvatarMenu` | User menu (sibling in `AppBar`) |\n| `Navigation` | In-product nav alternative |\n"}}},"ui-components-appliedfilters":{"id":"ui-components-appliedfilters","name":"AppliedFilters","path":"./src/stories/ui-components/AppliedFilters.stories.tsx","stories":[{"id":"ui-components-appliedfilters--basic","name":"Basic","snippet":"const Basic = () => {\n    const [filters, setFilters] = useState<AppliedFilter[]>([\n      {\n        id: 'campaign',\n        label: 'Campaign',\n        value: 'mohit_omni_camp',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'campaign'));\n        },\n      },\n      {\n        id: 'queue',\n        label: 'Queue',\n        value: 'chat_Q1',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'queue'));\n        },\n      },\n      {\n        id: 'channel',\n        label: 'Channel',\n        value: 'Voice',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'channel'));\n        },\n      },\n      {\n        id: 'status',\n        label: 'Status',\n        value: 'Active',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'status'));\n        },\n      },\n      {\n        id: 'agent',\n        label: 'Agent',\n        value: 'John Doe',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'agent'));\n        },\n      },\n      {\n        id: 'date-range',\n        label: 'Date Range',\n        value: 'Jan 20, 2026 - Jan 23, 2026',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'date-range'));\n        },\n      },\n    ]);\n\n    return (\n        <Box>\n            <AppliedFilters maxVisible={4} show filters={filters} onClearAll={() => setFilters([])} />\n            <Box sx={{ p: 2, textAlign: 'center', color: 'text.secondary' }}>\n                {filters.length === 0\n                  ? 'All filters cleared'\n                  : 'Content area below filters'}\n            </Box>\n        </Box>\n    );\n};","description":"Basic usage with a few filters"},{"id":"ui-components-appliedfilters--with-disposition","name":"With Disposition","snippet":"const WithDisposition = () => {\n    const [filters, setFilters] = useState<AppliedFilter[]>([\n      {\n        id: 'campaign',\n        label: 'Campaign',\n        value: 'mohit_omni_camp',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'campaign'));\n        },\n      },\n      {\n        id: 'queue',\n        label: 'Queue',\n        value: 'chat_Q1',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'queue'));\n        },\n      },\n      {\n        id: 'channel',\n        label: 'Channel',\n        value: 'Voice',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'channel'));\n        },\n      },\n      {\n        id: 'disposition',\n        label: 'Disposition',\n        value: 'failed.call.auto.dispose',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'disposition'));\n        },\n      },\n    ]);\n\n    return (\n        <Box>\n            <AppliedFilters maxVisible={4} show filters={filters} onClearAll={() => setFilters([])} />\n            <Box sx={{ p: 2, textAlign: 'center', color: 'text.secondary' }}>\n                {filters.length === 0\n                  ? 'All filters cleared'\n                  : 'Closed Interactions table content would appear here'}\n            </Box>\n        </Box>\n    );\n};","description":"Matching the reference image with disposition filter"},{"id":"ui-components-appliedfilters--with-overflow","name":"With Overflow","snippet":"const WithOverflow = () => {\n    const [filters, setFilters] = useState<AppliedFilter[]>([\n      {\n        id: 'campaign',\n        label: 'Campaign',\n        value: 'mohit_omni_camp',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'campaign'));\n        },\n      },\n      {\n        id: 'queue',\n        label: 'Queue',\n        value: 'chat_Q1',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'queue'));\n        },\n      },\n      {\n        id: 'channel',\n        label: 'Channel',\n        value: 'Voice',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'channel'));\n        },\n      },\n      {\n        id: 'disposition',\n        label: 'Disposition',\n        value: 'failed.call.auto.dispose',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'disposition'));\n        },\n      },\n      {\n        id: 'status',\n        label: 'Status',\n        value: 'Active',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'status'));\n        },\n      },\n      {\n        id: 'priority',\n        label: 'Priority',\n        value: 'High',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'priority'));\n        },\n      },\n    ]);\n\n    return (\n        <Box>\n            <AppliedFilters show filters={filters} onClearAll={() => setFilters([])} maxVisible={3} />\n            <Box sx={{ p: 2, textAlign: 'center', color: 'text.secondary' }}>\n                {filters.length === 0\n                  ? 'All filters cleared'\n                  : 'Hover over \"+X More\" to see all filters'}\n            </Box>\n        </Box>\n    );\n};","description":"With overflow - shows \"+X More\" chip and popup"},{"id":"ui-components-appliedfilters--with-multi-value-filters","name":"With Multi Value Filters","snippet":"const WithMultiValueFilters = () => {\n    const [filters, setFilters] = useState<AppliedFilter[]>([\n      {\n        id: 'campaign',\n        label: 'Campaign',\n        value: 'mohit_omni_camp',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'campaign'));\n        },\n      },\n      {\n        id: 'disposition',\n        label: 'Disposition',\n        value: ['Callback', 'schedule.callback', 'Open'],\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'disposition'));\n        },\n      },\n      {\n        id: 'status',\n        label: 'Status',\n        value: ['Active', 'Pending', 'In Progress'],\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'status'));\n        },\n      },\n    ]);\n\n    return (\n        <Box>\n            <AppliedFilters maxVisible={4} show filters={filters} onClearAll={() => setFilters([])} />\n            <Box sx={{ p: 2, textAlign: 'center', color: 'text.secondary' }}>\n                {filters.length === 0\n                  ? 'All filters cleared'\n                  : 'Multi-value filters show as \"First Value +2\" format'}\n            </Box>\n        </Box>\n    );\n};","description":"With multi-value filters"},{"id":"ui-components-appliedfilters--many-filters","name":"Many Filters","snippet":"const ManyFilters = () => {\n    const [filters, setFilters] = useState<AppliedFilter[]>([\n      {\n        id: 'date',\n        label: 'Date',\n        value: 'Jan 21 - Jan 27',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'date'));\n        },\n      },\n      {\n        id: 'campaign',\n        label: 'Campaign',\n        value: 'mohit_omni_camp',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'campaign'));\n        },\n      },\n      {\n        id: 'queue',\n        label: 'Queue',\n        value: 'chat_Q1',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'queue'));\n        },\n      },\n      {\n        id: 'channel',\n        label: 'Channel',\n        value: 'Voice',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'channel'));\n        },\n      },\n      {\n        id: 'disposition',\n        label: 'Disposition',\n        value: ['Callback', 'schedule.callback'],\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'disposition'));\n        },\n      },\n      {\n        id: 'status',\n        label: 'Status',\n        value: 'Active',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'status'));\n        },\n      },\n      {\n        id: 'priority',\n        label: 'Priority',\n        value: 'High',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'priority'));\n        },\n      },\n      {\n        id: 'agent',\n        label: 'Agent',\n        value: 'John Doe',\n        onRemove: () => {\n          setFilters((prev) => prev.filter((f) => f.id !== 'agent'));\n        },\n      },\n    ]);\n\n    return (\n        <Box>\n            <AppliedFilters maxVisible={4} show filters={filters} onClearAll={() => setFilters([])} />\n            <Box sx={{ p: 2, textAlign: 'center', color: 'text.secondary' }}>\n                {filters.length === 0\n                  ? 'All filters cleared'\n                  : `${filters.length} filters applied - hover \"+X More\" to see all`}\n            </Box>\n        </Box>\n    );\n};","description":"Many filters with overflow"},{"id":"ui-components-appliedfilters--empty-state","name":"Empty State","snippet":"const EmptyState = () => {\n    return (\n        <Box>\n            <AppliedFilters maxVisible={4} show filters={[]} onClearAll={() => {}} />\n            <Box sx={{ p: 2, textAlign: 'center', color: 'text.secondary' }}>No filters applied - component is hidden\n                        </Box>\n        </Box>\n    );\n};","description":"Empty state - no filters"},{"id":"ui-components-appliedfilters--interactive","name":"Interactive","snippet":"const Interactive = () => {\n    const allPossibleFilters: AppliedFilter[] = [\n      {\n        id: 'campaign',\n        label: 'Campaign',\n        value: 'mohit_omni_camp',\n        onRemove: () => {},\n      },\n      {\n        id: 'queue',\n        label: 'Queue',\n        value: 'chat_Q1',\n        onRemove: () => {},\n      },\n      {\n        id: 'channel',\n        label: 'Channel',\n        value: 'Voice',\n        onRemove: () => {},\n      },\n      {\n        id: 'disposition',\n        label: 'Disposition',\n        value: 'failed.call.auto.dispose',\n        onRemove: () => {},\n      },\n      {\n        id: 'status',\n        label: 'Status',\n        value: 'Active',\n        onRemove: () => {},\n      },\n    ];\n\n    const [activeFilters, setActiveFilters] = useState<string[]>([\n      'campaign',\n      'queue',\n      'channel',\n    ]);\n\n    const filters = allPossibleFilters\n      .filter((f) => activeFilters.includes(f.id))\n      .map((f) => ({\n        ...f,\n        onRemove: () => {\n          setActiveFilters((prev) => prev.filter((id) => id !== f.id));\n        },\n      }));\n\n    const availableFilters = allPossibleFilters.filter(\n      (f) => !activeFilters.includes(f.id)\n    );\n\n    return (\n        <Box>\n            <Box sx={{ p: 2, display: 'flex', gap: 1, flexWrap: 'wrap', mb: 2 }}>\n                <Box sx={{ width: '100%', mb: 1 }}>\n                    <strong>Click to add filters:</strong>\n                </Box>\n                {availableFilters.map((filter) => (\n                  <button\n                    key={filter.id}\n                    onClick={() => {\n                      setActiveFilters((prev) => [...prev, filter.id]);\n                    }}\n                    style={{\n                      padding: '8px 16px',\n                      border: '1px solid #ddd',\n                      borderRadius: '4px',\n                      background: 'white',\n                      cursor: 'pointer',\n                    }}\n                  >\n                    Add {filter.label}\n                  </button>\n                ))}\n            </Box>\n            <AppliedFilters\n                maxVisible={3}\n                show\n                filters={filters}\n                onClearAll={() => setActiveFilters([])} />\n            <Box sx={{ p: 2, textAlign: 'center', color: 'text.secondary' }}>\n                {filters.length === 0\n                  ? 'No filters applied - add some above!'\n                  : `${filters.length} filter(s) applied`}\n            </Box>\n        </Box>\n    );\n};","description":"Interactive example with add/remove"}],"import":"import { AppliedFilters } from \"@exotel-npm-dev/signal-design-system\";\nimport { Box } from \"@mui/material\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"AppliedFilters","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/AppliedFilters/AppliedFilters.tsx","actualName":"AppliedFilters","exportName":"AppliedFilters","props":{"filters":{"required":true,"tsType":{"name":"Array","elements":[{"name":"AppliedFilter"}],"raw":"AppliedFilter[]"},"description":"Array of applied filters"},"onClearAll":{"required":true,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":"Callback when \"Clear All\" is clicked"},"onRemove":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(filterId: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"filterId"}],"return":{"name":"void"}}},"description":"Callback when an individual filter is removed (receives filterId)\nIf not provided, will use the onRemove callback from each filter object"},"maxVisible":{"required":false,"tsType":{"name":"number"},"description":"Maximum number of filters to show before truncating","defaultValue":{"value":"4","computed":false}},"show":{"required":false,"tsType":{"name":"boolean"},"description":"Whether to show the component at all","defaultValue":{"value":"true","computed":false}}}},"docs":{"ui-components-appliedfilters--docs":{"id":"ui-components-appliedfilters--docs","name":"Docs","path":"./src/stories/ui-components/AppliedFilters.mdx","title":"UI Components/AppliedFilters","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AppliedFiltersStories from './AppliedFilters.stories';\nimport { AppliedFilters } from '../../components/AppliedFilters';\n\n<Meta of={AppliedFiltersStories} />\n\n# AppliedFilters\n\n## Overview\n\n`AppliedFilters` displays active filter selections as removable `Chip` components with a \"Clear All\" action and overflow handling. When filters exceed `maxVisible`, a `+X More` chip reveals all filters in a hover `Popover`.\n\n```tsx\nimport { AppliedFilters, type AppliedFilter } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Data tables and list views showing currently applied search/filter criteria\n- Filter bars above `DataGrid` or report content (pairs with `showAppliedFilters` on `DataGrid`)\n- Any UI where users need to see, remove individual filters, or clear all at once\n\n**When not to use**\n\n- Filter input controls themselves → use toolbar filters, `Select`, `MultiSelect`, or `Autocomplete`\n- Single filter badge on an icon → use `Badge` or `Chip` alone\n- Inline status messages → use `Alert`\n- Navigation chips → use `Chip` with `onClick`\n\n## Anatomy\n\n```\nAppliedFilters\n├── Typography (\"Applied Filters\")\n├── Chip[] (visible filters)     ← label: value, onDelete\n├── Chip (\"+X More\")             ← when overflow; opens Popover on hover/click\n│   └── Popover\n│       └── filter rows + remove buttons\n└── Button (\"Clear All\")         ← variant outlined, color error\n```\n\n## Props\n\n### AppliedFiltersProps\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `filters` | `AppliedFilter[]` | — (required) | Active filters to display | Empty array hides component |\n| `onClearAll` | `() => void` | — (required) | Clears all filters | Wire to host filter state reset |\n| `onRemove` | `(filterId: string) => void` | — | Removes filter by ID | Alternative to per-filter `onRemove` |\n| `maxVisible` | `number` | `4` | Max chips before overflow | Tune for layout width (`3` in overflow stories) |\n| `show` | `boolean` | `true` | Whether to render | Set `false` to force hide |\n\n### AppliedFilter shape\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `id` | `string` | yes | Unique filter identifier |\n| `label` | `string` | yes | Filter category (e.g. `\"Campaign\"`, `\"Status\"`) |\n| `value` | `string \\| string[]` | yes | Display value(s) |\n| `onRemove` | `() => void` | no | Per-filter remove callback (used when `onRemove` prop not set) |\n\n<ArgTypes of={AppliedFilters} />\n\n## Variants\n\nNo `variant` prop. Visual elements:\n\n| Element | Component | Style |\n|---------|-----------|-------|\n| Filter chips | `Chip` | `size=\"small\"`, default variant, `onDelete` |\n| Overflow chip | `Chip` | `variant=\"outlined\"`, `+X More` label |\n| Clear action | `Button` | `variant=\"outlined\"`, `size=\"small\"`, `color=\"error\"` |\n\n## States\n\n| State | Condition | Behavior |\n|-------|-----------|----------|\n| Hidden | `show={false}` or `filters.length === 0` | Returns `null` |\n| Normal | filters ≤ `maxVisible` | All chips visible |\n| Overflow | filters > `maxVisible` | First N chips + `+X More` chip |\n| Popover open | Hover/click on `+X More` | Shows all filters with full values |\n| Multi-value | `value` is `string[]` | Displays `\"First +N\"` on chip; full list in popover |\n\n## Behavior\n\n- Chip label format: `` `${label}: ${displayValue}` ``.\n- Multi-value format: first value + `+{count}` (e.g. `\"Callback +2\"`).\n- Popover shows full comma-separated values for multi-value filters.\n- Remove: `onRemove(filterId)` if provided at component level; else `filter.onRemove()`.\n- Overflow popover opens on chip hover or click; stays open while hovering popover.\n- Popover row remove buttons call `filter.onRemove` directly — prefer component-level `onRemove` for consistent state updates.\n- Component renders nothing when no filters are applied (`EmptyState`).\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-applied-filters--basic`\n\nSix filters with `maxVisible: 4` — demonstrates default overflow.\n\n**Recommended usage:** Standard filter bar above tables with Campaign, Queue, Channel, and related ECC filters.\n\n<Canvas of={AppliedFiltersStories.Basic} />\n\n### WithDisposition\n\n**Story ID:** `ui-components-applied-filters--with-disposition`\n\nCampaign, Queue, Channel, and Disposition filters — matches reference table pattern.\n\n**Recommended usage:** Closed Interactions and similar report tables with disposition filtering.\n\n<Canvas of={AppliedFiltersStories.WithDisposition} />\n\n### WithOverflow\n\n**Story ID:** `ui-components-applied-filters--with-overflow`\n\n`maxVisible: 3` with six filters — hover `+X More` to see popup.\n\n<Canvas of={AppliedFiltersStories.WithOverflow} />\n\n### WithMultiValueFilters\n\n**Story ID:** `ui-components-applied-filters--with-multi-value-filters`\n\nDisposition and Status with multiple values — truncated chip display.\n\n<Canvas of={AppliedFiltersStories.WithMultiValueFilters} />\n\n### ManyFilters\n\n**Story ID:** `ui-components-applied-filters--many-filters`\n\nEight filters with `maxVisible: 4` — `+4 More` overflow.\n\n<Canvas of={AppliedFiltersStories.ManyFilters} />\n\n### EmptyState\n\n**Story ID:** `ui-components-applied-filters--empty-state`\n\nEmpty `filters` array — component hidden.\n\n<Canvas of={AppliedFiltersStories.EmptyState} />\n\n### Interactive\n\n**Story ID:** `ui-components-applied-filters--interactive`\n\nDynamic add/remove filters via external buttons. Demonstrates host-controlled filter state with `maxVisible: 3`.\n\n**Recommended usage:** Playground pattern for wiring filter state; not a production layout.\n\n<Canvas of={AppliedFiltersStories.Interactive} />\n\n## Content guidelines\n\n### Chip label format\n\n| Part | Rule | Example |\n|------|------|---------|\n| Label | Short filter category name | `Campaign`, `Queue`, `Disposition` |\n| Value | Actual selected value(s) | `mohit_omni_camp`, `Voice` |\n| Multi-value | First value + count on chip | `Callback +2` |\n| Full values | Shown in overflow popover | `Callback, schedule.callback, Open` |\n\n### Writing principles\n\n- Use consistent label names matching filter field labels in the toolbar.\n- Values should match what users selected in filter controls.\n- Date ranges: use readable format (`Jan 20, 2026 - Jan 23, 2026`).\n- Keep labels concise — the chip already includes `label: value` prefix.\n\n### Guidance for AI-generated content\n\n- Generate `label` from the filter field name, not the raw API key (unless keys are user-facing).\n- Use realistic Exotel domain values from stories (Campaign, Queue, Channel, Disposition).\n- For multi-select filters, pass `value` as `string[]`; component handles truncation.\n- Do not invent placeholder filter labels like \"Filter 1\" — use domain-specific names.\n\n## Accessibility\n\n- Filter chips use MUI `Chip` `onDelete` — delete button is keyboard accessible.\n- Overflow popover remove buttons are native `<button>` elements with click handlers.\n- `+X More` chip is hover- and click-activated; keyboard users can click to open.\n- No explicit `aria-live` region — filter changes should be announced by surrounding context.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best practices\n\n- Place above filtered content (table, list, report).\n- Wire `onClearAll` to reset all host filter state.\n- Provide either component-level `onRemove` or per-filter `onRemove`.\n- Set `maxVisible` based on available horizontal space.\n- Pair with `DataGrid` `showAppliedFilters` for integrated table filtering.\n- Use domain-consistent labels (Campaign, Queue, Channel, Status, Disposition).\n\n## Anti-patterns\n\n- Using `AppliedFilters` as the filter input UI — it only displays applied state.\n- Rendering with empty filters and expecting a visible empty state — component hides itself.\n- Hardcoding chip labels without syncing to actual filter state.\n- Setting `maxVisible` too high on narrow layouts — causes wrapping clutter.\n- Omitting remove handlers — chips render but removal does nothing.\n\n## Guidance for AI Agents\n\n### When to choose `AppliedFilters`\n\n- Showing active filters above a data table or list\n- Letting users remove individual filters or clear all\n- Overflow handling for many simultaneous filters\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Filter input controls | `Select`, `MultiSelect`, `Autocomplete`, DataGrid toolbar filters |\n| Single removable tag | `Chip` with `onDelete` |\n| Filter count on icon | `Badge` |\n| Persistent status message | `Alert` |\n\n### Prop selection guidance\n\n| Use case | Recommended props |\n|----------|-------------------|\n| Standard table filters | `maxVisible: 4`, `onClearAll`, per-filter `onRemove` |\n| Narrow layout | `maxVisible: 3` |\n| Centralized remove logic | `onRemove={(id) => ...}` at component level |\n| Force hide | `show: false` |\n\n### Preferred composition pattern\n\n```tsx\nconst [filters, setFilters] = useState<AppliedFilter[]>([...]);\n\n<AppliedFilters\n  filters={filters}\n  maxVisible={4}\n  onClearAll={() => setFilters([])}\n  onRemove={(id) => setFilters((prev) => prev.filter((f) => f.id !== id))}\n/>\n{/* DataGrid or table below */}\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default filter bar | `Basic` |\n| Table with disposition | `WithDisposition` |\n| Overflow popover | `WithOverflow` |\n| Multi-value filters | `WithMultiValueFilters` |\n| Many filters | `ManyFilters` |\n| No filters (hidden) | `EmptyState` |\n| Dynamic add/remove | `Interactive` |\n\n### Common mistakes to avoid\n\n- Rendering when `filters` is empty — component auto-hides; do not add separate empty UI unless needed.\n- Passing raw API keys as labels without user-friendly names.\n- Forgetting to update host state in `onRemove` / `onClearAll`.\n- Using `AppliedFilters` inside filter popover — place above content.\n- Inventing a `variant` prop — does not exist.\n\n### Composition guidance\n\n- Place directly above `DataGrid` or filtered content area.\n- Filter toolbar above, `AppliedFilters` below toolbar, table below filters.\n- Use `Chip` tonal variant is not used here — default small chips with delete.\n- Combine with `DataGrid` `showAppliedFilters` prop for built-in integration.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Chip` | Individual filter display |\n| `Button` | Clear All action |\n| `Popover` | Overflow filter list |\n| `Typography` | \"Applied Filters\" label |\n| `Divider` | Popover section separator |\n| `DataGrid` | Primary consumer (`showAppliedFilters`) |\n| `Select` / `MultiSelect` | Filter input controls |\n"}}},"ui-components-autocomplete":{"id":"ui-components-autocomplete","name":"Autocomplete","path":"./src/stories/ui-components/Autocomplete.stories.tsx","stories":[{"id":"ui-components-autocomplete--basic","name":"Basic","snippet":"const Basic = () => (\n  <Autocomplete\n    label=\"Movie\"\n    options={topFilms}\n    sx={{ width: 300 }}\n  />\n);","description":"Basic autocomplete with a label"},{"id":"ui-components-autocomplete--without-label","name":"Without Label","snippet":"const WithoutLabel = () => (\n  <Autocomplete\n    options={topFilms}\n    sx={{ width: 300 }}\n  />\n);","description":"Without label"},{"id":"ui-components-autocomplete--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '300px' }}>\n    <Autocomplete label=\"Small\" options={topFilms} size=\"small\" />\n    <Autocomplete label=\"Medium\" options={topFilms} size=\"medium\" />\n    <Autocomplete label=\"Large\" options={topFilms} size=\"large\" />\n  </div>\n);","description":"Different sizes"},{"id":"ui-components-autocomplete--multiple","name":"Multiple","snippet":"const Multiple = () => {\n  const [value, setValue] = useState<typeof topFilms>([]);\n  return (\n    <Autocomplete\n      multiple\n      label=\"Movies\"\n      options={topFilms}\n      value={value}\n      onChange={(_event: any, newValue: any) => setValue(newValue)}\n      sx={{ width: 400 }}\n    />\n  );\n};","description":"Multiple selection"},{"id":"ui-components-autocomplete--free-solo","name":"Free Solo","snippet":"const FreeSolo = () => (\n  <Autocomplete\n    freeSolo\n    label=\"Type or select\"\n    options={topFilms.map((option) => option.label)}\n    sx={{ width: 300 }}\n  />\n);","description":"Free solo allows arbitrary text input"},{"id":"ui-components-autocomplete--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <Autocomplete\n    disabled\n    label=\"Disabled\"\n    options={topFilms}\n    value={topFilms[0]}\n    sx={{ width: 300 }}\n  />\n);","description":"Disabled state"},{"id":"ui-components-autocomplete--disable-clearable","name":"Disable Clearable","snippet":"const DisableClearable = () => (\n  <Autocomplete\n    disableClearable\n    label=\"Cannot clear\"\n    options={topFilms}\n    value={topFilms[0]}\n    sx={{ width: 300 }}\n  />\n);","description":"Disable clearable hides the clear button"},{"id":"ui-components-autocomplete--grouped","name":"Grouped","snippet":"const Grouped = () => (\n  <Autocomplete\n    label=\"Grouped\"\n    options={topFilms.sort((a, b) => a.label[0].localeCompare(b.label[0]))}\n    groupBy={(option: any) => option.label[0]}\n    getOptionLabel={(option: any) => option.label}\n    sx={{ width: 300 }}\n  />\n);","description":"Grouped options by first letter"},{"id":"ui-components-autocomplete--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [value, setValue] = useState<typeof topFilms[0] | null>(null);\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '300px' }}>\n      <Autocomplete\n        label=\"Controlled\"\n        value={value}\n        onChange={(_event: any, newValue: any) => setValue(newValue)}\n        options={topFilms}\n      />\n      <div style={{ fontSize: '14px', color: '#666' }}>\n        Selected: {value ? value.label : 'None'}\n      </div>\n    </div>\n  );\n};","description":"Controlled autocomplete"},{"id":"ui-components-autocomplete--interactive","name":"Interactive","snippet":"const Interactive = () => <Autocomplete\n    label=\"Interactive\"\n    options={topFilms}\n    size=\"medium\"\n    disabled={false}\n    loading={false}\n    multiple={false}\n    freeSolo={false}\n    disableClearable={false}\n    sx={{ width: 300 }} />;","description":"Interactive autocomplete with all controls"}],"import":"import { Autocomplete } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Autocomplete","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Autocomplete/Autocomplete.tsx","actualName":"Autocomplete","exportName":"Autocomplete","props":{"label":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"The label content displayed above the input."},"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the component.\n@default 'medium'"},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted.\nPass an empty string to disable the default placeholder."}}},"docs":{"ui-components-autocomplete--docs":{"id":"ui-components-autocomplete--docs","name":"Docs","path":"./src/stories/ui-components/Autocomplete.mdx","title":"UI Components/Autocomplete","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AutocompleteStories from './Autocomplete.stories';\nimport { Autocomplete } from '../../components';\n\n<Meta of={AutocompleteStories} />\n\n# Autocomplete\n\n## Overview\n\n`Autocomplete` is the Signal Design System wrapper around MUI `Autocomplete`. It applies Exotel field patterns: an external label via `FieldWrapper`, an outlined input via `EnhancedTextField`, and multi-select chips with checkboxes in the dropdown.\n\nUse `Autocomplete` when users need to search or type ahead through a list of options and pick one or more values. Do not use it for fixed dropdowns without search.\n\n```tsx\nimport { Autocomplete } from '@exotel-npm-dev/signal-design-system';\n```\n\n**Do not** import MUI `Autocomplete` from `@mui/material` — use Signal `Autocomplete` (see UX Constitution → Form Inputs).\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Typeahead selection from a searchable list of options\n- Multi-select with chip tags and checkbox options in the dropdown\n- Free-text entry when combined with `freeSolo`\n- Grouped options with `groupBy`\n\n**When not to use**\n\n- Fixed dropdown without search → use `Select` or `MultiSelect`\n- Simple text input without suggestions → use `EnhancedTextField` or `Input`\n- Tag display without search or selection → use `Chip` row or `AppliedFilters`\n- Structured filter toolbars with select-all → use `MultiSelect`\n\n## Content guidelines\n\nRules for labels, placeholders, and option text in Exotel ECC and other Signal products.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Label names the field | Use a noun or short noun phrase: \"Movie\", \"Agent\", \"Disposition\" |\n| Options are scannable | Keep option labels concise; use `groupBy` for long lists |\n| Placeholder hints action | \"Select items\", \"Type or select\" — not instructional paragraphs |\n| Sentence case | Match theme default — not Title Case Every Word |\n| Specific over generic | \"Campaign name\" not \"Name\" when context is ambiguous |\n\n**Voice:** Labels describe what is being chosen. Placeholders describe the empty state. Option text matches what appears in reports and filters.\n\n### Label and option patterns\n\n| Context | Label | Option / placeholder pattern | Signal reference |\n|---------|-------|------------------------------|------------------|\n| Single entity pick | Movie, Agent, Queue | Object name from data | `Basic` story |\n| Multi pick | Movies, Dispositions | Comma-separated in field; chips in dropdown | `Multiple` story |\n| Free text allowed | Type or select | String options or `freeSolo` labels | `FreeSolo` story |\n| Grouped list | Grouped | First-letter or category group headers | `Grouped` story |\n\n### Do and don't\n\n**Do**\n\n- \"Disposition\"\n- \"Select dispositions\" (placeholder)\n- \"The Shawshank Redemption\" (option matches data label)\n- Group headers that match business categories\n\n**Don't**\n\n- \"Please select a movie from the list below\"\n- \"Click here to search\"\n- Truncated option labels that lose meaning\n- Duplicate label and placeholder text\n\n### Multi-select display\n\n- Selected values render as `Chip` tags inside the input (multiple mode).\n- Dropdown stays open on select (`disableCloseOnSelect` is enforced when `multiple`).\n- Checkbox in each option reflects `selected` state.\n\n## Anatomy\n\n```\nFieldWrapper (external label)\n└── MuiAutocomplete\n    ├── EnhancedTextField (renderInput — outlined only)\n    ├── Options list\n    │   └── Checkbox + option label (multiple mode only)\n    └── Chip tags (multiple mode, renderValue)\n```\n\nOnly the **outlined** variant is supported (via `EnhancedTextField`). There is no `variant` prop on `Autocomplete`.\n\n## Props\n\n`AutocompleteProps` extends MUI `AutocompleteProps` (minus `ref`, `renderInput`, and `size`), plus Signal-specific props.\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `label` | `React.ReactNode` | — | Label content displayed above the input | Wired to `FieldWrapper` with `htmlFor={id}`. Omit for unlabeled fields (see `WithoutLabel`). |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'medium'` | Input size passed to `EnhancedTextField` | Use `small` in dense toolbars; `large` for prominent form fields. |\n\n### Behavior enforced by wrapper\n\n| Behavior | Condition | Notes |\n|----------|-----------|-------|\n| `disableCloseOnSelect` | `true` when `multiple` | Keeps dropdown open for multi-pick |\n| Checkbox in options | `multiple` mode only | Uses Signal `Checkbox` with `checked={selected}` |\n| `Chip` tags in input | `multiple` mode via `renderValue` | One chip per selected option |\n| Outlined input only | Always | `renderInput` uses `EnhancedTextField` |\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `options` | `readonly T[]` | `[]` | List of selectable options | Required. Use objects with `label` or strings with `getOptionLabel`. |\n| `value` | `T \\| T[] \\| null` | — | Controlled selected value(s) | Pair with `onChange` for controlled usage (`Controlled` story). |\n| `onChange` | `(event, value, reason, details?) => void` | — | Fires when selection changes | Required for controlled components. |\n| `multiple` | `boolean` | `false` | Enables multi-select | Enables chips, checkboxes, and `disableCloseOnSelect`. |\n| `freeSolo` | `boolean` | `false` | Allows values not in `options` | Use when users may type custom values. |\n| `disabled` | `boolean` | `false` | Disables interaction | See `Disabled` story. |\n| `loading` | `boolean` | `false` | Shows loading indicator | Use during async option fetch. |\n| `disableClearable` | `boolean` | `false` | Hides clear button | See `DisableClearable` story. |\n| `fullWidth` | `boolean` | `false` | Stretches to container width | Use in form layouts. |\n| `groupBy` | `(option) => string` | — | Groups options under headers | See `Grouped` story. |\n| `getOptionLabel` | `(option) => string` | — | Maps option to display string | Required for non-string options. |\n| `id` | `string` | — | Input id | Associates external label via `FieldWrapper`. |\n\nAdditional standard MUI `AutocompleteProps` pass through via spread. See the generated table below for the full API.\n\n<ArgTypes of={Autocomplete} />\n\n## Variants\n\nNo custom `variant` prop — the input is always **outlined** via `EnhancedTextField`. Do not pass `variant` to the underlying text field; it is not exposed.\n\n## Sizes\n\nThree sizes are supported via the Signal `size` prop on `EnhancedTextField`.\n\n| Size | Use for |\n|------|---------|\n| `small` | Dense toolbars, filter rows, DataGrid contexts |\n| `medium` | Default form fields |\n| `large` | Prominent single-field forms |\n\n<Canvas of={AutocompleteStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Empty | Default | Shows placeholder; no selection |\n| Selected (single) | `value` set | Clear button visible unless `disableClearable` |\n| Selected (multiple) | `multiple` + `value[]` | Chips in input; checkboxes in list |\n| Disabled | `disabled={true}` | Non-interactive; see `Disabled` story |\n| Loading | `loading={true}` | Shows MUI loading adornment |\n| Free solo | `freeSolo={true}` | Accepts typed values not in `options` |\n| No clear | `disableClearable={true}` | Hides clear button when value is set |\n\n<Canvas of={AutocompleteStories.Disabled} />\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-autocomplete--basic`\n\nCanonical single-select autocomplete with external label `\"Movie\"` and `options={topFilms}`.\n\n**Recommended usage:** Default pattern for searchable single-value fields in forms.\n\n<Canvas of={AutocompleteStories.Basic} />\n\n### WithoutLabel\n\n**Story ID:** `ui-components-autocomplete--without-label`\n\nAutocomplete without `label` prop — `FieldWrapper` omits the label row.\n\n**Recommended usage:** When a visible label is provided elsewhere (e.g. table column header, dialog title). Prefer labeled fields for accessibility.\n\n### Sizes\n\n**Story ID:** `ui-components-autocomplete--sizes`\n\nRenders `small`, `medium`, and `large` stacked vertically with the same options.\n\n**Recommended usage:** Reference for choosing input scale in a layout.\n\n### Multiple\n\n**Story ID:** `ui-components-autocomplete--multiple`\n\nControlled multi-select with `multiple`, chip tags, checkbox options, and `disableCloseOnSelect`.\n\n**Recommended usage:** Multi-value search fields where users pick from a known list (tags, categories).\n\n<Canvas of={AutocompleteStories.Multiple} />\n\n### FreeSolo\n\n**Story ID:** `ui-components-autocomplete--free-solo`\n\n`freeSolo` with string options derived from `topFilms.map((o) => o.label)`.\n\n**Recommended usage:** Fields that accept either a known option or custom typed input.\n\n<Canvas of={AutocompleteStories.FreeSolo} />\n\n### Disabled\n\n**Story ID:** `ui-components-autocomplete--disabled`\n\n`disabled` with a pre-selected value (`topFilms[0]`).\n\n**Recommended usage:** Read-only or unavailable fields that still show the current selection.\n\n### DisableClearable\n\n**Story ID:** `ui-components-autocomplete--disable-clearable`\n\n`disableClearable` with a pre-selected value — no clear (×) button.\n\n**Recommended usage:** Required selections where clearing would leave an invalid empty state.\n\n### Grouped\n\n**Story ID:** `ui-components-autocomplete--grouped`\n\nOptions sorted and grouped by first letter via `groupBy={(option) => option.label[0]}`.\n\n**Recommended usage:** Long option lists organized by category or alphabet.\n\n<Canvas of={AutocompleteStories.Grouped} />\n\n### Controlled\n\n**Story ID:** `ui-components-autocomplete--controlled`\n\nControlled single-select with `useState`, displaying selected label below the field.\n\n**Recommended usage:** Reference for wiring `value` and `onChange` in React forms.\n\n<Canvas of={AutocompleteStories.Controlled} />\n\n### Interactive\n\n**Story ID:** `ui-components-autocomplete--interactive`\n\nExposes all Storybook controls for prop exploration.\n\n**Recommended usage:** Playground only; not a production pattern.\n\n## Accessibility\n\n- Inherits MUI Autocomplete keyboard navigation: Arrow keys to move through options, Enter to select, Escape to close.\n- External `label` + `id` are wired via `FieldWrapper` (`htmlFor={id}`) for associated labeling.\n- In `multiple` mode, checkbox options reflect `selected` state visually and via MUI option semantics.\n- `disabled` removes the control from interaction; native input semantics apply via MUI.\n- For unlabeled fields (`WithoutLabel`), ensure an accessible name via `aria-label` or surrounding context.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Always provide `label` unless another visible label satisfies WCAG naming requirements.\n- Use `multiple` for multi-pick with search; use `MultiSelect` for structured filter dropdowns without typeahead.\n- Pair `value` and `onChange` for controlled forms (`Controlled` story).\n- Use `getOptionLabel` when options are objects; use `isOptionEqualToValue` when comparing by a field other than reference equality.\n- Use `groupBy` for lists longer than ~15 options.\n- Wrap the application in `ExotelThemeProvider` for consistent outlined field styling.\n- See **Content guidelines** for label and option copy rules.\n\n## Anti-patterns\n\n- Using `Autocomplete` for a fixed short list with no search → use `Select`.\n- Using `Autocomplete` for toolbar filters with select-all and groups → use `MultiSelect`.\n- Omitting `getOptionLabel` for object options — labels will not render correctly.\n- Importing `@mui/material/Autocomplete` directly — import from `@exotel-npm-dev/signal-design-system`.\n- Expecting `standard` or `filled` variants — only outlined is supported.\n- Passing custom `renderInput` — the Signal wrapper owns input rendering.\n- Uncontrolled multi-select in forms without handling `onChange` — selection state will not persist.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation. Follow these rules to produce correct Signal Design System code.\n\n### When to choose `Autocomplete`\n\n- Searchable option list with typeahead filtering\n- Multi-select from a searchable list with chip display\n- Free-text entry combined with suggestions (`freeSolo`)\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Fixed option list, no search | `Select`, `MultiSelect` |\n| Plain text without suggestions | `EnhancedTextField` |\n| Filter toolbar with select-all / groups | `MultiSelect` |\n| Selected values shown as chips elsewhere | `MultiSelect` with `showSelectedValuesInTrigger={false}` + `AppliedFilters` |\n\n### Canonical prop combinations\n\nCopy these patterns directly from stories. Do not invent alternatives.\n\n```tsx\n// Single select — story: Basic\n<Autocomplete\n  label=\"Movie\"\n  options={topFilms}\n  sx={{ width: 300 }}\n/>\n\n// Multi select — story: Multiple\n<Autocomplete\n  multiple\n  label=\"Movies\"\n  options={topFilms}\n  value={value}\n  onChange={(_e, newValue) => setValue(newValue)}\n/>\n\n// Free solo — story: FreeSolo\n<Autocomplete\n  freeSolo\n  label=\"Type or select\"\n  options={topFilms.map((o) => o.label)}\n/>\n\n// Grouped — story: Grouped\n<Autocomplete\n  label=\"Grouped\"\n  options={sortedFilms}\n  groupBy={(option) => option.label[0]}\n  getOptionLabel={(option) => option.label}\n/>\n\n// Controlled — story: Controlled\n<Autocomplete\n  label=\"Controlled\"\n  value={value}\n  onChange={(_e, newValue) => setValue(newValue)}\n  options={topFilms}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default single select | `Basic` (`ui-components-autocomplete--basic`) |\n| Multi select with chips | `Multiple` |\n| Custom typed values | `FreeSolo` |\n| Grouped long lists | `Grouped` |\n| Controlled form wiring | `Controlled` |\n| Size selection | `Sizes` |\n| Disabled appearance | `Disabled` |\n| No clear button | `DisableClearable` |\n\n### Label copy\n\nGenerate labels using **noun or short noun phrase**, sentence case.\n\n| Context | Label pattern | Example |\n|---------|---------------|---------|\n| Entity field | `{Entity}` | Movie, Agent, Queue |\n| Multi entity | `{Entities}` | Movies, Dispositions |\n| Free text field | Type or select | Type or select |\n\n### Common mistakes to avoid\n\n- Do not pass `variant` — outlined is enforced.\n- Do not override `renderInput` — use Signal `Autocomplete` as-is.\n- Do not use `Autocomplete` when `MultiSelect` filter patterns apply (select-all, bottom sheet).\n- Do not omit `onChange` in controlled multi-select forms.\n- `size` accepts `'large'` in implementation though Storybook argTypes may only list `small` and `medium`.\n\n### Composition guidance\n\n- Place `Autocomplete` inside form layouts with consistent `width` or `fullWidth`.\n- For multi-select, ensure parent state holds `T[]` and updates on every `onChange`.\n- Pair with `FormControl` only when composing with other MUI primitives; `FieldWrapper` handles labeling internally.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `EnhancedTextField` | Renders the outlined input via `renderInput` |\n| `FieldWrapper` | External label above the autocomplete |\n| `Checkbox` | Option checkboxes in `multiple` mode |\n| `Chip` | Selected value tags in `multiple` mode |\n| `Select` | Fixed single-select dropdown without search |\n| `MultiSelect` | Structured multi-select with groups and select-all |\n| `AppliedFilters` | Displays selected filter chips when trigger shows label only |\n"}}},"ui-components-avatar":{"id":"ui-components-avatar","name":"Avatar","path":"./src/stories/ui-components/Avatar.stories.tsx","stories":[{"id":"ui-components-avatar--text","name":"Text","snippet":"const Text = () => <Avatar>AB</Avatar>;","description":"Text avatar"},{"id":"ui-components-avatar--image","name":"Image","snippet":"const Image = () => <Avatar src=\"https://mui.com/static/images/avatar/1.jpg\" alt=\"Avatar\" />;","description":"Image avatar"},{"id":"ui-components-avatar--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Avatar size=\"small\">S</Avatar>\n    <Avatar size=\"medium\">M</Avatar>\n    <Avatar size=\"large\">L</Avatar>\n  </div>\n);","description":"Different sizes"},{"id":"ui-components-avatar--variants","name":"Variants","snippet":"const Variants = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Avatar variant=\"circular\">C</Avatar>\n    <Avatar variant=\"rounded\">R</Avatar>\n    <Avatar variant=\"square\">S</Avatar>\n  </div>\n);","description":"Different variants"},{"id":"ui-components-avatar--with-badge","name":"With Badge","snippet":"const WithBadge = () => (\n  <div style={{ display: 'flex', gap: '24px', alignItems: 'center' }}>\n    <Badge badgeContent={4} color=\"primary\">\n      <Avatar>AB</Avatar>\n    </Badge>\n    <Badge badgeContent={99} color=\"error\">\n      <Avatar src=\"https://mui.com/static/images/avatar/1.jpg\" alt=\"Avatar\" />\n    </Badge>\n    <Badge badgeContent={0} color=\"primary\" variant=\"dot\">\n      <Avatar>CD</Avatar>\n    </Badge>\n  </div>\n);","description":"Avatar with Badge"},{"id":"ui-components-avatar--interactive","name":"Interactive","snippet":"const Interactive = (args) => {\n  const { sizes, src, children, ...rest } = args;\n  return (\n    <Avatar {...rest} size={sizes} src={src || undefined}>\n      {src ? undefined : children}\n    </Avatar>\n  );\n};","description":"Interactive avatar with all controls"}],"import":"import { Avatar, Badge } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Avatar","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Avatar/Avatar.tsx","actualName":"Avatar","exportName":"Avatar","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-avatar--docs":{"id":"ui-components-avatar--docs","name":"Docs","path":"./src/stories/ui-components/Avatar.mdx","title":"UI Components/Avatar","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AvatarStories from './Avatar.stories';\nimport { Avatar } from '../../components/Avatar';\n\n<Meta of={AvatarStories} />\n\n# Avatar\n\n## Overview\n\n`Avatar` is the Signal Design System wrapper around MUI `Avatar`. It is a thin `forwardRef` pass-through with no custom logic. It displays user images, initials text, or icon content in a compact circular, rounded, or square frame.\n\nUse `Avatar` to represent people, accounts, or entities in lists, headers, menus, and profile triggers. Pair with `Badge` for notification counts or status dots.\n\n```tsx\nimport { Avatar } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- User profile image or initials in headers and lists\n- Entity representation in chips or menus\n- Visual identity anchor for `Badge` notification overlays\n- Image thumbnails in compact round or square frames\n\n**When not to use**\n\n- Full profile menus with dropdown → use `AvatarMenu`\n- Large hero images → use `img` or media components\n- Generic icons without identity context → use `Icon` or `IconButton`\n- Count overlays alone → use `Badge` on an appropriate host\n\n## Anatomy\n\n`Avatar` is a single visual element. Content is provided via `src` (image), `children` (text/icon), or both with fallback behavior per MUI.\n\n```\nAvatar                          ← Signal wrapper\n├── img (when src set)          ← Profile image\n└── children (fallback)         ← Initials or icon when no image\n```\n\nWith notification overlay (from `WithBadge` story):\n\n```tsx\n<Badge badgeContent={4} color=\"primary\">\n  <Avatar>AB</Avatar>\n</Badge>\n```\n\nFigma Code Connect sizes avatars via `sx={{ width, height }}` (18px, 24px, 32px, 40px) rather than a typed `size` prop on the component.\n\n## Content guidelines\n\nAvatar content is set via `children` (initials) or `src` + `alt` (image).\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Initials | 1–2 uppercase characters from name (`AB`, `S`, `M`, `L` in stories) |\n| Image alt | Descriptive `alt` when using `src` — story uses `alt=\"Avatar\"` |\n| Fallback | Provide `children` initials when image may fail to load |\n| Consistency | Use same initials logic across app (see `getInitials` in `src/functions/avatar.ts`) |\n| Contrast | Initials text vs avatar background must be **≥ 4.5:1** (WCAG AA); use `getAvatarColors(name)` and set **both** `bgcolor` and `color` |\n| Theme modes | Do not rely on `theme.palette.text.*` for initials on colored avatars — explicit `color` from `getAvatarColors` keeps contrast in **light and dark** |\n\n### Do and don't\n\n**Do**\n\n- `children=\"AB\"` for two-letter initials\n- `src` + `alt=\"Avatar\"` for profile photos\n- Wrap with `Badge` for notification counts\n\n**Don't**\n\n- Long names as `children` — truncate to initials\n- Omit `alt` on meaningful profile images\n- Use avatars for non-identity decorative graphics\n\n## Props\n\n`AvatarProps` extends MUI `AvatarProps` (minus `ref`). Documented props from stories argTypes:\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `variant` | `'circular' \\| 'rounded' \\| 'square'` | `'circular'` | Avatar shape | `circular` for profiles; `rounded`/`square` for product-specific branding. |\n| `alt` | `string` | — | Image alt text | Use with `src` for accessible image description. |\n| `src` | `string` | — | Image URL | Profile photo. When set, `children` are not shown (MUI fallback rules). |\n| `children` | `React.ReactNode` | — | Fallback content | Initials or icon when no image. `Text` story uses `'AB'`. |\n\n### Props used in stories (not in AvatarProps interface)\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `size` | `'small' \\| 'medium' \\| 'large'` | Used in `Sizes` and `Interactive` stories | Stories pass `size` to `Avatar`, but `AvatarProps` does not declare a Signal `size` prop — implementation is MUI pass-through. Figma Code Connect uses `sx={{ width, height }}` for explicit dimensions. |\n\nStory argType control is named `sizes` (maps to `size` in `Interactive` render).\n\n### Commonly used inherited props\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `sx` | `SxProps` | Style overrides | Figma template sets `width` and `height` explicitly. |\n\nNo `MuiAvatar` theme overrides in Exotel `theme.ts`.\n\n<ArgTypes of={Avatar} />\n\n## Variants\n\nThree shape variants are demonstrated in `Variants` story.\n\n| Variant | Shape | Use for |\n|---------|-------|---------|\n| `circular` | Full circle | Default user avatars |\n| `rounded` | Rounded rectangle | Softer non-circular identity |\n| `square` | Square corners | Grid tiles, product icon frames |\n\n<Canvas of={AvatarStories.Variants} />\n\n## Sizes\n\n`Sizes` story uses `size=\"small\"`, `size=\"medium\"`, `size=\"large\"` with single-letter children. Figma spec maps sizes to 18px, 24px, 32px, and 40px via `sx`.\n\n| Approach | Example |\n|----------|---------|\n| Story `size` prop | `<Avatar size=\"small\">S</Avatar>` |\n| Explicit dimensions (Figma) | `<Avatar sx={{ width: 32, height: 32 }}>AB</Avatar>` |\n\n<Canvas of={AvatarStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Text initials | `children` without `src` | `Text` story |\n| Image | `src` + `alt` | `Image` story |\n| With badge overlay | Wrap in `Badge` | `WithBadge` story |\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Image vs text | When `src` loads, image displays; `children` serve as fallback |\n| Badge pairing | `WithBadge` shows count, error count, and dot variants on avatars |\n| Ref forwarding | `forwardRef<HTMLDivElement>` |\n| Helper utilities | `getInitials` and `getAvatarColors` in `src/functions/avatar.ts` for initials and ≥ 4.5:1 bg/text pairs (not built into component) |\n\n## Stories\n\n### Text\n\n**Story ID:** `ui-components-avatar--text`\n\n`children=\"AB\"` — initials avatar.\n\n**Recommended usage:** Default text fallback when no profile image is available.\n\n<Canvas of={AvatarStories.Text} />\n\n### Image\n\n**Story ID:** `ui-components-avatar--image`\n\n`src` set to MUI sample avatar URL, `alt=\"Avatar\"`.\n\n**Recommended usage:** Profile photo display.\n\n<Canvas of={AvatarStories.Image} />\n\n### Sizes\n\n**Story ID:** `ui-components-avatar--sizes`\n\n`size=\"small\"`, `size=\"medium\"`, `size=\"large\"` with single-letter children.\n\n**Recommended usage:** Size comparison reference.\n\n<Canvas of={AvatarStories.Sizes} />\n\n### Variants\n\n**Story ID:** `ui-components-avatar--variants`\n\n`circular`, `rounded`, and `square` with single-letter children.\n\n**Recommended usage:** Shape selection reference.\n\n<Canvas of={AvatarStories.Variants} />\n\n### WithBadge\n\n**Story ID:** `ui-components-avatar--with-badge`\n\nThree avatars wrapped in `Badge`: count (`primary`), image with error count, dot variant with zero.\n\n**Recommended usage:** User notification and status patterns.\n\n<Canvas of={AvatarStories.WithBadge} />\n\n### Interactive\n\n**Story ID:** `ui-components-avatar--interactive`\n\nExposes `variant`, `sizes`, `src`, `alt`, `children` controls.\n\n**Recommended usage:** Playground only.\n\n## Accessibility\n\n- Renders a `<div>` containing either an `<img>` (when `src` is set) or text/icon content.\n- Set `alt` on image avatars for screen reader description (`Image` story).\n- Text initials in `children` are exposed as text content; ensure they meaningfully represent the user.\n- **Color contrast:** Avatar background and initials text must meet **≥ 4.5:1** contrast. Use `getAvatarColors(name)` and apply both `bgcolor` and `color` on the `Avatar` so contrast holds in **light and dark** theme (theme `text.primary` must not be the only text color on a filled avatar).\n- When wrapped in `Badge`, the avatar host should include notification context in nearby text or `aria-label` on parent interactive elements.\n- No custom ARIA logic in the Signal wrapper.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Provide `alt` for all meaningful profile images.\n- Use 1–2 character initials in `children` when image is unavailable.\n- Use `variant=\"circular\"` as the default for user identity.\n- Wrap with `Badge` for notification counts; use `variant=\"dot\"` for presence-only signals.\n- Use `sx={{ width, height }}` for precise sizing aligned with Figma (18–40px).\n- Use `getInitials` and `getAvatarColors` for consistent initials and accessible fill/text pairs in application code.\n- Spread `getAvatarColors(name)` on `Avatar` `sx` (`bgcolor` + `color`); never set background without the paired text color.\n- Wrap the application in `ExotelThemeProvider`.\n\n## Anti-patterns\n\n- Full names or long strings as `children`.\n- Image avatars without `alt` text.\n- Using `Avatar` for non-identity decorative images.\n- Importing `@mui/material/Avatar` directly — use design system package.\n- Expecting `AvatarMenu` behavior from `Avatar` alone.\n- Inventing shape variants beyond `circular`, `rounded`, `square`.\n\n## Guidance for AI Agents\n\n### When to choose `Avatar`\n\n- User or entity identity (image or initials)\n- Profile trigger visual (pair with `AvatarMenu` for menus)\n- Host element for `Badge` notification overlays\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Profile menu with dropdown | `AvatarMenu` |\n| Notification on icon only | `IconButton` + `Badge` |\n| Generic icon | `Icon` |\n| Standalone count | `Badge` on appropriate host |\n\n### Canonical prop combinations\n\n```tsx\n// Initials with accessible colors — use in DataGrid cells, menus, etc.\nconst { bgcolor, color } = getAvatarColors(name);\n<Avatar sx={{ bgcolor, color, width: 24, height: 24 }}>{getInitials(name)}</Avatar>\n\n// Initials — story: Text (neutral; production identity avatars should use getAvatarColors)\n<Avatar>AB</Avatar>\n\n// Profile image — story: Image\n<Avatar src=\"https://mui.com/static/images/avatar/1.jpg\" alt=\"Avatar\" />\n\n// Figma-aligned sizing (Code Connect)\n<Avatar sx={{ width: 32, height: 32 }}>AB</Avatar>\n\n// Shapes — story: Variants\n<Avatar variant=\"circular\">C</Avatar>\n<Avatar variant=\"rounded\">R</Avatar>\n<Avatar variant=\"square\">S</Avatar>\n\n// With notification — story: WithBadge\n<Badge badgeContent={4} color=\"primary\">\n  <Avatar>AB</Avatar>\n</Badge>\n\n<Badge badgeContent={0} color=\"primary\" variant=\"dot\">\n  <Avatar>CD</Avatar>\n</Badge>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Initials avatar | `Text` (`ui-components-avatar--text`) |\n| Image avatar | `Image` |\n| Size comparison | `Sizes` |\n| Shape comparison | `Variants` |\n| Badge overlay | `WithBadge` |\n\n### Common mistakes to avoid\n\n- Omitting `alt` on `src` images.\n- Using more than 2 characters in initials.\n- Confusing `sizes` story argType name with production API — prefer `sx` dimensions for explicit sizing.\n- Generating `AvatarMenu` when only a static avatar is needed.\n\n### Composition guidance\n\n- Wrap identity avatars in `Badge` for unread counts; use `color=\"error\"` for urgent counts.\n- Use `overlap=\"circular\"` on `Badge` when anchoring to circular avatars (Figma Code Connect).\n- Apply `getInitials(name)` and `getAvatarColors(name)` from `src/functions/avatar.ts` before passing to `children` / `sx`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Badge` | Notification counts and dots on avatars |\n| `AvatarMenu` | Profile dropdown built on avatar trigger |\n| `Chip` | May include avatar leading visual (`Chip` `WithAvatar` story) |\n| `Icon` | Icon content alternative to initials |\n| `IconButton` | Alternative host for `Badge` on actions |\n"}}},"ui-components-avatarmenu":{"id":"ui-components-avatarmenu","name":"AvatarMenu","path":"./src/stories/ui-components/AvatarMenu.stories.tsx","stories":[{"id":"ui-components-avatarmenu--default","name":"Default","snippet":"const Default = () => {\n    const [selectedTheme, setSelectedTheme] = useState<ThemeMode>('system');\n\n    return (\n        <AvatarMenu\n            avatarName=\"Anjali Srivastava\"\n            menuGroups={[PRIMARY_GROUP, SECONDARY_GROUP]}\n            footerInfo={FOOTER_INFO}\n            onLogout={() => console.log('logout')}\n            selectedTheme={selectedTheme}\n            onThemeChange={(mode) => { setSelectedTheme(mode); console.log('theme changed:', mode); }} />\n    );\n};"},{"id":"ui-components-avatarmenu--light-theme-selected","name":"Light theme pre-selected","snippet":"const LightThemeSelected = () => <AvatarMenu\n    avatarName=\"Olivia Pope\"\n    menuGroups={[PRIMARY_GROUP, SECONDARY_GROUP]}\n    footerInfo={FOOTER_INFO}\n    selectedTheme=\"light\"\n    onThemeChange={(mode) => console.log('theme:', mode)}\n    onLogout={() => console.log('logout')} />;"},{"id":"ui-components-avatarmenu--three-groups","name":"Three groups","snippet":"const ThreeGroups = () => {\n    const [selectedTheme, setSelectedTheme] = useState<ThemeMode>('dark');\n\n    return (\n        <AvatarMenu\n            avatarName=\"Rudraksh Prasanth\"\n            menuGroups={[\n              {\n                id: 'g1',\n                items: [\n                  { id: 'item1', label: 'Menu Item 1', onClick: () => console.log('item1') },\n                  { id: 'item2', label: 'Menu Item 2', onClick: () => console.log('item2') },\n                  { id: 'item3', label: 'Menu Item 3', onClick: () => console.log('item3') },\n                ],\n              },\n              {\n                id: 'g2',\n                items: [\n                  { id: 'error-logs', label: 'Send Error Logs', onClick: () => console.log('error-logs') },\n                  { id: 'shortcuts', label: 'Keyboard Shortcuts', onClick: () => console.log('shortcuts') },\n                ],\n              },\n            ]}\n            footerInfo={[\n              { label: 'Last Login', value: 'Mar 23 at 11:00' },\n              { label: 'Version', value: '6.0' },\n            ]}\n            onLogout={() => console.log('logout')}\n            selectedTheme={selectedTheme}\n            onThemeChange={(mode) => { setSelectedTheme(mode); console.log('theme:', mode); }} />\n    );\n};"}],"import":"import { AvatarMenu } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"AvatarMenu","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/AvatarMenu/AvatarMenu.tsx","actualName":"AvatarMenu","exportName":"AvatarMenu","props":{"avatarName":{"required":true,"tsType":{"name":"string"},"description":"Full name used to derive initials and avatar background colour"},"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"Size of the avatar\n@default 'medium'","defaultValue":{"value":"'small'","computed":false}},"menuGroups":{"required":true,"tsType":{"name":"Array","elements":[{"name":"AvatarMenuGroup"}],"raw":"AvatarMenuGroup[]"},"description":"Grouped menu items. Each group is rendered as a block separated from the\nnext by a Divider. Groups map to the sections visible in the popup."},"footerInfo":{"required":true,"tsType":{"name":"Array","elements":[{"name":"AvatarMenuFooterInfo"}],"raw":"AvatarMenuFooterInfo[]"},"description":"Static info rows displayed beneath the Logout row.\ne.g. [{ label: 'Last Login', value: 'Jun 21 at 08:37' }, { label: 'Version', value: '6.0' }]"},"selectedTheme":{"required":true,"tsType":{"name":"union","raw":"'light' | 'dark' | 'system'","elements":[{"name":"literal","value":"'light'"},{"name":"literal","value":"'dark'"},{"name":"literal","value":"'system'"}]},"description":"Currently active theme mode — used to highlight the selected option in the submenu"},"onThemeChange":{"required":true,"tsType":{"name":"signature","type":"function","raw":"(mode: ThemeMode) => void","signature":{"arguments":[{"type":{"name":"union","raw":"'light' | 'dark' | 'system'","elements":[{"name":"literal","value":"'light'"},{"name":"literal","value":"'dark'"},{"name":"literal","value":"'system'"}]},"name":"mode"}],"return":{"name":"void"}}},"description":"Called when the user picks a theme option in the Theme submenu"},"onLogout":{"required":true,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":"Called when the constant \"Logout\" row is clicked"}}},"docs":{"ui-components-avatarmenu--docs":{"id":"ui-components-avatarmenu--docs","name":"Docs","path":"./src/stories/ui-components/AvatarMenu.mdx","title":"UI Components/AvatarMenu","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AvatarMenuStories from './AvatarMenu.stories';\nimport { AvatarMenu } from '../../components/AvatarMenu';\n\n<Meta of={AvatarMenuStories} />\n\n# AvatarMenu\n\n## Overview\n\n`AvatarMenu` is a composed user account menu for the Exotel application shell. It renders an avatar trigger with an online-status badge, a structured dropdown with a user header, host-supplied grouped menu items, built-in Theme and Logout rows, and static footer info (last login, version, etc.).\n\n```tsx\nimport { AvatarMenu } from '@exotel-npm-dev/signal-design-system';\nimport type { AvatarMenuGroup, AvatarMenuFooterInfo, ThemeMode } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling and theme switching.\n\n**When to use**\n\n- Application header user menu (composed inside `AppBar` via `avatarMenuProps`)\n- Account settings, shortcuts, theme selection, and logout in one dropdown\n- Any shell where the signed-in user needs a profile trigger with grouped actions\n\n**When not to use**\n\n- Generic action lists unrelated to the signed-in user → use `Menu`\n- Product or application switching → use `AppLauncher`\n- Navigation within a product → use `Navigation` or `NavigationDrawer`\n- Standalone avatar display without menu → use `Avatar`\n\n## Anatomy\n\n```\nAvatarMenu\n├── AvatarMenuTrigger              ← avatar + online Badge dot; keyboard/click opens menu\n└── Menu (width 230px)\n    ├── AvatarMenuHeader           ← avatar initials + full name (built-in)\n    ├── menuGroups[]               ← host-supplied; each group followed by Divider\n    ├── Theme row (built-in)       ← opens ThemeSubmenu to the left\n    ├── Logout row (built-in)      ← sign-out icon + onLogout callback\n    └── footerInfo[]               ← static caption rows (Last Login, Version, etc.)\n```\n\nTheme submenu (rendered outside the main `Menu` to avoid clipping):\n\n```\nThemeSubmenu (Popover)\n├── Light Mode\n├── Dark Mode\n└── Same as System\n```\n\nTheme and Logout rows are **not** supplied via `menuGroups` — they are built-in constants in the implementation.\n\n## Props\n\n### AvatarMenuProps\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `avatarName` | `string` | — (required) | Full display name | Drives initials and accessible avatar colors via `getInitials` / `getAvatarColors` (≥ 4.5:1 in light and dark) |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'small'` | Avatar trigger size | Maps to 32px / 40px / 48px via `avatarSizeMap`. `AppBar` uses default `small`. |\n| `menuGroups` | `AvatarMenuGroup[]` | — (required) | Grouped menu items | Each group is separated by a `Divider`. Do not include Theme or Logout here. |\n| `footerInfo` | `AvatarMenuFooterInfo[]` | — (required) | Static footer rows | e.g. Last Login, Version. Rendered as `{label} : {value}` caption text. |\n| `selectedTheme` | `ThemeMode` | — (required) | Active theme mode | `'light' \\| 'dark' \\| 'system'` — highlights selection in Theme submenu |\n| `onThemeChange` | `(mode: ThemeMode) => void` | — (required) | Theme selection handler | Wire to `useThemeMode()` or host theme state |\n| `onLogout` | `() => void` | — (required) | Logout handler | Called when built-in Logout row is clicked |\n\n### AvatarMenuGroup\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `id` | `string` | yes | Unique group identifier |\n| `items` | `AvatarMenuItem[]` | yes | Menu items in this group |\n\n### AvatarMenuItem\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `id` | `string` | yes | Unique item identifier |\n| `label` | `string` | yes | Display label |\n| `icon` | `IconName` | no | Optional Phosphor icon on the left |\n| `disabled` | `boolean` | no | Disables the menu item |\n| `onClick` | `() => void` | yes | Click handler (menu closes before callback) |\n\n### AvatarMenuFooterInfo\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `label` | `string` | yes | Footer row label (e.g. `Last Login`) |\n| `value` | `string` | yes | Footer row value (e.g. `Jun 21 at 08:37`) |\n\n<ArgTypes of={AvatarMenu} />\n\n## Variants\n\n`AvatarMenu` has no `variant` prop. Visual differences come from configuration:\n\n| Configuration | Effect | Story |\n|---------------|--------|-------|\n| Default groups (2) | Primary + secondary item groups | `Default` |\n| Light theme selected | `selectedTheme: 'light'` highlights Light Mode in submenu | `LightThemeSelected` |\n| Three groups | Additional menu group before Theme row | `ThreeGroups` |\n| Avatar size | `size=\"small\" \\| \"medium\" \\| \"large\"` | Controlled via prop (default in stories) |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Closed | Default | Avatar trigger visible; `aria-expanded={false}` |\n| Menu open | Click or Enter/Space on trigger | Main menu anchored bottom-right of trigger |\n| Theme submenu open | Click Theme row | `Popover` opens to the left; Theme row gets `action.selected` background |\n| Disabled item | `disabled: true` on `AvatarMenuItem` | MUI `MenuItem` disabled semantics |\n| Theme selected | `selectedTheme` prop | Matching option highlighted in Theme submenu |\n\n## Behavior\n\n- Trigger opens menu on click; Enter and Space on trigger also open (`AvatarMenuTrigger`).\n- Menu closes when an item is clicked, when backdrop is dismissed, or on Escape (MUI `Menu` default).\n- Each `menuGroups` entry renders `AvatarMenuGroupItems` followed by a `Divider`.\n- **Theme row** is constant — opens `ThemeSubmenu` anchored to the left of the Theme row.\n- **Logout row** is constant — calls `onLogout()` after closing the menu; includes `sign-out` icon.\n- `footerInfo` renders below Logout as `Typography variant=\"caption\"` rows.\n- Avatar initials and color are derived from `avatarName` automatically.\n- Online badge dot is always shown on the trigger (`Badge variant=\"dot\"`).\n- Theme submenu is rendered **outside** the main `Menu` paper to prevent clipping.\n\n## Stories\n\n### Default\n\n**Story ID:** `ui-components-avatar-menu--default`\n\nTwo menu groups (primary + secondary), `selectedTheme: 'system'`, interactive theme state in render function.\n\n**Recommended usage:** Standard Exotel user menu in `AppBar` with account actions and system theme default.\n\n<Canvas of={AvatarMenuStories.Default} />\n\n### LightThemeSelected\n\n**Story ID:** `ui-components-avatar-menu--light-theme-pre-selected`\n\n`selectedTheme: 'light'` with user `Olivia Pope`. Light Mode option is pre-highlighted in Theme submenu.\n\n**Recommended usage:** When the host already knows the user prefers light mode.\n\n<Canvas of={AvatarMenuStories.LightThemeSelected} />\n\n### ThreeGroups\n\n**Story ID:** `ui-components-avatar-menu--three-groups`\n\nThree item groups with `selectedTheme: 'dark'` and alternate footer values.\n\n**Recommended usage:** Products needing more than two custom menu sections before Theme/Logout.\n\n<Canvas of={AvatarMenuStories.ThreeGroups} />\n\n## Content guidelines\n\n### Menu item labels\n\n| Principle | Rule |\n|-----------|------|\n| Action-first | Describe what happens: \"Send Error Logs\", not \"Error logs menu\" |\n| Concise | 1–3 words where possible |\n| Sentence case | Match Signal typography defaults |\n| Domain-specific | Use product terms agents recognize (Keyboard Shortcuts, not \"Shortcuts menu\") |\n\n### Footer info rows\n\n| Label | Example value | Notes |\n|-------|---------------|-------|\n| Last Login | `Jun 21 at 08:37` | Human-readable timestamp |\n| Version | `6.0` | App or build version string |\n\nDo not use footer rows for interactive actions — they are static caption text only.\n\n### Built-in rows (do not duplicate in menuGroups)\n\n- **Theme** — opens theme submenu\n- **Logout** — triggers `onLogout`\n\n## Accessibility\n\n- Trigger: `role=\"button\"`, `tabIndex={0}`, `aria-label=\"Open user menu\"`, `aria-haspopup=\"true\"`, `aria-expanded`.\n- Keyboard: Enter and Space open the menu from the trigger.\n- Menu items use MUI `MenuItem` — standard roving focus and arrow-key navigation within the menu.\n- Theme submenu options use `role=\"button\"` with click activation; consider adding keyboard support in host if extending.\n- Disabled items use native MUI disabled semantics.\n- Avatar accessible name comes from `avatarName` in the header; trigger relies on `aria-label`.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best practices\n\n- Pass complete `menuGroups`, `footerInfo`, `selectedTheme`, `onThemeChange`, and `onLogout` from the host.\n- Wire `onThemeChange` to `useThemeMode()` or equivalent app theme state.\n- Use meaningful `id` values on groups and items for stable keys.\n- Provide optional `icon` on items when icons aid recognition (e.g. settings, help).\n- Compose inside `AppBar` via `avatarMenuProps` for the standard shell pattern.\n- Keep footer info to non-interactive metadata (login time, version).\n- Wrap the app in `ExotelThemeProvider` so Theme submenu changes apply correctly.\n\n## Anti-patterns\n\n- Adding Theme or Logout items to `menuGroups` — they are built-in and will duplicate.\n- Using `AvatarMenu` for non-user action lists — use `Menu` instead.\n- Omitting `onLogout` or `onThemeChange` — both are required props.\n- Empty `menuGroups` — renders only header, Theme, Logout, and footer (valid but unusual).\n- Hardcoding theme state without syncing `selectedTheme` to actual app mode.\n- Importing raw MUI `Menu` for the user account dropdown when `AvatarMenu` matches the spec.\n\n## Guidance for AI Agents\n\n### When to choose `AvatarMenu`\n\n- Signed-in user profile menu in the application header\n- Needs theme switching (light/dark/system), logout, and grouped account actions\n- Composed as part of `AppBar`\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Full app header (logo, launcher, notifications, user menu) | `AppBar` |\n| Product switching | `AppLauncher` |\n| Generic contextual menu | `Menu` |\n| Avatar display only | `Avatar` |\n| In-product side navigation | `Navigation` |\n\n### Canonical prop combinations\n\n```tsx\n// Standard AppBar integration — story: Default\n<AppBar\n  brandLogo={logoUrl}\n  brandLogoAlt=\"Exotel\"\n  appLauncherProps={{ type: 'sectioned', products }}\n  avatarMenuProps={{\n    avatarName: 'Anjali Srivastava',\n    menuGroups: [\n      {\n        id: 'primary',\n        items: [\n          { id: 'profile', label: 'My Profile', onClick: () => navigate('/profile') },\n          { id: 'settings', label: 'Settings', icon: 'gear', onClick: () => navigate('/settings') },\n        ],\n      },\n      {\n        id: 'secondary',\n        items: [\n          { id: 'error-logs', label: 'Send Error Logs', onClick: sendLogs },\n          { id: 'shortcuts', label: 'Keyboard Shortcuts', onClick: openShortcuts },\n        ],\n      },\n    ],\n    footerInfo: [\n      { label: 'Last Login', value: 'Jun 21 at 08:37' },\n      { label: 'Version', value: '6.0' },\n    ],\n    selectedTheme: 'system',\n    onThemeChange: (mode) => setThemeMode(mode),\n    onLogout: () => signOut(),\n  }}\n  onNotificationClick={openNotifications}\n/>\n\n// Standalone — story: Default\n<AvatarMenu\n  avatarName=\"Anjali Srivastava\"\n  menuGroups={menuGroups}\n  footerInfo={footerInfo}\n  selectedTheme=\"system\"\n  onThemeChange={(mode) => setThemeMode(mode)}\n  onLogout={() => signOut()}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default user menu | `Default` (`ui-components-avatar-menu--default`) |\n| Light theme pre-selected | `LightThemeSelected` |\n| Multiple menu groups | `ThreeGroups` |\n\n### Common mistakes to avoid\n\n- Do not add Theme or Logout to `menuGroups`.\n- Do not omit required callbacks (`onThemeChange`, `onLogout`).\n- Do not use invalid `IconName` values for item icons.\n- Do not assume `size` defaults to `medium` — implementation default is `'small'`.\n- Sync `selectedTheme` with actual app theme state after `onThemeChange`.\n\n### Composition guidance\n\n- In `AppBar`, pass all avatar props via `avatarMenuProps`.\n- Place destructive or infrequent actions in a secondary group below primary account actions.\n- Theme selection should update both local state and `ExotelThemeProvider` mode.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `AppBar` | Primary consumer; composes `AvatarMenu` via `avatarMenuProps` |\n| `Avatar` | Used in trigger and header for initials display |\n| `Badge` | Online-status dot on trigger |\n| `Menu` | Main dropdown container |\n| `Popover` | Theme submenu container |\n| `Icon` | Logout icon and optional item icons |\n| `Divider` | Separates menu groups |\n| `ThemeProvider` | `ExotelThemeProvider` / `useThemeMode` for theme switching |\n| `AppLauncher` | Sibling in `AppBar` (product switcher, not user menu) |\n"}}},"ui-components-badge":{"id":"ui-components-badge","name":"Badge","path":"./src/stories/ui-components/Badge.stories.tsx","stories":[{"id":"ui-components-badge--with-icon-button","name":"With Icon Button","snippet":"const WithIconButton = () => <Badge badgeContent={4} color=\"primary\">\n    <IconButton>\n        <Icon name=\"mail\" />\n    </IconButton>\n</Badge>;","description":"Badge with IconButton"},{"id":"ui-components-badge--with-avatar","name":"With Avatar","snippet":"const WithAvatar = () => <Badge badgeContent={4} color=\"error\">\n    <Avatar>AB</Avatar>\n</Badge>;","description":"Badge with Avatar"},{"id":"ui-components-badge--with-button","name":"With Button","snippet":"const WithButton = () => <Badge badgeContent={99} color=\"primary\">\n    <Button variant=\"contained\">Messages</Button>\n</Badge>;","description":"Badge with Button"},{"id":"ui-components-badge--dot","name":"Dot","snippet":"const Dot = () => <Badge variant=\"dot\" color=\"error\">\n    <IconButton>\n        <Icon name=\"bell\" />\n    </IconButton>\n</Badge>;","description":"Dot variant"},{"id":"ui-components-badge--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Badge badgeContent={4} color=\"default\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={4} color=\"primary\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={4} color=\"secondary\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={4} color=\"error\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={4} color=\"success\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={4} color=\"warning\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={4} color=\"info\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n  </div>\n);","description":"Different colors"},{"id":"ui-components-badge--tonal-colors","name":"Tonal Colors","snippet":"const TonalColors = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center', flexWrap: 'wrap' }}>\n    <Badge badgeContent={1} variant=\"tonal\" color=\"default\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={1} variant=\"tonal\" color=\"primary\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={1} variant=\"tonal\" color=\"secondary\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={1} variant=\"tonal\" color=\"error\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={1} variant=\"tonal\" color=\"warning\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={1} variant=\"tonal\" color=\"info\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={1} variant=\"tonal\" color=\"success\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n  </div>\n);","description":"Tonal variant — light tint background with hue-matched label (Signal Design System / Figma)."},{"id":"ui-components-badge--max-count","name":"Max Count","snippet":"const MaxCount = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Badge badgeContent={99} color=\"primary\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n    <Badge badgeContent={150} max={99} color=\"primary\">\n      <IconButton><Icon name=\"mail\" /></IconButton>\n    </Badge>\n  </div>\n);","description":"Max count"},{"id":"ui-components-badge--interactive","name":"Interactive","snippet":"const Interactive = () => <Badge\n    badgeContent={4}\n    color=\"primary\"\n    variant=\"standard\"\n    max={99}\n    showZero={false}\n    invisible={false}>\n    <IconButton>\n        <Icon name=\"mail\" />\n    </IconButton>\n</Badge>;","description":"Interactive badge with all controls"}],"import":"import { Avatar, Badge, Button, Icon, IconButton } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Badge","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Badge/Badge.tsx","actualName":"Badge","exportName":"Badge","props":{"variant":{"required":false,"tsType":{"name":"union","raw":"'standard' | 'dot' | 'tonal'","elements":[{"name":"literal","value":"'standard'"},{"name":"literal","value":"'dot'"},{"name":"literal","value":"'tonal'"}]},"description":"MUI `standard` and `dot`, plus Exotel `tonal` (alpha-tinted surface + hue-matched label text).","defaultValue":{"value":"'standard'","computed":false}},"color":{"defaultValue":{"value":"'default'","computed":false},"required":false}},"composes":["Omit"]},"docs":{"ui-components-badge--docs":{"id":"ui-components-badge--docs","name":"Docs","path":"./src/stories/ui-components/Badge.mdx","title":"UI Components/Badge","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as BadgeStories from './Badge.stories';\nimport { Badge } from '../../components/Badge';\n\n<Meta of={BadgeStories} />\n\n# Badge\n\n## Overview\n\n`Badge` is the Signal Design System wrapper around MUI `Badge`. It applies Exotel theme defaults and adds a custom `tonal` variant: light tint background with saturated hue-matched label text, per the Figma Badge spec.\n\nUse `Badge` to overlay a small count or status indicator on a child element — typically an `IconButton`, `Avatar`, or `Button`. The badge anchors to the child; it is not a standalone label.\n\n```tsx\nimport { Badge } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Notification counts on icons, avatars, or buttons\n- Unread message or alert counts\n- A small status dot (`variant=\"dot\"`) when a numeric count is unnecessary\n- Tonal badges for softer emphasis matching `Chip` tonal styling\n\n**When not to use**\n\n- Standalone inline labels or tags → use `Chip`\n- Persistent status messages or banners → use `Alert`\n- Toggle on/off state → use `Switch` or `Checkbox`\n- Text-only metadata without a host element → use `Chip` or `Typography`\n\n## Anatomy\n\n`Badge` is a wrapper component. It requires exactly one child element to anchor against.\n\n```\nBadge                         ← Signal wrapper (positions overlay)\n└── child (single element)    ← IconButton, Avatar, Button, etc.\n    └── badge overlay         ← Rendered by MUI (.MuiBadge-badge)\n```\n\nCanonical structure:\n\n```tsx\n<Badge badgeContent={4} color=\"primary\">\n  <IconButton>\n    <Icon name=\"mail\" />\n  </IconButton>\n</Badge>\n```\n\nThe overlay content is set via `badgeContent`. For `variant=\"dot\"`, `badgeContent` is not displayed.\n\n## Content guidelines\n\n`badgeContent` carries the visible count or short label inside the badge.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Numeric counts | Use integers for unread counts (`4`, `99`). MUI formats values above `max` as `{max}+`. |\n| Dot variant | Omit numeric content; the dot alone signals \"something new\" or \"attention needed\". |\n| Brevity | Keep text badges to 1–3 characters when not using numbers. |\n| Zero handling | By default, zero is hidden unless `showZero={true}`. |\n\n### Do and don't\n\n**Do**\n\n- `badgeContent={4}` for unread mail count\n- `badgeContent={99}` with `max={99}` for capped display (`99+`)\n- `variant=\"dot\" color=\"error\"` for alert presence without a number\n\n**Don't**\n\n- Long sentences in `badgeContent` — use `Chip` or `Alert` instead\n- Relying on badge alone for critical safety information\n- Showing `badgeContent={0}` without intentional `showZero` when zero means \"none\"\n\n## Props\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `variant` | `'standard' \\| 'dot' \\| 'tonal'` | `'standard'` | Visual style of the badge overlay | `standard` shows filled count pill. `dot` shows a small circle. `tonal` applies tinted background with hue-matched text via `data-variant=\"tonal\"`. |\n| `badgeContent` | `React.ReactNode` | — | Content rendered inside the badge | Required for `standard` and `tonal` count display. Ignored visually for `dot`. |\n| `color` | `'default' \\| 'primary' \\| 'secondary' \\| 'error' \\| 'info' \\| 'success' \\| 'warning'` | `'default'` | Semantic color of the badge | For `tonal`, drives tint and text via `palette[color].main`. For `standard`/`dot`, uses MUI semantic badge colors. |\n| `max` | `number` | `99` | Maximum count before showing `{max}+` | Use `max={99}` for notification caps. Story `MaxCount` shows `150` → `99+`. |\n| `showZero` | `boolean` | `false` | Show badge when `badgeContent` is zero | Set `true` only when zero is meaningful (e.g. explicit \"0 items\" state). |\n| `invisible` | `boolean` | `false` | Hides the badge overlay | Use to temporarily suppress the badge without unmounting the wrapper. |\n\n### Tonal variant implementation\n\nWhen `variant=\"tonal\"`:\n\n- Maps internally to MUI `variant=\"standard\"` with `color=\"default\"`.\n- Sets `data-variant=\"tonal\"` on the root.\n- Applies `tonalBadgeSx`: `fontWeight: medium`, `fontSize: 0.75rem`, `lineHeight: 20px`.\n- **Light:** solid `palette.tonal` tokens (same as `Chip` tonal).\n- **Dark:** `alpha(palette.main, 0.32)` background; text via `TONAL_TEXT_RAMP`.\n- `color=\"default\"`: text is `grey[800]` (light) or `common.white` (dark).\n\n### Commonly used inherited props\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `children` | `React.ReactElement` | Single child element to anchor the badge | Must be one focusable or visual host (`IconButton`, `Avatar`, `Button`). |\n| `anchorOrigin` | `object` | Badge position relative to child | MUI default anchors top-right. Adjust for layout needs. |\n| `overlap` | `'rectangular' \\| 'circular'` | How badge overlaps child corners | Use `circular` with round avatars (see `Avatar` `WithBadge` story). |\n| `sx` | `SxProps` | Style overrides | Merged with tonal styles when `variant=\"tonal\"`. |\n\nAdditional standard MUI `BadgeProps` pass through via prop spread. See the generated table below for the full API.\n\n<ArgTypes of={Badge} />\n\n## Variants\n\nThree variants are defined in Signal. `tonal` is Signal-specific.\n\n| Variant | Emphasis | Use for |\n|---------|----------|---------|\n| `standard` | High | Numeric counts; solid semantic fill via MUI |\n| `dot` | Medium | Presence indicator without a number |\n| `tonal` | Medium-soft | Tinted count pill aligned with `Chip` tonal styling |\n\n<Canvas of={BadgeStories.Colors} />\n\n## Colors\n\nSeven semantic colors are demonstrated in stories for `standard` variant.\n\n| Color | Use for |\n|-------|---------|\n| `default` | Neutral counts |\n| `primary` | Primary notifications |\n| `secondary` | Secondary emphasis |\n| `error` | Errors, critical alerts |\n| `success` | Positive status |\n| `warning` | Warnings |\n| `info` | Informational counts |\n\n`TonalColors` demonstrates the same palette on `variant=\"tonal\"`.\n\n<Canvas of={BadgeStories.TonalColors} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Visible (default) | `badgeContent` set, `invisible={false}` | Standard interactive appearance |\n| Hidden | `invisible={true}` | Badge overlay not shown |\n| Zero hidden | `badgeContent={0}`, `showZero={false}` | Default MUI behavior; badge not rendered |\n| Zero visible | `badgeContent={0}`, `showZero={true}` | Shown in `Avatar` `WithBadge` dot example context |\n| Capped count | `badgeContent` > `max` | Displays `{max}+` (e.g. `99+`) |\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Child anchoring | Badge positions relative to its single child element |\n| Max overflow | Values above `max` render as `{max}+` |\n| Tonal color mapping | `color` prop selects palette tint; MUI `color` is set to `default` internally for tonal |\n| Tab integration | Theme `MuiTab` overrides position badges inline (`position: static`) when used inside tabs |\n\n## Stories\n\n### WithIconButton\n\n**Story ID:** `ui-components-badge--with-icon-button`\n\n`badgeContent={4}`, `color=\"primary\"` on an `IconButton` with mail icon.\n\n**Recommended usage:** Canonical notification count on an icon action.\n\n<Canvas of={BadgeStories.WithIconButton} />\n\n### WithAvatar\n\n**Story ID:** `ui-components-badge--with-avatar`\n\n`badgeContent={4}`, `color=\"error\"` wrapping a text `Avatar`.\n\n**Recommended usage:** User presence or notification count on profile avatars.\n\n<Canvas of={BadgeStories.WithAvatar} />\n\n### WithButton\n\n**Story ID:** `ui-components-badge--with-button`\n\n`badgeContent={99}`, `color=\"primary\"` on a contained `Button` labeled \"Messages\".\n\n**Recommended usage:** Count on a labeled action when the button itself is the host.\n\n### Dot\n\n**Story ID:** `ui-components-badge--dot`\n\n`variant=\"dot\"`, `color=\"error\"` on a bell `IconButton`.\n\n**Recommended usage:** Alert presence without displaying a number.\n\n<Canvas of={BadgeStories.Dot} />\n\n### Colors\n\n**Story ID:** `ui-components-badge--colors`\n\nAll seven semantic colors on `standard` variant with `badgeContent={4}`.\n\n**Recommended usage:** Reference for standard variant color selection.\n\n### TonalColors\n\n**Story ID:** `ui-components-badge--tonal-colors`\n\nAll seven semantic colors on `variant=\"tonal\"` with `badgeContent={1}`.\n\n**Recommended usage:** Reference for tonal badge color selection; pairs with `Chip` `TonalColors`.\n\n### MaxCount\n\n**Story ID:** `ui-components-badge--max-count`\n\nCompares `badgeContent={99}` vs `badgeContent={150}` with `max={99}`.\n\n**Recommended usage:** Reference for count capping behavior.\n\n<Canvas of={BadgeStories.MaxCount} />\n\n### Interactive\n\n**Story ID:** `ui-components-badge--interactive`\n\nExposes all story argTypes controls on an `IconButton` host.\n\n**Recommended usage:** Playground only; not a production pattern.\n\n## Accessibility\n\n- Renders a wrapping `<span>` (MUI `Badge` root) around the child; the child remains the interactive element when using `IconButton` or `Button`.\n- The badge overlay is decorative for counts unless exposed separately; the host button should have an accessible name (e.g. `aria-label=\"Messages, 4 unread\"` on the `IconButton`).\n- `variant=\"dot\"` provides a visual indicator only; supplement with text or `aria-label` on the host for screen reader users.\n- `invisible={true}` hides the badge visually; ensure state changes are communicated on the host if the count is meaningful.\n- No custom ARIA logic in the Signal wrapper; standard MUI `aria-*` props pass through.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Wrap a single child element; do not pass fragments or multiple children.\n- Use `variant=\"dot\"` when presence matters more than the exact count.\n- Use `variant=\"tonal\"` for softer emphasis consistent with `Chip` tonal pills.\n- Set `max={99}` (default) for notification counts to avoid layout breakage on large numbers.\n- Pair `color=\"error\"` with genuinely urgent or error-related counts.\n- Use `IconButton` with a descriptive `aria-label` when the icon alone is not self-explanatory.\n- Wrap the application in `ExotelThemeProvider` for correct palette and tonal tokens.\n\n## Anti-patterns\n\n- Using `Badge` as a standalone label without a child host → use `Chip`.\n- Placing long text in `badgeContent` → use `Chip` or `Typography`.\n- Expecting `variant=\"tonal\"` to behave like MUI built-in — it is Signal-specific and sets `data-variant=\"tonal\"`.\n- Importing `@mui/material/Badge` directly in consumer apps — import from `@exotel-npm-dev/signal-design-system`.\n- Relying on the badge alone to convey critical information accessible only visually.\n- Nesting multiple badges on the same child without clear UX intent.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation. Follow these rules to produce correct Signal Design System code.\n\n### When to choose `Badge`\n\n- Overlaying a count or dot on an `IconButton`, `Avatar`, or `Button`\n- Notification or unread indicators anchored to another control\n- Tonal count pills matching `Chip` tonal styling\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Standalone tag or filter pill | `Chip` |\n| Inline alert or banner message | `Alert` |\n| Icon-only action without count overlay | `IconButton` |\n| User profile image or initials alone | `Avatar` |\n| Toggle selection | `Checkbox` or `Switch` |\n\n### Variant selection\n\n| Intent | Preferred props |\n|--------|-----------------|\n| Numeric count (solid) | `variant=\"standard\"` + semantic `color` |\n| Presence only | `variant=\"dot\"` + `color=\"error\"` or `primary` |\n| Soft count pill | `variant=\"tonal\"` + semantic `color` |\n\n### Canonical prop combinations\n\nCopy these patterns directly from stories. Do not invent alternatives.\n\n```tsx\n// Icon notification — story: WithIconButton\n<Badge badgeContent={4} color=\"primary\">\n  <IconButton aria-label=\"Mail, 4 unread\">\n    <Icon name=\"mail\" />\n  </IconButton>\n</Badge>\n\n// Avatar notification — story: WithAvatar\n<Badge badgeContent={4} color=\"error\">\n  <Avatar>AB</Avatar>\n</Badge>\n\n// Button with count — story: WithButton\n<Badge badgeContent={99} color=\"primary\">\n  <Button variant=\"contained\">Messages</Button>\n</Badge>\n\n// Dot indicator — story: Dot\n<Badge variant=\"dot\" color=\"error\">\n  <IconButton aria-label=\"Notifications\">\n    <Icon name=\"bell\" />\n  </IconButton>\n</Badge>\n\n// Tonal count — story: TonalColors\n<Badge badgeContent={1} variant=\"tonal\" color=\"primary\">\n  <IconButton><Icon name=\"mail\" /></IconButton>\n</Badge>\n\n// Capped count — story: MaxCount\n<Badge badgeContent={150} max={99} color=\"primary\">\n  <IconButton><Icon name=\"mail\" /></IconButton>\n</Badge>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default icon badge | `WithIconButton` (`ui-components-badge--with-icon-button`) |\n| Avatar overlay | `WithAvatar` |\n| Status dot | `Dot` |\n| Compare standard colors | `Colors` |\n| Compare tonal colors | `TonalColors` |\n| Max count behavior | `MaxCount` |\n| Prop playground | `Interactive` |\n\n### Common mistakes to avoid\n\n- Omitting the required single child element.\n- Using `variant=\"tonal\"` without importing `Badge` from the design system package.\n- Inventing badge variants beyond `standard`, `dot`, `tonal`.\n- Setting `badgeContent` on `variant=\"dot\"` expecting visible numbers.\n- Forgetting `max` when displaying large notification counts.\n- Using `Badge` for removable filter tags — use `Chip` with `onDelete`.\n\n### Composition guidance\n\n- Place `Badge` outside the host control: `<Badge><IconButton /></Badge>`, not inside the button.\n- For circular avatars, set `overlap=\"circular\"` when anchoring to avatar corners (Figma Code Connect pattern).\n- Match tonal badge `color` with related `Chip` tonal tags in the same view for visual consistency.\n- Ensure the host `IconButton` or `Button` has an accessible name that includes count context when relevant.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `IconButton` | Common host for notification badges on icons |\n| `Avatar` | Common host for user-related counts and dots |\n| `Button` | Host for labeled actions with counts |\n| `Chip` | Standalone tags; shares tonal color logic with `Badge` tonal |\n| `Icon` | Used inside `IconButton` hosts in stories |\n| `Alert` | Persistent status messages instead of overlay counts |\n"}}},"ui-components-box":{"id":"ui-components-box","name":"Box","path":"./src/stories/ui-components/Box.stories.tsx","stories":[{"id":"ui-components-box--basic","name":"Basic","snippet":"const Basic = () => (\n  <Box sx={{ width: 200, height: 100, bgcolor: 'primary.main', color: 'white', p: 2, borderRadius: 1 }}>\n    <Typography>Box Component</Typography>\n  </Box>\n);","description":"Basic box"},{"id":"ui-components-box--theme-colors","name":"Theme Colors","snippet":"const ThemeColors = () => (\n  <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n    <Box sx={{ width: 150, height: 80, bgcolor: 'primary.main', color: 'white', p: 2, borderRadius: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n      Primary\n    </Box>\n    <Box sx={{ width: 150, height: 80, bgcolor: 'secondary.main', color: 'white', p: 2, borderRadius: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n      Secondary\n    </Box>\n    <Box sx={{ width: 150, height: 80, bgcolor: 'error.main', color: 'white', p: 2, borderRadius: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n      Error\n    </Box>\n    <Box sx={{ width: 150, height: 80, bgcolor: 'success.main', color: 'white', p: 2, borderRadius: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n      Success\n    </Box>\n  </div>\n);","description":"Box with theme colors"},{"id":"ui-components-box--as-component","name":"As Component","snippet":"const AsComponent = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n    <Box component=\"section\" sx={{ p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>\n      <Typography variant=\"h6\">Box as section</Typography>\n    </Box>\n    <Box component=\"article\" sx={{ p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>\n      <Typography variant=\"h6\">Box as article</Typography>\n    </Box>\n    <Box component=\"div\" sx={{ p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>\n      <Typography variant=\"h6\">Box as div (default)</Typography>\n    </Box>\n  </div>\n);","description":"Box as different HTML elements"},{"id":"ui-components-box--flexbox","name":"Flexbox","snippet":"const Flexbox = () => (\n  <Box\n    sx={{\n      display: 'flex',\n      gap: 2,\n      p: 2,\n      bgcolor: 'grey.100',\n      borderRadius: 1,\n      minWidth: 400,\n    }}\n  >\n    <Button variant=\"contained\">Button 1</Button>\n    <Button variant=\"outlined\">Button 2</Button>\n    <Button variant=\"text\">Button 3</Button>\n  </Box>\n);","description":"Box with flexbox layout"},{"id":"ui-components-box--spacing","name":"Spacing","snippet":"const Spacing = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n    <Box sx={{ p: 1, bgcolor: 'primary.main', color: 'white', borderRadius: 1 }}>\n      Padding: 1 (8px)\n    </Box>\n    <Box sx={{ p: 2, bgcolor: 'primary.main', color: 'white', borderRadius: 1 }}>\n      Padding: 2 (16px)\n    </Box>\n    <Box sx={{ p: 3, bgcolor: 'primary.main', color: 'white', borderRadius: 1 }}>\n      Padding: 3 (24px)\n    </Box>\n  </Box>\n);","description":"Box with spacing and padding"}],"import":"import { Box, Button, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"ExotelThemeProvider","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/ThemeProvider/ThemeProvider.tsx","actualName":"ExotelThemeProvider","exportName":"ExotelThemeProvider","props":{"children":{"required":true,"tsType":{"name":"ReactNode"},"description":""},"defaultMode":{"required":false,"tsType":{"name":"union","raw":"\"light\" | \"dark\" | \"system\"","elements":[{"name":"literal","value":"\"light\""},{"name":"literal","value":"\"dark\""},{"name":"literal","value":"\"system\""}]},"description":"The initial color mode applied on first visit (before any user toggle).\n- `'light'`  — start in light mode (default)\n- `'dark'`   — start in dark mode\n- `'system'` — follow the user's OS preference\n\nAfter the user changes the mode via `useThemeMode().setMode()`,\ntheir choice is persisted and takes priority over this value.","defaultValue":{"value":"\"light\"","computed":false}},"defaultFont":{"required":false,"tsType":{"name":"union","raw":"keyof typeof FONT_OPTIONS","elements":[{"name":"literal","value":"\"noto-sans\""},{"name":"literal","value":"\"ibm-plex-sans\""}]},"description":"Initial font. Defaults to `\"noto-sans\"`.\nCan be changed at runtime via `useFont().setFont()`.","defaultValue":{"value":"\"noto-sans\"","computed":false}},"adapterLocale":{"required":false,"tsType":{"name":"string"},"description":"Locale string passed to the dayjs date adapter (e.g. \"en\", \"de\", \"ja\").\nControls formatting for all date/time picker components."},"themeOverrides":{"required":false,"tsType":{"name":"ThemeOptions"},"description":"Partial theme overrides deep-merged on top of the base Exotel theme.\nUse this to extend palette colors, add component overrides, or\nadjust typography without forking the design system theme."},"contextData":{"required":false,"tsType":{"name":"Record","elements":[{"name":"string"},{"name":"unknown"}],"raw":"Record<string, unknown>"},"description":"Arbitrary data accessible anywhere via `useSignal().data`.\nUse this to pass global app-level context (tenant info, feature flags,\npermissions, etc.) without creating additional providers.","defaultValue":{"value":"{}","computed":false}}}},"docs":{"ui-components-box--docs":{"id":"ui-components-box--docs","name":"Docs","path":"./src/stories/ui-components/Box.mdx","title":"UI Components/Box","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as BoxStories from './Box.stories';\nimport { Box } from '../../components/Box';\n\n<Meta of={BoxStories} />\n\n# Box\n\n## Overview\n\n`Box` is the Signal Design System wrapper around MUI `Box`. It is a thin `forwardRef` pass-through with no custom logic. `Box` is a generic layout and styling primitive with full access to the Exotel theme via the `sx` prop and theme-aware shorthand values.\n\nUse `Box` for layout containers, spacing wrappers, flex/grid shells, and semantic HTML elements when you need theme-integrated styling without importing raw HTML elements.\n\n```tsx\nimport { Box } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for theme token resolution in `sx` (e.g. `bgcolor: 'primary.main'`).\n\n**When to use**\n\n- Layout containers with theme-aware `sx` styling\n- Flexbox or spacing wrappers around child components\n- Rendering semantic HTML (`section`, `article`) with theme integration\n- Quick prototyping of padded or colored regions using palette tokens\n\n**When not to use**\n\n- Elevated content surfaces with defined structure → use `Card`\n- Form field layout with labels → use `FormField` or `Stack`\n- Repeated vertical/horizontal spacing between siblings → prefer `Stack` when available\n- Interactive clickable regions → use `Button`, `ListItemButton`, or appropriate interactive component\n\n## Props\n\n`BoxProps` extends MUI `BoxProps` (minus `ref`). All MUI props pass through via spread.\n\n### Props documented in stories argTypes\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `component` | `string \\| React.ElementType` | `'div'` | Root HTML element or component | Use `'section'`, `'article'`, or other semantic elements for document structure. Default is `div`. |\n\n### Props demonstrated in stories\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `sx` | `SxProps<Theme>` | Theme-aware style object | Primary styling API. Supports palette paths (`primary.main`), spacing scale (`p: 2` = 16px), flexbox, borders, and responsive breakpoints. |\n| `children` | `React.ReactNode` | Box content | Any valid React children. |\n\nAdditional standard MUI `BoxProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Box} />\n\n## Variants\n\n`Box` has no visual variants. Appearance is fully controlled via `sx`, `className`, and the `component` prop.\n\n## Sizes\n\n`Box` has no fixed sizes. Dimensions are set via `sx` (`width`, `height`, `minWidth`, `p`, `m`, etc.). The `Spacing` story demonstrates padding scale `p: 1` (8px), `p: 2` (16px), `p: 3` (24px).\n\n<Canvas of={BoxStories.Spacing} />\n\n## States\n\n`Box` is a non-interactive container by default. It has no built-in disabled, hover, or focus states unless styled via `sx` or wrapping interactive children.\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Theme `sx` resolution | Values like `bgcolor: 'primary.main'` resolve against Exotel palette |\n| Polymorphic root | `component` prop changes the rendered HTML element |\n| Ref forwarding | `forwardRef<HTMLDivElement>` — ref attaches to the root element |\n| No theme overrides | No `MuiBox` entry in `theme.ts`; inherits MUI defaults |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-box--basic`\n\nA single `Box` with `width: 200`, `height: 100`, `bgcolor: 'primary.main'`, white text, `p: 2`, `borderRadius: 1`, and `Typography` child.\n\n**Recommended usage:** Minimal themed container with padding and background.\n\n<Canvas of={BoxStories.Basic} />\n\n### ThemeColors\n\n**Story ID:** `ui-components-box--theme-colors`\n\nFour boxes using `primary.main`, `secondary.main`, `error.main`, and `success.main` backgrounds.\n\n**Recommended usage:** Reference for semantic palette paths in `sx`.\n\n<Canvas of={BoxStories.ThemeColors} />\n\n### AsComponent\n\n**Story ID:** `ui-components-box--as-component`\n\n`Box` rendered as `section`, `article`, and `div` with grey background and padding.\n\n**Recommended usage:** Semantic HTML wrappers with theme styling.\n\n<Canvas of={BoxStories.AsComponent} />\n\n### Flexbox\n\n**Story ID:** `ui-components-box--flexbox`\n\n`Box` with `display: 'flex'`, `gap: 2`, padding, and three `Button` children.\n\n**Recommended usage:** Horizontal action row or toolbar layout shell.\n\n<Canvas of={BoxStories.Flexbox} />\n\n### Spacing\n\n**Story ID:** `ui-components-box--spacing`\n\nThree stacked boxes with `p: 1`, `p: 2`, and `p: 3` demonstrating the spacing scale.\n\n**Recommended usage:** Reference for padding token usage.\n\n## Accessibility\n\n- Renders a `<div>` by default (or the element specified by `component`).\n- `Box` itself is not interactive; it does not add ARIA roles or keyboard behavior.\n- Use semantic `component` values (`section`, `article`, `nav`, `main`) to improve document structure for assistive technology.\n- When `Box` wraps interactive children (`Button`, links), ensure focus order and labels belong to those children.\n- No custom ARIA logic in the Signal wrapper.\n\n## Best Practices\n\n- Prefer theme palette paths in `sx` (`primary.main`, `grey.100`) over hardcoded hex values.\n- Use the spacing scale (`p`, `m`, `gap`) for consistent rhythm with the design system.\n- Set `component` to semantic HTML elements when the container carries document meaning.\n- Use `display: 'flex'` with `gap` for simple horizontal or vertical layouts.\n- Wrap the application in `ExotelThemeProvider` so `sx` palette tokens resolve correctly.\n\n## Anti-patterns\n\n- Using `Box` with inline `style={{}}` for theme colors when `sx` palette paths are available.\n- Replacing `Card` with a manually styled `Box` when elevation or outlined surfaces are needed.\n- Adding `onClick` to `Box` without `role=\"button\"`, keyboard handlers, and focus styles — use `Button` or `ListItemButton` instead.\n- Importing `@mui/material/Box` directly in consumer apps — import from `@exotel-npm-dev/signal-design-system`.\n- Deeply nesting many `Box` wrappers without semantic structure.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation. Follow these rules to produce correct Signal Design System code.\n\n### When to choose `Box`\n\n- Generic layout wrapper with theme-aware styling\n- Flex row/column shells around other Signal components\n- Semantic HTML container (`section`, `article`) with `sx` styling\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Elevated content panel | `Card` |\n| Vertical/horizontal stack with gap | `Stack` (if available) |\n| Clickable action | `Button` |\n| Form field with label | `FormField` |\n| Text content | `Typography` |\n\n### Canonical prop combinations\n\nCopy these patterns directly from stories.\n\n```tsx\n// Themed container — story: Basic\n<Box sx={{ width: 200, height: 100, bgcolor: 'primary.main', color: 'white', p: 2, borderRadius: 1 }}>\n  <Typography>Box Component</Typography>\n</Box>\n\n// Semantic section — story: AsComponent\n<Box component=\"section\" sx={{ p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>\n  <Typography variant=\"h6\">Box as section</Typography>\n</Box>\n\n// Flex row — story: Flexbox\n<Box sx={{ display: 'flex', gap: 2, p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>\n  <Button variant=\"contained\">Button 1</Button>\n  <Button variant=\"outlined\">Button 2</Button>\n</Box>\n\n// Padding scale — story: Spacing\n<Box sx={{ p: 2, bgcolor: 'primary.main', color: 'white', borderRadius: 1 }}>\n  Padding: 2 (16px)\n</Box>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Basic themed box | `Basic` (`ui-components-box--basic`) |\n| Palette backgrounds | `ThemeColors` |\n| Semantic HTML | `AsComponent` |\n| Flex layout | `Flexbox` |\n| Spacing scale | `Spacing` |\n\n### Common mistakes to avoid\n\n- Hardcoding colors instead of using palette tokens in `sx`.\n- Treating `Box` as a clickable surface without proper accessibility.\n- Inventing a `variant` or `size` prop — `Box` has neither in Signal.\n- Omitting `ExotelThemeProvider` so palette paths fail to resolve.\n\n### Composition guidance\n\n- Use `Box` as an outer layout shell; place `Typography`, `Button`, and other Signal components inside.\n- Combine `display: 'flex'`, `alignItems`, and `justifyContent` for alignment patterns shown in `ThemeColors` and `Flexbox`.\n- Prefer `borderRadius: 1` (theme shape token) for consistent corner rounding.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Card` | Structured elevated surface for grouped content |\n| `Typography` | Text content commonly placed inside `Box` |\n| `Button` | Interactive children in flex layouts |\n| `Stack` | Alternative for gap-based stacking when available |\n"}}},"ui-components-breadcrumbs":{"id":"ui-components-breadcrumbs","name":"Breadcrumbs","path":"./src/stories/ui-components/Breadcrumbs.stories.tsx","stories":[{"id":"ui-components-breadcrumbs--default","name":"Default","snippet":"const Default = () => (\n  <Breadcrumbs>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\">\n      Home\n    </Link>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\">\n      Settings\n    </Link>\n    <Typography color=\"text.primary\">General</Typography>\n  </Breadcrumbs>\n);"},{"id":"ui-components-breadcrumbs--with-icons","name":"With Icons","snippet":"const WithIcons = () => (\n  <Breadcrumbs>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\" sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n      <Icon name=\"house\" size=\"xs\" />\n      Home\n    </Link>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\" sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n      <Icon name=\"gear\" size=\"xs\" />\n      Settings\n    </Link>\n    <Typography color=\"text.primary\" sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n      <Icon name=\"user\" size=\"xs\" />\n      Profile\n    </Typography>\n  </Breadcrumbs>\n);"},{"id":"ui-components-breadcrumbs--custom-separator","name":"Custom Separator","snippet":"const CustomSeparator = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n    <Breadcrumbs separator=\"›\">\n      <Link underline=\"hover\" color=\"inherit\" href=\"#\">Home</Link>\n      <Link underline=\"hover\" color=\"inherit\" href=\"#\">Category</Link>\n      <Typography color=\"text.primary\">Item</Typography>\n    </Breadcrumbs>\n    <Breadcrumbs separator=\"-\">\n      <Link underline=\"hover\" color=\"inherit\" href=\"#\">Home</Link>\n      <Link underline=\"hover\" color=\"inherit\" href=\"#\">Category</Link>\n      <Typography color=\"text.primary\">Item</Typography>\n    </Breadcrumbs>\n    <Breadcrumbs separator={<Icon name=\"caret-right\" size=\"xs\" />}>\n      <Link underline=\"hover\" color=\"inherit\" href=\"#\">Home</Link>\n      <Link underline=\"hover\" color=\"inherit\" href=\"#\">Category</Link>\n      <Typography color=\"text.primary\">Item</Typography>\n    </Breadcrumbs>\n  </Box>\n);"},{"id":"ui-components-breadcrumbs--collapsed","name":"Collapsed","snippet":"const Collapsed = () => <Breadcrumbs maxItems={3} itemsBeforeCollapse={1} itemsAfterCollapse={1}>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\">Home</Link>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\">Dashboard</Link>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\">Settings</Link>\n    <Link underline=\"hover\" color=\"inherit\" href=\"#\">Security</Link>\n    <Typography color=\"text.primary\">Passwords</Typography>\n</Breadcrumbs>;"}],"import":"import { Box, Breadcrumbs, Icon, Link, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Breadcrumbs","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Breadcrumbs/Breadcrumbs.tsx","actualName":"Breadcrumbs","exportName":"Breadcrumbs","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-breadcrumbs--docs":{"id":"ui-components-breadcrumbs--docs","name":"Docs","path":"./src/stories/ui-components/Breadcrumbs.mdx","title":"UI Components/Breadcrumbs","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as BreadcrumbsStories from './Breadcrumbs.stories';\nimport { Breadcrumbs } from '../../components/Breadcrumbs';\n\n<Meta of={BreadcrumbsStories} />\n\n# Breadcrumbs\n\n## Overview\n\n`Breadcrumbs` wraps MUI `Breadcrumbs` for hierarchical navigation trails showing the user's current location within a page hierarchy.\n\n```tsx\nimport { Breadcrumbs, Link, Typography } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Show current location in page hierarchy\n- Multi-level navigation (Settings > Security > Passwords)\n- Help users navigate back to parent pages\n\n**When not to use**\n\n- Primary app navigation → use `Navigation`\n- Step progress → use `Stepper`\n- Flat page switching → use `Tabs`\n\n## Props\n\n<ArgTypes of={Breadcrumbs} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `separator` | `ReactNode` | `'/'` | Custom separator node between items |\n| `maxItems` | `number` | `8` | Maximum items before collapsing |\n| `itemsBeforeCollapse` | `number` | `1` | Items shown before the ellipsis |\n| `itemsAfterCollapse` | `number` | `1` | Items shown after the ellipsis |\n\n## Stories\n\n### Default\n\nBasic breadcrumb trail with Link items and a Typography current page.\n\n<Canvas of={BreadcrumbsStories.Default} />\n\n### WithIcons\n\nBreadcrumbs with Icon components alongside text labels.\n\n<Canvas of={BreadcrumbsStories.WithIcons} />\n\n### CustomSeparator\n\nVarious separator styles: `›`, `-`, and a caret Icon.\n\n<Canvas of={BreadcrumbsStories.CustomSeparator} />\n\n### Collapsed\n\nLong breadcrumb trail collapsed with ellipsis using `maxItems`.\n\n<Canvas of={BreadcrumbsStories.Collapsed} />\n\n## Guidance for AI Agents\n\nUse `Link` for navigable segments; `Typography` with `color=\"text.primary\"` for the current page (last item). Always place the current page as the final non-clickable element.\n\n```tsx\n<Breadcrumbs>\n  <Link underline=\"hover\" color=\"inherit\" href=\"#\">Home</Link>\n  <Link underline=\"hover\" color=\"inherit\" href=\"#\">Settings</Link>\n  <Typography color=\"text.primary\">General</Typography>\n</Breadcrumbs>\n```\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `Link` | Used for navigable breadcrumb segments |\n| `Typography` | Used for the current page (non-clickable) |\n| `Navigation` | Primary sidebar navigation |\n| `Icon` | Can be added inline with breadcrumb labels |\n"}}},"ui-components-button":{"id":"ui-components-button","name":"Button","path":"./src/stories/ui-components/Button.stories.tsx","stories":[{"id":"ui-components-button--primary","name":"Primary","snippet":"const Primary = () => <Button variant=\"contained\" color=\"primary\">Button</Button>;","description":"Primary button - the default variant for primary actions"},{"id":"ui-components-button--with-start-icon","name":"With Start Icon","snippet":"const WithStartIcon = () => <Button variant=\"contained\" color=\"primary\" startIconProps={{ name: 'plus' }}>Button</Button>;","description":"Button with start icon"},{"id":"ui-components-button--with-end-icon","name":"With End Icon","snippet":"const WithEndIcon = () => <Button\n    variant=\"contained\"\n    color=\"primary\"\n    endIconProps={{ name: 'arrow-right' }}>Button</Button>;","description":"Button with end icon"},{"id":"ui-components-button--with-icons","name":"With Icons","snippet":"const WithIcons = () => <Button\n    variant=\"contained\"\n    color=\"primary\"\n    startIconProps={{ name: 'check' }}\n    endIconProps={{ name: 'arrow-right' }}>Button</Button>;","description":"Button with both start and end icons"},{"id":"ui-components-button--interactive","name":"Interactive","snippet":"const Interactive = () => <Button\n    variant=\"contained\"\n    color=\"primary\"\n    size=\"medium\"\n    disabled={false}\n    fullWidth={false}\n    disableElevation={false}\n    disableRipple={false}>Button</Button>;","description":"Interactive button with all controls"},{"id":"ui-components-button--secondary","name":"Secondary","snippet":"const Secondary = () => <Button variant=\"contained\" color=\"secondary\">Button</Button>;","description":"Secondary button - for secondary actions"},{"id":"ui-components-button--outlined","name":"Outlined","snippet":"const Outlined = () => <Button variant=\"outlined\" color=\"primary\">Button</Button>;","description":"Outlined button - for less prominent actions"},{"id":"ui-components-button--text","name":"Text","snippet":"const Text = () => <Button variant=\"text\" color=\"primary\">Button</Button>;","description":"Text button - for the least prominent actions"},{"id":"ui-components-button--tonal","name":"Tonal","snippet":"const Tonal = () => <Button variant=\"tonal\" color=\"primary\">Button</Button>;","description":"Tonal button - Material 3 style with softer background"},{"id":"ui-components-button--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Button size=\"small\" variant=\"contained\">Small</Button>\n    <Button size=\"medium\" variant=\"contained\">Medium</Button>\n    <Button size=\"large\" variant=\"contained\">Large</Button>\n    <Button size=\"extraLarge\" variant=\"contained\">Extra Large</Button>\n  </div>\n);","description":"Different sizes available"},{"id":"ui-components-button--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n    <Button variant=\"contained\" color=\"primary\">Primary</Button>\n    <Button variant=\"contained\" color=\"secondary\">Secondary</Button>\n    <Button variant=\"contained\" color=\"success\">Success</Button>\n    <Button variant=\"contained\" color=\"error\">Error</Button>\n    <Button variant=\"contained\" color=\"info\">Info</Button>\n    <Button variant=\"contained\" color=\"warning\">Warning</Button>\n  </div>\n);","description":"Different colors available"},{"id":"ui-components-button--tonal-colors","name":"Tonal Colors","snippet":"const TonalColors = () => (\n  <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n    <Button variant=\"tonal\" color=\"primary\">Primary</Button>\n    <Button variant=\"tonal\" color=\"secondary\">Secondary</Button>\n    <Button variant=\"tonal\" color=\"success\">Success</Button>\n    <Button variant=\"tonal\" color=\"error\">Error</Button>\n    <Button variant=\"tonal\" color=\"info\">Info</Button>\n    <Button variant=\"tonal\" color=\"warning\">Warning</Button>\n  </div>\n);","description":"Tonal button colors - Material 3 style with softer backgrounds"},{"id":"ui-components-button--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <div style={{ display: 'flex', gap: '16px' }}>\n    <Button variant=\"contained\" disabled>Disabled</Button>\n    <Button variant=\"outlined\" disabled>Disabled</Button>\n    <Button variant=\"text\" disabled>Disabled</Button>\n    <Button variant=\"tonal\" disabled>Tonal Disabled</Button>\n  </div>\n);","description":"Disabled state"},{"id":"ui-components-button--variants","name":"Variants","snippet":"const Variants = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n    <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n      <Button variant=\"contained\" color=\"primary\">Contained</Button>\n      <Button variant=\"tonal\" color=\"primary\">Tonal</Button>\n      <Button variant=\"outlined\" color=\"primary\">Outlined</Button>\n      <Button variant=\"text\" color=\"primary\">Text</Button>\n    </div>\n  </div>\n);","description":"All variants comparison"},{"id":"ui-components-button--full-width","name":"Full Width","snippet":"const FullWidth = () => <Button variant=\"contained\" color=\"primary\" fullWidth>Full Width Button</Button>;","description":"Full width button"}],"import":"import { Button } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"description":"Button component Wraps MUI's Button component with Exotel-specific defaults and styling. Supports Exotel's custom 'tonal' variant which maps to MUI's 'contained' with special styling applied via theme overrides.","reactDocgen":{"description":"Button component\n\nWraps MUI's Button component with Exotel-specific defaults and styling.\nSupports Exotel's custom 'tonal' variant which maps to MUI's 'contained'\nwith special styling applied via theme overrides.","methods":[],"displayName":"Button","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Button/Button.tsx","actualName":"Button","exportName":"Button","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"The content of the button"},"variant":{"required":false,"tsType":{"name":"union","raw":"'text' | 'outlined' | 'contained' | 'tonal'","elements":[{"name":"literal","value":"'text'"},{"name":"literal","value":"'outlined'"},{"name":"literal","value":"'contained'"},{"name":"literal","value":"'tonal'"}]},"description":"The variant of the button\n- 'text': Text button (MUI native)\n- 'outlined': Outlined button (MUI native)\n- 'contained': Filled button (MUI native)\n- 'tonal': Material 3 tonal button (Exotel custom)"},"startIcon":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"Start Icon\n@deprecated It's deprecated by Exotel Design System. Use startIconProps instead"},"endIcon":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"End Icon\n@deprecated It's deprecated by Exotel Design System. Use endIconProps instead"},"startIconProps":{"required":false,"tsType":{"name":"IconProps"},"description":"Start Icon"},"endIconProps":{"required":false,"tsType":{"name":"IconProps"},"description":"End Icon"}},"composes":["Omit"]},"docs":{"ui-components-button--docs":{"id":"ui-components-button--docs","name":"Docs","path":"./src/stories/ui-components/Button.mdx","title":"UI Components/Button","content":"import { Meta, Canvas, Story, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\nimport { Button } from '../../components/Button';\n\n<Meta of={ButtonStories} />\n\n# Button\n\n## Overview\n\n`Button` is the Signal Design System wrapper around MUI `Button`. It applies Exotel theme defaults and adds a custom `tonal` variant and `extraLarge` size.\n\nUse `Button` for in-page actions that trigger a response—submitting a form, confirming a dialog, saving data, or opening a panel. Do not use it for navigation to another route or URL.\n\n```tsx\nimport { Button } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- A labeled action with optional icon\n- Form submission or dialog confirmation\n- Primary, secondary, or tertiary actions within a view\n\n**When not to use**\n\n- Navigation to external or internal URLs → use `Link`\n- Icon-only actions without a text label → use `IconButton`\n- List row selection or navigation → use `ListItemButton`\n- Floating page-level actions → use `Fab`\n- Toggle on/off state → use `Switch` or `Checkbox`\n\n## Content guidelines\n\nRules for writing button labels in Exotel ECC and other Signal products. Labels are set via the `children` prop.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Action-first | Describe what happens when clicked, not UI chrome (\"Save\", not \"Click to save\") |\n| Present tense | Use simple verbs: Save, Create, Add, Delete, Confirm |\n| Specific | Name the object: \"Add contact\", \"Create campaign\" — not bare \"Add\" |\n| Concise | Prefer 1–3 words; avoid full sentences in buttons |\n| Sentence case | Match theme default (`textTransform: 'none'`) — not Title Case Every Word |\n| User goal | Lead with the outcome agents care about when space allows |\n\n**Voice:** Use imperative action labels (\"Save changes\", \"Add contact\") for standard product buttons. Reserve first-person (\"I understand\", \"I agree\") only for explicit user acknowledgments or legal consent — a narrow exception, not the default.\n\n### Label patterns by action type\n\nExamples are taken from existing Signal stories and docs.\n\n| Action type | Preferred label | Signal reference | Variant / color |\n|-------------|-----------------|------------------|-----------------|\n| Primary submit | Save, Confirm | Drawer, StructuredDialog | `contained` + `primary` |\n| Primary create | Create campaign, Create configuration | PageHeader, Drawer | `contained` + `primary` |\n| Compound action | Save and Dial | StructuredDialog | `contained` + `primary` |\n| Secondary dismiss | Cancel, Back | Drawer, Dialog footers | `outlined` or `text` |\n| Destructive | Delete | StructuredDialog (`color=\"error\"`) | `contained` or `outlined` + `error` |\n| Filter / toolbar | Filter, Export | DataGrid toolbar docs | `tonal` or `outlined` |\n\n### Button pairs (dialog and drawer footers)\n\nCanonical label pairs used in Signal:\n\n```\n[Cancel]  [Save]\n[Cancel]  [Create Configuration]\n[Delete]  [Save Changes]\n```\n\n- **Dismiss** on the leading side (left in LTR): \"Cancel\"\n- **Commit** on the trailing side (right in LTR): specific verb — \"Save\", \"Create\", \"Confirm\"\n- Destructive commit uses `color=\"error\"` and names the object when irreversible (\"Delete campaign\")\n\n### Do and don't\n\n**Do**\n\n- \"Add contact\"\n- \"Create campaign\"\n- \"Save and Dial\"\n- \"Delete\"\n- \"Export\"\n\n**Don't**\n\n- \"OK\" / \"Yes\" (unless a minimal system alert)\n- \"Click here\"\n- \"Submit form\"\n- \"Add\" (without object)\n- \"Delete stuff\"\n- Title Case Every Word\n\n### Icons and labels\n\n- Icons reinforce the verb; they do not replace the label. Use `IconButton` for icon-only actions.\n- When an icon is present, keep the label short — the icon carries affordance (\"Add contact\" + `plus`).\n- Do not duplicate meaning (\"Delete\" with a trash icon is fine; \"Delete item\" with a trash icon and redundant wording is not).\n\n### Length and localization\n\n- No fixed character cap — design for label growth across ECC locales (e.g. Hindi, Tamil, German expansions).\n- Avoid width-constrained containers that truncate button text.\n- Prefer shorter base labels that stay clear when translated.\n- `fullWidth` buttons may wrap; do not apply truncation CSS to `children`.\n\n### Content anti-patterns\n\n- Generic \"Submit\" when \"Save queue settings\" is clearer.\n- Using \"OK\" for destructive confirmation.\n- Different label in docs vs UI (\"Get started\" in help text, \"Start\" on the button).\n- Passive phrasing (\"Configuration will be saved\") — buttons take active verbs.\n- Trailing periods or unnecessary punctuation in labels.\n\n## Props\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `children` | `React.ReactNode` | — | Button label or content | Sets the visible label. See **Content guidelines** for writing rules. Required for accessible naming. |\n| `variant` | `'text' \\| 'outlined' \\| 'contained' \\| 'tonal'` | `'text'` | Visual style of the button | Use `contained` for primary actions, `tonal` or `outlined` for secondary, `text` for tertiary. `tonal` maps internally to MUI `contained` with `data-variant=\"tonal\"`. |\n| `startIconProps` | `IconProps` | — | Props for the leading icon | Pass `{ name: 'plus' }` etc. Icon renders only when `name` is set. Preferred over deprecated `startIcon`. |\n| `endIconProps` | `IconProps` | — | Props for the trailing icon | Pass `{ name: 'arrow-right' }` etc. Icon renders only when `name` is set. Preferred over deprecated `endIcon`. |\n| `startIcon` | `React.ReactNode` | — | **Deprecated.** Raw start icon node | Do not use. Use `startIconProps` instead. |\n| `endIcon` | `React.ReactNode` | — | **Deprecated.** Raw end icon node | Do not use. Use `endIconProps` instead. |\n\n`IconProps` fields: `name` (required `IconName`), `size` (`'xs' \\| 'sm' \\| 'md' \\| 'lg'`, default `'md'`), `weight` (`'regular' \\| 'bold' \\| 'fill' \\| 'light'`), `color` (optional string).\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `color` | `'inherit' \\| 'primary' \\| 'secondary' \\| 'success' \\| 'error' \\| 'info' \\| 'warning'` | `'primary'` | Semantic color palette | Use `primary` for main actions, `error` for destructive, `success`/`warning`/`info` for status-driven actions. |\n| `size` | `'small' \\| 'medium' \\| 'large' \\| 'extraLarge'` | `'medium'` | Button dimensions | `extraLarge` is Signal-specific. Use `extraLarge` for prominent CTAs; `small` for dense UIs. |\n| `disabled` | `boolean` | `false` | Disables interaction | Prevents click and sets native `disabled` attribute. |\n| `fullWidth` | `boolean` | `false` | Stretches to container width | Use in form footers or mobile layouts. |\n| `disableElevation` | `boolean` | `true` (theme default) | Removes drop shadow | Theme sets `disableElevation: true` globally via `MuiButton.defaultProps`. Pass `false` to re-enable elevation. |\n| `disableRipple` | `boolean` | `false` | Disables ripple feedback | Rarely needed; MUI ripple is on by default. |\n\nAdditional standard MUI `ButtonProps` (e.g. `onClick`, `type`, `href`, `component`, `aria-*`) pass through via prop spread. See the generated table below for the full API.\n\n<ArgTypes of={Button} />\n\n## Variants\n\nFour variants exist. Emphasis decreases from `contained` to `text`.\n\n| Variant | Emphasis | Use for |\n|---------|----------|---------|\n| `contained` | Highest | Primary actions; solid filled background |\n| `tonal` | Medium-high | Softer filled actions; Material 3 style with tinted background via `data-variant=\"tonal\"` |\n| `outlined` | Medium | Secondary actions; border without fill |\n| `text` | Lowest | Tertiary or inline actions; no border or fill |\n\n<Canvas of={ButtonStories.Variants} />\n\n## Sizes\n\nFour sizes are defined in the Exotel theme. All use `textTransform: 'none'` and token-based typography.\n\n| Size | minHeight | Typography token |\n|------|-----------|------------------|\n| `small` | 24px | `label1` |\n| `medium` | 32px | `label2` (default) |\n| `large` | 40px | `label2` |\n| `extraLarge` | 44px | `label3` |\n\n`extraLarge` is a Signal extension not present in base MUI.\n\n<Canvas of={ButtonStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Enabled | Default | Interactive; responds to hover, focus, and press via MUI + theme styles |\n| Disabled | `disabled={true}` | Non-interactive; reduced opacity and `action.disabled` color on tonal |\n| Hover / Focus / Pressed | Automatic | Styled by MUI and theme overrides; no separate Signal stories |\n\n<Canvas of={ButtonStories.Disabled} />\n\n## Stories\n\n### Primary\n\n**Story ID:** `ui-components-button--primary`\n\nCanonical primary call-to-action. `variant=\"contained\"` with `color=\"primary\"`.\n\n**Recommended usage:** Single main action per view (save, submit, confirm).\n\n<Canvas of={ButtonStories.Primary} />\n\n### Secondary\n\n**Story ID:** `ui-components-button--secondary`\n\n`variant=\"contained\"` with `color=\"secondary\"`.\n\n**Recommended usage:** Secondary emphasis when a second filled button is needed alongside a primary CTA.\n\n### Outlined\n\n**Story ID:** `ui-components-button--outlined`\n\n`variant=\"outlined\"` with `color=\"primary\"`.\n\n**Recommended usage:** Medium-prominence actions such as \"Cancel\" adjacent to a primary button.\n\n### Text\n\n**Story ID:** `ui-components-button--text`\n\n`variant=\"text\"` with `color=\"primary\"`.\n\n**Recommended usage:** Low-prominence inline actions (e.g. \"Learn more\", \"Skip\").\n\n### Tonal\n\n**Story ID:** `ui-components-button--tonal`\n\n`variant=\"tonal\"` with `color=\"primary\"`.\n\n**Recommended usage:** Softer emphasis alternative to `contained` or `outlined`; filters, secondary toolbar actions.\n\n<Canvas of={ButtonStories.Tonal} />\n\n### WithStartIcon\n\n**Story ID:** `ui-components-button--with-start-icon`\n\n`startIconProps={{ name: 'plus' }}` on a contained primary button.\n\n**Recommended usage:** Create/add actions where the icon reinforces the label.\n\n<Canvas of={ButtonStories.WithStartIcon} />\n\n### WithEndIcon\n\n**Story ID:** `ui-components-button--with-end-icon`\n\n`endIconProps={{ name: 'arrow-right' }}` on a contained primary button.\n\n**Recommended usage:** Forward/continue actions (next step, proceed).\n\n### WithIcons\n\n**Story ID:** `ui-components-button--with-icons`\n\nBoth `startIconProps={{ name: 'check' }}` and `endIconProps={{ name: 'arrow-right' }}`.\n\n**Recommended usage:** Rare; only when both leading and trailing icons add meaning.\n\n### Interactive\n\n**Story ID:** `ui-components-button--interactive`\n\nExposes all controls for prop exploration in Storybook.\n\n**Recommended usage:** Playground only; not a production pattern.\n\n### Sizes\n\n**Story ID:** `ui-components-button--sizes`\n\nRenders `small`, `medium`, `large`, and `extraLarge` side by side.\n\n**Recommended usage:** Reference for choosing button scale in a layout.\n\n### Colors\n\n**Story ID:** `ui-components-button--colors`\n\nAll semantic colors on `variant=\"contained\"`: `primary`, `secondary`, `success`, `error`, `info`, `warning`.\n\n**Recommended usage:** Reference for semantic color selection on filled buttons.\n\n### TonalColors\n\n**Story ID:** `ui-components-button--tonal-colors`\n\nAll semantic colors on `variant=\"tonal\"`.\n\n**Recommended usage:** Reference for semantic color selection on tonal buttons.\n\n### Disabled\n\n**Story ID:** `ui-components-button--disabled`\n\nDisabled state across `contained`, `outlined`, `text`, and `tonal`.\n\n**Recommended usage:** Reference for disabled appearance per variant.\n\n### Variants\n\n**Story ID:** `ui-components-button--variants`\n\nSide-by-side comparison of all four variants with `color=\"primary\"`.\n\n**Recommended usage:** Variant selection reference.\n\n### FullWidth\n\n**Story ID:** `ui-components-button--full-width`\n\n`fullWidth={true}` on a contained primary button.\n\n**Recommended usage:** Form footers, dialog actions, or full-width mobile CTAs.\n\n## Accessibility\n\n- Renders a native `<button>` element by default via MUI `Button` (`forwardRef<HTMLButtonElement>`).\n- `disabled` sets the native `disabled` attribute, removing the button from the tab order and blocking activation.\n- Keyboard: activatable with Enter and Space (MUI default).\n- Focus: MUI `:focus-visible` ring is applied automatically.\n- Labels: accessible name comes from `children` text content. Icons are decorative unless separately named.\n- `textTransform: 'none'` is applied globally in the theme for readable mixed-case labels.\n- No custom ARIA logic in the Signal wrapper; standard MUI `aria-*` props pass through via `{...buttonProps}`.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Use one `variant=\"contained\" color=\"primary\"` button as the main CTA per view.\n- Use `startIconProps` / `endIconProps` with Phosphor icon `name` strings, not raw React nodes.\n- Use `tonal` for softer emphasis without a full outline.\n- Use `extraLarge` for prominent form or page-level actions.\n- Wrap the application in `ExotelThemeProvider` so theme defaults (including `disableElevation: true` and `textTransform: 'none'`) apply.\n- Pair destructive `color=\"error\"` buttons with a confirmation dialog for irreversible actions.\n- See **Content guidelines** for button label writing rules.\n\n## Anti-patterns\n\n- Using deprecated `startIcon` / `endIcon` ReactNode props instead of `startIconProps` / `endIconProps`.\n- Passing `startIconProps` without `name` — the icon will not render (implementation checks `startIconProps?.name`).\n- Using `Button` with `href` for navigation — use `Link` instead.\n- Icon-only buttons without a text label — use `IconButton`.\n- Multiple competing `contained` + `primary` buttons in the same UI state.\n- Importing `@mui/material/Button` directly in consumer apps — import from `@exotel-npm-dev/signal-design-system`.\n- Inventing `variant=\"primary\"` — the valid API is `variant=\"contained\" color=\"primary\"`.\n- Using `Button` for toggle state — use `Switch` or `Checkbox`.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation. Follow these rules to produce correct Signal Design System code.\n\n### When to choose `Button`\n\n- Triggering an in-page action (save, delete, submit, open dialog, apply filter)\n- The control has a text label, optionally with an icon\n- The action does not navigate away from the current route\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Navigate to a URL or route | `Link` |\n| Icon-only, no text label | `IconButton` |\n| List item selection or navigation | `ListItemButton` |\n| Floating page-level action | `Fab` |\n| On/off toggle | `Switch` or `Checkbox` |\n\n### Variant selection\n\n| Intent | Preferred props |\n|--------|-----------------|\n| Primary action | `variant=\"contained\" color=\"primary\"` |\n| Secondary action | `variant=\"outlined\" color=\"primary\"` or `variant=\"tonal\" color=\"primary\"` or `variant=\"contained\" color=\"secondary\"` |\n| Destructive action | `color=\"error\"` with `variant=\"contained\"` (confirm) or `variant=\"outlined\"` (dismiss-adjacent) |\n| Tertiary / inline action | `variant=\"text\" color=\"primary\"` |\n\n### Canonical prop combinations\n\nCopy these patterns directly from stories. Do not invent alternatives.\n\n```tsx\n// Primary CTA — story: Primary\n<Button variant=\"contained\" color=\"primary\">Save</Button>\n\n// Secondary filled — story: Secondary\n<Button variant=\"contained\" color=\"secondary\">Cancel</Button>\n\n// Soft secondary — story: Tonal\n<Button variant=\"tonal\" color=\"primary\">Filter</Button>\n\n// Outlined secondary — story: Outlined\n<Button variant=\"outlined\" color=\"primary\">Back</Button>\n\n// Destructive — story: Colors (error)\n<Button variant=\"contained\" color=\"error\">Delete</Button>\n\n// With icon — story: WithStartIcon, PageHeader\n<Button variant=\"outlined\" startIconProps={{ name: 'plus' }}>Add contact</Button>\n\n// Full width — story: FullWidth\n<Button variant=\"contained\" color=\"primary\" fullWidth>Continue</Button>\n\n// Large CTA — story: Sizes\n<Button variant=\"contained\" color=\"primary\" size=\"extraLarge\">Get started</Button>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default primary button | `Primary` (`ui-components-button--primary`) |\n| Icon before label | `WithStartIcon` |\n| Icon after label | `WithEndIcon` |\n| Compare all variants | `Variants` |\n| Pick a size | `Sizes` |\n| Pick a semantic color | `Colors` or `TonalColors` |\n| Disabled appearance | `Disabled` |\n| Full-width layout | `FullWidth` |\n\n### Button label copy\n\nGenerate labels using **action + object**, present tense, sentence case.\n\n| Action type | Label pattern | ECC example |\n|-------------|---------------|-------------|\n| Primary submit | `{Verb}` or `{Verb} {object}` | Save, Confirm |\n| Primary create | `Create {object}` | Create campaign, Create configuration |\n| Compound action | `{Verb} and {verb}` | Save and Dial |\n| Dismiss | Cancel, Back | Cancel |\n| Destructive | `Delete` or `Delete {object}` | Delete |\n| Toolbar | `{Verb}` or `{Verb} {object}` | Export, Filter |\n\n**Canonical ECC labels from stories:**\n\n```tsx\n<Button variant=\"contained\" color=\"primary\">Save</Button>\n<Button variant=\"contained\" color=\"primary\">Create campaign</Button>\n<Button variant=\"contained\" color=\"primary\">Save and Dial</Button>\n<Button variant=\"outlined\" color=\"primary\">Cancel</Button>\n<Button variant=\"contained\" color=\"error\">Delete</Button>\n<Button variant=\"contained\" color=\"primary\" startIconProps={{ name: 'plus' }}>Add contact</Button>\n```\n\n**Copy mistakes to avoid:**\n\n- \"OK\", \"Yes\", \"Submit\" — use a specific verb instead.\n- Bare \"Add\" — include the object (\"Add contact\").\n- Title Case labels — use sentence case.\n- Labels that differ from help text or docs references to the same control.\n\n### Common mistakes to avoid\n\n- `variant=\"primary\"` does not exist. Use `variant=\"contained\" color=\"primary\"`.\n- Do not pass raw `<Icon />` or MUI icon nodes to `startIcon`/`endIcon`. Use `startIconProps={{ name: '...' }}`.\n- Do not invent sizes beyond `small`, `medium`, `large`, `extraLarge`.\n- Do not omit `ExotelThemeProvider` in app setup.\n- Do not use `Button` when the user intent is navigation — use `Link`.\n- `tonal` is a Signal-specific variant. It is not a MUI built-in; import `Button` from the design system package.\n\n### Composition guidance\n\n- Place primary and secondary buttons in a row with the primary action on the trailing side (right in LTR layouts).\n- Limit to one `contained` + `primary` button per view or dialog.\n- For icon + label buttons, prefer `startIconProps` for additive actions (\"Add\", \"Create\") and `endIconProps` for forward actions (\"Next\", \"Continue\").\n- In forms, use `fullWidth` on mobile breakpoints for the submit button.\n- Pair `color=\"error\"` buttons with explicit confirmation for irreversible operations.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Icon` | Provides the `name`-based API used by `startIconProps` and `endIconProps` |\n| `IconButton` | Icon-only actions without a text label |\n| `Link` | Navigation to URLs or routes |\n| `ListItemButton` | Clickable list row actions |\n| `Fab` | Floating action button for page-level primary actions |\n"}}},"ui-components-card":{"id":"ui-components-card","name":"Card","path":"./src/stories/ui-components/Card.stories.tsx","stories":[{"id":"ui-components-card--basic","name":"Basic","snippet":"const Basic = () => (\n  <Card sx={{ minWidth: 275, padding: 2 }}>\n    <Typography variant=\"h6\" component=\"div\">\n      Card Title\n    </Typography>\n    <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n      This is a basic card component with some content.\n    </Typography>\n  </Card>\n);","description":"Basic card"},{"id":"ui-components-card--elevations","name":"Elevations","snippet":"const Elevations = () => (\n  <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n    {[0, 1, 2, 4, 8, 16].map((elevation) => (\n      <Card key={elevation} elevation={elevation} sx={{ padding: 2, minWidth: 200 }}>\n        <Typography variant=\"h6\">Elevation {elevation}</Typography>\n        <Typography variant=\"body2\" color=\"text.secondary\">\n          Card with elevation {elevation}\n        </Typography>\n      </Card>\n    ))}\n  </div>\n);","description":"Different elevations"},{"id":"ui-components-card--outlined","name":"Outlined","snippet":"const Outlined = () => (\n  <Card variant=\"outlined\" sx={{ minWidth: 275, padding: 2 }}>\n    <Typography variant=\"h6\" component=\"div\">\n      Outlined Card\n    </Typography>\n    <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n      This card uses the outlined variant instead of elevation.\n    </Typography>\n  </Card>\n);","description":"Outlined variant"},{"id":"ui-components-card--with-content","name":"With Content","snippet":"const WithContent = () => (\n  <Card sx={{ maxWidth: 400, padding: 2 }}>\n    <Typography variant=\"h5\" component=\"div\" gutterBottom>\n      Card Title\n    </Typography>\n    <Typography variant=\"body1\" paragraph>\n      This is a card with more detailed content. It can contain paragraphs,\n      lists, images, and any other content you need.\n    </Typography>\n    <Typography variant=\"body2\" color=\"text.secondary\">\n      Additional information or metadata can go here.\n    </Typography>\n  </Card>\n);","description":"Card with more content"},{"id":"ui-components-card--interactive","name":"Interactive","snippet":"const Interactive = () => <Card\n    variant=\"elevation\"\n    elevation={1}\n    square={false}\n    sx={{ minWidth: 300, padding: 2 }}>\n    <Typography variant=\"h6\" component=\"div\">Interactive Card\n              </Typography>\n    <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>Use the controls to change variant, elevation, and square properties.\n              </Typography>\n</Card>;","description":"Interactive card with all controls"}],"import":"import { Card } from \"@exotel-npm-dev/signal-design-system\";\nimport { Typography } from \"@mui/material\";","jsDocTags":{},"description":"Card component Wraps MUI's Card component with Exotel-specific defaults and styling. All MUI Card props are supported.","reactDocgen":{"description":"Card component\n\nWraps MUI's Card component with Exotel-specific defaults and styling.\nAll MUI Card props are supported.","methods":[],"displayName":"Card","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Card/Card.tsx","actualName":"Card","exportName":"Card","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"The content of the card"}},"composes":["Omit"]},"docs":{"ui-components-card--docs":{"id":"ui-components-card--docs","name":"Docs","path":"./src/stories/ui-components/Card.mdx","title":"UI Components/Card","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as CardStories from './Card.stories';\nimport { Card } from '../../components/Card';\n\n<Meta of={CardStories} />\n\n# Card\n\n## Overview\n\n`Card` is the Signal Design System wrapper around MUI `Card`. It is a thin `forwardRef` pass-through with no custom logic. It provides a contained surface for grouping related content with optional elevation or outline.\n\nUse `Card` to present a bounded block of content — summaries, settings sections, or item previews — with consistent Exotel theme styling.\n\n```tsx\nimport { Card } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Grouping related content in a bounded, visually distinct surface\n- Dashboard tiles or summary panels\n- Item previews with title and supporting text\n- Settings or configuration sections\n\n**When not to use**\n\n- Page-level layout shells without elevation intent → use `Box`\n- Modal or overlay content → use `Dialog` or `Drawer`\n- Expandable sections → use `Accordion`\n- Full-page navigation containers → use app layout components\n\n## Anatomy\n\n`Card` is a surface container. Stories place content directly inside `Card` with `Typography`. MUI also provides `CardContent`, `CardHeader`, and `CardActions` (not Signal-wrapped; import from MUI or the design system if re-exported).\n\n```\nCard                          ← Signal wrapper (surface)\n└── children                  ← Typography, images, actions, etc.\n```\n\nCanonical structure from stories:\n\n```tsx\n<Card sx={{ minWidth: 275, padding: 2 }}>\n  <Typography variant=\"h6\" component=\"div\">\n    Card Title\n  </Typography>\n  <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n    Supporting description text.\n  </Typography>\n</Card>\n```\n\n## Content guidelines\n\nCard content is provided via `children`. Stories use `Typography` for titles and body text.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Title first | Lead with a concise heading (`variant=\"h6\"` or `h5`) |\n| Supporting detail | Use `body2` with `color=\"text.secondary\"` for metadata or descriptions |\n| Scannable | Keep card content focused on one topic or entity |\n| Hierarchy | One primary title per card; avoid multiple competing headings |\n\n### Do and don't\n\n**Do**\n\n- \"Card Title\" + one paragraph of supporting context\n- Use `Outlined` variant when elevation feels too heavy\n\n**Don't**\n\n- Cram unrelated sections into one card\n- Use cards for full-page forms without clear grouping logic\n- Rely on elevation alone to convey interactive affordance\n\n## Props\n\n`CardProps` extends MUI `CardProps` (minus `ref`). All MUI props pass through via spread.\n\n### Props documented in stories argTypes\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `variant` | `'elevation' \\| 'outlined'` | `'elevation'` | Surface style | `elevation` uses shadow depth. `outlined` uses a border without shadow. |\n| `elevation` | `number` | `1` | Shadow depth (0–24) | Only applies when `variant=\"elevation\"`. Higher values increase shadow. `Elevations` story shows 0, 1, 2, 4, 8, 16. |\n| `square` | `boolean` | `false` | Disables rounded corners | Use for flush grid layouts matching rectangular containers. |\n\n### Props demonstrated in stories\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `sx` | `SxProps` | Style overrides | Stories use `padding`, `minWidth`, `maxWidth` via `sx`. |\n| `children` | `React.ReactNode` | Card content | Typography, media, actions. |\n\n### Theme notes\n\n`MuiCard` in `theme.ts` has commented placeholder overrides only — no active global style changes. Cards use MUI defaults.\n\nAdditional standard MUI `CardProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Card} />\n\n## Variants\n\nTwo MUI variants are demonstrated in stories.\n\n| Variant | Emphasis | Use for |\n|---------|----------|---------|\n| `elevation` | Raised surface | Default cards with configurable shadow (`elevation` prop) |\n| `outlined` | Flat bordered | Lighter visual weight; border instead of shadow |\n\n<Canvas of={CardStories.Outlined} />\n\n## Elevations\n\nWhen `variant=\"elevation\"`, the `elevation` prop controls shadow depth.\n\n| Elevation | Story reference |\n|-----------|-----------------|\n| `0` | Flat, no shadow |\n| `1` | Default interactive story value |\n| `2`, `4`, `8`, `16` | Progressive depth in `Elevations` story |\n\n<Canvas of={CardStories.Elevations} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Default | No props | Standard surface appearance |\n| Square corners | `square={true}` | Disables theme border radius on corners |\n| Outlined | `variant=\"outlined\"` | Border-based surface, no elevation shadow |\n\n`Card` is not interactive by default in stories. Click or hover states require wrapping or custom `sx`.\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Elevation shadow | Applied only when `variant=\"elevation\"` |\n| `square` | Removes rounded corners when `true` |\n| Ref forwarding | `forwardRef<HTMLDivElement>` |\n| Theme | No active `MuiCard` style overrides in Exotel theme |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-card--basic`\n\nMinimal card with title and body `Typography`, `minWidth: 275`, `padding: 2`.\n\n**Recommended usage:** Default card pattern for simple content blocks.\n\n<Canvas of={CardStories.Basic} />\n\n### Elevations\n\n**Story ID:** `ui-components-card--elevations`\n\nSix cards at elevations 0, 1, 2, 4, 8, and 16.\n\n**Recommended usage:** Reference for choosing shadow depth.\n\n<Canvas of={CardStories.Elevations} />\n\n### Outlined\n\n**Story ID:** `ui-components-card--outlined`\n\n`variant=\"outlined\"` with title and description.\n\n**Recommended usage:** Flat bordered cards in dense layouts or on already-elevated backgrounds.\n\n<Canvas of={CardStories.Outlined} />\n\n### WithContent\n\n**Story ID:** `ui-components-card--with-content`\n\nLarger card (`maxWidth: 400`) with `h5` title, `body1` paragraph, and secondary metadata line.\n\n**Recommended usage:** Cards with multi-paragraph detail content.\n\n<Canvas of={CardStories.WithContent} />\n\n### Interactive\n\n**Story ID:** `ui-components-card--interactive`\n\nExposes `variant`, `elevation`, and `square` controls.\n\n**Recommended usage:** Playground only; not a production pattern.\n\n## Accessibility\n\n- Renders a `<div>` by default via MUI `Card`.\n- `Card` is not interactive unless given `onClick`, `component=\"button\"`, or wrapping interactive children.\n- Ensure headings inside cards use appropriate `Typography` `component` values (`h5`, `h6`) for document outline.\n- No custom ARIA logic in the Signal wrapper.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Use `variant=\"outlined\"` on backgrounds that already have depth or busy imagery.\n- Keep one clear title per card using `Typography variant=\"h6\"` or `h5`.\n- Use `elevation={1}` (default) for standard tiles; increase sparingly for emphasis.\n- Apply padding via `sx` consistently (`padding: 2` in stories).\n- Wrap the application in `ExotelThemeProvider` for theme-consistent surfaces.\n\n## Anti-patterns\n\n- Stacking many high-elevation cards (`elevation={16}`) across a single view.\n- Using `Card` for every `Box`-level layout need without surface intent.\n- Making entire cards clickable without keyboard support and focus indication.\n- Importing `@mui/material/Card` directly — import from `@exotel-npm-dev/signal-design-system`.\n- Inventing a `variant` beyond `elevation` and `outlined`.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `Card`\n\n- Bounded content surface with title and supporting text\n- Dashboard tile or summary panel\n- Visually grouped settings or item preview\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Generic layout wrapper | `Box` |\n| Collapsible section | `Accordion` |\n| Modal content | `Dialog` |\n| List row | `ListItem` |\n\n### Variant selection\n\n| Intent | Preferred props |\n|--------|-----------------|\n| Standard raised tile | `variant=\"elevation\"` (default), `elevation={1}` |\n| Flat bordered panel | `variant=\"outlined\"` |\n| Flush grid cell | `square={true}` |\n\n### Canonical prop combinations\n\n```tsx\n// Basic card — story: Basic\n<Card sx={{ minWidth: 275, padding: 2 }}>\n  <Typography variant=\"h6\" component=\"div\">Card Title</Typography>\n  <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n    This is a basic card component with some content.\n  </Typography>\n</Card>\n\n// Outlined — story: Outlined\n<Card variant=\"outlined\" sx={{ minWidth: 275, padding: 2 }}>\n  <Typography variant=\"h6\" component=\"div\">Outlined Card</Typography>\n  <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n    This card uses the outlined variant instead of elevation.\n  </Typography>\n</Card>\n\n// Higher elevation — story: Elevations\n<Card elevation={4} sx={{ padding: 2, minWidth: 200 }}>\n  <Typography variant=\"h6\">Elevation 4</Typography>\n</Card>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default card | `Basic` (`ui-components-card--basic`) |\n| Shadow depth | `Elevations` |\n| Bordered card | `Outlined` |\n| Rich content | `WithContent` |\n| Prop playground | `Interactive` |\n\n### Common mistakes to avoid\n\n- Setting `elevation` when `variant=\"outlined\"` — elevation applies only to elevation variant.\n- Omitting padding — stories consistently use `sx={{ padding: 2 }}`.\n- Inventing card variants beyond `elevation` and `outlined`.\n\n### Composition guidance\n\n- Place `Typography` as the first child for titles, then supporting `body2` text.\n- Use `maxWidth` in `sx` to constrain wide content (`WithContent` uses `maxWidth: 400`).\n- Pair outlined cards with dense grid layouts; use elevation for standalone tiles.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Box` | Generic layout primitive without card surface semantics |\n| `Typography` | Primary content element inside cards in stories |\n| `Accordion` | Collapsible sections alternative to static cards |\n| `Paper` | MUI surface primitive; `Card` builds on similar patterns |\n"}}},"ui-components-checkbox":{"id":"ui-components-checkbox","name":"Checkbox","path":"./src/stories/ui-components/Checkbox.stories.tsx","stories":[{"id":"ui-components-checkbox--basic","name":"Basic","snippet":"const Basic = () => {\n  const [checked, setChecked] = useState(false);\n  return (\n    <Checkbox\n      checked={checked}\n      onChange={(e) => setChecked(e.target.checked)}\n    />\n  );\n};","description":"Basic checkbox"},{"id":"ui-components-checkbox--checked","name":"Checked","snippet":"const Checked = () => <Checkbox checked />;","description":"Checked state"},{"id":"ui-components-checkbox--unchecked","name":"Unchecked","snippet":"const Unchecked = () => <Checkbox checked={false} />;","description":"Unchecked state"},{"id":"ui-components-checkbox--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Checkbox defaultChecked color=\"default\" />\n    <Checkbox defaultChecked color=\"primary\" />\n    <Checkbox defaultChecked color=\"secondary\" />\n    <Checkbox defaultChecked color=\"success\" />\n    <Checkbox defaultChecked color=\"error\" />\n    <Checkbox defaultChecked color=\"info\" />\n    <Checkbox defaultChecked color=\"warning\" />\n  </div>\n);","description":"Different colors"},{"id":"ui-components-checkbox--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Checkbox defaultChecked size=\"small\" />\n    <Checkbox defaultChecked size=\"medium\" />\n  </div>\n);","description":"Different sizes"},{"id":"ui-components-checkbox--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <FormGroup>\n    <FormControlLabel disabled control={<Checkbox />} label=\"Unchecked\" />\n    <FormControlLabel disabled control={<Checkbox defaultChecked />} label=\"Checked\" />\n    <FormControlLabel disabled control={<Checkbox indeterminate />} label=\"Indeterminate\" />\n  </FormGroup>\n);","description":"Disabled state"},{"id":"ui-components-checkbox--indeterminate","name":"Indeterminate","snippet":"const Indeterminate = () => <Checkbox indeterminate />;","description":"Indeterminate state"},{"id":"ui-components-checkbox--with-label","name":"With Label","snippet":"const WithLabel = (args) => (\n  <FormGroup>\n    <FormControlLabel control={<Checkbox defaultChecked size={args.size} />} label=\"Accept terms and conditions\" />\n    <FormControlLabel required control={<Checkbox size={args.size} />} label=\"Required\" />\n    <FormControlLabel disabled control={<Checkbox size={args.size} />} label=\"Disabled\" />\n  </FormGroup>\n);","description":"With label using FormControlLabel"},{"id":"ui-components-checkbox--interactive","name":"Interactive","snippet":"const Interactive = () => {\n    const [checked, setChecked] = useState(args.checked);\n\n    return (\n        <Checkbox\n            color=\"primary\"\n            size=\"medium\"\n            disabled={false}\n            indeterminate={false}\n            checked={checked}\n            onChange={(e) => setChecked(e.target.checked)} />\n    );\n};","description":"Interactive checkbox with all controls"}],"import":"import { Checkbox } from \"@exotel-npm-dev/signal-design-system\";\nimport { FormControlLabel, FormGroup } from \"@mui/material\";","jsDocTags":{},"description":"Checkbox component Wraps MUI's Checkbox component with Exotel-specific defaults and styling. All MUI Checkbox props are supported.","reactDocgen":{"description":"Checkbox component\n\nWraps MUI's Checkbox component with Exotel-specific defaults and styling.\nAll MUI Checkbox props are supported.","methods":[],"displayName":"Checkbox","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Checkbox/Checkbox.tsx","actualName":"Checkbox","exportName":"Checkbox","props":{"checked":{"required":false,"tsType":{"name":"boolean"},"description":"If true, the component is checked"},"disabled":{"required":false,"tsType":{"name":"boolean"},"description":"If true, the component is disabled"},"onChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => void","signature":{"arguments":[{"type":{"name":"ReactChangeEvent","raw":"React.ChangeEvent<HTMLInputElement>","elements":[{"name":"HTMLInputElement"}]},"name":"event"},{"type":{"name":"boolean"},"name":"checked"}],"return":{"name":"void"}}},"description":"Callback fired when the state is changed"},"icon":{"defaultValue":{"value":"<CheckboxOutlineIcon />","computed":false},"required":false}},"composes":["Omit"]},"docs":{"ui-components-checkbox--docs":{"id":"ui-components-checkbox--docs","name":"Docs","path":"./src/stories/ui-components/Checkbox.mdx","title":"UI Components/Checkbox","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as CheckboxStories from './Checkbox.stories';\nimport { Checkbox } from '../../components/Checkbox';\n\n<Meta of={CheckboxStories} />\n\n# Checkbox\n\n## Overview\n\n`Checkbox` is the Signal Design System wrapper around MUI `Checkbox`. It is a thin `forwardRef` pass-through with no custom logic. It provides a binary selection control for forms, lists, and settings.\n\nUse `Checkbox` when users need to select zero, one, or multiple independent options. Pair with MUI `FormControlLabel` for visible labels.\n\n```tsx\nimport { Checkbox } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Multi-select in forms or lists\n- Accepting terms or optional settings\n- Parent \"select all\" with indeterminate state\n- Binary toggles where the checked state should persist visibly\n\n**When not to use**\n\n- Single on/off settings with immediate effect → use `Switch`\n- Mutually exclusive options (pick one) → use `Radio` or `RadioGroup`\n- Primary page actions → use `Button`\n- Navigation → use `Link` or `ListItemButton`\n\n## Anatomy\n\n`Checkbox` is typically composed with `FormControlLabel` for accessible labeling.\n\n```\nFormControlLabel (MUI)          ← Label + control wrapper\n├── Checkbox                    ← Signal wrapper (input control)\n└── label (string)              ← Visible label text\n```\n\nStandalone (no label):\n\n```tsx\n<Checkbox checked={checked} onChange={(e) => setChecked(e.target.checked)} />\n```\n\nWith label (from `WithLabel` story):\n\n```tsx\n<FormControlLabel\n  control={<Checkbox defaultChecked />}\n  label=\"Accept terms and conditions\"\n/>\n```\n\n## Content guidelines\n\nLabels are provided via `FormControlLabel` `label` prop in stories, not on `Checkbox` directly.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Positive framing | State what enabling does: \"Accept terms and conditions\" |\n| Specific | Name the setting or object being selected |\n| Required fields | Use `FormControlLabel required` for mandatory consent |\n| Indeterminate label | Describe partial selection context (\"Select all\") |\n\n### Do and don't\n\n**Do**\n\n- \"Accept terms and conditions\"\n- \"Required\" (with `required` on `FormControlLabel`)\n\n**Don't**\n\n- \"Click here\" or \"Check this box\"\n- Using checkbox for mutually exclusive choices\n\n## Props\n\n`CheckboxProps` extends MUI `CheckboxProps` (minus `ref`). Documented props from stories argTypes:\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `checked` | `boolean` | `false` | Controlled checked state | Use with `onChange` for controlled forms. `Basic` and `Interactive` stories. |\n| `color` | `'default' \\| 'primary' \\| 'secondary' \\| 'error' \\| 'info' \\| 'success' \\| 'warning'` | `'primary'` | Semantic color when checked | `Colors` story shows all options with `defaultChecked`. |\n| `size` | `'small' \\| 'medium'` | `'medium'` | Control dimensions | `Sizes` story compares `small` and `medium`. |\n| `disabled` | `boolean` | `false` | Disables interaction | Shown in `Disabled` and `WithLabel` stories. |\n| `indeterminate` | `boolean` | `false` | Partial selection state | Use for parent \"select all\" when some children are checked. `Indeterminate` and `Disabled` stories. |\n\n### Commonly used inherited props\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `onChange` | `(event, checked: boolean) => void` | Fires on toggle | Required for controlled usage. |\n| `defaultChecked` | `boolean` | Uncontrolled initial state | Used in `Colors`, `Sizes`, `WithLabel` stories. |\n\nUnchecked state uses Signal `CheckboxOutlineIcon`: same **18×18** outer bounds as MUI, with a thinner stroke (**1.5px** medium, **1px** small).\n\n<ArgTypes of={Checkbox} />\n\n## Variants\n\n`Checkbox` has no visual variants. Appearance is controlled by `color` and `size`.\n\n## Sizes\n\n| Size | Use for |\n|------|---------|\n| `medium` | Default; standard forms |\n| `small` | Dense tables, compact lists |\n\n<Canvas of={CheckboxStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Unchecked | `checked={false}` or default | Default state |\n| Checked | `checked={true}` or `defaultChecked` | `Checked` story |\n| Indeterminate | `indeterminate={true}` | Partial selection; `Indeterminate` story |\n| Disabled unchecked | `disabled` without check | `Disabled` story |\n| Disabled checked | `disabled` + `defaultChecked` | Non-interactive checked |\n| Disabled indeterminate | `disabled` + `indeterminate` | Non-interactive partial |\n\n<Canvas of={CheckboxStories.Disabled} />\n\n## Colors\n\n| Color | Use for |\n|-------|---------|\n| `primary` | Default form selections |\n| `secondary` | Secondary emphasis |\n| `error` | Error-related consent or flags |\n| `success` | Positive confirmation |\n| `info` | Informational flags |\n| `warning` | Warning-related options |\n| `default` | Neutral styling |\n\n<Canvas of={CheckboxStories.Colors} />\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Controlled mode | `checked` + `onChange` — `Basic`, `Interactive` |\n| Uncontrolled mode | `defaultChecked` — `Colors`, `WithLabel` |\n| Indeterminate | Visual dash; does not set `checked` to true |\n| Ref forwarding | `forwardRef<HTMLButtonElement>` (MUI Checkbox button root) |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-checkbox--basic`\n\nControlled checkbox with `useState` toggling `checked` via `onChange`.\n\n**Recommended usage:** Canonical controlled checkbox pattern.\n\n<Canvas of={CheckboxStories.Basic} />\n\n### Checked\n\n**Story ID:** `ui-components-checkbox--checked`\n\n`checked={true}`.\n\n**Recommended usage:** Reference for checked appearance.\n\n### Unchecked\n\n**Story ID:** `ui-components-checkbox--unchecked`\n\n`checked={false}`.\n\n**Recommended usage:** Reference for unchecked appearance.\n\n### Colors\n\n**Story ID:** `ui-components-checkbox--colors`\n\nAll seven semantic colors with `defaultChecked`.\n\n**Recommended usage:** Color selection reference.\n\n### Sizes\n\n**Story ID:** `ui-components-checkbox--sizes`\n\n`small` and `medium` with `defaultChecked`.\n\n**Recommended usage:** Size selection reference.\n\n### Disabled\n\n**Story ID:** `ui-components-checkbox--disabled`\n\n`FormGroup` with disabled unchecked, checked, and indeterminate labels.\n\n**Recommended usage:** Disabled state reference with labels.\n\n<Canvas of={CheckboxStories.Disabled} />\n\n### Indeterminate\n\n**Story ID:** `ui-components-checkbox--indeterminate`\n\n`indeterminate={true}` standalone.\n\n**Recommended usage:** Parent select-all partial state.\n\n<Canvas of={CheckboxStories.Indeterminate} />\n\n### WithLabel\n\n**Story ID:** `ui-components-checkbox--with-label`\n\n`FormControlLabel` examples: default checked, required unchecked, disabled unchecked.\n\n**Recommended usage:** Production pattern for labeled checkboxes.\n\n<Canvas of={CheckboxStories.WithLabel} />\n\n### Interactive\n\n**Story ID:** `ui-components-checkbox--interactive`\n\nAll argTypes exposed with controlled `checked` state.\n\n**Recommended usage:** Playground only.\n\n## Accessibility\n\n- Renders a MUI checkbox with an internal native `<input type=\"checkbox\">`.\n- `checked` and `indeterminate` map to native input states.\n- `disabled` sets native `disabled`, removing from tab order.\n- Keyboard: Space toggles the checkbox (MUI default).\n- Always pair with a visible label via `FormControlLabel` or `aria-label` when standalone.\n- `FormControlLabel` `required` adds required indicator to label (`WithLabel` story).\n- No custom ARIA logic in the Signal wrapper.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Use `FormControlLabel` for every checkbox with visible text.\n- Use controlled `checked` + `onChange` in forms with React state.\n- Use `indeterminate` only for parent rows in hierarchical selection.\n- Use `size=\"small\"` in dense DataGrid or table rows.\n- Use `color=\"primary\"` unless semantic color is intentional.\n- Wrap the application in `ExotelThemeProvider`.\n\n## Anti-patterns\n\n- Standalone checkboxes without `aria-label` or `FormControlLabel`.\n- Using checkbox for mutually exclusive options → use `Radio`.\n- Using checkbox for immediate on/off settings better suited to `Switch`.\n- Importing `@mui/material/Checkbox` directly — use design system package.\n- Leaving `indeterminate` set when all children become fully checked or unchecked.\n\n## Guidance for AI Agents\n\n### When to choose `Checkbox`\n\n- Multi-select or binary opt-in with visible checked state\n- Terms acceptance, optional settings, list multi-selection\n- Parent \"select all\" with `indeterminate`\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Immediate on/off setting | `Switch` |\n| Pick exactly one option | `Radio` |\n| Primary action | `Button` |\n| Toggle in button style | `Button` with state |\n\n### Canonical prop combinations\n\n```tsx\n// Controlled — story: Basic\nconst [checked, setChecked] = useState(false);\n<Checkbox\n  checked={checked}\n  onChange={(e) => setChecked(e.target.checked)}\n/>\n\n// With label — story: WithLabel\n<FormControlLabel\n  control={<Checkbox defaultChecked />}\n  label=\"Accept terms and conditions\"\n/>\n\n// Indeterminate parent — story: Indeterminate\n<Checkbox indeterminate />\n\n// Disabled group — story: Disabled\n<FormControlLabel disabled control={<Checkbox />} label=\"Unchecked\" />\n\n// Small dense — story: Sizes\n<Checkbox defaultChecked size=\"small\" />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Controlled toggle | `Basic` (`ui-components-checkbox--basic`) |\n| With label | `WithLabel` |\n| Indeterminate | `Indeterminate` |\n| Disabled states | `Disabled` |\n| Colors | `Colors` |\n| Sizes | `Sizes` |\n\n### Common mistakes to avoid\n\n- Generating checkbox without label or `aria-label`.\n- Using `Switch` and `Checkbox` interchangeably for settings.\n- Forgetting `onChange` in controlled mode.\n- Inventing checkbox variants or sizes beyond `small` and `medium`.\n\n### Composition guidance\n\n- Wrap multiple related checkboxes in MUI `FormGroup`.\n- Use `FormControlLabel required` for mandatory consent fields.\n- Sync `indeterminate` parent state with child selection logic in application code.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Switch` | Alternative for on/off settings |\n| `Radio` | Mutually exclusive single selection |\n| `FormControlLabel` | Label pairing used in stories |\n| `FormGroup` | Groups related checkboxes (`Disabled`, `WithLabel`) |\n| `Button` | Commits form actions; does not replace checkbox selection |\n"}}},"ui-components-chip":{"id":"ui-components-chip","name":"Chip","path":"./src/stories/ui-components/Chip.stories.tsx","stories":[{"id":"ui-components-chip--basic","name":"Basic","snippet":"const Basic = () => <Chip label=\"Chip\" />;","description":"Basic chip"},{"id":"ui-components-chip--tonal","name":"Tonal","snippet":"const Tonal = () => <Chip label=\"Tonal\" variant=\"tonal\" color=\"primary\" />;","description":"Tonal chip — use controls to change `color` and other props (matches Badge tonal styling)."},{"id":"ui-components-chip--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>\n    <Chip label=\"Default\" color=\"default\" />\n    <Chip label=\"Primary\" color=\"primary\" />\n    <Chip label=\"Secondary\" color=\"secondary\" />\n    <Chip label=\"Success\" color=\"success\" />\n    <Chip label=\"Error\" color=\"error\" />\n    <Chip label=\"Info\" color=\"info\" />\n    <Chip label=\"Warning\" color=\"warning\" />\n  </div>\n);","description":"Different colors"},{"id":"ui-components-chip--variants","name":"Variants","snippet":"const Variants = () => (\n  <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>\n    <Chip label=\"Filled\" variant=\"filled\" />\n    <Chip label=\"Outlined\" variant=\"outlined\" />\n    <Chip label=\"Tonal\" variant=\"tonal\" color=\"primary\" />\n  </div>\n);","description":"Different variants"},{"id":"ui-components-chip--tonal-colors","name":"Tonal Colors","snippet":"const TonalColors = () => (\n  <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', alignItems: 'center' }}>\n    <Chip label=\"Default\" variant=\"tonal\" color=\"default\" />\n    <Chip label=\"Primary\" variant=\"tonal\" color=\"primary\" />\n    <Chip label=\"Secondary\" variant=\"tonal\" color=\"secondary\" />\n    <Chip label=\"Success\" variant=\"tonal\" color=\"success\" />\n    <Chip label=\"Error\" variant=\"tonal\" color=\"error\" />\n    <Chip label=\"Info\" variant=\"tonal\" color=\"info\" />\n    <Chip label=\"Warning\" variant=\"tonal\" color=\"warning\" />\n  </div>\n);","description":"Tonal variant — same color logic as Badge tonal (theme palette, light/dark)."},{"id":"ui-components-chip--tonal-interactive","name":"Tonal Interactive","snippet":"const TonalInteractive = () => (\n  <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', alignItems: 'center' }}>\n    <Chip label=\"Clickable\" variant=\"tonal\" color=\"primary\" clickable onClick={() => {}} />\n    <Chip label=\"Deletable\" variant=\"tonal\" color=\"success\" onDelete={() => {}} />\n    <Chip\n      label=\"With icon\"\n      variant=\"tonal\"\n      color=\"info\"\n      icon={<Icon name=\"check\" size=\"sm\" />}\n    />\n    <Chip\n      label=\"All\"\n      variant=\"tonal\"\n      color=\"warning\"\n      icon={<Icon name=\"tag\" size=\"sm\" />}\n      clickable\n      onClick={() => {}}\n      onDelete={() => {}}\n    />\n  </div>\n);","description":"Tonal with clickable, delete, and leading icon (parity with standard chip behavior)."},{"id":"ui-components-chip--clickable","name":"Clickable","snippet":"const Clickable = () => <Chip label=\"Clickable\" clickable onClick={() => {}} />;","description":"Clickable chip"},{"id":"ui-components-chip--deletable","name":"Deletable","snippet":"const Deletable = () => <Chip label=\"Deletable\" onDelete={() => {}} />;","description":"Deletable chip"},{"id":"ui-components-chip--with-icon","name":"With Icon","snippet":"const WithIcon = () => <Chip label=\"With Icon\" icon={<Icon name=\"check\" size=\"sm\" />} />;","description":"Chip with icon"},{"id":"ui-components-chip--with-avatar","name":"With Avatar","snippet":"const WithAvatar = () => (\n  <Chip\n    avatar={<div style={{ width: 24, height: 24, borderRadius: '50%', background: '#1976d2', color: 'white', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12 }}>AB</div>}\n    label=\"Avatar Chip\"\n    color=\"primary\"\n  />\n);","description":"Chip with avatar"},{"id":"ui-components-chip--interactive","name":"Interactive","snippet":"const Interactive = (args) => {\n  const { clickable, deletable, ...chipProps } = args;\n  return (\n    <Chip\n      {...chipProps}\n      onClick={clickable ? () => {} : undefined}\n      onDelete={deletable ? () => {} : undefined}\n    />\n  );\n};","description":"Interactive chip with all controls"}],"import":"import { Chip, Icon } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Chip","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Chip/Chip.tsx","actualName":"Chip","exportName":"Chip","props":{"label":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""},"variant":{"required":false,"tsType":{"name":"union","raw":"MuiChipProps['variant'] | 'tonal'","elements":[{"name":"MuiChipProps['variant']","raw":"MuiChipProps['variant']"},{"name":"literal","value":"'tonal'"}]},"description":"Includes `tonal` (Signal DS); also augmented on `@mui/material/Chip`.","defaultValue":{"value":"'filled'","computed":false}},"color":{"defaultValue":{"value":"'default'","computed":false},"required":false}},"composes":["Omit"]},"docs":{"ui-components-chip--docs":{"id":"ui-components-chip--docs","name":"Docs","path":"./src/stories/ui-components/Chip.mdx","title":"UI Components/Chip","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ChipStories from './Chip.stories';\nimport { Chip } from '../../components/Chip';\n\n<Meta of={ChipStories} />\n\n# Chip\n\n## Overview\n\n`Chip` is the Signal Design System wrapper around MUI `Chip`. It applies Exotel theme defaults, replaces the default delete icon with Signal `Icon` (`name=\"x\"`), and adds a custom `tonal` variant: tinted background with hue-matched label, icons, and delete control — aligned with `Badge` tonal styling.\n\nUse `Chip` for compact labels, tags, filters, and removable tokens. Chips are self-contained; they do not wrap other elements like `Badge`.\n\n```tsx\nimport { Chip } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Tags and category labels\n- Filter pills in toolbars or search UIs\n- Removable tokens (with `onDelete`)\n- Tonal status indicators matching `Badge` tonal counts\n- Clickable filter toggles (with `clickable` and `onClick`)\n\n**When not to use**\n\n- Overlay counts on another control → use `Badge`\n- Persistent alert messages → use `Alert`\n- Primary page actions → use `Button`\n- Binary on/off selection in forms → use `Checkbox` or `Switch`\n\n## Anatomy\n\n`Chip` is a single self-contained element. Optional leading `icon` or `avatar`, central `label`, and trailing delete control when `onDelete` is provided.\n\n```\nChip                              ← Signal wrapper\n├── icon | avatar (optional)      ← Leading visual\n├── label                         ← Primary text (children via label prop)\n└── deleteIcon (when onDelete)    ← Signal Icon name=\"x\" size=\"xs\" weight=\"bold\"\n```\n\nCanonical structure:\n\n```tsx\n<Chip label=\"Filter\" variant=\"tonal\" color=\"primary\" onDelete={() => {}} />\n```\n\n## Content guidelines\n\nChip labels are set via the `label` prop.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Concise | 1–3 words: \"Primary\", \"Deletable\", \"With Icon\" |\n| Noun or filter name | Tags name categories: \"Success\", \"Error\", filter names |\n| Sentence case | Match product tone; stories use sentence case labels |\n| Removable context | Deletable chips should name what is being removed |\n\n### Do and don't\n\n**Do**\n\n- \"Primary\", \"Success\", \"Filter active\"\n- Short filter names in toolbars\n\n**Don't**\n\n- Full sentences in chip labels\n- Using chips for primary CTAs (\"Save changes\" → use `Button`)\n- Duplicate meaning in both icon and long label text\n\n## Props\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `label` | `React.ReactNode` | — | Visible chip text | Primary content. Required for meaningful chips. |\n| `variant` | `'filled' \\| 'outlined' \\| 'tonal'` | `'filled'` | Visual style | `filled` is solid MUI chip. `outlined` is border-only. `tonal` applies tinted surface via `data-variant=\"tonal\"`. |\n| `color` | `'default' \\| 'primary' \\| 'secondary' \\| 'error' \\| 'info' \\| 'success' \\| 'warning'` | `'default'` | Semantic color | Drives MUI color on `filled`/`outlined`; drives tonal tint on `tonal`. |\n| `size` | `'small' \\| 'medium'` | `'medium'` | Chip dimensions | Use `small` in dense toolbars. |\n| `disabled` | `boolean` | `false` | Disables interaction | Prevents click and delete. |\n| `clickable` | `boolean` | `false` | Applies clickable styling | Pair with `onClick` for filter toggles. Story `Clickable` sets both. |\n| `onDelete` | `() => void` | — | Enables delete affordance | When set, shows Signal `Icon` `x` as delete icon. Story argType `deletable` maps to this in `Interactive`. |\n\n### Tonal variant implementation\n\nWhen `variant=\"tonal\"`:\n\n- Maps internally to MUI `variant=\"filled\"` with `color=\"default\"`.\n- Sets `data-variant=\"tonal\"`.\n- Applies `tonalChipSx` via `resolveTonalColor` — icons/delete inherit text color.\n- **Light:** solid `palette.tonal` tokens (e.g. `primary` bg `indigo[50]`, text `indigo[800]`).\n- **Dark:** `alpha(palette.main, 0.32)` background; text via `TONAL_TEXT_RAMP` (e.g. `primary[200]`, `success[400]`).\n- `color=\"default\"`: light uses `grey[200]`/`grey[800]`; dark uses `alpha(grey[500], 32%)` / `common.white`.\n\n### Delete icon\n\nSignal replaces MUI default delete icon with:\n\n```tsx\n<Icon name=\"x\" size=\"xs\" weight=\"bold\" />\n```\n\n### Theme overrides (`MuiChip`)\n\n- `filled`: `border: none`\n- `outlined`: `border: 1px solid currentColor` (stroke matches label color)\n- `borderRadius: theme.shape.borderRadius`\n- `fontWeight: medium`\n- `lineHeight: 1.38`\n- `letterSpacing: 0.16px`\n\n### Commonly used inherited props\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `icon` | `React.ReactElement` | Leading icon | Pass `<Icon name=\"check\" size=\"sm\" />` per `WithIcon` story. |\n| `avatar` | `React.ReactElement` | Leading avatar | `WithAvatar` uses a styled div avatar. |\n| `onClick` | `() => void` | Click handler | Required for interactive chips; set `clickable={true}` for styling. |\n\nAdditional standard MUI `ChipProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Chip} />\n\n## Variants\n\nThree variants are demonstrated in stories. `tonal` is Signal-specific.\n\n| Variant | Emphasis | Use for |\n|---------|----------|---------|\n| `filled` | High | Default solid chips |\n| `outlined` | Medium | Border matches text color (`currentColor`) |\n| `tonal` | Medium-soft | Tinted tags matching `Badge` tonal |\n\n<Canvas of={ChipStories.Variants} />\n\n## Colors\n\nSeven semantic colors in `Colors` (filled default) and `TonalColors` (tonal).\n\n| Color | Use for |\n|-------|---------|\n| `default` | Neutral tags |\n| `primary` | Primary filters or categories |\n| `secondary` | Secondary emphasis |\n| `success` | Positive status |\n| `error` | Error or destructive tags |\n| `info` | Informational tags |\n| `warning` | Warning status |\n\n<Canvas of={ChipStories.TonalColors} />\n\n## Sizes\n\n| Size | Use for |\n|------|---------|\n| `medium` | Default; standard toolbars and forms |\n| `small` | Dense layouts (MUI default sizing) |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Enabled | Default | Interactive when `onClick` or `onDelete` set |\n| Disabled | `disabled={true}` | Non-interactive |\n| Clickable | `clickable={true}` + `onClick` | `Clickable` story |\n| Deletable | `onDelete` handler | Shows Signal `x` delete icon |\n| Hover / Focus | Automatic | MUI chip focus ring when interactive |\n\n<Canvas of={ChipStories.TonalInteractive} />\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Delete | `onDelete` renders Signal `Icon` `x`; fires on delete click |\n| Click | `onClick` with optional `clickable` for pointer cursor and ripple |\n| Tonal mapping | Light: solid `palette.tonal`; dark: `tonalSurface` alpha + `TONAL_TEXT_RAMP` text |\n| Module augmentation | `tonal` declared in `mui-augmentation.ts` on `ChipPropsVariantOverrides` |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-chip--basic`\n\nDefault `label=\"Chip\"` with `filled` variant.\n\n**Recommended usage:** Minimal chip with default styling.\n\n<Canvas of={ChipStories.Basic} />\n\n### Tonal\n\n**Story ID:** `ui-components-chip--tonal`\n\n`variant=\"tonal\"`, `color=\"primary\"`, `label=\"Tonal\"`.\n\n**Recommended usage:** Single tonal chip; use controls to explore color.\n\n<Canvas of={ChipStories.Tonal} />\n\n### Colors\n\n**Story ID:** `ui-components-chip--colors`\n\nAll seven semantic colors on default `filled` variant.\n\n**Recommended usage:** Filled chip color reference.\n\n### Variants\n\n**Story ID:** `ui-components-chip--variants`\n\n`filled`, `outlined`, and `tonal` side by side.\n\n**Recommended usage:** Variant selection reference.\n\n### TonalColors\n\n**Story ID:** `ui-components-chip--tonal-colors`\n\nAll seven semantic colors on `variant=\"tonal\"`.\n\n**Recommended usage:** Tonal color reference; pairs with `Badge` `TonalColors`.\n\n### TonalInteractive\n\n**Story ID:** `ui-components-chip--tonal-interactive`\n\nTonal chips with `clickable` + `onClick`, `onDelete`, leading `icon`, and combined all three.\n\n**Recommended usage:** Tonal chips with full interaction patterns.\n\n### Clickable\n\n**Story ID:** `ui-components-chip--clickable`\n\n`clickable={true}` with `onClick`.\n\n**Recommended usage:** Filter toggle chips.\n\n### Deletable\n\n**Story ID:** `ui-components-chip--deletable`\n\n`onDelete` handler on `label=\"Deletable\"`.\n\n**Recommended usage:** Removable tags in search or filter UIs.\n\n### WithIcon\n\n**Story ID:** `ui-components-chip--with-icon`\n\nLeading `<Icon name=\"check\" size=\"sm\" />`.\n\n**Recommended usage:** Status chips with reinforcing icon.\n\n### WithAvatar\n\n**Story ID:** `ui-components-chip--with-avatar`\n\nChip with custom avatar element and `color=\"primary\"`.\n\n**Recommended usage:** User or entity tags with avatar leading visual.\n\n### Interactive\n\n**Story ID:** `ui-components-chip--interactive`\n\nExposes all story argTypes; maps `deletable` to `onDelete`, `clickable` to `onClick`.\n\n**Recommended usage:** Playground only.\n\n## Accessibility\n\n- Renders a `<div>` with `role=\"button\"` when `onClick` is provided (MUI default).\n- Delete control is a separate focusable button inside the chip when `onDelete` is set.\n- `disabled` removes chip from interaction.\n- `label` text provides the accessible name for the chip.\n- Leading `icon` is decorative unless given separate accessible text.\n- No custom ARIA logic beyond MUI defaults in the Signal wrapper.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Use `variant=\"tonal\"` for soft status tags consistent with `Badge` tonal.\n- Use `onDelete` for removable filters; do not add a separate delete `IconButton`.\n- Pass `Icon` components via `icon` prop, not raw SVG nodes.\n- Use `clickable` with `onClick` for filter toggles.\n- Use `color=\"error\"` sparingly for destructive or error-category tags.\n- Wrap the application in `ExotelThemeProvider` for `MuiChip` theme overrides.\n\n## Anti-patterns\n\n- Using `Chip` to overlay counts on icons → use `Badge`.\n- Omitting `onClick` while setting `clickable={true}` alone — both are needed for interactive behavior.\n- Expecting custom delete icon — Signal always uses `Icon name=\"x\"`.\n- Importing `@mui/material/Chip` directly — import from `@exotel-npm-dev/signal-design-system`.\n- Inventing variants beyond `filled`, `outlined`, `tonal`.\n- Long paragraph text in `label`.\n\n## Guidance for AI Agents\n\n### When to choose `Chip`\n\n- Standalone tag, filter pill, or removable token\n- Tonal status label matching `Badge` tonal styling\n- Clickable filter with `onClick`\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Count on icon/avatar/button | `Badge` |\n| Primary action | `Button` |\n| Alert message | `Alert` |\n| Binary form selection | `Checkbox` |\n\n### Variant selection\n\n| Intent | Preferred props |\n|--------|-----------------|\n| Default tag | `variant=\"filled\"` |\n| Bordered tag | `variant=\"outlined\"` |\n| Soft status/filter | `variant=\"tonal\" color=\"primary\"` |\n| Removable filter | `onDelete={() => {}}` |\n| Toggle filter | `clickable onClick={() => {}}` |\n\n### Canonical prop combinations\n\n```tsx\n// Default — story: Basic\n<Chip label=\"Chip\" />\n\n// Tonal status — story: Tonal\n<Chip label=\"Tonal\" variant=\"tonal\" color=\"primary\" />\n\n// Removable — story: Deletable\n<Chip label=\"Deletable\" onDelete={() => {}} />\n\n// Clickable filter — story: Clickable\n<Chip label=\"Clickable\" clickable onClick={() => {}} />\n\n// With icon — story: WithIcon\n<Chip label=\"With Icon\" icon={<Icon name=\"check\" size=\"sm\" />} />\n\n// Tonal interactive — story: TonalInteractive\n<Chip\n  label=\"All\"\n  variant=\"tonal\"\n  color=\"warning\"\n  icon={<Icon name=\"tag\" size=\"sm\" />}\n  clickable\n  onClick={() => {}}\n  onDelete={() => {}}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default chip | `Basic` (`ui-components-chip--basic`) |\n| Tonal chip | `Tonal` |\n| Compare variants | `Variants` |\n| Tonal colors | `TonalColors` |\n| Interactive tonal | `TonalInteractive` |\n| Deletable | `Deletable` |\n| With icon | `WithIcon` |\n\n### Common mistakes to avoid\n\n- Using `Badge` patterns for standalone tags.\n- Forgetting `onDelete` when generating removable chips.\n- Inventing a custom delete icon — Signal uses `Icon name=\"x\"`.\n- `variant=\"tonal\"` without design system import.\n- Using `deletable` prop in production code — it is a story-only argType alias for `onDelete`.\n\n### Composition guidance\n\n- Group related filter chips in a flex row with `gap: 8px` (per story layouts).\n- Match tonal chip `color` with tonal `Badge` in the same notification context.\n- Use `size=\"small\"` in DataGrid toolbars or dense filter bars.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Badge` | Overlay counts; shares tonal color logic |\n| `Icon` | Leading icons and default delete icon |\n| `Avatar` | Optional leading avatar in `WithAvatar` |\n| `Button` | Primary actions; higher emphasis than chips |\n| `Alert` | Persistent messages instead of inline tags |\n"}}},"ui-components-circularprogress":{"id":"ui-components-circularprogress","name":"CircularProgress","path":"./src/stories/ui-components/CircularProgress.stories.tsx","stories":[{"id":"ui-components-circularprogress--indeterminate","name":"Indeterminate","snippet":"const Indeterminate = () => <CircularProgress />;"},{"id":"ui-components-circularprogress--determinate","name":"Determinate","snippet":"const Determinate = () => <CircularProgress variant=\"determinate\" value={75} />;"}],"import":"import { CircularProgress } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"CircularProgress","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/CircularProgress/CircularProgress.tsx","actualName":"CircularProgress","exportName":"CircularProgress","composes":["Omit"]},"docs":{"ui-components-circularprogress--docs":{"id":"ui-components-circularprogress--docs","name":"Docs","path":"./src/stories/ui-components/CircularProgress.mdx","title":"UI Components/CircularProgress","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as CircularProgressStories from './CircularProgress.stories';\nimport { CircularProgress } from '../../components/CircularProgress';\n\n<Meta of={CircularProgressStories} />\n\n# CircularProgress\n\n## Overview\n\n`CircularProgress` is the Signal Design System wrapper around MUI `CircularProgress`. It is a thin `forwardRef` pass-through with no custom logic. It displays a circular loading indicator for indeterminate or determinate progress.\n\nUse `CircularProgress` to indicate that content is loading or an operation is in progress. Place it inline within a view or centered in a loading region.\n\n```tsx\nimport { CircularProgress } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct primary color styling.\n\n**When to use**\n\n- Inline loading while fetching data\n- Determinate progress when completion percentage is known\n- Centered spinner in a content area during async operations\n\n**When not to use**\n\n- Full-page blocking loads with overlay → use `Backdrop` + `CircularProgress` (MUI pattern)\n- Linear file upload progress → use `LinearProgress`\n- Skeleton placeholders for known layout → use `Skeleton`\n- Button loading state → use `Button` `loading` prop if available, or disable button with inline spinner\n\n## Props\n\n`CircularProgressProps` extends MUI `CircularProgressProps` (minus `ref`). All MUI props pass through via spread.\n\n### Props demonstrated in stories\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `variant` | `'indeterminate' \\| 'determinate'` | `'indeterminate'` | Progress mode | `indeterminate` spins continuously. `determinate` shows arc fill based on `value`. |\n| `value` | `number` | `0` | Completion percentage | Required for `variant=\"determinate\"`. `Determinate` story uses `value={75}`. |\n\n### Commonly used inherited props (MUI)\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `color` | `'primary' \\| 'secondary' \\| 'error' \\| 'info' \\| 'success' \\| 'warning' \\| 'inherit'` | `'primary'` | Spinner color | Use `primary` for default loading. |\n| `size` | `number \\| string` | `40` | Diameter in pixels | Use smaller sizes (e.g. `24`) for inline button-area loading. |\n| `thickness` | `number` | `3.6` | Stroke thickness | Adjust for visual weight. |\n| `disableShrink` | `boolean` | `false` | Disables shrink animation | Rarely needed. |\n\nNo `MuiCircularProgress` theme overrides in Exotel `theme.ts`. No story argTypes defined.\n\n<ArgTypes of={CircularProgress} />\n\n## Variants\n\nTwo MUI variants are demonstrated in stories.\n\n| Variant | Behavior | Use for |\n|---------|----------|---------|\n| `indeterminate` | Continuous rotation | Unknown duration loading |\n| `determinate` | Arc fill 0–100% | Known progress percentage |\n\n<Canvas of={CircularProgressStories.Indeterminate} />\n\n## Sizes\n\nNo dedicated size story. MUI default diameter is `40px`. Override with `size` prop (number or string). `ChatInputBox` uses `size={24}` inline in the codebase.\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Indeterminate loading | Default / `variant=\"indeterminate\"` | `Indeterminate` story |\n| Determinate progress | `variant=\"determinate\" value={n}` | `Determinate` story with `value={75}` |\n| Hidden | Do not render | Remove spinner when loading completes |\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Animation | CSS rotation for indeterminate; arc sweep for determinate |\n| `value` range | 0–100 for determinate variant |\n| Ref forwarding | `forwardRef<HTMLSpanElement>` |\n| Accessibility | MUI sets `role=\"progressbar\"` |\n\n## Stories\n\n### Indeterminate\n\n**Story ID:** `ui-components-circular-progress--indeterminate`\n\nDefault `CircularProgress` with no args — indeterminate spinning indicator.\n\n**Recommended usage:** Generic loading when duration is unknown.\n\n<Canvas of={CircularProgressStories.Indeterminate} />\n\n### Determinate\n\n**Story ID:** `ui-components-circular-progress--determinate`\n\n`variant=\"determinate\"`, `value={75}` — 75% filled arc.\n\n**Recommended usage:** Operations with measurable progress (upload, processing percentage).\n\n<Canvas of={CircularProgressStories.Determinate} />\n\n## Accessibility\n\n- MUI renders `role=\"progressbar\"` on the root `<span>`.\n- Indeterminate: no `aria-valuenow`; indicates activity in progress.\n- Determinate: `aria-valuenow`, `aria-valuemin=\"0\"`, `aria-valuemax=\"100\"` set from `value` (MUI default).\n- Supplement with visible loading text or `aria-label` when the spinner is the sole loading indicator.\n- No custom ARIA logic in the Signal wrapper.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Use `indeterminate` when load time is unknown.\n- Use `determinate` only when `value` reflects real progress.\n- Center spinners in their loading region or place inline adjacent to the triggering control.\n- Remove the spinner when loading completes — do not leave it mounted indefinitely.\n- Use smaller `size` for compact inline contexts.\n- Wrap the application in `ExotelThemeProvider` for primary color consistency.\n\n## Anti-patterns\n\n- Showing determinate progress with a static or fake `value`.\n- Using `CircularProgress` as the only loading indicator without text on full-page loads.\n- Leaving spinners running after errors — show error state instead.\n- Importing `@mui/material/CircularProgress` directly — use design system package.\n- Inventing variants beyond `indeterminate` and `determinate`.\n\n## Guidance for AI Agents\n\n### When to choose `CircularProgress`\n\n- Loading state with circular indicator\n- Known percentage progress (`determinate`)\n- Unknown duration wait (`indeterminate`)\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Horizontal progress bar | `LinearProgress` |\n| Content shape placeholder | `Skeleton` |\n| Full-screen blocking overlay | `Backdrop` + `CircularProgress` |\n| Button in-flight state | Disabled `Button` + small `CircularProgress` |\n\n### Canonical prop combinations\n\n```tsx\n// Unknown duration — story: Indeterminate\n<CircularProgress />\n\n// 75% complete — story: Determinate\n<CircularProgress variant=\"determinate\" value={75} />\n\n// Compact inline (codebase pattern)\n<CircularProgress size={24} />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default spinner | `Indeterminate` (`ui-components-circular-progress--indeterminate`) |\n| Percentage progress | `Determinate` |\n\n### Common mistakes to avoid\n\n- Setting `value` without `variant=\"determinate\"`.\n- Using determinate mode without updating `value` as progress changes.\n- Inventing custom variants or Signal-specific props — wrapper is pass-through only.\n- Omitting `ExotelThemeProvider`.\n\n### Composition guidance\n\n- Center in a `Box` with `display: 'flex'`, `justifyContent: 'center'`, `p: 2` for region loading.\n- Pair with `Typography` loading message for full-section waits.\n- Use `size={24}` when embedding beside buttons or in compact panels.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `LinearProgress` | Horizontal progress indicator |\n| `Skeleton` | Layout placeholder during content load |\n| `Backdrop` | Overlay container for blocking loads |\n| `Box` | Layout wrapper for centering spinners |\n"}}},"ui-components-container":{"id":"ui-components-container","name":"Container","path":"./src/stories/ui-components/Container.stories.tsx","stories":[{"id":"ui-components-container--default","name":"Default","snippet":"const Default = () => <Container maxWidth=\"lg\">\n    <Paper sx={{ p: 3, textAlign: 'center' }}>\n        <Typography variant=\"h6\">Container (lg)</Typography>\n        <Typography variant=\"body2\" color=\"text.secondary\">Content is centered and horizontally constrained.\n                    </Typography>\n    </Paper>\n</Container>;"},{"id":"ui-components-container--max-widths","name":"Max Widths","snippet":"const MaxWidths = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, py: 2 }}>\n    {(['xs', 'sm', 'md', 'lg', 'xl'] as const).map((size) => (\n      <Container key={size} maxWidth={size}>\n        <Paper sx={{ p: 2, textAlign: 'center', bgcolor: 'action.hover' }}>\n          <Typography variant=\"body2\" fontWeight={600}>maxWidth=&quot;{size}&quot;</Typography>\n        </Paper>\n      </Container>\n    ))}\n  </Box>\n);"},{"id":"ui-components-container--fixed","name":"Fixed","snippet":"const Fixed = () => <Container fixed>\n    <Paper sx={{ p: 3, textAlign: 'center' }}>\n        <Typography variant=\"h6\">Fixed Container</Typography>\n        <Typography variant=\"body2\" color=\"text.secondary\">Width snaps to the current breakpoint.\n                    </Typography>\n    </Paper>\n</Container>;"},{"id":"ui-components-container--disable-gutters","name":"Disable Gutters","snippet":"const DisableGutters = () => <Container disableGutters maxWidth=\"md\">\n    <Paper sx={{ p: 3, textAlign: 'center' }}>\n        <Typography variant=\"h6\">No Gutters</Typography>\n        <Typography variant=\"body2\" color=\"text.secondary\">Content extends to the edges without horizontal padding.\n                    </Typography>\n    </Paper>\n</Container>;"}],"import":"import { Box, Container, Paper, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Container","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Container/Container.tsx","actualName":"Container","exportName":"Container","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-container--docs":{"id":"ui-components-container--docs","name":"Docs","path":"./src/stories/ui-components/Container.mdx","title":"UI Components/Container","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ContainerStories from './Container.stories';\nimport { Container } from '../../components/Container';\n\n<Meta of={ContainerStories} />\n\n# Container\n\n## Overview\n\n`Container` wraps MUI `Container` for centered max-width page content. It horizontally constrains content to responsive breakpoint widths.\n\n```tsx\nimport { Container } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Page-level content width constraint (`maxWidth=\"lg\"`, etc.)\n- Centering content within a full-width layout\n- Responsive width snapping with `fixed`\n\n**When not to use**\n\n- Arbitrary layout → use `Box` or `Stack`\n- Grid-based layouts → use `Grid`\n- Full-bleed content → no container needed\n\n## Props\n\n<ArgTypes of={Container} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `maxWidth` | `'xs' \\| 'sm' \\| 'md' \\| 'lg' \\| 'xl' \\| false` | `'lg'` | Maximum content width |\n| `fixed` | `boolean` | `false` | If true, width snaps to the current breakpoint |\n| `disableGutters` | `boolean` | `false` | If true, removes left/right padding |\n\n## Stories\n\n### Default\n\nContainer with `maxWidth=\"lg\"` centering content.\n\n<Canvas of={ContainerStories.Default} />\n\n### MaxWidths\n\nAll five breakpoint sizes compared.\n\n<Canvas of={ContainerStories.MaxWidths} />\n\n### Fixed\n\nFixed container that snaps width to the current breakpoint.\n\n<Canvas of={ContainerStories.Fixed} />\n\n### DisableGutters\n\nContainer without horizontal padding for edge-to-edge content.\n\n<Canvas of={ContainerStories.DisableGutters} />\n\n## Best Practices\n\n- Use `maxWidth=\"lg\"` as the default for most page content.\n- Use `fixed` for layouts that should snap between breakpoints rather than being fluid.\n- Use `disableGutters` when content needs to extend to the container edges (e.g. full-width images).\n- Nest within `Box` for background colors that extend full-width while content stays constrained.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `Box` | Generic layout primitive for spacing and backgrounds |\n| `Grid` | Column-based responsive layouts within a Container |\n| `Stack` | Vertical/horizontal stacking with consistent spacing |\n"}}},"ui-components-datagrid":{"id":"ui-components-datagrid","name":"DataGrid","path":"./src/stories/ui-components/DataGrid.stories.tsx","stories":[{"id":"ui-components-datagrid--without-toolbar","name":"Without Toolbar","snippet":"const WithoutToolbar = () => <StoryWrapper>\n    <DataGrid\n        rows={sampleRows}\n        columns={sampleColumns}\n        tableHeader={{ title: entityTitle() }}\n        showToolbar={false} />\n</StoryWrapper>;"},{"id":"ui-components-datagrid--with-custom-toolbar-buttons","name":"With Custom Toolbar Buttons","snippet":"const WithCustomToolbarButtons = () => <StoryWrapper>\n    <DataGrid\n        rows={sampleRows}\n        columns={sampleColumns}\n        tableHeader={{ title: entityTitle() }}\n        initialState={{ pagination: { paginationModel: { page: 0, pageSize: 5 } } }}\n        pageSizeOptions={[5, 10, 25]}\n        pagination\n        customToolbarButtons={[\n          { id: 'add', icon: <Icon name=\"plus\" size={20} />, label: 'Add New', tooltip: 'Add new row', onClick: () => alert('Add'), color: 'primary' },\n          { id: 'delete', icon: <Icon name=\"trash\" size={20} />, label: 'Delete', tooltip: 'Delete', onClick: () => alert('Delete'), color: 'error' },\n        ] as ToolbarButtonConfig[]} />\n</StoryWrapper>;"},{"id":"ui-components-datagrid--loading-state","name":"Loading State","snippet":"const LoadingState = () => <StoryWrapper height={480}>\n    <DataGrid\n        rows={[]}\n        columns={sampleColumns}\n        tableHeader={{ title: entityTitle() }}\n        loading />\n</StoryWrapper>;"},{"id":"ui-components-datagrid--error-state","name":"Error State","snippet":"const ErrorState = () => <StoryWrapper height={480}>\n    <DataGrid\n        rows={sampleRows}\n        columns={sampleColumns}\n        tableHeader={{ title: entityTitle() }}\n        error\n        onRefresh={() => alert('Refreshing...')} />\n</StoryWrapper>;"},{"id":"ui-components-datagrid--with-checkbox-bulk-delete","name":"With Checkbox Bulk Delete","snippet":"const WithCheckboxBulkDelete = () => <StoryWrapper>\n    <DataGrid\n        rows={sampleRows}\n        columns={sampleColumns}\n        tableHeader={{ title: entityTitle() }}\n        checkboxSelection\n        initialState={{ pagination: { paginationModel: { page: 0, pageSize: 5 } } }}\n        pageSizeOptions={[5, 10, 25]}\n        pagination\n        bulkDeleteConfig={bulkDeleteConfig} />\n</StoryWrapper>;"},{"id":"ui-components-datagrid--default-list-view","name":"Default List View","snippet":"const DefaultListView = () => <>\n    <ViewportHint />\n    <StoryWrapper height={640}>\n        <DataGrid\n            rows={sampleRows}\n            columns={sampleColumns}\n            tableHeader={{ title: entityTitle() }}\n            listCellConfig={{\n              primaryField: 'name',\n              secondaryField: 'joinDate',\n              iconName: 'user',\n              excludeFields: ['id', 'email'],\n            }}\n            initialState={{ pagination: { paginationModel: { page: 0, pageSize: 10 } } }}\n            pageSizeOptions={[5, 10, 25]}\n            pagination />\n    </StoryWrapper>\n</>;"},{"id":"ui-components-datagrid--custom-list-view","name":"Custom List View","snippet":"const CustomListView = () => {\n    const listViewColumn: GridListViewColDef = {\n      field: 'listColumn',\n      renderCell: (params: GridRenderCellParams) => {\n        const name = params.row.name as string;\n        const status = params.row.status as string;\n        const color = statusChipColor(status);\n        const avatarColors = getAvatarColors(name);\n\n        return (\n          <Stack\n            direction=\"row\"\n            spacing={1.5}\n            alignItems=\"center\"\n            sx={{\n              width: '100%',\n              height: '100%',\n              px: 2,\n              borderBottom: '1px solid',\n              borderColor: 'divider',\n            }}\n          >\n            <Avatar\n              sx={{\n                width: 44,\n                height: 44,\n                flexShrink: 0,\n                typography: 'label2',\n                bgcolor: avatarColors.bgcolor,\n                color: avatarColors.color,\n                border: '2px solid',\n                borderColor: color === 'success' ? 'success.main' : 'grey.400',\n              }}\n            >\n              {getInitials(name)}\n            </Avatar>\n\n            <Stack spacing={0.25} sx={{ flex: 1, minWidth: 0 }}>\n              <Stack direction=\"row\" spacing={1} alignItems=\"center\">\n                <Typography variant=\"title2\" noWrap>\n                  {params.row.name}\n                </Typography>\n                <Chip label={status} variant=\"tonal\" color={color} size=\"small\" />\n              </Stack>\n              <Typography variant=\"body2\" color=\"text.secondary\" noWrap>\n                {params.row.email} · {params.row.role}\n              </Typography>\n            </Stack>\n\n            <Icon name=\"caret-right\" size=\"sm\" color=\"text.secondary\" />\n          </Stack>\n        );\n      },\n    };\n\n    return (\n        <StoryWrapper height={640}>\n            <DataGrid\n                rows={sampleRows}\n                columns={sampleColumns}\n                tableHeader={{ title: entityTitle() }}\n                initialState={{ pagination: { paginationModel: { page: 0, pageSize: 10 } } }}\n                pageSizeOptions={[5, 10, 25]}\n                pagination\n                listView\n                listViewColumn={listViewColumn}\n                rowHeight={80} />\n        </StoryWrapper>\n    );\n};"},{"id":"ui-components-datagrid--with-table-header","name":"With Table Header","snippet":"const WithTableHeader = () => {\n    const [search, setSearch] = useState('');\n    const filteredRows = sampleRows.filter((row) => {\n      if (!search) return true;\n      const term = search.toLowerCase();\n      return (\n        String(row.name).toLowerCase().includes(term) ||\n        String(row.email).toLowerCase().includes(term) ||\n        String(row.role).toLowerCase().includes(term)\n      );\n    });\n\n    return (\n        <StoryWrapper>\n            <DataGrid\n                columns={sampleColumns}\n                initialState={{ pagination: { paginationModel: { page: 0, pageSize: 10 } } }}\n                pageSizeOptions={[5, 10, 25]}\n                pagination\n                rows={filteredRows}\n                tableHeader={{\n                  title: entityTitle(filteredRows.length),\n                  subtitle: 'Manage your team members and their roles',\n                  showSearch: true,\n                  searchType: 'basic',\n                  onBasicSearch: setSearch,\n                  actions: [\n                    { id: 'export', children: 'Export', variant: 'outlined' },\n                    { id: 'add', children: 'Add Member', variant: 'contained', startIconProps: { name: 'plus' } },\n                  ],\n                }} />\n        </StoryWrapper>\n    );\n};"},{"id":"ui-components-datagrid--with-pagination-server-side","name":"With Pagination Server Side","snippet":"const WithPaginationServerSide = () => {\n    const [rows, setRows] = useState<RowData[]>([]);\n    const [loading, setLoading] = useState(true);\n    const [rowCount, setRowCount] = useState(0);\n    const [paginationModel, setPaginationModel] = useState({ page: 0, pageSize: 10 });\n\n    const fetchPage = useCallback((page: number, pageSize: number) => {\n      setLoading(true);\n      fakeServerFetch(sampleRows, {}, [], page, pageSize).then((result) => {\n        setRows(result.rows);\n        setRowCount(result.totalRows);\n        setLoading(false);\n      });\n    }, []);\n\n    useEffect(() => {\n      fetchPage(paginationModel.page, paginationModel.pageSize);\n    }, []);\n\n    const handlePaginationModelChange = useCallback(\n      (newModel: typeof paginationModel) => {\n        setPaginationModel(newModel);\n        fetchPage(newModel.page, newModel.pageSize);\n      },\n      [fetchPage]\n    );\n\n    return (\n        <StoryWrapper>\n            <DataGrid\n                columns={sampleColumns}\n                pagination\n                pageSizeOptions={[5, 10, 25]}\n                rows={rows}\n                loading={loading}\n                rowCount={rowCount}\n                paginationMode=\"server\"\n                paginationModel={paginationModel}\n                onPaginationModelChange={handlePaginationModelChange}\n                tableHeader={{ title: entityTitle(rowCount) }} />\n        </StoryWrapper>\n    );\n};"},{"id":"ui-components-datagrid--with-filters-server-side","name":"With Filters Server Side","snippet":"const WithFiltersServerSide = () => {\n    const [rows, setRows] = useState<RowData[]>([]);\n    const [loading, setLoading] = useState(true);\n    const [rowCount, setRowCount] = useState(0);\n    const [paginationModel, setPaginationModel] = useState({ page: 0, pageSize: 10 });\n    const filtersRef = useRef<FilterRecords>({\n      status: 'all',\n      role: [],\n      joinDate: emptyDateRange,\n    });\n\n    const fetchData = useCallback((filters: FilterRecords, page: number, pageSize: number) => {\n      setLoading(true);\n      fakeServerFetch(sampleRows, filters, [], page, pageSize).then((result) => {\n        setRows(result.rows);\n        setRowCount(result.totalRows);\n        setLoading(false);\n      });\n    }, []);\n\n    useEffect(() => {\n      fetchData(filtersRef.current, paginationModel.page, paginationModel.pageSize);\n    }, []);\n\n    const handleFiltersChange = useCallback(\n      (newFilters: FilterRecords) => {\n        filtersRef.current = newFilters;\n        setPaginationModel((prev) => ({ ...prev, page: 0 }));\n        fetchData(newFilters, 0, paginationModel.pageSize);\n      },\n      [paginationModel.pageSize, fetchData]\n    );\n\n    const handlePaginationModelChange = useCallback(\n      (newModel: typeof paginationModel) => {\n        setPaginationModel(newModel);\n        fetchData(filtersRef.current, newModel.page, newModel.pageSize);\n      },\n      [fetchData]\n    );\n\n    return (\n        <StoryWrapper>\n            <DataGrid\n                columns={sampleColumns}\n                pagination\n                pageSizeOptions={[5, 10, 25]}\n                rows={rows}\n                loading={loading}\n                rowCount={rowCount}\n                paginationMode=\"server\"\n                paginationModel={paginationModel}\n                onPaginationModelChange={handlePaginationModelChange}\n                tableHeader={{ title: entityTitle(rowCount) }}\n                showAppliedFilters\n                maxVisibleAppliedFilters={4}\n                customToolbarFilters={[\n                  createStatusFilter(),\n                  createRoleMultiSelectFilter(),\n                  createJoinDateRangeFilter(),\n                ]}\n                onToolbarFiltersChange={handleFiltersChange} />\n        </StoryWrapper>\n    );\n};"},{"id":"ui-components-datagrid--density","name":"Density","snippet":"const Density = () => {\n    const [density, setDensity] = useState<GridDensity>('standard');\n\n    return (\n        <Stack spacing={1.5}>\n            <Stack direction=\"row\" spacing={1}>\n                {densityOptions.map((option) => (\n                  <Chip\n                    key={option.value}\n                    label={option.label}\n                    size=\"small\"\n                    variant={density === option.value ? 'tonal' : 'outlined'}\n                    color={density === option.value ? 'primary' : 'default'}\n                    onClick={() => setDensity(option.value)}\n                  />\n                ))}\n            </Stack>\n            <StoryWrapper>\n                <DataGrid\n                    rows={sampleRows}\n                    columns={sampleColumns}\n                    tableHeader={{ title: entityTitle() }}\n                    initialState={{ pagination: { paginationModel: { page: 0, pageSize: 10 } } }}\n                    pageSizeOptions={[5, 10, 25]}\n                    pagination\n                    density={density} />\n            </StoryWrapper>\n        </Stack>\n    );\n};","description":"Row density via the `density` prop — toggle between `compact`, `standard`, and `comfortable` to adjust row height and cell padding."},{"id":"ui-components-datagrid--interactive","name":"Interactive","snippet":"const Interactive = () => {\n    const [rows, setRows] = useState<RowData[]>([]);\n    const [loading, setLoading] = useState(true);\n    const [rowCount, setRowCount] = useState(0);\n    const [sortModel, setSortModel] = useState<GridSortModel>([]);\n    const [paginationModel, setPaginationModel] = useState({ page: 0, pageSize: 10 });\n    const [search, setSearch] = useState('');\n    const filtersRef = useRef<FilterRecords>({ status: 'all', role: 'all' });\n\n    const fetchData = useCallback(\n      (filters: FilterRecords, sort: GridSortModel, page: number, pageSize: number, searchTerm: string) => {\n        setLoading(true);\n        fakeServerFetch(sampleRows, filters, sort, page, pageSize).then((result) => {\n          const term = searchTerm.toLowerCase();\n          const rows = term\n            ? result.rows.filter(\n                (row) =>\n                  row.name.toLowerCase().includes(term) ||\n                  row.email.toLowerCase().includes(term) ||\n                  row.role.toLowerCase().includes(term)\n              )\n            : result.rows;\n          setRows(rows);\n          setRowCount(result.totalRows);\n          setLoading(false);\n        });\n      },\n      []\n    );\n\n    useEffect(() => {\n      fetchData(filtersRef.current, sortModel, paginationModel.page, paginationModel.pageSize, search);\n    }, []);\n\n    const handleFiltersChange = useCallback(\n      (newFilters: FilterRecords) => {\n        filtersRef.current = newFilters;\n        setPaginationModel((prev) => ({ ...prev, page: 0 }));\n        fetchData(newFilters, sortModel, 0, paginationModel.pageSize, search);\n      },\n      [sortModel, paginationModel.pageSize, search, fetchData]\n    );\n\n    const handleSortModelChange = useCallback(\n      (newSort: GridSortModel) => {\n        setSortModel(newSort);\n        setPaginationModel((prev) => ({ ...prev, page: 0 }));\n        fetchData(filtersRef.current, newSort, 0, paginationModel.pageSize, search);\n      },\n      [paginationModel.pageSize, search, fetchData]\n    );\n\n    const handlePaginationModelChange = useCallback(\n      (newModel: typeof paginationModel) => {\n        setPaginationModel(newModel);\n        fetchData(filtersRef.current, sortModel, newModel.page, newModel.pageSize, search);\n      },\n      [sortModel, search, fetchData]\n    );\n\n    const handleSearch = useCallback(\n      (term: string) => {\n        setSearch(term);\n        setPaginationModel((prev) => ({ ...prev, page: 0 }));\n        fetchData(filtersRef.current, sortModel, 0, paginationModel.pageSize, term);\n      },\n      [sortModel, paginationModel.pageSize, fetchData]\n    );\n\n    const handleRefresh = useCallback(() => {\n      fetchData(filtersRef.current, sortModel, paginationModel.page, paginationModel.pageSize, search);\n    }, [sortModel, paginationModel, search, fetchData]);\n\n    return (\n        <StoryWrapper height={760}>\n            <DataGrid\n                columns={interactiveColumns}\n                pagination\n                pageSizeOptions={[5, 10, 25]}\n                rows={rows}\n                loading={loading}\n                rowCount={rowCount}\n                paginationMode=\"server\"\n                paginationModel={paginationModel}\n                onPaginationModelChange={handlePaginationModelChange}\n                sortModel={sortModel}\n                onSortModelChange={handleSortModelChange}\n                onRefresh={handleRefresh}\n                checkboxSelection\n                bulkDeleteConfig={bulkDeleteConfig}\n                showAppliedFilters\n                maxVisibleAppliedFilters={4}\n                customToolbarFilters={[createStatusFilter('all'), createRoleFilter('all')]}\n                onToolbarFiltersChange={handleFiltersChange}\n                tableHeader={{\n                  title: entityTitle(rowCount),\n                  subtitle: 'Manage your team members and their roles',\n                  showSearch: true,\n                  searchType: 'basic',\n                  onBasicSearch: handleSearch,\n                  actions: [\n                    { id: 'add', children: 'Add Member', variant: 'contained', startIconProps: { name: 'plus' } },\n                  ],\n                }} />\n        </StoryWrapper>\n    );\n};","description":"Full-featured playground combining table header, search, server-side filters, sorting, pagination, checkbox selection, bulk delete, row actions, and refresh. Use the controls panel to explore individual props against this composition."}],"import":"import {\n    Alert,\n    Avatar,\n    Box,\n    Chip,\n    DataGrid,\n    Icon,\n    IconButton,\n    Menu,\n    Stack,\n    Tooltip,\n    Typography,\n} from \"@exotel-npm-dev/signal-design-system\";\nimport ListItemIcon from \"@mui/material/ListItemIcon\";\nimport ListItemText from \"@mui/material/ListItemText\";\nimport MenuItem from \"@mui/material/MenuItem\";","jsDocTags":{},"description":"DataGrid Component A thin wrapper around MUI X DataGridPro that: - Forwards all props to the underlying DataGridPro - Maintains ref forwarding for DOM access - Provides a consistent naming convention - Enables toolbar with quick filter by default - Below 756px width: toolbar filters, manage columns, sort, and date range use bottom drawers; at 756px+ use standard dropdowns/popovers - Does NOT duplicate MUI DataGridPro logic","reactDocgen":{"description":"DataGrid Component\n\nA thin wrapper around MUI X DataGridPro that:\n- Forwards all props to the underlying DataGridPro\n- Maintains ref forwarding for DOM access\n- Provides a consistent naming convention\n- Enables toolbar with quick filter by default\n- Below 756px width: toolbar filters, manage columns, sort, and date range use bottom drawers; at 756px+ use standard dropdowns/popovers\n- Does NOT duplicate MUI DataGridPro logic","methods":[],"displayName":"DataGrid","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/DataGrid/DataGrid.tsx","actualName":"DataGrid","exportName":"DataGrid","props":{"columns":{"required":true,"tsType":{"name":"Array","elements":[{"name":"intersection","raw":"GridColDef & {\n  iconName?: IconName;\n}","elements":[{"name":"GridColDef"},{"name":"signature","type":"object","raw":"{\n  iconName?: IconName;\n}","signature":{"properties":[{"key":"iconName","value":{"name":"unknown","required":false}}]}}]}],"raw":"DataGridColDef[]"},"description":""},"customToolbarButtons":{"required":false,"tsType":{"name":"Array","elements":[{"name":"ToolbarButtonConfig"}],"raw":"ToolbarButtonConfig[]"},"description":""},"customToolbarFilters":{"required":false,"tsType":{"name":"Array","elements":[{"name":"ToolbarFilterConfig"}],"raw":"ToolbarFilterConfig[]"},"description":""},"hideSort":{"required":false,"tsType":{"name":"boolean"},"description":""},"sortModel":{"required":false,"tsType":{"name":"GridSortModel"},"description":""},"onSortModelChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(sortModel: GridSortModel) => void","signature":{"arguments":[{"type":{"name":"GridSortModel"},"name":"sortModel"}],"return":{"name":"void"}}},"description":""},"onToolbarFiltersChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(appliedFilters: FilterRecords) => void","signature":{"arguments":[{"type":{"name":"Record","elements":[{"name":"string"},{"name":"union","raw":"string | DateRangeValue | string[] | undefined","elements":[{"name":"string"},{"name":"DateRangeValue"},{"name":"Array","elements":[{"name":"string"}],"raw":"string[]"},{"name":"undefined"}]}],"raw":"Record<string, FilterValue>"},"name":"appliedFilters"}],"return":{"name":"void"}}},"description":""},"onRefresh":{"required":false,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":""},"showAppliedFilters":{"required":false,"tsType":{"name":"boolean"},"description":""},"maxVisibleAppliedFilters":{"required":false,"tsType":{"name":"number"},"description":""},"bulkDeleteConfig":{"required":false,"tsType":{"name":"BulkDeleteConfig"},"description":""},"tableHeader":{"required":false,"tsType":{"name":"DataGridTableHeaderProps"},"description":""},"listCellConfig":{"required":false,"tsType":{"name":"ListCellConfig"},"description":"Configuration for the mobile list-view cell.\nControls which fields are shown and their display order."},"emptyStateMessage":{"required":false,"tsType":{"name":"string"},"description":"Message displayed in the empty state overlay when rows are empty.\n@default 'No data available'"},"emptyLightImage":{"required":false,"tsType":{"name":"string"},"description":"Image shown in the empty state overlay for light mode.\nAlso used in dark mode (with invert filter) when emptyDarkImage is not provided."},"emptyDarkImage":{"required":false,"tsType":{"name":"string"},"description":"Image shown in the empty state overlay for dark mode.\nWhen omitted, emptyLightImage is used with an invert filter."},"error":{"required":false,"tsType":{"name":"boolean"},"description":"When true, shows an error overlay instead of the data grid content.\n@default false"},"errorTitle":{"required":false,"tsType":{"name":"string"},"description":"Title displayed in the error overlay.\n@default \"Data couldn't be loaded\""},"errorMessage":{"required":false,"tsType":{"name":"string"},"description":"Description displayed below the title in the error overlay.\n@default \"We're having trouble fetching it right now. Please try again.\""},"errorLightImage":{"required":false,"tsType":{"name":"string"},"description":"Image shown in the error overlay for light mode.\nAlso used in dark mode (with invert filter) when errorDarkImage is not provided."},"errorDarkImage":{"required":false,"tsType":{"name":"string"},"description":"Image shown in the error overlay for dark mode.\nWhen omitted, errorLightImage is used with an invert filter."}},"composes":["Omit"]},"docs":{"ui-components-datagrid--docs":{"id":"ui-components-datagrid--docs","name":"Docs","path":"./src/stories/ui-components/DataGrid.mdx","title":"UI Components/DataGrid","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DataGridStories from './DataGrid.stories';\nimport { DataGrid } from '../../components/DataGrid';\n\n<Meta of={DataGridStories} />\n\n# DataGrid\n\n## Overview\n\n`DataGrid` wraps **MUI X DataGrid Pro** with Exotel toolbar, filters, applied filters bar, bulk delete, table header (`PageHeader`), sort controls, list view, and empty/error overlays.\n\nUse for management screens, list pages, monitoring views, and administrative interfaces in Signal-powered applications. Do not use for simple static HTML tables — use `Table`.\n\n```tsx\nimport { DataGrid } from '@exotel-npm-dev/signal-design-system';\nimport type { DataGridColDef, ToolbarFilterConfig } from '@exotel-npm-dev/signal-design-system';\n```\n\nRequires `ExotelThemeProvider`. Responsive toolbar: below **756px** width, filters/columns/sort use bottom drawers; at **756px+** use dropdowns/popovers. Implementation switches to **list view** at `theme.breakpoints.down('sm')` (600px) automatically when using the default `DataGrid` wrapper.\n\n**When to use**\n\n- ECC data tables with search, filters, bulk actions, pagination\n- Server-side pagination and filtering (`WithPaginationServerSide`, `WithFiltersServerSide`)\n- Mobile list view (`DefaultListView`, `CustomListView`)\n\n**When not to use**\n\n- Simple read-only tables without grid features → `Table`\n- Card-based layouts → `Card` + `Stack`\n\n## Usage guidelines\n\n> **Product-level rules:** See **UX Constitution → Table Pages (DataGrid)** in Storybook Documentation (read before this section for full product context).\n\nThese rules define how `DataGrid` should be implemented across Signal-powered applications. AI agents should follow them when generating tables, list pages, management screens, monitoring views, and administrative interfaces.\n\nUnless explicitly instructed otherwise, assume the **default Signal DataGrid experience** below. When unsure, prefer consistency over customization.\n\n### Default DataGrid configuration\n\nEvery management `DataGrid` should include:\n\n| Capability | How to enable | Signal reference |\n|------------|---------------|------------------|\n| Search | `tableHeader.showSearch: true` + `onBasicSearch` | `WithTableHeader`, `Interactive` |\n| Filters | `customToolbarFilters` (≥1 filter) | `WithFiltersServerSide`, `Interactive` |\n| Applied filters visible | `showAppliedFilters: true` | `WithFiltersServerSide`, `Interactive` |\n| Bulk selection | `checkboxSelection: true` | `WithCheckboxBulkDelete`, `Interactive` |\n| Bulk actions | `bulkDeleteConfig` and/or `customToolbarButtons` | `WithCheckboxBulkDelete`, `WithCustomToolbarButtons` |\n| Pagination | `pagination` + `initialState.pagination` + `pageSizeOptions` | `WithPaginationServerSide`, `Interactive` |\n| Total count in heading | `tableHeader.title` with count | See **Header structure** |\n| Responsive list view | Default wrapper (`listView` on small screens) + `listCellConfig` | `DefaultListView`, `CustomListView` |\n\n**Component code defaults** (if props omitted): `showToolbar={true}`, `showAppliedFilters={false}`. Product default for AI-generated UIs is to **opt in explicitly** to search, filters, applied filters, selection, and pagination — do not ship a bare grid for management pages.\n\n### Header structure\n\nEvery management `DataGrid` must include a heading via `tableHeader`.\n\n**Format:** entity name + total record count in parentheses.\n\n```text\nUsers (50)\nCampaigns (124)\nQueues (12)\nAgents (86)\n```\n\nThe count should represent the **total** records available (not just the current page). For server-side grids, use `rowCount` from the server response (`WithPaginationServerSide`, `WithFiltersServerSide`, `Interactive`).\n\n```tsx\ntableHeader={{\n  title: `Team Members (${totalCount})`,\n  subtitle: 'Manage your team members and their roles',\n  showSearch: true,\n  searchType: 'basic',\n  onBasicSearch: setSearchTerm,\n  actions: [\n    { id: 'add', children: 'Add Member', variant: 'contained', startIconProps: { name: 'plus' } },\n  ],\n}}\n```\n\n**Story reference:** `WithTableHeader` — title with total count, subtitle, search, and CTA.\n\n### Search\n\nSearch should be enabled by default for management grids.\n\n- Appears in the **header area** via `PageHeader` (`tableHeader.showSearch`).\n- Search across meaningful fields (name, email, role, etc.) in parent state, or as a server request (`Interactive`).\n- Updates results without full page refresh (client filter or server refetch).\n\nDo not remove search unless explicitly requested.\n\n### Filters\n\nEvery management `DataGrid` should support filtering.\n\n- Define at least one `customToolbarFilters` entry (`select`, `date-range`, or `multi-select`).\n- Set `showAppliedFilters: true` so active filters remain visible (`AppliedFilters` bar).\n- Wire `onToolbarFiltersChange` to sync filter state — server-side in `WithFiltersServerSide` and `Interactive`.\n\nUsers must never lose visibility of active filters.\n\n### Bulk selection\n\nBulk selection should be enabled by default on management grids.\n\n- `checkboxSelection: true`\n- Selecting rows reveals bulk actions via `bulkDeleteConfig` (toolbar delete button when rows selected) and/or `customToolbarButtons`.\n\n**Bulk delete** (`WithCheckboxBulkDelete`, `Interactive`):\n\n```tsx\nbulkDeleteConfig={{\n  onDelete: (selectedIds) => handleBulkDelete(selectedIds),\n  label: (count) => `Delete ${count} Rows`,\n}}\n```\n\nUse context-aware bulk actions defined by product requirements (Delete, Assign, Export, Archive, Change Status). Implement additional actions via `customToolbarButtons` when `bulkDeleteConfig` alone is insufficient.\n\n### Pagination\n\nPagination should be enabled by default.\n\n```tsx\npagination\ninitialState={{ pagination: { paginationModel: { page: 0, pageSize: 10 } } }}\npageSizeOptions={[5, 10, 25]}\n```\n\nDo not render excessively large client-side datasets without pagination. Use server-driven pagination (`WithPaginationServerSide`) with `paginationMode=\"server\"` and `rowCount` for large datasets.\n\n### User representation\n\nCell content is composed via `renderCell` on `DataGridColDef`. Signal does not provide built-in user columns — follow these product rules in column definitions.\n\n#### Single user\n\nA single user must be represented as **Avatar + Name** (see the `name` column in every story's `sampleColumns`):\n\n```tsx\n{\n  field: 'name',\n  headerName: 'Name',\n  renderCell: (params) => (\n    <Stack direction=\"row\" spacing={1} alignItems=\"center\" height=\"100%\">\n      <Avatar>{params.row.initials}</Avatar>\n      <Typography variant=\"body2\">{params.row.name}</Typography>\n    </Stack>\n  ),\n}\n```\n\nDo not display names without identity context when an avatar is available.\n\n#### Multiple users\n\nMultiple users should use an **avatar group** pattern:\n\n- Show up to **4** avatars\n- Overflow indicator: `+12`\n\nMUI `AvatarGroup` is available via `@exotel-npm-dev/signal-design-system` (MUI re-export). There is no dedicated Signal `AvatarGroup` wrapper or DataGrid story — implement in `renderCell`.\n\nExample overflow format: `[A] [B] [C] [D] +12`\n\n#### Overflow interaction\n\nWhen the overflow indicator is selected, display a list with **Avatar + Name** for all associated users (e.g. `Menu` or `Popover` with `List` + `ListItemAvatar`). Users should view complete membership without leaving the current page.\n\n### Status representation\n\nStatuses should use **tonal `Chip`** components in `renderCell`, not plain text.\n\nMap semantic color to status meaning:\n\n| Severity | Example statuses | Chip props |\n|----------|------------------|------------|\n| Success | Active, Connected, Completed | `variant=\"tonal\" color=\"success\"` |\n| Warning | Pending, Awaiting Review | `variant=\"tonal\" color=\"warning\"` |\n| Error | Failed, Disconnected | `variant=\"tonal\" color=\"error\"` |\n| Info | Draft, Scheduled | `variant=\"tonal\" color=\"info\"` |\n\n```tsx\nrenderCell: (params) => (\n  <Chip label={params.value} variant=\"tonal\" color=\"success\" size=\"small\" />\n)\n```\n\nEvery story's `status` column renders a tonal `Chip`. Include a text label on chips so status is not conveyed by color alone.\n\n### Actions\n\nRow-level actions **must** be behind a **3-dot menu** in an `actions` column — never as standalone Edit/Delete icon buttons in the cell.\n\n**Story reference:** `Interactive` — outlined `IconButton` with `dots-three-vertical` opening a `Menu`.\n\n| Property | Value |\n|----------|-------|\n| Trigger | `IconButton size=\"small\" variant=\"outlined\"` |\n| Icon | `dots-three-vertical` |\n| Actions | `Menu` + `MenuItem` (Edit, View, Delete, etc.) |\n| Column width | **56–72px**, `pinnedColumns: { right: ['actions'] }` |\n\n```tsx\n// renderCell pattern (see Interactive story)\n<IconButton size=\"small\" variant=\"outlined\" aria-label=\"Row actions\">\n  <Icon name=\"dots-three-vertical\" size=\"sm\" />\n</IconButton>\n<Menu>{/* MenuItem per action */}</Menu>\n```\n\n- Prioritize common tasks inside the menu (Edit, View, Assign, Delete).\n- Avoid exposing unnecessary menu items.\n- Trigger requires `aria-label=\"Row actions\"` (and optional `Tooltip`).\n- Destructive actions (Delete) open a confirmation `Dialog` after menu selection — not inline in the grid.\n\n### CTA placement\n\nPrimary CTAs belong in the **header area** via `tableHeader.actions` (`PageHeader`).\n\n**Story reference:** `WithTableHeader`, `Interactive` — `Add Member` as `variant=\"contained\"` with `startIconProps`.\n\nExamples: Create User, Create Campaign, Add Queue, Add Agent. Use action-oriented labels (`Add Member`, not `Click to add`).\n\n### Responsive behavior\n\n`DataGrid` must be responsive.\n\n- **Default wrapper:** `listView={isMobile}` when viewport is below the `sm` breakpoint (600px); uses the built-in `ListCell` with `listCellConfig` (`DefaultListView`).\n- **756px toolbar:** compact toolbar uses bottom drawers for filters/sort/columns.\n- **Custom list cell:** override the mobile row entirely with a custom `listViewColumn` (`CustomListView`) when `listCellConfig` isn't expressive enough.\n\nList layout should preserve identity, status, important metadata, and actions. Configure via `listCellConfig`:\n\n```tsx\nlistCellConfig={{\n  primaryField: 'name',\n  secondaryField: 'joinDate',\n  iconName: 'user',\n  excludeFields: ['id', 'email'],\n}}\n```\n\nAvoid horizontal scrolling on mobile when possible.\n\n## Anatomy\n\n```\nDataGrid\n├── PageHeader (tableHeader)        ← Title (+ count), subtitle, search, CTAs\n├── CustomToolbar                   ← Filters, refresh, bulk delete, sort, columns\n├── AppliedFilters (optional)       ← showAppliedFilters\n├── DataGridPro core                ← rows, columns, pagination, checkboxSelection\n├── EmptyOverlay / ErrorOverlay     ← empty rows or error prop\n└── ListCell (mobile list view)     ← listCellConfig, or custom listViewColumn\n```\n\n## Props\n\n### Wrapper-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `columns` | `DataGridColDef[]` | required | Columns; supports `iconName`, `renderCell` | Use `renderCell` for Avatar, Chip, actions |\n| `customToolbarFilters` | `ToolbarFilterConfig[]` | — | Toolbar filter controls | At least one for management grids |\n| `customToolbarButtons` | `ToolbarButtonConfig[]` | — | Extra toolbar buttons | `WithCustomToolbarButtons` |\n| `showAppliedFilters` | `boolean` | `false` | Show `AppliedFilters` bar | Set `true` for management grids |\n| `maxVisibleAppliedFilters` | `number` | `4` | Applied filter chip overflow | |\n| `onToolbarFiltersChange` | `(filters: FilterRecords) => void` | — | Filter state callback | Required with filters |\n| `bulkDeleteConfig` | `BulkDeleteConfig` | — | Bulk delete when rows selected | `onDelete`, `label` |\n| `tableHeader` | `PageHeaderProps` | — | Title, search, actions | Include total count in `title` |\n| `listCellConfig` | `ListCellConfig` | — | Mobile list field layout | `DefaultListView` |\n| `showToolbar` | `boolean` | `true` | Show toolbar | `WithoutToolbar` disables |\n| `hideSort` | `boolean` | `false` | Hide sort UI | |\n| `sortModel` / `onSortModelChange` | `GridSortModel` | — | Controlled sort | `Interactive` |\n| `onRefresh` | `() => void` | — | Toolbar refresh | `ErrorState`, `Interactive` |\n| `error` | `boolean` | `false` | Show error overlay | `ErrorState` |\n| `emptyStateMessage` | `string` | `'No data available'` | Empty overlay | |\n\n### ToolbarFilterConfig\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | `string` | Filter key |\n| `type` | `'select' \\| 'date-range' \\| 'multi-select'` | Control type |\n| `label` | `string` | Display label |\n| `options` | `{ value, label }[]` | For `select` |\n| `multiSelectOptions` | `MultiSelectOption[]` | For `multi-select` |\n| `shortcuts` | `DateRangeShortcut[]` | For `date-range` |\n| `initialValue` | `FilterValue` | Initial filter value |\n\n### Inherited DataGridPro props\n\n`rows`, `pagination`, `checkboxSelection`, `loading`, `rowCount`, `density`, `onRowSelectionModelChange`, `paginationMode`, `listView`, `listViewColumn`, etc.\n\n<ArgTypes of={DataGrid} />\n\n## Variants / modes\n\n| Mode | Story |\n|------|-------|\n| No toolbar | `WithoutToolbar` |\n| Custom toolbar buttons | `WithCustomToolbarButtons` |\n| Checkbox + bulk delete | `WithCheckboxBulkDelete` |\n| Full header + search + CTA | `WithTableHeader` |\n| Server-side pagination | `WithPaginationServerSide` |\n| Server-side filters | `WithFiltersServerSide` |\n| Default mobile list | `DefaultListView` |\n| Custom mobile list | `CustomListView` |\n| Full-featured playground | `Interactive` |\n| Row density | `Density` |\n\n## States\n\n| State | How | Story |\n|-------|-----|-------|\n| Loading | `loading={true}` | `LoadingState` |\n| Error | `error={true}` | `ErrorState` |\n| With selection | `checkboxSelection` | `WithCheckboxBulkDelete` |\n\n## Stories\n\n### WithoutToolbar — `ui-components-data-grid--without-toolbar`\n\nGrid with the toolbar hidden via `showToolbar={false}`.\n\n<Canvas of={DataGridStories.WithoutToolbar} />\n\n### WithCustomToolbarButtons — `ui-components-data-grid--with-custom-toolbar-buttons`\n\nAdditional toolbar actions via `customToolbarButtons`.\n\n<Canvas of={DataGridStories.WithCustomToolbarButtons} />\n\n### LoadingState — `ui-components-data-grid--loading-state`\n\nLoading skeleton while data is fetched.\n\n<Canvas of={DataGridStories.LoadingState} />\n\n### ErrorState — `ui-components-data-grid--error-state`\n\nError overlay with a refresh action.\n\n<Canvas of={DataGridStories.ErrorState} />\n\n### WithCheckboxBulkDelete — `ui-components-data-grid--with-checkbox-bulk-delete`\n\n`checkboxSelection` + `bulkDeleteConfig` — canonical bulk pattern.\n\n<Canvas of={DataGridStories.WithCheckboxBulkDelete} />\n\n### DefaultListView — `ui-components-data-grid--default-list-view`\n\nBuilt-in mobile list layout driven by `listCellConfig`. Resize the preview below 600px (or use the mobile viewport) to see list mode.\n\n<Canvas of={DataGridStories.DefaultListView} />\n\n### CustomListView — `ui-components-data-grid--custom-list-view`\n\nFully custom mobile row via `listView` + `listViewColumn`, overriding the default `ListCell`.\n\n<Canvas of={DataGridStories.CustomListView} />\n\n### WithTableHeader — `ui-components-data-grid--with-table-header`\n\nTitle with count, subtitle, search, and header CTA — canonical management page header.\n\n<Canvas of={DataGridStories.WithTableHeader} />\n\n### WithPaginationServerSide — `ui-components-data-grid--with-pagination-server-side`\n\nServer-driven pagination with `paginationMode=\"server\"` and `rowCount`.\n\n<Canvas of={DataGridStories.WithPaginationServerSide} />\n\n### WithFiltersServerSide — `ui-components-data-grid--with-filters-server-side`\n\nServer-driven filters covering all three `ToolbarFilterConfig` types — `select` (Status), `multi-select` (Role), `date-range` (Join date) — with `showAppliedFilters` and a fake server refetch per filter change. Filters start cleared so the applied filters bar's **Clear All** action has a visible effect (resets every control to `initialValue` and refetches the unfiltered list) rather than snapping back to a pre-applied preset.\n\n<Canvas of={DataGridStories.WithFiltersServerSide} />\n\n### Interactive — `ui-components-data-grid--interactive`\n\nFull-featured playground: header search, server-side filters/sort/pagination, checkbox selection with bulk delete, and a row actions menu.\n\n<Canvas of={DataGridStories.Interactive} />\n\n### Density — `ui-components-data-grid--density`\n\nRow density via `density` — toggle between `compact`, `standard`, and `comfortable`.\n\n<Canvas of={DataGridStories.Density} />\n\n## Accessibility\n\n- MUI DataGrid provides keyboard navigation for rows, cells, and selection.\n- Row checkboxes: native selection with `checkboxSelection`.\n- Search field: `PageHeader` / `EnhancedTextField` semantics when `showSearch` is enabled.\n- Pagination: MUI pagination controls are keyboard accessible.\n- **Status chips:** use `Chip` with text labels — never rely on color alone.\n- Row action trigger: `aria-label=\"Row actions\"` on the outlined 3-dot `IconButton` (`Interactive` pattern).\n- Toolbar refresh: `aria-label=\"Refresh\"` on refresh `IconButton` (implementation).\n- Storybook a11y addon: `test: 'todo'`.\n\n## Best Practices\n\n- Ship management grids with search, filters, applied filters, selection, pagination, and titled header (see `Interactive`).\n- Include total count in `tableHeader.title` for server and client datasets.\n- Use `showAppliedFilters: true` whenever `customToolbarFilters` is set.\n- Use tonal `Chip` for status columns; Avatar + Name for user columns.\n- Place primary CTA in `tableHeader.actions` (`variant=\"contained\"`).\n- Use `paginationMode=\"server\"` + `rowCount` for large datasets (`WithPaginationServerSide`).\n- Configure `listCellConfig` for readable mobile list rows; use `listViewColumn` only when the default layout isn't expressive enough.\n- Use `iconName` on column headers for consistent toolbar-style headers.\n\n## Anti-patterns\n\n- Bare grid for production management pages (no search, filters, or selection).\n- Plain text status when tonal `Chip` is available.\n- User names without `Avatar` when identity is shown.\n- Hiding active filters (`showAppliedFilters: false` with filters enabled).\n- Unpaginated large client-side row arrays.\n- Inline Edit/Delete icon buttons in the actions column (use 3-dot `Menu` instead).\n- Row action menu trigger without `aria-label`.\n- Inventing filter `type` values beyond `select`, `date-range`, `multi-select`.\n- Raw `@mui/x-data-grid-pro` when Exotel toolbar integration is needed.\n\n## Guidance for AI Agents\n\n**Read UX Constitution first** (Storybook Documentation → UX Constitution) before using this component doc.\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `DataGrid`\n\n- Management interfaces: users, campaigns, queues, agents, monitoring tables\n- Any list page needing search, filters, bulk actions, pagination\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Simple static table | `Table` |\n| Filter chips only (no grid) | `AppliedFilters` |\n| Page title without grid | `PageHeader` |\n\n### Default assumptions (unless told otherwise)\n\nAlways assume for management interfaces:\n\n- ✓ Search enabled (`tableHeader.showSearch`)\n- ✓ Filters enabled (`customToolbarFilters` + `showAppliedFilters`)\n- ✓ Bulk selection enabled (`checkboxSelection`)\n- ✓ Bulk actions enabled (`bulkDeleteConfig` and/or `customToolbarButtons`)\n- ✓ Pagination enabled (server-side for large datasets)\n- ✓ Total count in header title\n- ✓ Tonal `Chip` for status columns\n- ✓ Avatar + Name for single-user cells\n- ✓ Avatar group pattern for multi-user cells (up to 4 + overflow)\n- ✓ Responsive list view (`listCellConfig` or custom `listViewColumn`)\n\nOnly omit these when explicitly instructed.\n\n### Canonical management grid pattern\n\nSee the `Interactive` story for the full composition:\n\n```tsx\n<DataGrid\n  rows={rows}\n  rowCount={totalCount}           // server-side\n  columns={columns}               // renderCell: Avatar, Chip, actions\n  paginationMode=\"server\"\n  paginationModel={paginationModel}\n  onPaginationModelChange={setPaginationModel}\n  checkboxSelection\n  showAppliedFilters\n  customToolbarFilters={[\n    { id: 'status', type: 'select', label: 'Status', options: [...] },\n  ]}\n  onToolbarFiltersChange={setFilters}\n  bulkDeleteConfig={{\n    onDelete: handleBulkDelete,\n    label: (n) => `Delete ${n} Rows`,\n  }}\n  tableHeader={{\n    title: `Team Members (${totalCount})`,\n    showSearch: true,\n    searchType: 'basic',\n    onBasicSearch: setSearch,\n    actions: [\n      { id: 'add', children: 'Add Member', variant: 'contained', startIconProps: { name: 'plus' } },\n    ],\n  }}\n  listCellConfig={{\n    primaryField: 'name',\n    secondaryField: 'status',\n    excludeFields: ['id'],\n  }}\n  pageSizeOptions={[5, 10, 25]}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Full management header | `WithTableHeader` |\n| Server-side filters | `WithFiltersServerSide` |\n| Server-side pagination | `WithPaginationServerSide` |\n| Bulk delete + selection | `WithCheckboxBulkDelete` |\n| Custom toolbar buttons | `WithCustomToolbarButtons` |\n| No toolbar | `WithoutToolbar` |\n| Default mobile list | `DefaultListView` |\n| Custom mobile list | `CustomListView` |\n| Everything combined | `Interactive` |\n\n### Common mistakes to avoid\n\n- Shipping a bare grid without search/filters/selection for management UIs.\n- `title: 'Users'` without total count — use `` `Users (${totalCount})` ``.\n- `showAppliedFilters: false` when filters are active.\n- Plain string status column instead of tonal `Chip`.\n- Name-only user column without `Avatar`.\n- Forgetting `listCellConfig` (or a custom `listViewColumn`) for mobile readability.\n- Inventing built-in `AvatarGroup` DataGrid column — compose in `renderCell`.\n\n### Composition guidance\n\n- Header: `tableHeader` → `PageHeader` (search + CTAs above grid).\n- Toolbar: filters + bulk delete appear when rows selected.\n- Cells: `renderCell` for Avatar, Chip; row actions via outlined 3-dot `Menu` trigger.\n- Mobile: rely on wrapper `listView` + `listCellConfig` by default; pass a custom `listViewColumn` only when the row needs bespoke layout (`CustomListView`).\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `PageHeader` | `tableHeader` — title, search, CTAs |\n| `AppliedFilters` | Visible active filters bar |\n| `Chip` | Tonal status in cells |\n| `Avatar` | Single-user cell identity |\n| `Button` | Header CTAs and bulk actions |\n| `IconButton` + `Menu` | Row actions — 3-dot outlined trigger (`Interactive`) |\n| `MultiSelect` | Multi-select toolbar filters |\n| `DateRangePicker` | Date-range toolbar filter |\n| `Table` | Simple static tables |\n"}}},"ui-components-dialog":{"id":"ui-components-dialog","name":"Dialog","path":"./src/stories/ui-components/Dialog.stories.tsx","stories":[{"id":"ui-components-dialog--basic","name":"Basic","snippet":"const Basic = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog</Button>\n      <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth>\n        <DialogTitle>\n          Heading\n          <IconButton\n            edge=\"end\"\n            onClick={() => setOpen(false)}\n            aria-label=\"close dialog\"\n            size=\"small\"\n            sx={{\n              color: 'text.primary',\n              '& svg': {\n                color: 'inherit',\n              },\n            }}\n          >\n            <Icon name=\"x\" size=\"sm\" />\n          </IconButton>\n        </DialogTitle>\n        <DialogContent dividers>\n          <Typography variant=\"body2\">\n            This is the body content of the dialog. You can add any content here,\n            such as forms, lists, or other components.\n          </Typography>\n        </DialogContent>\n        <DialogActions>\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Save and Dial\n          </Button>\n        </DialogActions>\n      </Dialog>\n    </Box>\n  );\n};","description":"Basic dialog with structured layout"},{"id":"ui-components-dialog--with-form","name":"With Form","snippet":"const WithForm = () => {\n  const [open, setOpen] = useState(false);\n  const [channel, setChannel] = useState('whatsapp');\n  const [number, setNumber] = useState('9876543210');\n  const [template, setTemplate] = useState('Hi {Customer name} can we connect ?');\n\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Form Dialog</Button>\n      <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth>\n        <DialogTitle>\n          Heading\n          <IconButton\n            edge=\"end\"\n            onClick={() => setOpen(false)}\n            aria-label=\"close dialog\"\n            size=\"small\"\n            sx={{\n              color: 'text.primary',\n              '& svg': {\n                color: 'inherit',\n              },\n            }}\n          >\n            <Icon name=\"x\" size=\"sm\" />\n          </IconButton>\n        </DialogTitle>\n        <DialogContent dividers>\n          {/* Channel Selection */}\n          <Box sx={{ mb: 3 }}>\n            <Typography variant=\"body2\" sx={{ mb: 2, fontWeight: 500 }}>\n              Channel\n            </Typography>\n            <FormControl>\n              <RadioGroup\n                value={channel}\n                onChange={(e) => setChannel(e.target.value)}\n                row\n              >\n                <FormControlLabel value=\"call\" control={<Radio />} label=\"Call\" />\n                <FormControlLabel\n                  value=\"whatsapp\"\n                  control={<Radio />}\n                  label=\"WhatsApp Chat\"\n                />\n              </RadioGroup>\n            </FormControl>\n          </Box>\n\n          {/* Note */}\n          <Box\n            sx={{\n              p: 2,\n              mb: 3,\n              backgroundColor: 'action.hover',\n              borderRadius: 1,\n            }}\n          >\n            <Typography variant=\"body3\" color=\"text.secondary\">\n              Note : Please ensure the selected number is available on WhatsApp\n            </Typography>\n          </Box>\n\n          {/* Number Input */}\n          <Box sx={{ mb: 3 }}>\n            <TextField\n              fullWidth\n              label=\"Enter or select number\"\n              value={number}\n              onChange={(e) => setNumber(e.target.value)}\n            />\n          </Box>\n\n          {/* Template Text Area */}\n          <Box>\n            <TextField\n              fullWidth\n              label=\"Select Template\"\n              multiline\n              rows={4}\n              value={template}\n              onChange={(e) => setTemplate(e.target.value)}\n            />\n          </Box>\n        </DialogContent>\n        <DialogActions>\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Save and Dial\n          </Button>\n        </DialogActions>\n      </Dialog>\n    </Box>\n  );\n};","description":"Dialog with form content (matching Figma design)"},{"id":"ui-components-dialog--scrollable-body","name":"Scrollable Body","snippet":"const ScrollableBody = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Scrollable Dialog</Button>\n      <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth>\n        <DialogTitle>\n          Long Content Example\n          <IconButton\n            edge=\"end\"\n            onClick={() => setOpen(false)}\n            aria-label=\"close dialog\"\n            size=\"small\"\n            sx={{\n              color: 'text.primary',\n              '& svg': {\n                color: 'inherit',\n              },\n            }}\n          >\n            <Icon name=\"x\" size=\"sm\" />\n          </IconButton>\n        </DialogTitle>\n        <DialogContent dividers>\n          {Array.from({ length: 50 }, (_, i) => (\n            <Typography key={i} variant=\"body2\" sx={{ mb: 2 }}>\n              This is paragraph {i + 1}. The body section should scroll when\n              content overflows, while the header and footer remain fixed.\n            </Typography>\n          ))}\n        </DialogContent>\n        <DialogActions>\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Save\n          </Button>\n        </DialogActions>\n      </Dialog>\n    </Box>\n  );\n};","description":"Dialog with long, scrollable body"},{"id":"ui-components-dialog--without-header","name":"Without Header","snippet":"const WithoutHeader = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog (No Header)</Button>\n      <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth>\n        <DialogContent dividers>\n          <Typography variant=\"body2\">\n            This dialog does not have a header. The close button is not rendered\n            when the header is hidden. Users must use the footer action or click\n            outside to close.\n          </Typography>\n        </DialogContent>\n        <DialogActions>\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Continue\n          </Button>\n        </DialogActions>\n      </Dialog>\n    </Box>\n  );\n};","description":"Dialog without header"},{"id":"ui-components-dialog--without-footer","name":"Without Footer","snippet":"const WithoutFooter = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog (No Footer)</Button>\n      <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth>\n        <DialogTitle>\n          Information Dialog\n          <IconButton\n            edge=\"end\"\n            onClick={() => setOpen(false)}\n            aria-label=\"close dialog\"\n            size=\"small\"\n            sx={{\n              color: 'text.primary',\n              '& svg': {\n                color: 'inherit',\n              },\n            }}\n          >\n            <Icon name=\"x\" size=\"sm\" />\n          </IconButton>\n        </DialogTitle>\n        <DialogContent dividers>\n          <Typography variant=\"body2\">\n            This dialog does not have a footer. It's useful for informational\n            dialogs where the only action is to close via the header close button\n            or backdrop click.\n          </Typography>\n        </DialogContent>\n      </Dialog>\n    </Box>\n  );\n};","description":"Dialog without footer"},{"id":"ui-components-dialog--multiple-footer-actions","name":"Multiple Footer Actions","snippet":"const MultipleFooterActions = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog (Multiple Actions)</Button>\n      <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth>\n        <DialogTitle>\n          Confirm Action\n          <IconButton\n            edge=\"end\"\n            onClick={() => setOpen(false)}\n            aria-label=\"close dialog\"\n            size=\"small\"\n            sx={{\n              color: 'text.primary',\n              '& svg': {\n                color: 'inherit',\n              },\n            }}\n          >\n            <Icon name=\"x\" size=\"sm\" />\n          </IconButton>\n        </DialogTitle>\n        <DialogContent dividers>\n          <Typography variant=\"body2\">\n            This dialog has multiple actions in the footer. Notice there's no\n            default Cancel button - the close (×) button is the primary dismissal\n            action.\n          </Typography>\n        </DialogContent>\n        <DialogActions>\n          <Button variant=\"outlined\" color=\"error\" onClick={() => setOpen(false)}>\n            Delete\n          </Button>\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Save Changes\n          </Button>\n        </DialogActions>\n      </Dialog>\n    </Box>\n  );\n};","description":"Dialog with multiple footer actions"},{"id":"ui-components-dialog--small-dialog","name":"Small Dialog","snippet":"const SmallDialog = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Small Dialog</Button>\n      <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth>\n        <DialogTitle>\n          Confirmation\n          <IconButton\n            edge=\"end\"\n            onClick={() => setOpen(false)}\n            aria-label=\"close dialog\"\n            size=\"small\"\n            sx={{\n              color: 'text.primary',\n              '& svg': {\n                color: 'inherit',\n              },\n            }}\n          >\n            <Icon name=\"x\" size=\"sm\" />\n          </IconButton>\n        </DialogTitle>\n        <DialogContent dividers>\n          <Typography variant=\"body2\">\n            Are you sure you want to proceed with this action?\n          </Typography>\n        </DialogContent>\n        <DialogActions>\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Confirm\n          </Button>\n        </DialogActions>\n      </Dialog>\n    </Box>\n  );\n};","description":"Small dialog with minimal content"},{"id":"ui-components-dialog--legacy","name":"Legacy","snippet":"const Legacy = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Legacy Dialog</Button>\n      <Dialog open={open} onClose={() => setOpen(false)}>\n        <Box sx={{ p: 3 }}>\n          <Typography variant=\"h6\" gutterBottom>\n            Legacy Dialog\n          </Typography>\n          <Typography variant=\"body2\">\n            This is a legacy dialog without structured layout. All existing\n            Dialog usage patterns continue to work.\n          </Typography>\n          <Box sx={{ mt: 2, display: 'flex', justifyContent: 'flex-end', gap: 2 }}>\n            <Button variant=\"outlined\" onClick={() => setOpen(false)}>\n              Cancel\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen(false)}>\n              OK\n            </Button>\n          </Box>\n        </Box>\n      </Dialog>\n    </Box>\n  );\n};","description":"Legacy dialog (backward compatibility)"}],"import":"import {\n    Box,\n    Button,\n    Dialog,\n    FormControl,\n    Icon,\n    IconButton,\n    Radio,\n    EnhancedTextField as TextField,\n    Typography,\n} from \"@exotel-npm-dev/signal-design-system\";\nimport { DialogActions, DialogContent, DialogTitle, FormControlLabel, RadioGroup } from \"@mui/material\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Dialog","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Dialog/Dialog.tsx","actualName":"Dialog","exportName":"Dialog","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-dialog--docs":{"id":"ui-components-dialog--docs","name":"Docs","path":"./src/stories/ui-components/Dialog.mdx","title":"UI Components/Dialog","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DialogStories from './Dialog.stories';\nimport { Dialog } from '../../components/Dialog';\n\n<Meta of={DialogStories} />\n\n# Dialog\n\n## Overview\n\n`Dialog` is the Signal Design System wrapper around MUI `Dialog`. It applies responsive `maxHeight` constraints (90vh on mobile and tablet, 80vh on desktop) and flex column layout on the paper surface so header, body, and footer regions scroll predictably.\n\nCompose with MUI `DialogTitle`, `DialogContent`, and `DialogActions` for the Exotel Header / Body / Footer pattern. These subcomponents are **not** Signal wrappers — import them from `@mui/material` (as in stories) or use `StructuredDialog` for a built-in structured API.\n\n> **UX Constitution:** See **Interaction Patterns → Dialog Usage Rules** (confirmations and destructive actions only — not settings or long forms).\n\n```tsx\nimport { Dialog, Button, IconButton, Icon } from '@exotel-npm-dev/signal-design-system';\nimport { DialogTitle, DialogContent, DialogActions } from '@mui/material';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling. Theme overrides in [`theme.ts`](../../theme/theme.ts) style `MuiDialogTitle`, `MuiDialogContent`, and `MuiDialogActions` to match Drawer header/footer tokens.\n\n**When to use**\n\n- Centered modal overlays that block interaction with the page beneath\n- Custom dialog composition where you control every section manually\n- Confirmation, forms, or focused tasks requiring user attention\n\n**When not to use**\n\n- Standard Exotel modal with built-in header/body/footer API → use `StructuredDialog`\n- Off-canvas side panel → use `Drawer`\n- Brief auto-dismissing global feedback → use `Snackbar` (with `Alert` child)\n- Persistent inline messages → use `Alert`\n\n## Anatomy\n\nSignal does not provide `DialogHeader` or `DialogBody` subcomponents on `Dialog`. Use MUI composition:\n\n```\nDialog                       ← Signal wrapper (responsive maxHeight)\n├── DialogTitle (optional)   ← MUI header; title + close IconButton\n├── DialogContent              ← MUI scrollable body; use dividers prop\n└── DialogActions (optional)   ← MUI footer; trailing Button actions\n```\n\nCanonical structured layout (from `Basic` story):\n\n```tsx\n<Dialog open={open} onClose={handleClose} maxWidth=\"sm\" fullWidth>\n  <DialogTitle>\n    Heading\n    <IconButton\n      edge=\"end\"\n      onClick={handleClose}\n      aria-label=\"close dialog\"\n      size=\"small\"\n    >\n      <Icon name=\"x\" size=\"sm\" />\n    </IconButton>\n  </DialogTitle>\n  <DialogContent dividers>\n    {/* body content */}\n  </DialogContent>\n  <DialogActions>\n    <Button variant=\"contained\" onClick={handleClose}>\n      Save and Dial\n    </Button>\n  </DialogActions>\n</Dialog>\n```\n\n## Content guidelines\n\nRules for writing dialog copy in Exotel ECC and other Signal products.\n\n### Title (`DialogTitle`)\n\n| Principle | Rule |\n|-----------|------|\n| Task-focused | Name the action or object: \"Confirm deletion\", \"Create email settings\" |\n| Concise | 1–5 words; sentence case |\n| No punctuation | Omit trailing periods in titles |\n| Specific | \"Confirm action\" only when the body carries detail |\n\n**Canonical titles from stories:** \"Heading\", \"Long Content Example\", \"Confirm Action\", \"Confirmation\", \"Information Dialog\".\n\n### Body (`DialogContent`)\n\n| Principle | Rule |\n|-----------|------|\n| Lead with context | State what the user is doing or deciding in the first sentence |\n| Scannable | Use `Typography variant=\"body2\"` for body copy; section labels use `fontWeight: 500` |\n| Notes | Inline notes use `body3` + `text.secondary` in a tinted `action.hover` box (see `WithForm`) |\n| Form labels | Use `EnhancedTextField` with external labels; field labels are nouns (\"Enter or select number\") |\n\n**Example note copy from `WithForm`:** \"Note : Please ensure the selected number is available on WhatsApp\"\n\n### Footer actions (`DialogActions`)\n\n| Principle | Rule |\n|-----------|------|\n| Commit verb | Primary button names the outcome: \"Save\", \"Confirm\", \"Save and Dial\", \"Save Changes\" |\n| Dismiss | When no header close is available, provide \"Cancel\" or \"Continue\" explicitly |\n| Destructive | Use `color=\"error\"` on delete buttons; name the action (\"Delete\") |\n| Placement | Trailing (right in LTR): primary commit; leading: dismiss or destructive secondary |\n\n**Canonical footer pairs from stories:**\n\n```\n[Delete]  [Save Changes]     ← MultipleFooterActions (destructive leading)\n[Save and Dial]                ← Basic, WithForm (single primary; × dismisses)\n[Confirm]                      ← SmallDialog\n[Continue]                     ← WithoutHeader\n[Cancel]  [OK]                 ← Legacy (avoid \"OK\" in new work)\n```\n\n### Do and don't\n\n**Do**\n\n- \"Save and Dial\"\n- \"Save Changes\"\n- \"Confirm\"\n- \"Are you sure you want to proceed with this action?\" (body question)\n\n**Don't**\n\n- \"OK\" / \"Yes\" in new dialogs (Legacy story only)\n- Empty `DialogTitle` with critical instructions only in body\n- Multiple competing `variant=\"contained\"` primaries without hierarchy\n- Long titles that wrap awkwardly on mobile\n\n### Guidance for AI-generated dialog copy\n\n- Generate titles as task nouns or imperatives: \"Confirm action\", \"Create configuration\".\n- Body copy: 1–3 sentences max for confirmation dialogs; use scrollable body for long forms.\n- Primary footer label = specific verb + object when possible (\"Save Changes\", not \"Submit\").\n- When only one footer button exists, rely on header `IconButton` with `aria-label=\"close dialog\"` for dismiss (see `Basic`, `MultipleFooterActions` story notes).\n- Destructive flows: `Button variant=\"outlined\" color=\"error\"` for delete, `variant=\"contained\"` for save/commit.\n\n## Props\n\n`DialogProps` extends MUI `DialogProps` (minus `ref`). All MUI props pass through via spread.\n\n### Signal-specific behavior\n\n| Behavior | Implementation | Notes |\n|----------|----------------|-------|\n| Responsive `maxHeight` | `90vh` mobile/tablet, `80vh` desktop | Applied via `PaperProps.sx` in `Dialog.tsx` |\n| Flex column paper | `display: 'flex'`, `flexDirection: 'column'` | Enables fixed header/footer with scrollable body |\n| Paper margin | `theme.spacing(2)` | Consistent inset from viewport edges |\n\n### Props documented in stories argTypes\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `open` | `boolean` | `false` | Controls dialog visibility | Parent state required; pair with `onClose` |\n| `fullWidth` | `boolean` | `false` | Stretches paper to `maxWidth` | Use `true` with `maxWidth=\"sm\"` in structured stories |\n| `maxWidth` | `'xs' \\| 'sm' \\| 'md' \\| 'lg' \\| 'xl' \\| false` | `'sm'` | Maximum paper width breakpoint | Stories use `maxWidth=\"sm\"`; `SmallDialog` story name references minimal content, not `maxWidth=\"xs\"` |\n\n### Props used in stories (not in argTypes)\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `onClose` | `(event, reason?) => void` | Fires on backdrop click, Escape, or programmatic close | Required for dismissible dialogs |\n| `PaperProps` | `object` | MUI paper props | Signal merges `sx` for maxHeight; extend via `PaperProps.sx` |\n\nAdditional standard MUI `DialogProps` pass through (e.g. `scroll`, `disableEscapeKeyDown`, `aria-*`). See the generated table below for the full API.\n\n<ArgTypes of={Dialog} />\n\n## Variants\n\n`Dialog` has no visual variants. Layout variation comes from composition:\n\n| Pattern | Structure | Story |\n|---------|-----------|-------|\n| Full structure | Title + Content + Actions | `Basic`, `WithForm`, `ScrollableBody` |\n| No header | Content + Actions only | `WithoutHeader` |\n| No footer | Title + Content only | `WithoutFooter` |\n| Multiple footer actions | Title + Content + multiple Buttons | `MultipleFooterActions` |\n| Legacy flat layout | Single `Box` with inline padding | `Legacy` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Closed | `open={false}` | Default; trigger opens via parent state |\n| Open | `open={true}` | Focus trapped inside dialog (MUI default) |\n| Scrollable body | Long content in `DialogContent` | Header and footer remain fixed; body scrolls (`ScrollableBody`) |\n| Without header | Omit `DialogTitle` | No close button; dismiss via footer or backdrop (`WithoutHeader`) |\n| Without footer | Omit `DialogActions` | Dismiss via header close or backdrop (`WithoutFooter`) |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Open / close | Parent `useState` + `open` / `onClose` | All stories |\n| Header close | `IconButton` with `aria-label=\"close dialog\"` + `Icon name=\"x\"` | `Basic`, `WithForm`, etc. |\n| Scrollable overflow | `DialogContent` with `flex: 1`, `overflowY: auto` (theme) | `ScrollableBody` |\n| Form in dialog | `EnhancedTextField`, `RadioGroup`, section `Typography` | `WithForm` |\n| Backdrop dismiss | MUI `onClose` with `reason: 'backdropClick'` | Default MUI behavior |\n| Escape dismiss | MUI `onClose` with `reason: 'escapeKeyDown'` | Default MUI behavior |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-dialog--basic`\n\nStructured dialog with `DialogTitle` (heading + close button), `DialogContent dividers`, and single `DialogActions` button \"Save and Dial\". `maxWidth=\"sm\" fullWidth`.\n\n**Recommended usage:** Standard modal with header dismiss and one primary commit action.\n\n<Canvas of={DialogStories.Basic} />\n\n### WithForm\n\n**Story ID:** `ui-components-dialog--with-form`\n\nForm dialog with channel `RadioGroup`, informational note box, `EnhancedTextField` for number and template. Footer: \"Save and Dial\".\n\n**Recommended usage:** Multi-field modal workflows (ECC dial-out, messaging templates).\n\n<Canvas of={DialogStories.WithForm} />\n\n### ScrollableBody\n\n**Story ID:** `ui-components-dialog--scrollable-body`\n\n50 paragraphs in `DialogContent` demonstrating body scroll with fixed header/footer. Footer: \"Save\".\n\n**Recommended usage:** Long content modals where header and footer must remain visible.\n\n<Canvas of={DialogStories.ScrollableBody} />\n\n### WithoutHeader\n\n**Story ID:** `ui-components-dialog--without-header`\n\nNo `DialogTitle`; body explains dismiss via footer or backdrop. Footer: \"Continue\".\n\n**Recommended usage:** Simple prompts where a title bar is unnecessary.\n\n<Canvas of={DialogStories.WithoutHeader} />\n\n### WithoutFooter\n\n**Story ID:** `ui-components-dialog--without-footer`\n\nHeader + body only; dismiss via header close or backdrop click. Title: \"Information Dialog\".\n\n**Recommended usage:** Informational modals with no commit action.\n\n<Canvas of={DialogStories.WithoutFooter} />\n\n### MultipleFooterActions\n\n**Story ID:** `ui-components-dialog--multiple-footer-actions`\n\nFooter with `Delete` (`variant=\"outlined\" color=\"error\"`) and `Save Changes` (`variant=\"contained\"`). Header × is primary dismiss.\n\n**Recommended usage:** Destructive + commit pairs without a separate Cancel button.\n\n<Canvas of={DialogStories.MultipleFooterActions} />\n\n### SmallDialog\n\n**Story ID:** `ui-components-dialog--small-dialog`\n\nMinimal confirmation copy with single \"Confirm\" button. Title: \"Confirmation\".\n\n**Recommended usage:** Short yes/no style confirmations with one commit action.\n\n<Canvas of={DialogStories.SmallDialog} />\n\n### Legacy\n\n**Story ID:** `ui-components-dialog--legacy`\n\nUnstructured layout: padded `Box` with inline title, body, and `Cancel` + `OK` buttons. No `DialogTitle`/`DialogContent`/`DialogActions`.\n\n**Recommended usage:** Backward compatibility only; prefer structured layout for new work.\n\n<Canvas of={DialogStories.Legacy} />\n\n## Accessibility\n\n- MUI `Dialog` renders with `role=\"dialog\"` and `aria-modal=\"true\"` by default.\n- Focus is trapped inside the dialog while open (MUI default).\n- Header close `IconButton` must include `aria-label=\"close dialog\"` (all structured stories do).\n- `DialogTitle` should contain the dialog accessible name; use visible title text.\n- `onClose` handles Escape key and backdrop click unless `disableEscapeKeyDown` is set.\n- Footer buttons use visible text labels from `Button` children for accessible names.\n- No custom ARIA logic in the Signal wrapper; standard MUI `aria-*` props pass through.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Use `maxWidth=\"sm\" fullWidth` for standard ECC modals (matches stories).\n- Always provide a dismiss path: header close button, footer Cancel, or explicit single-action pattern.\n- Use `DialogContent dividers` for structured layout so theme padding and scroll apply correctly.\n- Place primary commit on the trailing side in `DialogActions`.\n- Use `StructuredDialog` when you do not need custom MUI composition.\n- Import `Dialog` from `@exotel-npm-dev/signal-design-system`; import `DialogTitle`, `DialogContent`, `DialogActions` from `@mui/material`.\n- Wrap the application in `ExotelThemeProvider`.\n\n## Anti-patterns\n\n- Using `Dialog` when `StructuredDialog` covers the same layout with less boilerplate.\n- Omitting dismiss affordance in both header and footer (`WithoutHeader` must have footer action).\n- Using \"OK\" for primary actions in new dialogs (see `Legacy` only).\n- Multiple `variant=\"contained\"` buttons with equal emphasis and no clear primary.\n- Importing `@mui/material/Dialog` directly in consumer apps — use Signal `Dialog`.\n- Inventing `showHeader` / `showFooter` props on `Dialog` — those exist on `StructuredDialog` only.\n- Hardcoding viewport height instead of relying on Signal's responsive `maxHeight`.\n\n## Guidance for AI Agents\n\n**Read UX Constitution first** (Interaction Patterns → Dialog Usage Rules).\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `Dialog`\n\n- Custom MUI composition with full control over `DialogTitle`, `DialogContent`, `DialogActions`\n- Legacy patterns that cannot migrate to `StructuredDialog` yet\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Standard Exotel header/body/footer modal | `StructuredDialog` |\n| Off-canvas form or filter panel | `Drawer` |\n| Transient toast notification | `Snackbar` + `Alert` |\n| Inline persistent message | `Alert` |\n\n### Canonical prop combinations\n\nCopy these patterns from stories. Do not invent alternatives.\n\n```tsx\n// Structured modal — story: Basic\n<Dialog open={open} onClose={handleClose} maxWidth=\"sm\" fullWidth>\n  <DialogTitle>\n    Heading\n    <IconButton edge=\"end\" onClick={handleClose} aria-label=\"close dialog\" size=\"small\">\n      <Icon name=\"x\" size=\"sm\" />\n    </IconButton>\n  </DialogTitle>\n  <DialogContent dividers>{/* body */}</DialogContent>\n  <DialogActions>\n    <Button variant=\"contained\" onClick={handleClose}>Save and Dial</Button>\n  </DialogActions>\n</Dialog>\n\n// Destructive + commit — story: MultipleFooterActions\n<DialogActions>\n  <Button variant=\"outlined\" color=\"error\" onClick={handleDelete}>Delete</Button>\n  <Button variant=\"contained\" onClick={handleSave}>Save Changes</Button>\n</DialogActions>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default structured modal | `Basic` (`ui-components-dialog--basic`) |\n| Form inside modal | `WithForm` |\n| Long scrollable content | `ScrollableBody` |\n| No header | `WithoutHeader` |\n| No footer | `WithoutFooter` |\n| Delete + save footer | `MultipleFooterActions` |\n| Simple confirmation | `SmallDialog` |\n\n### Common mistakes to avoid\n\n- Do not import `DialogTitle` from the design system package — it is not exported; use `@mui/material`.\n- Do not omit `open` and `onClose` state management.\n- Do not use `StructuredDialog` props (`title`, `showFooter`) on raw `Dialog`.\n- Do not invent `maxWidth` values not in MUI's API.\n- Do not skip `aria-label` on the header close `IconButton`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `StructuredDialog` | Built-in Header/Body/Footer API on the same MUI Dialog primitive |\n| `Drawer` | Off-canvas panel with similar header/body/footer structure |\n| `Button` | Footer commit and dismiss actions |\n| `IconButton` / `Icon` | Header close control (`name=\"x\"`) |\n| `EnhancedTextField` | Form fields inside dialog body (`WithForm`) |\n| `Alert` | Inline messages; not a dialog replacement |\n| `Snackbar` | Transient feedback after dialog actions complete |\n"}}},"ui-components-divider":{"id":"ui-components-divider","name":"Divider","path":"./src/stories/ui-components/Divider.stories.tsx","stories":[{"id":"ui-components-divider--default","name":"Default","snippet":"const Default = () => <Divider />;"},{"id":"ui-components-divider--with-text","name":"With Text","snippet":"const WithText = () => <Divider>OR</Divider>;"},{"id":"ui-components-divider--with-chip","name":"With Chip","snippet":"const WithChip = () => (\n  <Box sx={{ width: 400 }}>\n    <Divider>\n      <Chip label=\"Section\" size=\"small\" />\n    </Divider>\n  </Box>\n);"},{"id":"ui-components-divider--variants","name":"Variants","snippet":"const Variants = () => (\n  <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>\n    <Typography variant=\"caption\" color=\"text.secondary\">fullWidth</Typography>\n    <Divider variant=\"fullWidth\" />\n    <Typography variant=\"caption\" color=\"text.secondary\">inset</Typography>\n    <Divider variant=\"inset\" />\n    <Typography variant=\"caption\" color=\"text.secondary\">middle</Typography>\n    <Divider variant=\"middle\" />\n  </Box>\n);"},{"id":"ui-components-divider--vertical","name":"Vertical","snippet":"const Vertical = () => (\n  <Box sx={{ display: 'flex', alignItems: 'center', gap: 2, height: 40 }}>\n    <Typography variant=\"body2\">Item 1</Typography>\n    <Divider orientation=\"vertical\" flexItem />\n    <Typography variant=\"body2\">Item 2</Typography>\n    <Divider orientation=\"vertical\" flexItem />\n    <Typography variant=\"body2\">Item 3</Typography>\n  </Box>\n);"},{"id":"ui-components-divider--text-alignment","name":"Text Alignment","snippet":"const TextAlignment = () => (\n  <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>\n    <Divider textAlign=\"left\">Left</Divider>\n    <Divider textAlign=\"center\">Center</Divider>\n    <Divider textAlign=\"right\">Right</Divider>\n  </Box>\n);"}],"import":"import { Box, Chip, Divider, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Divider","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Divider/Divider.tsx","actualName":"Divider","exportName":"Divider","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-divider--docs":{"id":"ui-components-divider--docs","name":"Docs","path":"./src/stories/ui-components/Divider.mdx","title":"UI Components/Divider","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DividerStories from './Divider.stories';\nimport { Divider } from '../../components/Divider';\n\n<Meta of={DividerStories} />\n\n# Divider\n\n## Overview\n\n`Divider` wraps MUI `Divider` for horizontal or vertical separation between content. A thin line that groups content in lists and layouts.\n\n```tsx\nimport { Divider } from '@exotel-npm-dev/signal-design-system';\n```\n\nAlso exported as `ListDivider` from the List suite for list-specific usage.\n\n**When to use**\n\n- Separate list groups, menu sections, form sections\n- Visual break between content areas in cards or panels\n- Inline separation between horizontal items (vertical orientation)\n\n**When not to use**\n\n- Large layout gaps → use `Stack` spacing or `Box` padding\n- Decorative borders → use `Box` `border` or `sx`\n- Section headings → use `Typography` with spacing\n\n## Props\n\n<ArgTypes of={Divider} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `orientation` | `'horizontal' \\| 'vertical'` | `'horizontal'` | The component orientation |\n| `variant` | `'fullWidth' \\| 'inset' \\| 'middle'` | `'fullWidth'` | Controls indentation of the divider |\n| `textAlign` | `'center' \\| 'left' \\| 'right'` | `'center'` | Text alignment when children are provided |\n| `flexItem` | `boolean` | `false` | If true, the divider spans the flex container (needed for vertical in flex) |\n| `light` | `boolean` | `false` | If true, the divider has a lighter color |\n| `children` | `ReactNode` | — | Content rendered within the divider (text or Chip) |\n\n## Stories\n\n### Default\n\nBasic horizontal full-width divider.\n\n<Canvas of={DividerStories.Default} />\n\n### WithText\n\nDivider with centered text content (\"OR\").\n\n<Canvas of={DividerStories.WithText} />\n\n### WithChip\n\nDivider with a `Chip` component as content for section labeling.\n\n<Canvas of={DividerStories.WithChip} />\n\n### Variants\n\nComparison of `fullWidth`, `inset`, and `middle` variants.\n\n<Canvas of={DividerStories.Variants} />\n\n### Vertical\n\nVertical divider separating inline items within a flex container.\n\n<Canvas of={DividerStories.Vertical} />\n\n### TextAlignment\n\nDividers with left, center, and right text alignment.\n\n<Canvas of={DividerStories.TextAlignment} />\n\n## Best Practices\n\n- Use `variant=\"inset\"` in lists to align with `ListItemText` indentation.\n- Use `variant=\"middle\"` for subtle separation with side padding.\n- Add `flexItem` when using vertical orientation inside a flex container.\n- Use children (text or Chip) sparingly — most dividers should be plain lines.\n- Prefer `Stack` spacing over dividers when content sections don't need visual separation.\n\n## Accessibility\n\n- Renders as an `<hr>` element with implicit `separator` role.\n- When `children` are provided, MUI sets `role=\"presentation\"` since it's no longer a pure separator.\n- No additional ARIA attributes needed for standard usage.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `List` / `ListDivider` | List-specific divider exported from the List module |\n| `Menu` | Menu sections often use Divider between groups |\n| `Stack` | Spacing between elements without visual lines |\n| `Chip` | Can be embedded inside a Divider for section labels |\n"}}},"ui-components-drawer":{"id":"ui-components-drawer","name":"Drawer","path":"./src/stories/ui-components/Drawer.stories.tsx","stories":[{"id":"ui-components-drawer--basic","name":"Basic","snippet":"const Basic = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Drawer</Button>\n      <Drawer\n        anchor=\"right\"\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Create Email Settings\"\n        footerActions={\n          <>\n            <Button variant=\"outlined\" color=\"error\" onClick={() => setOpen(false)}>\n              Cancel\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen(false)}>\n              Create Configuration\n            </Button>\n          </>\n        }\n      >\n        <Typography variant=\"body2\" sx={{ mb: 2 }}>\n          This is the body content of the drawer. You can add any content here,\n          such as forms, lists, or other components.\n        </Typography>\n      </Drawer>\n    </Box>\n  );\n};","description":"Basic Drawer with header, body, and footer"},{"id":"ui-components-drawer--scrollable-body","name":"Scrollable Body","snippet":"const ScrollableBody = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Scrollable Drawer</Button>\n      <Drawer\n        anchor=\"right\"\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Long Content Example\"\n        footerActions={\n          <>\n            <Button variant=\"outlined\" color=\"error\" onClick={() => setOpen(false)}>\n              Cancel\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen(false)}>\n              Save\n            </Button>\n          </>\n        }\n      >\n        {Array.from({ length: 50 }, (_, i) => (\n          <Typography key={i} variant=\"body2\" sx={{ mb: 2 }}>\n            This is paragraph {i + 1}. The body section should scroll when\n            content overflows, while the header and footer remain fixed.\n          </Typography>\n        ))}\n      </Drawer>\n    </Box>\n  );\n};","description":"Drawer with long, scrollable body"},{"id":"ui-components-drawer--with-form","name":"With Form","snippet":"const WithForm = () => {\n  const [open, setOpen] = useState(false);\n  const [value, setValue] = useState('smtp');\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Form Drawer</Button>\n      <Drawer\n        anchor=\"right\"\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Create Email Settings\"\n        footerActions={\n          <>\n            <Button variant=\"outlined\" color=\"error\" onClick={() => setOpen(false)}>\n              Cancel\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen(false)}>\n              Create Configuration\n            </Button>\n          </>\n        }\n      >\n        {/* Basic Information Section */}\n        <Box sx={{ mb: 4 }}>\n          <Typography variant=\"h6\" sx={{ mb: 1 }}>\n            Basic Information\n          </Typography>\n          <Typography variant=\"body3\" color=\"text.secondary\" sx={{ mb: 2 }}>\n            Enter the core information to define and identify your Email Settings\n          </Typography>\n          <TextField\n            fullWidth\n            label=\"Entity Name\"\n            required\n            placeholder=\"Entity Name*\"\n            sx={{ mb: 2 }}\n          />\n        </Box>\n\n        <Divider sx={{ mb: 4 }} />\n\n        {/* SMTP Server Settings Section */}\n        <Box sx={{ mb: 4 }}>\n          <Typography variant=\"h6\" sx={{ mb: 1 }}>\n            SMTP Server Settings\n          </Typography>\n          <Typography variant=\"body3\" color=\"text.secondary\" sx={{ mb: 2 }}>\n            Provided by your email service eg: smtp.example.com\n          </Typography>\n          <TextField\n            fullWidth\n            label=\"SMTP Host\"\n            placeholder=\"SMTP Host\"\n            sx={{ mb: 2 }}\n          />\n          <Typography variant=\"body3\" color=\"text.secondary\" sx={{ mb: 2, ml: 1 }}>\n            Provided by your email service eg: smtp.example.com\n          </Typography>\n          <TextField\n            fullWidth\n            label=\"Port\"\n            placeholder=\"Port\"\n            sx={{ mb: 2 }}\n          />\n          <Typography variant=\"body3\" color=\"text.secondary\" sx={{ mb: 2, ml: 1 }}>\n            eg: 587\n          </Typography>\n          <FormControl sx={{ mb: 2 }}>\n            <RadioGroup\n              value={value}\n              onChange={(e) => setValue(e.target.value)}\n              row\n            >\n              <FormControlLabel value=\"smtp\" control={<Radio />} label=\"SMTP\" />\n              <FormControlLabel value=\"smtps\" control={<Radio />} label=\"SMTPS\" />\n            </RadioGroup>\n          </FormControl>\n          <Typography variant=\"body3\" color=\"text.secondary\" sx={{ ml: 1 }}>\n            Note: Choose SMTPS if your server requires SSL/TLS\n          </Typography>\n        </Box>\n\n        <Divider sx={{ mb: 4 }} />\n\n        {/* Authentication Credentials Section */}\n        <Box>\n          <Typography variant=\"h6\" sx={{ mb: 1 }}>\n            Authentication Credentials\n          </Typography>\n          <Typography variant=\"body3\" color=\"text.secondary\" sx={{ mb: 2 }}>\n            Enter the credentials used to authenticate with your email server\n          </Typography>\n          <TextField\n            fullWidth\n            label=\"Username\"\n            required\n            placeholder=\"Username*\"\n            sx={{ mb: 2 }}\n          />\n          <TextField\n            fullWidth\n            label=\"Password\"\n            type=\"password\"\n            required\n            placeholder=\"Password*\"\n          />\n        </Box>\n      </Drawer>\n    </Box>\n  );\n};","description":"Drawer with form content (matching Figma design)"},{"id":"ui-components-drawer--footer-variations","name":"Footer Variations","snippet":"const FooterVariations = () => {\n  const [open1, setOpen1] = useState(false);\n  const [open2, setOpen2] = useState(false);\n  const [open3, setOpen3] = useState(false);\n  return (\n    <Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>\n      <Button onClick={() => setOpen1(true)}>Primary Only</Button>\n      <Button onClick={() => setOpen2(true)}>Cancel + Primary</Button>\n      <Button onClick={() => setOpen3(true)}>Multiple Actions</Button>\n\n      {/* Primary action only */}\n      <Drawer\n        anchor=\"right\"\n        open={open1}\n        onClose={() => setOpen1(false)}\n        title=\"Primary Action Only\"\n        footerActions={\n          <Button variant=\"contained\" onClick={() => setOpen1(false)}>\n            Save\n          </Button>\n        }\n      >\n        <Typography variant=\"body2\">\n          This drawer has only a primary action button in the footer.\n        </Typography>\n      </Drawer>\n\n      {/* Cancel + Primary */}\n      <Drawer\n        anchor=\"right\"\n        open={open2}\n        onClose={() => setOpen2(false)}\n        title=\"Cancel + Primary\"\n        footerActions={\n          <>\n            <Button variant=\"outlined\" onClick={() => setOpen2(false)}>\n              Cancel\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen2(false)}>\n              Create\n            </Button>\n          </>\n        }\n      >\n        <Typography variant=\"body2\">\n          This drawer has both cancel and primary action buttons.\n        </Typography>\n      </Drawer>\n\n      {/* Multiple actions */}\n      <Drawer\n        anchor=\"right\"\n        open={open3}\n        onClose={() => setOpen3(false)}\n        title=\"Multiple Actions\"\n        footerActions={\n          <>\n            <Button variant=\"text\" onClick={() => setOpen3(false)}>\n              Reset\n            </Button>\n            <Button variant=\"outlined\" onClick={() => setOpen3(false)}>\n              Cancel\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen3(false)}>\n              Save & Continue\n            </Button>\n          </>\n        }\n      >\n        <Typography variant=\"body2\">\n          This drawer has multiple action buttons in the footer.\n        </Typography>\n      </Drawer>\n    </Box>\n  );\n};","description":"Drawer with different footer button combinations"},{"id":"ui-components-drawer--without-close-button","name":"Without Close Button","snippet":"const WithoutCloseButton = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Drawer (No Close Button)</Button>\n      <Drawer\n        anchor=\"right\"\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"No Close Button\"\n        showCloseButton={false}\n        footerActions={\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Close\n          </Button>\n        }\n      >\n        <Typography variant=\"body2\">\n          This drawer does not show a close button in the header. Users must use\n          the footer action or click outside to close.\n        </Typography>\n      </Drawer>\n    </Box>\n  );\n};","description":"Drawer without close button"},{"id":"ui-components-drawer--custom-header","name":"Custom Header","snippet":"const CustomHeader = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Custom Header Drawer</Button>\n      <Drawer\n        anchor=\"right\"\n        open={open}\n        onClose={() => setOpen(false)}\n        headerContent={\n          <Box\n            sx={{\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'space-between',\n              minHeight: 64,\n              padding: 2,\n              borderBottom: 1,\n              borderColor: 'divider',\n            }}\n          >\n            <Typography variant=\"h6\">Custom Header</Typography>\n            <Button variant=\"text\" size=\"small\" onClick={() => setOpen(false)}>\n              Close\n            </Button>\n          </Box>\n        }\n        footerActions={\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Done\n          </Button>\n        }\n      >\n        <Typography variant=\"body2\">\n          This drawer uses a custom header instead of the default title + close button.\n        </Typography>\n      </Drawer>\n    </Box>\n  );\n};","description":"Drawer with custom header content"},{"id":"ui-components-drawer--left-anchor","name":"Left Anchor","snippet":"const LeftAnchor = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Left Drawer</Button>\n      <Drawer\n        anchor=\"left\"\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Left Anchor\"\n        footerActions={\n          <>\n            <Button variant=\"outlined\" color=\"error\" onClick={() => setOpen(false)}>\n              Cancel\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen(false)}>\n              Apply\n            </Button>\n          </>\n        }\n      >\n        <Typography variant=\"body2\">\n          This drawer slides in from the left side.\n        </Typography>\n      </Drawer>\n    </Box>\n  );\n};","description":"Left anchor drawer"}],"import":"import {\n    Box,\n    Button,\n    Drawer,\n    FormControl,\n    Radio,\n    EnhancedTextField as TextField,\n    Typography,\n} from \"@exotel-npm-dev/signal-design-system\";\nimport { Divider, FormControlLabel, RadioGroup } from \"@mui/material\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Drawer","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Drawer/Drawer.tsx","actualName":"Drawer","exportName":"Drawer","props":{"title":{"required":false,"tsType":{"name":"string"},"description":"Title displayed in the header"},"onClose":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: React.SyntheticEvent) => void","signature":{"arguments":[{"type":{"name":"ReactSyntheticEvent","raw":"React.SyntheticEvent"},"name":"event"}],"return":{"name":"void"}}},"description":"Callback fired when the close button is clicked"},"footerActions":{"required":false,"tsType":{"name":"ReactNode"},"description":"Footer actions (buttons) to display in the footer"},"children":{"required":false,"tsType":{"name":"ReactNode"},"description":"Main content to display in the body section"},"headerContent":{"required":false,"tsType":{"name":"ReactNode"},"description":"Custom header content (overrides title and default close button)"},"footerContent":{"required":false,"tsType":{"name":"ReactNode"},"description":"Custom footer content (overrides footerActions)"},"showCloseButton":{"required":false,"tsType":{"name":"boolean"},"description":"Whether to show the close button in the header\n@default true","defaultValue":{"value":"true","computed":false}}},"composes":["Omit"]},"docs":{"ui-components-drawer--docs":{"id":"ui-components-drawer--docs","name":"Docs","path":"./src/stories/ui-components/Drawer.mdx","title":"UI Components/Drawer","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DrawerStories from './Drawer.stories';\nimport { Drawer } from '../../components/Drawer';\n\n<Meta of={DrawerStories} />\n\n# Drawer\n\n## Overview\n\n`Drawer` is the Signal Design System structured off-canvas panel. It wraps MUI `Drawer` with a fixed Header / scrollable Body / optional Footer layout: title, close button, body content, and trailing footer actions.\n\n> **UX Constitution:** See **Interaction Patterns → Drawer Usage Rules** (560px row edit, 726px manage assignments). Read UX Constitution before this doc.\n\n```tsx\nimport { Drawer, Button } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling. Header styling matches `DialogTitle` theme tokens (`action.hover` background, `divider` border).\n\n**When to use**\n\n- Off-canvas forms, filters, detail panels, and create/edit flows\n- Secondary tasks that need more space than a centered modal\n- Multi-section configuration wizards (email settings, entity setup)\n\n**When not to use**\n\n- Centered blocking modal → `Dialog` or `StructuredDialog`\n- Application navigation rail → `Navigation` / `NavigationDrawer`\n- Brief transient feedback → `Snackbar` + `Alert`\n\n## Anatomy\n\n```\nDrawer                       ← Signal wrapper (MUI Drawer + internal layout)\n├── Header strip             ← title + close IconButton (or headerContent)\n├── Body (scrollable)        ← children\n└── Footer strip (optional)  ← footerActions or footerContent (trailing)\n```\n\nCanonical structure (from `Basic` story):\n\n```tsx\n<Drawer\n  anchor=\"right\"\n  open={open}\n  onClose={handleClose}\n  title=\"Create Email Settings\"\n  footerActions={\n    <>\n      <Button variant=\"outlined\" color=\"error\" onClick={handleClose}>Cancel</Button>\n      <Button variant=\"contained\" onClick={handleClose}>Create Configuration</Button>\n    </>\n  }\n>\n  {/* body content */}\n</Drawer>\n```\n\nFooter layout: actions render in a trailing `Box` with `gap: theme.spacing(2)`. A leading flex spacer is reserved for future secondary actions.\n\n## Content guidelines\n\nRules for writing Drawer copy in Exotel ECC and other Signal products.\n\n### Title (`title` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Task + object | \"Create Email Settings\", \"Long Content Example\" |\n| Concise | 2–5 words; sentence case |\n| Match workflow | Title reflects create vs edit vs filter intent |\n\n**Canonical titles from stories:** \"Create Email Settings\", \"Long Content Example\", \"Primary Action Only\", \"Cancel + Primary\", \"Multiple Actions\", \"No Close Button\", \"Custom Header\", \"Left Anchor\".\n\n### Body (`children`)\n\n| Principle | Rule |\n|-----------|------|\n| Section structure | `Typography variant=\"h6\"` for section titles; `body3` + `text.secondary` for descriptions |\n| Field labels | `EnhancedTextField` with noun labels (\"Entity Name\", \"SMTP Host\", \"Port\") |\n| Helper hints | Secondary hints below fields in `body3` (\"eg: 587\", \"Provided by your email service eg: smtp.example.com\") |\n| Notes | Protocol notes as plain `body3` (\"Note: Choose SMTPS if your server requires SSL/TLS\") |\n| Dividers | `Divider` between major sections (`WithForm`) |\n\n### Footer actions (`footerActions`)\n\n| Principle | Rule |\n|-----------|------|\n| Dismiss leading | \"Cancel\" with `variant=\"outlined\"` — stories use `color=\"error\"` for Cancel |\n| Commit trailing | Specific verb: \"Save\", \"Create Configuration\", \"Apply\", \"Save & Continue\" |\n| Tertiary | \"Reset\" as `variant=\"text\"` on leading side of button group (`FooterVariations`) |\n| Single action | \"Save\", \"Close\", or \"Done\" when header × handles dismiss |\n\n**Canonical footer patterns from stories:**\n\n```\n[Cancel]  [Create Configuration]   ← Basic, WithForm\n[Cancel]  [Save]                   ← ScrollableBody\n[Save]                             ← FooterVariations (primary only)\n[Cancel]  [Create]                 ← FooterVariations\n[Reset]  [Cancel]  [Save & Continue] ← FooterVariations (multiple)\n[Close]                            ← WithoutCloseButton\n[Done]                             ← CustomHeader\n[Cancel]  [Apply]                  ← LeftAnchor\n```\n\n### Do and don't\n\n**Do**\n\n- \"Create Configuration\"\n- \"Save & Continue\"\n- Section descriptions that explain what to enter\n- Required field markers via `EnhancedTextField required`\n\n**Don't**\n\n- Generic \"Submit\" when \"Create Configuration\" is accurate\n- Omit footer dismiss when `showCloseButton={false}` without \"Close\" button\n- Cram entire forms without section headings in long drawers\n\n### Guidance for AI-generated drawer copy\n\n- `title` = verb + object for create flows (\"Create Email Settings\").\n- Section pattern: `h6` title → `body3` description → fields → `Divider`.\n- Footer: always pair Cancel (outlined) + commit (contained) for edit/create flows unless story shows single-primary pattern.\n- Use `color=\"error\"` on Cancel only when matching story convention — not because Cancel is destructive.\n- Placeholder text may echo label (\"Entity Name*\", \"Username*\") per `WithForm` story.\n\n## Props\n\n`DrawerProps` extends MUI `DrawerProps` (minus `ref` and `children`).\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `title` | `string` | — | Header title | `Typography variant=\"h6\" component=\"h2\"` |\n| `onClose` | `(event) => void` | — | Close handler | Enables header close and MUI drawer dismiss |\n| `footerActions` | `ReactNode` | — | Footer buttons | Trailing-aligned button group |\n| `children` | `ReactNode` | — | Scrollable body content | Forms, typography, lists |\n| `headerContent` | `ReactNode` | — | Custom header | Replaces default title + close (`CustomHeader`) |\n| `footerContent` | `ReactNode` | — | Custom footer | Overrides `footerActions` when set |\n| `showCloseButton` | `boolean` | `true` | Header close icon | Set `false` when footer provides dismiss (`WithoutCloseButton`) |\n\n### Props documented in stories argTypes\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `anchor` | `'left' \\| 'right' \\| 'top' \\| 'bottom'` | `'right'` | Slide-in edge | Stories default `right`; `LeftAnchor` uses `left` |\n| `variant` | `'permanent' \\| 'persistent' \\| 'temporary'` | `'temporary'` | Drawer behavior | Stories use default temporary overlay |\n| `open` | `boolean` | `false` | Visibility | Parent state required |\n| `title` | `string` | — | Header title | See Content guidelines |\n| `showCloseButton` | `boolean` | `true` | Toggle header × | `WithoutCloseButton` sets `false` |\n\nAdditional MUI `DrawerProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Drawer} />\n\n## Variants\n\n| Pattern | Configuration | Story |\n|---------|---------------|-------|\n| Standard create flow | `anchor=\"right\"`, Cancel + Create footer | `Basic`, `WithForm` |\n| Scrollable long body | Same structure, many paragraphs | `ScrollableBody` |\n| Primary-only footer | Single Save button | `FooterVariations` (drawer 1) |\n| Cancel + primary | Two buttons | `FooterVariations` (drawer 2) |\n| Three footer actions | Reset + Cancel + Save & Continue | `FooterVariations` (drawer 3) |\n| No header close | `showCloseButton={false}` + footer Close | `WithoutCloseButton` |\n| Custom header | `headerContent` replaces default | `CustomHeader` |\n| Left anchor | `anchor=\"left\"` | `LeftAnchor` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Closed | `open={false}` | Default |\n| Open | `open={true}` | Overlay drawer (temporary variant) |\n| Close button visible | `showCloseButton={true}` (default) | `IconButton` with `aria-label=\"close drawer\"` |\n| Close button hidden | `showCloseButton={false}` | Footer must provide dismiss |\n| Scrollable body | Long `children` | Body `Box` has `overflowY: auto`, `flex: 1` |\n| Custom header | `headerContent` set | Default title/close not rendered |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Open trigger | `Button` sets `open` true | All stories |\n| Header close | Built-in `IconButton` + `Icon name=\"x\"` | Default header |\n| Backdrop dismiss | MUI `onClose` on overlay click | Temporary variant |\n| Form sections | `Typography`, `Divider`, `EnhancedTextField`, `RadioGroup` | `WithForm` |\n| Footer-only dismiss | `showCloseButton={false}` | `WithoutCloseButton` |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-drawer--basic`\n\n`anchor=\"right\"`, title \"Create Email Settings\", body paragraph, footer Cancel (outlined error) + Create Configuration (contained).\n\n**Recommended usage:** Default create/edit off-canvas panel.\n\n<Canvas of={DrawerStories.Basic} />\n\n### ScrollableBody\n\n**Story ID:** `ui-components-drawer--scrollable-body`\n\n50 paragraphs demonstrating body scroll with fixed header/footer. Footer: Cancel + Save.\n\n**Recommended usage:** Long forms or content lists in a drawer.\n\n<Canvas of={DrawerStories.ScrollableBody} />\n\n### WithForm\n\n**Story ID:** `ui-components-drawer--with-form`\n\nMulti-section email settings form: Basic Information, SMTP Server Settings, Authentication Credentials. Uses `EnhancedTextField`, `RadioGroup`, `Divider`. Footer: Cancel + Create Configuration.\n\n**Recommended usage:** Complex configuration flows matching Figma ECC patterns.\n\n<Canvas of={DrawerStories.WithForm} />\n\n### FooterVariations\n\n**Story ID:** `ui-components-drawer--footer-variations`\n\nThree drawers demonstrating primary-only, Cancel + Create, and Reset + Cancel + Save & Continue footers.\n\n**Recommended usage:** Reference for footer button combinations.\n\n<Canvas of={DrawerStories.FooterVariations} />\n\n### WithoutCloseButton\n\n**Story ID:** `ui-components-drawer--without-close-button`\n\n`showCloseButton={false}`, footer single \"Close\" button.\n\n**Recommended usage:** Forced explicit dismiss via footer when header close is undesirable.\n\n<Canvas of={DrawerStories.WithoutCloseButton} />\n\n### CustomHeader\n\n**Story ID:** `ui-components-drawer--custom-header`\n\n`headerContent` with custom layout and text \"Close\" button. Footer: \"Done\".\n\n**Recommended usage:** Custom header branding or actions beyond default title + ×.\n\n<Canvas of={DrawerStories.CustomHeader} />\n\n### LeftAnchor\n\n**Story ID:** `ui-components-drawer--left-anchor`\n\n`anchor=\"left\"`, footer Cancel + Apply.\n\n**Recommended usage:** Left-side panels (filters, navigation-adjacent content).\n\n<Canvas of={DrawerStories.LeftAnchor} />\n\n## Accessibility\n\n- MUI `Drawer` provides focus management for temporary overlays.\n- Built-in close uses `aria-label=\"close drawer\"`.\n- `title` renders as `Typography component=\"h2\"`.\n- Footer buttons use visible text labels.\n- When `showCloseButton={false}`, provide a labeled footer dismiss (\"Close\", \"Done\").\n- Custom `headerContent` must include accessible close control.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Default to `anchor=\"right\"` for create/edit flows in LTR layouts.\n- Use `footerActions` with Cancel (outlined) + specific commit (contained).\n- Structure long forms with section headings, descriptions, and `Divider`.\n- Use `EnhancedTextField` for labeled inputs in drawer bodies.\n- Set `showCloseButton={false}` only when footer explicitly dismisses.\n- Match `StructuredDialog` footer label conventions for cross-surface consistency.\n\n## Anti-patterns\n\n- Using `Drawer` for centered confirmations — use `StructuredDialog`.\n- Hiding close button without a footer dismiss action.\n- Inventing `footerContent` when `footerActions` is the story-documented API (both exist; stories use `footerActions`).\n- Permanent navigation drawer via this component — use app navigation patterns.\n- Empty `title` with default header (shows only close button).\n- Importing `@mui/material/Drawer` directly in consumer apps.\n\n## Guidance for AI Agents\n\n**Read UX Constitution first** (Interaction Patterns → Drawer Usage Rules).\n\n### When to choose `Drawer`\n\n- Off-canvas create/edit/filter panel\n- Multi-section form with scrollable body\n- Secondary task that should not fully block the page context\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Centered modal | `StructuredDialog` |\n| Custom dialog layout | `Dialog` |\n| App navigation | `NavigationDrawer` |\n| Toast feedback | `Snackbar` + `Alert` |\n\n### Canonical prop combinations\n\n```tsx\n// Create flow — story: Basic\n<Drawer\n  anchor=\"right\"\n  open={open}\n  onClose={handleClose}\n  title=\"Create Email Settings\"\n  footerActions={\n    <>\n      <Button variant=\"outlined\" color=\"error\" onClick={handleClose}>Cancel</Button>\n      <Button variant=\"contained\" onClick={handleClose}>Create Configuration</Button>\n    </>\n  }\n>\n  {/* body */}\n</Drawer>\n\n// No header close — story: WithoutCloseButton\n<Drawer\n  showCloseButton={false}\n  footerActions={\n    <Button variant=\"contained\" onClick={handleClose}>Close</Button>\n  }\n  {/* ... */}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default create drawer | `Basic` |\n| Long scrollable form | `ScrollableBody` |\n| Multi-section form | `WithForm` |\n| Footer button options | `FooterVariations` |\n| Left-side panel | `LeftAnchor` |\n| Custom header | `CustomHeader` |\n\n### Common mistakes to avoid\n\n- Using `footerContent` prop name from `StructuredDialog` — Drawer uses `footerActions` in stories.\n- Omitting `onClose` when `showCloseButton` is true.\n- Setting `anchor` to unsupported values — only `left`, `right`, `top`, `bottom`.\n- Inventing `showFooter` — footer renders when `footerActions` or `footerContent` is provided.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `StructuredDialog` | Centered modal with same footer conventions |\n| `Dialog` | Lower-level centered overlay |\n| `Button` | Footer commit and dismiss actions |\n| `EnhancedTextField` | Form inputs in drawer body |\n| `NavigationDrawer` | App-level navigation (distinct use case) |\n| `PageHeader` | Page-level actions that may open drawers |\n| `Divider` | Section separation in long drawer forms |\n"}}},"ui-components-enhancedtextfield":{"id":"ui-components-enhancedtextfield","name":"EnhancedTextField","path":"./src/stories/ui-components/EnhancedTextField.stories.tsx","stories":[{"id":"ui-components-enhancedtextfield--basic","name":"Basic","snippet":"const Basic = () => <EnhancedTextField label=\"Label\" />;","description":"Basic text field"},{"id":"ui-components-enhancedtextfield--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '300px' }}>\n    <EnhancedTextField label=\"Small\" size=\"small\" />\n    <EnhancedTextField label=\"Medium\" size=\"medium\" />\n    <EnhancedTextField label=\"Large\" size=\"large\" />\n  </div>\n);","description":"Different sizes"},{"id":"ui-components-enhancedtextfield--with-helper-text","name":"With Helper Text","snippet":"const WithHelperText = () => <EnhancedTextField label=\"Email\" helperText=\"Enter your email address\" />;","description":"With helper text"},{"id":"ui-components-enhancedtextfield--required","name":"Required","snippet":"const Required = () => <EnhancedTextField label=\"Required Field\" required />;","description":"Required field"},{"id":"ui-components-enhancedtextfield--error","name":"Error","snippet":"const Error = () => <EnhancedTextField label=\"Email\" error helperText=\"Invalid email address\" />;","description":"Error state"},{"id":"ui-components-enhancedtextfield--disabled","name":"Disabled","snippet":"const Disabled = () => <EnhancedTextField label=\"Disabled\" disabled defaultValue=\"Disabled value\" />;","description":"Disabled state"},{"id":"ui-components-enhancedtextfield--full-width","name":"Full Width","snippet":"const FullWidth = () => <EnhancedTextField label=\"Full Width\" fullWidth />;","description":"Full width"},{"id":"ui-components-enhancedtextfield--with-placeholder","name":"With Placeholder","snippet":"const WithPlaceholder = () => <EnhancedTextField label=\"Search\" placeholder=\"Type to search...\" />;","description":"With placeholder"},{"id":"ui-components-enhancedtextfield--with-start-icon","name":"With Start Icon","snippet":"const WithStartIcon = () => <EnhancedTextField\n    label=\"Search\"\n    InputProps={{\n      startAdornment: <Icon name=\"search\" size=\"sm\" />,\n    }} />;","description":"With start icon"},{"id":"ui-components-enhancedtextfield--with-end-icon","name":"With End Icon","snippet":"const WithEndIcon = () => <EnhancedTextField\n    label=\"Password\"\n    type=\"password\"\n    InputProps={{\n      endAdornment: <Icon name=\"eye\" size=\"sm\" />,\n    }} />;","description":"With end icon"},{"id":"ui-components-enhancedtextfield--with-icons","name":"With Icons","snippet":"const WithIcons = () => <EnhancedTextField\n    label=\"Search\"\n    InputProps={{\n      startAdornment: <Icon name=\"search\" size=\"sm\" />,\n      endAdornment: <Icon name=\"x\" size=\"sm\" />,\n    }} />;","description":"With both start and end icons"},{"id":"ui-components-enhancedtextfield--multiline","name":"Multiline","snippet":"const Multiline = (args) => {\n  const { showStartIcon, showEndIcon, ...rest } = args as EnhancedTextFieldStoryArgs;\n  return (\n    <div style={{ width: '350px' }}>\n      <EnhancedTextField multiline {...rest} />\n    </div>\n  );\n};","description":"Multiline input (textarea)"},{"id":"ui-components-enhancedtextfield--interactive","name":"Interactive","snippet":"const Interactive = (args) => {\n  const { showStartIcon, showEndIcon, ...textFieldProps } = args;\n  const InputProps: EnhancedTextFieldStoryArgs['InputProps'] = {};\n\n  if (showStartIcon) {\n    InputProps.startAdornment = <Icon name=\"search\" size=\"sm\" />;\n  }\n  if (showEndIcon) {\n    InputProps.endAdornment = <Icon name=\"x\" size=\"sm\" />;\n  }\n\n  return (\n    <EnhancedTextField\n      {...textFieldProps}\n      InputProps={Object.keys(InputProps).length > 0 ? InputProps : undefined}\n    />\n  );\n};","description":"Interactive text field with all controls"}],"import":"import { EnhancedTextField, Icon } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"description":"EnhancedTextField component Wraps MUI's TextField component with Exotel-specific defaults and styling. All MUI TextField props are supported.","reactDocgen":{"description":"EnhancedTextField component\n\nWraps MUI's TextField component with Exotel-specific defaults and styling.\nAll MUI TextField props are supported.","methods":[],"displayName":"EnhancedTextField","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/EnhancedTextField/EnhancedTextField.tsx","actualName":"EnhancedTextField","exportName":"EnhancedTextField","props":{"showLabel":{"required":false,"tsType":{"name":"boolean"},"description":"Controls whether the label is rendered"},"label":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"The label content"},"helperText":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"The helper text content"},"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the input"},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted.\nPass an empty string to disable the default placeholder."}},"composes":["Omit"]},"docs":{"ui-components-enhancedtextfield--docs":{"id":"ui-components-enhancedtextfield--docs","name":"Docs","path":"./src/stories/ui-components/EnhancedTextField.mdx","title":"UI Components/EnhancedTextField","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as EnhancedTextFieldStories from './EnhancedTextField.stories';\nimport { EnhancedTextField } from '../../components/EnhancedTextField';\n\n<Meta of={EnhancedTextFieldStories} />\n\n# EnhancedTextField\n\n## Overview\n\n`EnhancedTextField` is the Signal Design System text input. It wraps MUI `TextField` with an external label via `FieldWrapper` (stable label above the field, not a floating MUI label). The `variant` prop is omitted from the public API — MUI defaults to `outlined`.\n\nUsed across ECC forms, `Autocomplete`, date/time pickers, and dialog/drawer form stories.\n\n```tsx\nimport { EnhancedTextField } from '@exotel-npm-dev/signal-design-system';\n```\n\n**Do not** import MUI `TextField` from `@mui/material` — use `EnhancedTextField` (see UX Constitution → Form Inputs).\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Text, password, search, and multiline inputs with external label pattern\n- Forms inside `Dialog`, `StructuredDialog`, and `Drawer`\n- Any input needing MUI `TextField` features (multiline, `InputProps` adornments)\n\n**When not to use**\n\n- Simpler `FormControl` + `OutlinedInput` API → `FormField`\n- Dropdown selection → `Select`\n- Search-from-list with suggestions → `Autocomplete` (which uses `EnhancedTextField` internally)\n- Native MUI floating-label `TextField` pattern → compare `FormField` (`Comparison` story in FormField)\n\n## Anatomy\n\n```\nEnhancedTextField\n├── FieldWrapper\n│   ├── label (Typography body2, text.secondary)   ← when showLabel && label\n│   └── MuiTextField (outlined)\n│       ├── input / textarea\n│       └── FormHelperText (optional)\n```\n\nIcons and adornments attach via MUI `InputProps.startAdornment` / `endAdornment` (see `WithStartIcon`, `WithEndIcon`).\n\n## Content guidelines\n\nRules for labels, placeholders, and helper text in Exotel forms.\n\n### Label (`label` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Noun or noun phrase | \"Email\", \"Entity Name\", \"SMTP Host\", \"Select Template\" |\n| Sentence case | \"Enter or select number\" — not Title Case |\n| Required | Use `required` prop; do not rely on asterisk in label string alone |\n| External | Label always renders above field via `FieldWrapper` |\n\n### Placeholder (`placeholder` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Hint, not label | \"Type to search...\", \"Enter a description...\" |\n| Shorter than label | Placeholder supplements; label carries field name |\n| Examples in forms | May echo label with asterisk (\"Entity Name*\", \"Username*\") in drawer stories |\n\n### Helper text (`helperText` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Instruction or validation | \"Enter your email address\", \"Invalid email address\" |\n| Error state | Pair `error={true}` with specific fix guidance |\n| Left-aligned | Theme sets `marginLeft: 0`, `textAlign: left` |\n\n### Do and don't\n\n**Do**\n\n- \"Email\" + helper \"Enter your email address\"\n- \"Description\" + placeholder \"Enter a description...\"\n- `required` on mandatory fields\n\n**Don't**\n\n- Duplicate label text in placeholder (\"Email\" label + \"Email\" placeholder)\n- Use helper text for long paragraphs\n- Hide label without good reason (`showLabel={false}` only when context is obvious)\n\n### Guidance for AI-generated form copy\n\n- `label` = field noun; `placeholder` = input hint; `helperText` = validation or format guidance.\n- Error helper must state how to fix: \"Invalid email address\" not \"Error\".\n- Multiline fields: label describes content type (\"Description\", \"Select Template\").\n- Do not invent `variant` — outlined is implicit.\n\n## Props\n\n`EnhancedTextFieldProps` extends MUI `TextFieldProps` minus `ref`, `variant`, and `size` (redefined).\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `showLabel` | `boolean` | `true` | Toggle external label | Set `false` to hide `FieldWrapper` label |\n| `label` | `ReactNode` | — | External label content | Rendered above input by `FieldWrapper` |\n| `helperText` | `ReactNode` | — | Text below input | Validation messages, format hints |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'medium'` | Input height scale | Signal extension beyond MUI's two sizes |\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `disabled` | `boolean` | `false` | Disables input | Non-interactive; reduced opacity |\n| `required` | `boolean` | `false` | Required indicator | Shows required styling on label |\n| `error` | `boolean` | `false` | Error state | Pair with error `helperText` |\n| `fullWidth` | `boolean` | `false` | Stretch to container | Use in forms and drawers |\n| `placeholder` | `string` | — | Input hint | See Content guidelines |\n| `type` | `string` | `'text'` | HTML input type | `'password'` in `WithEndIcon` |\n| `multiline` | `boolean` | `false` | Textarea mode | `Multiline` story |\n| `rows` / `minRows` / `maxRows` | `number` | — | Textarea sizing | `Multiline` uses `minRows: 2` |\n| `InputProps` | `object` | — | Adornments, readOnly, etc. | `startAdornment` / `endAdornment` with `Icon` |\n| `value` / `defaultValue` | `string` | — | Controlled / uncontrolled value | Standard React input patterns |\n| `onChange` | `function` | — | Change handler | Required for controlled inputs |\n\n`variant` is excluded from the public API. Additional MUI `TextFieldProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={EnhancedTextField} />\n\n## Variants\n\n`EnhancedTextField` has no Signal visual variants. Input `type` and `multiline` provide functional variation:\n\n| Pattern | Props | Story |\n|---------|-------|-------|\n| Single-line text | Default | `Basic` |\n| Password | `type=\"password\"` | `WithEndIcon` |\n| Multiline | `multiline`, `minRows` | `Multiline` |\n| With search icon | `InputProps.startAdornment` | `WithStartIcon`, `WithIcons` |\n| With end icon | `InputProps.endAdornment` | `WithEndIcon`, `WithIcons` |\n\n## Sizes\n\nThree Signal sizes (theme token heights):\n\n| Size | Story label | Usage |\n|------|-------------|-------|\n| `small` | \"Small\" | Dense tables, compact forms |\n| `medium` | \"Medium\" | Default |\n| `large` | \"Large\" | Prominent forms, touch-friendly |\n\n<Canvas of={EnhancedTextFieldStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Default | No error/disabled | Standard input |\n| Required | `required={true}` | `Required` story |\n| Error | `error={true}` + error helper | `Error` story |\n| Disabled | `disabled={true}` | `Disabled` story |\n| With helper | `helperText` set | `WithHelperText` story |\n| With placeholder | `placeholder` set | `WithPlaceholder` story |\n| Full width | `fullWidth={true}` | `FullWidth` story |\n| Label hidden | `showLabel={false}` | Supported; not shown in dedicated story |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| External label | `FieldWrapper` + `htmlFor` from `id` or `name` | All stories |\n| Icon adornments | `InputProps.startAdornment` / `endAdornment` | `WithStartIcon`, `WithEndIcon`, `WithIcons` |\n| Auto-growing textarea | `multiline` + `minRows` | `Multiline` |\n| Interactive playground | Storybook controls | `Interactive` |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-enhanced-text-field--basic`\n\nDefault field with `label=\"Label\"`.\n\n**Recommended usage:** Standard single-line text input.\n\n<Canvas of={EnhancedTextFieldStories.Basic} />\n\n### Sizes\n\n**Story ID:** `ui-components-enhanced-text-field--sizes`\n\n`small`, `medium`, and `large` side by side.\n\n**Recommended usage:** Size selection reference.\n\n<Canvas of={EnhancedTextFieldStories.Sizes} />\n\n### WithHelperText\n\n**Story ID:** `ui-components-enhanced-text-field--with-helper-text`\n\n`label=\"Email\"`, `helperText=\"Enter your email address\"`.\n\n**Recommended usage:** Fields needing format or context hints.\n\n<Canvas of={EnhancedTextFieldStories.WithHelperText} />\n\n### Required\n\n**Story ID:** `ui-components-enhanced-text-field--required`\n\n`label=\"Required Field\"`, `required={true}`.\n\n**Recommended usage:** Mandatory form fields.\n\n<Canvas of={EnhancedTextFieldStories.Required} />\n\n### Error\n\n**Story ID:** `ui-components-enhanced-text-field--error`\n\n`error={true}`, `helperText=\"Invalid email address\"`.\n\n**Recommended usage:** Validation failure state.\n\n<Canvas of={EnhancedTextFieldStories.Error} />\n\n### Disabled\n\n**Story ID:** `ui-components-enhanced-text-field--disabled`\n\n`disabled={true}`, `defaultValue=\"Disabled value\"`.\n\n**Recommended usage:** Read-only or unavailable fields.\n\n<Canvas of={EnhancedTextFieldStories.Disabled} />\n\n### FullWidth\n\n**Story ID:** `ui-components-enhanced-text-field--full-width`\n\n`fullWidth={true}`, `label=\"Full Width\"`.\n\n**Recommended usage:** Form layouts and drawer/dialog forms.\n\n<Canvas of={EnhancedTextFieldStories.FullWidth} />\n\n### WithPlaceholder\n\n**Story ID:** `ui-components-enhanced-text-field--with-placeholder`\n\n`label=\"Search\"`, `placeholder=\"Type to search...\"`.\n\n**Recommended usage:** Search and filter inputs.\n\n<Canvas of={EnhancedTextFieldStories.WithPlaceholder} />\n\n### WithStartIcon\n\n**Story ID:** `ui-components-enhanced-text-field--with-start-icon`\n\n`InputProps.startAdornment` with `Icon name=\"search\"`.\n\n**Recommended usage:** Search fields with leading icon.\n\n<Canvas of={EnhancedTextFieldStories.WithStartIcon} />\n\n### WithEndIcon\n\n**Story ID:** `ui-components-enhanced-text-field--with-end-icon`\n\n`type=\"password\"`, `InputProps.endAdornment` with `Icon name=\"eye\"`.\n\n**Recommended usage:** Password visibility toggle affordance (icon only in story).\n\n<Canvas of={EnhancedTextFieldStories.WithEndIcon} />\n\n### WithIcons\n\n**Story ID:** `ui-components-enhanced-text-field--with-icons`\n\nBoth `search` start and `x` end adornments.\n\n**Recommended usage:** Search with clear action.\n\n<Canvas of={EnhancedTextFieldStories.WithIcons} />\n\n### Multiline\n\n**Story ID:** `ui-components-enhanced-text-field--multiline`\n\n`multiline`, `minRows: 2`, `label=\"Description\"`, `placeholder=\"Enter a description...\"`.\n\n**Recommended usage:** Textarea fields for descriptions and templates.\n\n<Canvas of={EnhancedTextFieldStories.Multiline} />\n\n### Interactive\n\n**Story ID:** `ui-components-enhanced-text-field--interactive`\n\nPlayground with controls for size, states, icons, label, helper text.\n\n**Recommended usage:** Development exploration only.\n\n<Canvas of={EnhancedTextFieldStories.Interactive} />\n\n## Accessibility\n\n- External label uses `Typography component=\"label\"` with `htmlFor` linked to input `id` or `name`.\n- `required` and `error` states propagate to MUI `TextField` for assistive technology.\n- `helperText` renders as `FormHelperText` associated with the input.\n- Icon adornments in stories are decorative unless given accessible names on interactive icons.\n- `disabled` removes input from tab order and editing.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Always provide a `label` for form fields (or explicit `showLabel={false}` with nearby context).\n- Pair `error` with specific `helperText` explaining the fix.\n- Use `fullWidth` in drawer, dialog, and form layouts.\n- Pass icons via `InputProps` adornments with Signal `Icon` component.\n- Use `multiline` + `minRows` for variable-length text (templates, descriptions).\n- Import from `@exotel-npm-dev/signal-design-system`.\n\n## Anti-patterns\n\n- Passing `variant` — it is excluded from the API.\n- Using floating-label MUI pattern — use `FormField` if `OutlinedInput` alone is preferred.\n- Icon-only fields without labels.\n- Generic error helper (\"Error\") without actionable detail.\n- Importing `@mui/material/TextField` in consumer apps for ECC forms.\n- Inventing `startIconProps` — use `InputProps.startAdornment` with `Icon`.\n\n## Guidance for AI Agents\n\n### When to choose `EnhancedTextField`\n\n- Text input with external label in ECC forms\n- Multiline template or description fields\n- Inputs inside `Dialog`, `Drawer`, or page forms needing MUI TextField features\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Simpler OutlinedInput API | `FormField` |\n| Dropdown | `Select` |\n| Typeahead list | `Autocomplete` |\n| Date/time | Date/time picker components |\n\n### Canonical prop combinations\n\n```tsx\n// Default — story: Basic\n<EnhancedTextField label=\"Label\" />\n\n// Form field with validation — story: Error\n<EnhancedTextField label=\"Email\" error helperText=\"Invalid email address\" />\n\n// Drawer form field — story: WithForm (StructuredDialog/Drawer)\n<EnhancedTextField fullWidth label=\"Entity Name\" required placeholder=\"Entity Name*\" />\n\n// Multiline template — story: Multiline\n<EnhancedTextField multiline minRows={2} label=\"Description\" placeholder=\"Enter a description...\" />\n\n// Search with icon — story: WithStartIcon\n<EnhancedTextField\n  label=\"Search\"\n  InputProps={{ startAdornment: <Icon name=\"search\" size=\"sm\" /> }}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default input | `Basic` |\n| Field sizes | `Sizes` |\n| Validation error | `Error` |\n| Required field | `Required` |\n| Full-width form | `FullWidth` |\n| Textarea | `Multiline` |\n| Search icon | `WithStartIcon` |\n\n### Common mistakes to avoid\n\n- `variant=\"outlined\"` — do not pass; it is implicit.\n- `size=\"extraLarge\"` — does not exist; use `small`, `medium`, `large`.\n- `startIconProps` — not part of API; use `InputProps`.\n- Omitting `label` in forms.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `FieldWrapper` | Shared external label primitive |\n| `FormField` | Alternative external-label input via `OutlinedInput` |\n| `Autocomplete` | Composes `EnhancedTextField` internally |\n| `Select` | Dropdown alternative |\n| `Icon` | Adornment icons in `InputProps` |\n| `Drawer` / `StructuredDialog` | Common form containers |\n"}}},"ui-components-fab":{"id":"ui-components-fab","name":"Fab","path":"./src/stories/ui-components/Fab.stories.tsx","stories":[{"id":"ui-components-fab--default","name":"Default","snippet":"const Default = () => <Fab color=\"primary\"><Icon name=\"plus\" /></Fab>;"},{"id":"ui-components-fab--extended","name":"Extended","snippet":"const Extended = () => <Fab variant=\"extended\" color=\"primary\">\n    <Icon name=\"plus\" />Create\n        </Fab>;"},{"id":"ui-components-fab--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>\n    <Fab size=\"small\" color=\"primary\">\n      <Icon name=\"plus\" />\n    </Fab>\n    <Fab size=\"medium\" color=\"primary\">\n      <Icon name=\"plus\" />\n    </Fab>\n    <Fab size=\"large\" color=\"primary\">\n      <Icon name=\"plus\" />\n    </Fab>\n  </Box>\n);"},{"id":"ui-components-fab--colors","name":"Colors","snippet":"const Colors = () => (\n  <Box sx={{ display: 'flex', alignItems: 'center', gap: 2, flexWrap: 'wrap' }}>\n    <Fab color=\"default\"><Icon name=\"plus\" /></Fab>\n    <Fab color=\"primary\"><Icon name=\"plus\" /></Fab>\n    <Fab color=\"secondary\"><Icon name=\"plus\" /></Fab>\n    <Fab color=\"success\"><Icon name=\"check\" /></Fab>\n    <Fab color=\"error\"><Icon name=\"x\" /></Fab>\n    <Fab color=\"warning\"><Icon name=\"warning\" /></Fab>\n    <Fab color=\"info\"><Icon name=\"info\" /></Fab>\n  </Box>\n);"},{"id":"ui-components-fab--disabled","name":"Disabled","snippet":"const Disabled = () => <Fab disabled><Icon name=\"plus\" /></Fab>;"}],"import":"import { Box, Fab, Icon } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Fab","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Fab/Fab.tsx","actualName":"Fab","exportName":"Fab","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-fab--docs":{"id":"ui-components-fab--docs","name":"Docs","path":"./src/stories/ui-components/Fab.mdx","title":"UI Components/Fab","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as FabStories from './Fab.stories';\nimport { Fab } from '../../components/Fab';\n\n<Meta of={FabStories} />\n\n# Fab\n\n## Overview\n\n`Fab` wraps MUI `Fab` (Floating Action Button) for primary page-level floating actions. It represents the single most important action on a screen.\n\n```tsx\nimport { Fab, Icon } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Single prominent create/add action floating over content\n- Primary action that should always be accessible regardless of scroll position\n\n**When not to use**\n\n- Toolbar actions → use `Button` or `IconButton`\n- Form submit → use `Button`\n- Multiple actions → use `Button` group or `Menu`\n\n## Props\n\n<ArgTypes of={Fab} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `color` | `'default' \\| 'primary' \\| 'secondary' \\| 'error' \\| 'info' \\| 'success' \\| 'warning' \\| 'inherit'` | `'default'` | The color of the button |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'large'` | The size of the button |\n| `variant` | `'circular' \\| 'extended'` | `'circular'` | Shape variant |\n| `disabled` | `boolean` | `false` | If true, the button is disabled |\n\n## Stories\n\n### Default\n\nPrimary circular FAB with a plus icon.\n\n<Canvas of={FabStories.Default} />\n\n### Extended\n\nExtended variant with icon and text label.\n\n<Canvas of={FabStories.Extended} />\n\n### Sizes\n\nAll three sizes (small, medium, large) compared side by side.\n\n<Canvas of={FabStories.Sizes} />\n\n### Colors\n\nAll available color options.\n\n<Canvas of={FabStories.Colors} />\n\n### Disabled\n\nDisabled FAB state.\n\n<Canvas of={FabStories.Disabled} />\n\n## Best Practices\n\n- Only one FAB per screen — it represents the primary action.\n- Use `variant=\"extended\"` when the icon alone isn't self-explanatory.\n- Position with `sx={{ position: 'fixed', bottom: 16, right: 16 }}` for floating behavior.\n- Always add `aria-label` on circular FABs for accessibility.\n- Use `color=\"primary\"` for the main action; reserve other colors for specific semantic meaning.\n\n## Accessibility\n\n- Extended FAB should include visible text alongside the icon.\n- Circular FAB needs `aria-label` since the icon alone is not accessible.\n- Ensure sufficient color contrast against the background.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `Button` | Standard button for toolbar and form actions |\n| `IconButton` | Icon-only button for secondary actions |\n| `Icon` | Icon content rendered inside the FAB |\n"}}},"ui-components-fieldwrapper":{"id":"ui-components-fieldwrapper","name":"FieldWrapper","path":"./src/stories/ui-components/FieldLabel.stories.tsx","stories":[{"id":"ui-components-fieldwrapper--default","name":"Default","snippet":"const Default = () => <FieldWrapper label=\"Email address\" htmlFor=\"email-input\">\n    <EnhancedTextField id=\"email-input\" placeholder=\"you@example.com\" size=\"small\" />\n</FieldWrapper>;"},{"id":"ui-components-fieldwrapper--required","name":"Required","snippet":"const Required = () => <FieldWrapper label=\"Full name\" htmlFor=\"name-input\" required>\n    <EnhancedTextField id=\"name-input\" placeholder=\"John Doe\" size=\"small\" />\n</FieldWrapper>;"},{"id":"ui-components-fieldwrapper--no-label","name":"No Label","snippet":"const NoLabel = () => <FieldWrapper label={undefined}>\n    <EnhancedTextField placeholder=\"No external label\" size=\"small\" />\n</FieldWrapper>;"}],"import":"import { EnhancedTextField, FieldWrapper } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"FieldWrapper","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/FieldLabel/FieldLabel.tsx","actualName":"FieldWrapper","exportName":"FieldWrapper","props":{"label":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"The label content. When falsy the label row is omitted."},"htmlFor":{"required":false,"tsType":{"name":"string"},"description":"Associates the label with an input via its id."},"required":{"required":false,"tsType":{"name":"boolean"},"description":"If true, a red asterisk is appended to the label. @default false","defaultValue":{"value":"false","computed":false}},"children":{"required":true,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"The field component(s) rendered below the label."}}},"docs":{"ui-components-fieldwrapper--docs":{"id":"ui-components-fieldwrapper--docs","name":"Docs","path":"./src/stories/ui-components/FieldLabel.mdx","title":"UI Components/FieldWrapper","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as FieldLabelStories from './FieldLabel.stories';\nimport { FieldWrapper } from '../../components/FieldLabel';\n\n<Meta of={FieldLabelStories} />\n\n# FieldWrapper\n\n## Overview\n\n`FieldWrapper` is a shared wrapper component that renders an external label above any field component. It is used internally by `EnhancedTextField`, `Autocomplete`, and all date/time pickers to provide consistent label positioning.\n\n```tsx\nimport { FieldWrapper } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Wrapping a custom input that needs an external label matching the Signal pattern\n- Composing a labeled field from lower-level primitives\n- Adding a \"required\" asterisk indicator above any form element\n\n**When not to use**\n\n- Standard text fields → use `EnhancedTextField` (includes FieldWrapper internally)\n- Select dropdowns → use `Select` or `MultiSelect` (includes label prop)\n- Autocomplete → use `Autocomplete` (includes label prop)\n\n## Anatomy\n\n```\nFieldWrapper (Stack, spacing: 0.5)\n├── Label row (Typography variant=\"label1\")\n│   ├── label text\n│   └── required asterisk (red \" *\") — when required={true}\n└── children (the field component)\n```\n\n## Props\n\n<ArgTypes of={FieldWrapper} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `label` | `ReactNode` | — | The label content. When falsy the label row is omitted. |\n| `htmlFor` | `string` | — | Associates the label with an input via its id. |\n| `required` | `boolean` | `false` | If true, a red asterisk is appended to the label. |\n| `children` | `ReactNode` | — | The field component(s) rendered below the label. |\n\n## Stories\n\n### Default\n\nBasic field wrapper with label and an `EnhancedTextField` child.\n\n<Canvas of={FieldLabelStories.Default} />\n\n### Required\n\nField wrapper showing the required asterisk indicator.\n\n<Canvas of={FieldLabelStories.Required} />\n\n### NoLabel\n\nWhen `label` is undefined/falsy, the wrapper renders only the children with no label row.\n\n<Canvas of={FieldLabelStories.NoLabel} />\n\n## Best Practices\n\n- Always set `htmlFor` to match the input's `id` for accessibility (clicking the label focuses the field).\n- Use `required` to indicate mandatory fields visually — also set `required` on the underlying input for form validation.\n- Keep labels concise (1–3 words): \"Email address\", \"Full name\", \"Password\".\n- Prefer `EnhancedTextField` with its built-in `label` prop over manually wrapping with `FieldWrapper`.\n\n## Accessibility\n\n- Renders a semantic `<label>` element via `Typography component=\"label\"`.\n- The `htmlFor` prop correctly links the label to the input for assistive technologies.\n- Required asterisk has `aria-hidden` to avoid screen readers announcing \"star\".\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `EnhancedTextField` | Recommended text input; uses FieldWrapper internally |\n| `Autocomplete` | Searchable select; uses FieldWrapper internally for its label |\n| `FormField` | Simple outlined input with integrated label |\n| `FormControl` | MUI context provider for error/disabled/required state propagation |\n"}}},"ui-components-formcontrol":{"id":"ui-components-formcontrol","name":"FormControl","path":"./src/stories/ui-components/FormControl.stories.tsx","stories":[{"id":"ui-components-formcontrol--default","name":"Default","snippet":"const Default = () => (\n  <FormControl>\n    <InputLabel htmlFor=\"default-input\">Name</InputLabel>\n    <Input id=\"default-input\" />\n    <FormHelperText>Enter your full name</FormHelperText>\n  </FormControl>\n);"},{"id":"ui-components-formcontrol--error-state","name":"Error State","snippet":"const ErrorState = () => (\n  <FormControl error>\n    <InputLabel htmlFor=\"error-input\">Email</InputLabel>\n    <Input id=\"error-input\" defaultValue=\"invalid\" />\n    <FormHelperText>Please enter a valid email</FormHelperText>\n  </FormControl>\n);"},{"id":"ui-components-formcontrol--disabled-state","name":"Disabled State","snippet":"const DisabledState = () => (\n  <FormControl disabled>\n    <InputLabel htmlFor=\"disabled-input\">Disabled</InputLabel>\n    <Input id=\"disabled-input\" defaultValue=\"Cannot edit\" />\n    <FormHelperText>This field is disabled</FormHelperText>\n  </FormControl>\n);"},{"id":"ui-components-formcontrol--required-field","name":"Required Field","snippet":"const RequiredField = () => (\n  <FormControl required>\n    <InputLabel htmlFor=\"required-input\">Required</InputLabel>\n    <Input id=\"required-input\" />\n    <FormHelperText>This field is required</FormHelperText>\n  </FormControl>\n);"},{"id":"ui-components-formcontrol--all-states","name":"All States","snippet":"const AllStates = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, width: 300 }}>\n    <FormControl>\n      <InputLabel>Default</InputLabel>\n      <Input />\n    </FormControl>\n    <FormControl error>\n      <InputLabel>Error</InputLabel>\n      <Input defaultValue=\"Invalid\" />\n      <FormHelperText>Something went wrong</FormHelperText>\n    </FormControl>\n    <FormControl disabled>\n      <InputLabel>Disabled</InputLabel>\n      <Input defaultValue=\"Locked\" />\n    </FormControl>\n    <FormControl required>\n      <InputLabel>Required</InputLabel>\n      <Input />\n    </FormControl>\n  </Box>\n);"}],"import":"import { Box, FormControl, FormHelperText, Input, InputLabel } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"FormControl","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/FormControl/FormControl.tsx","actualName":"FormControl","exportName":"FormControl","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-formcontrol--docs":{"id":"ui-components-formcontrol--docs","name":"Docs","path":"./src/stories/ui-components/FormControl.mdx","title":"UI Components/FormControl","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as FormControlStories from './FormControl.stories';\nimport { FormControl } from '../../components/FormControl';\n\n<Meta of={FormControlStories} />\n\n# FormControl\n\n## Overview\n\n`FormControl` is the Signal Design System wrapper around MUI `FormControl`. It is a thin `forwardRef` pass-through with no custom logic. Use it as a low-level wrapper to provide context (error, disabled, required, fullWidth, size) to form inputs and their labels.\n\nUse `FormControl` when composing MUI form primitives (`Select`, `RadioGroup`, `OutlinedInput`) that need shared state. Prefer `FormField` or `EnhancedTextField` for standard labeled text inputs in Signal products.\n\n```tsx\nimport {\n  FormControl,\n  FormLabel,\n  FormHelperText,\n  Select,\n  InputLabel,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Wrapping `Select` with `InputLabel`, error, and disabled state (`Select` stories)\n- Grouping `RadioGroup` options with `FormLabel`\n- Low-level MUI form composition not covered by `FormField`\n\n**When not to use**\n\n- Standard labeled text inputs → use `FormField` or `EnhancedTextField` (preferred)\n- Autocomplete fields → use `Autocomplete` (label via `FieldWrapper` internally)\n- Multi-select filters → use `MultiSelect` (self-contained)\n- Simple switch/checkbox with one label → use `FormControlLabel` directly\n\n## Content guidelines\n\nRules for labels and helper text when composing with `FormControl`.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Label names the field | Short noun phrase on `FormLabel` or `InputLabel` |\n| Helper text adds context | Validation errors or format hints via `FormHelperText` |\n| Error messages are specific | \"Select an age\" not \"Invalid input\" |\n| Required is visual + semantic | `required` on `FormControl` for asterisk and AT |\n| Consistent label pairing | `InputLabel` text must match `Select label` prop |\n\n### Composition patterns\n\n| Pattern | Components | Signal reference |\n|---------|------------|------------------|\n| Select field | `FormControl` + `InputLabel` + `Select` + `MenuItem` | `Select` stories |\n| Radio group | `FormControl` + `FormLabel` + `RadioGroup` + `FormControlLabel` | `Radio` `WithLabel` story |\n| Text input (preferred) | `FormField` or `EnhancedTextField` | `FormField` stories |\n\n### Do and don't\n\n**Do**\n\n- Set `error` on `FormControl` and the child input together\n- Use `FormHelperText` for validation messages when `error` is true\n- Use `fullWidth` for responsive form layouts\n\n**Don't**\n\n- Use bare `FormControl` without a label mechanism\n- Duplicate `FormControl` nesting unnecessarily\n- Use `FormControl` when `FormField` already provides the pattern\n\n## Anatomy\n\n```\nFormControl\n├── FormLabel | InputLabel     ← label (choose one pattern)\n├── Input component            ← Select, OutlinedInput, RadioGroup, etc.\n└── FormHelperText (optional)  ← hints and errors\n```\n\n`FormField` uses `FormControl` internally with `FormLabel`, `OutlinedInput`, and `FormHelperText`.\n\n## Props\n\n`FormControlProps` extends MUI `FormControlProps` (minus `ref`). All MUI props pass through via spread.\n\n### Signal-specific props\n\n`FormControl` adds no custom props beyond MUI:\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `children` | `React.ReactNode` | — | Form input and label children | Typically `InputLabel` + `Select` or `FormLabel` + input. |\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `error` | `boolean` | `false` | Puts child input in error state | Set on both `FormControl` and child (e.g. `Select error`). See `Select` `Error` story. |\n| `disabled` | `boolean` | `false` | Disables child input styling | See `Select` `Disabled` story. |\n| `required` | `boolean` | `false` | Marks field as required | Shows asterisk on compatible labels. |\n| `fullWidth` | `boolean` | `false` | Stretches to container width | See `Select` `FullWidth` story. |\n| `size` | `'small' \\| 'medium'` | `'medium'` | Size context for child input | Propagates to child components. |\n| `variant` | `'standard' \\| 'outlined' \\| 'filled'` | — | Variant context | Used with `InputLabel` and inputs. |\n| `margin` | `'none' \\| 'dense' \\| 'normal'` | `'none'` | Vertical spacing | Use `dense` in compact forms. |\n| `sx` | `SxProps` | — | Style overrides | e.g. `minWidth: 120` on select fields. |\n\nAdditional standard MUI `FormControlProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={FormControl} />\n\n## Variants\n\n`FormControl` has no visual variant of its own. It provides context; child inputs define appearance (`outlined`, `filled`, `standard`).\n\n| Child pattern | Variant source |\n|---------------|----------------|\n| `Select` + `InputLabel` | `variant` on `Select` |\n| `FormField` | Always outlined via `OutlinedInput` |\n| `RadioGroup` | N/A — radios have no variant |\n\n## Sizes\n\nPropagates `size` to compatible children.\n\n| Size | Use for |\n|------|---------|\n| `small` | Dense forms, compact selects |\n| `medium` | Default |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Default | No error/disabled | Standard interactive field |\n| Error | `error={true}` | Pair with `FormHelperText`; see `Select` `Error` story |\n| Disabled | `disabled={true}` | See `Select` `Disabled` story |\n| Required | `required={true}` | Label asterisk via MUI |\n| Full width | `fullWidth={true}` | See `Select` `FullWidth` story |\n\n## Stories\n\n### Default\n\nFormControl with InputLabel, Input, and FormHelperText.\n\n<Canvas of={FormControlStories.Default} />\n\n### ErrorState\n\nFormControl in error state with descriptive helper text.\n\n<Canvas of={FormControlStories.ErrorState} />\n\n### DisabledState\n\nFormControl with disabled children.\n\n<Canvas of={FormControlStories.DisabledState} />\n\n### RequiredField\n\nFormControl with required prop showing asterisk on label.\n\n<Canvas of={FormControlStories.RequiredField} />\n\n### AllStates\n\nAll states (default, error, disabled, required) compared side by side.\n\n<Canvas of={FormControlStories.AllStates} />\n\nSee also composed patterns in related component stories:\n\n| Pattern | Reference story | Story ID |\n|---------|-----------------|----------|\n| Select + FormControl | `Select` → `Basic` | `ui-components-select--basic` |\n| Select error state | `Select` → `Error` | `ui-components-select--error` |\n| Select disabled | `Select` → `Disabled` | `ui-components-select--disabled` |\n| Select full width | `Select` → `FullWidth` | `ui-components-select--full-width` |\n| Radio group | `Radio` → `WithLabel` | `ui-components-radio--with-label` |\n| Labeled text input | `FormField` stories | See `FormField` documentation |\n\n## Accessibility\n\n- Provides form field context to child inputs via MUI context API.\n- `error` should be paired with `FormHelperText` describing the error for screen readers.\n- `required` propagates required semantics to compatible child labels.\n- `disabled` disables interaction on child inputs when composed correctly.\n- Associate `FormLabel` or `InputLabel` with inputs per MUI composition rules.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Prefer `FormField` or `EnhancedTextField` for text inputs — they handle labeling consistently.\n- Use `FormControl` when composing `Select`, native MUI inputs, or `RadioGroup`.\n- Set `error` on both `FormControl` and the child input for consistent styling.\n- Always include `FormHelperText` when `error` is true.\n- Use `fullWidth` in responsive form layouts.\n- Set `sx={{ minWidth: 120 }}` on select `FormControl` to prevent collapse.\n- See **Content guidelines** for label and helper text copy rules.\n\n## Anti-patterns\n\n- Using `FormControl` for every field when `FormField`/`EnhancedTextField`/`Autocomplete`/`MultiSelect` suffice.\n- `error` without `FormHelperText` — screen readers miss the error description.\n- Nesting `FormControl` inside `FormField` — `FormField` already wraps `FormControl`.\n- Importing `@mui/material/FormControl` directly — import from `@exotel-npm-dev/signal-design-system`.\n- Mismatched `InputLabel` and `Select label` text.\n- `FormControl` with no label component — field lacks accessible name.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `FormControl`\n\n- Low-level MUI form composition with `Select` or `RadioGroup`\n- Propagating `error`, `disabled`, `required`, `fullWidth` to children\n- Custom form layouts not covered by `FormField`\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Labeled text input | `FormField`, `EnhancedTextField` |\n| Searchable select | `Autocomplete` |\n| Multi-select filter | `MultiSelect` |\n| Single labeled switch | `FormControlLabel` + `Switch` |\n\n### Canonical prop combinations\n\n```tsx\n// Select field — from Select Basic story\n<FormControl sx={{ minWidth: 120 }}>\n  <InputLabel>Age</InputLabel>\n  <Select value={value} onChange={handleChange} label=\"Age\">\n    <MenuItem value={10}>Ten</MenuItem>\n  </Select>\n</FormControl>\n\n// Error with helper text\n<FormControl error fullWidth>\n  <InputLabel>Status</InputLabel>\n  <Select value={value} onChange={handleChange} label=\"Status\" error>\n    <MenuItem value=\"open\">Open</MenuItem>\n  </Select>\n  <FormHelperText>Select a status</FormHelperText>\n</FormControl>\n\n// Radio group with FormLabel\n<FormControl>\n  <FormLabel>Gender</FormLabel>\n  <RadioGroup value={value} onChange={handleChange}>\n    <FormControlLabel value=\"female\" control={<Radio />} label=\"Female\" />\n    <FormControlLabel value=\"male\" control={<Radio />} label=\"Male\" />\n  </RadioGroup>\n</FormControl>\n```\n\n### Canonical references (no dedicated stories)\n\n| Task | Reference |\n|------|-----------|\n| Select composition | `Select` stories |\n| Text input (preferred) | `FormField` stories |\n| Radio group | `Radio` `WithLabel` story |\n\n### Common mistakes to avoid\n\n- Do not wrap `EnhancedTextField` in `FormControl` — it manages its own label via `FieldWrapper`.\n- Do not use `FormControl` when `FormField` is sufficient.\n- Always pair `error` with descriptive `FormHelperText`.\n- Import from `@exotel-npm-dev/signal-design-system`.\n- No dedicated `FormControl` stories exist — reference `Select` and `Radio` stories for live examples.\n\n### Composition guidance\n\n- One `FormControl` per form field group (label + input + helper).\n- Use `margin=\"dense\"` in compact settings panels.\n- In forms, stack `FormControl` fields with consistent `fullWidth` on mobile.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `FormField` | Higher-level wrapper; uses `FormControl` internally |\n| `EnhancedTextField` | Self-contained text input with `FieldWrapper` label |\n| `Select` | Primary child input in `FormControl` compositions |\n| `InputLabel` | Floating label for `Select` (MUI re-export) |\n| `FormLabel` | Static label for radio groups (MUI re-export) |\n| `FormHelperText` | Hint and error text below inputs (MUI re-export) |\n| `Radio` | Radio input composed inside `FormControl` |\n| `Checkbox` | Checkbox composed with `FormControlLabel` |\n"}}},"ui-components-formfield":{"id":"ui-components-formfield","name":"FormField","path":"./src/stories/ui-components/FormField.stories.tsx","stories":[{"id":"ui-components-formfield--basic","name":"Basic","snippet":"const Basic = () => <FormField label=\"Email\" placeholder=\"Enter your email\" />;","description":"Basic FormField"},{"id":"ui-components-formfield--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, width: 300 }}>\n    <FormField label=\"Small\" size=\"small\" placeholder=\"Small input\" />\n    <FormField label=\"Medium\" size=\"medium\" placeholder=\"Medium input\" />\n    <FormField label=\"Large\" size=\"large\" placeholder=\"Large input\" />\n  </Box>\n);","description":"All three sizes"},{"id":"ui-components-formfield--with-helper-text","name":"With Helper Text","snippet":"const WithHelperText = () => <FormField\n    label=\"Email\"\n    placeholder=\"Enter your email\"\n    helperText=\"We'll never share your email\" />;","description":"With helper text"},{"id":"ui-components-formfield--required","name":"Required","snippet":"const Required = () => <FormField\n    label=\"Email\"\n    placeholder=\"Enter your email\"\n    required\n    helperText=\"This field is required\" />;","description":"Required field"},{"id":"ui-components-formfield--error","name":"Error","snippet":"const Error = () => <FormField\n    label=\"Email\"\n    placeholder=\"Enter your email\"\n    error\n    helperText=\"Please enter a valid email address\"\n    defaultValue=\"invalid-email\" />;","description":"Error state"},{"id":"ui-components-formfield--disabled","name":"Disabled","snippet":"const Disabled = () => <FormField\n    label=\"Email\"\n    placeholder=\"Enter your email\"\n    disabled\n    defaultValue=\"disabled@example.com\" />;","description":"Disabled state"},{"id":"ui-components-formfield--number-input","name":"Number Input","snippet":"const NumberInput = () => <FormField\n    label=\"Quantity\"\n    type=\"number\"\n    defaultValue=\"0\"\n    inputProps={{ min: 0, max: 100 }}\n    helperText=\"Enter a number between 0 and 100\" />;","description":"Number input"},{"id":"ui-components-formfield--search-input","name":"Search Input","snippet":"const SearchInput = () => (\n  <Box sx={{ width: 300 }}>\n    <FormField\n      label=\"Search\"\n      type=\"search\"\n      placeholder=\"Search...\"\n      startAdornment={<Icon name=\"search\" size=\"sm\" style={{ color: 'inherit' }} />}\n    />\n  </Box>\n);","description":"Search input"},{"id":"ui-components-formfield--password-input","name":"Password Input","snippet":"const PasswordInput = () => <FormField\n    label=\"Password\"\n    type=\"password\"\n    placeholder=\"Enter your password\"\n    helperText=\"Must be at least 8 characters\" />;","description":"Password input"},{"id":"ui-components-formfield--with-start-adornment","name":"With Start Adornment","snippet":"const WithStartAdornment = () => (\n  <Box sx={{ width: 300 }}>\n    <FormField\n      label=\"Amount\"\n      placeholder=\"0.00\"\n      startAdornment=\"$\"\n    />\n  </Box>\n);","description":"With start adornment"},{"id":"ui-components-formfield--with-end-adornment","name":"With End Adornment","snippet":"const WithEndAdornment = () => (\n  <Box sx={{ width: 300 }}>\n    <FormField\n      label=\"Weight\"\n      placeholder=\"0\"\n      endAdornment=\"kg\"\n    />\n  </Box>\n);","description":"With end adornment"},{"id":"ui-components-formfield--all-states","name":"All States","snippet":"const AllStates = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, width: 300 }}>\n    <FormField label=\"Normal\" placeholder=\"Enter text\" />\n    <FormField label=\"With Value\" defaultValue=\"Some text\" />\n    <FormField label=\"Error\" error helperText=\"Error message\" />\n    <FormField label=\"Disabled\" disabled defaultValue=\"Disabled value\" />\n    <FormField label=\"Required\" required helperText=\"This field is required\" />\n    <FormField label=\"With Helper\" helperText=\"Helper text\" />\n  </Box>\n);","description":"All states together"},{"id":"ui-components-formfield--comparison","name":"Comparison","snippet":"const Comparison = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 4, width: 300 }}>\n    <Box>\n      <Box sx={{ mb: 2, fontWeight: 500 }}>FormField (External Label)</Box>\n      <FormField\n        label=\"Email\"\n        placeholder=\"Enter your email\"\n        helperText=\"External label pattern\"\n      />\n    </Box>\n    <Box>\n      <Box sx={{ mb: 2, fontWeight: 500 }}>TextField (Floating Label)</Box>\n      <TextField\n        label=\"Email\"\n        placeholder=\"Enter your email\"\n        helperText=\"Floating label pattern\"\n      />\n    </Box>\n  </Box>\n);","description":"Comparison: FormField vs TextField"}],"import":"import { Box } from \"@mui/material\";\nimport { FormField, Icon, EnhancedTextField as TextField } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"description":"FormField component A form field with external label positioning. Uses MUI FormControl, FormLabel, OutlinedInput, and FormHelperText.","reactDocgen":{"description":"FormField component\n\nA form field with external label positioning.\nUses MUI FormControl, FormLabel, OutlinedInput, and FormHelperText.","methods":[],"displayName":"FormField","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/FormField/FormField.tsx","actualName":"FormField","exportName":"FormField","props":{"label":{"required":false,"tsType":{"name":"string"},"description":"The label text displayed above the input"},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"The placeholder text inside the input"},"helperText":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"Helper text displayed below the input"},"error":{"required":false,"tsType":{"name":"boolean"},"description":"Error message (sets error state)","defaultValue":{"value":"false","computed":false}},"required":{"required":false,"tsType":{"name":"boolean"},"description":"Whether the field is required","defaultValue":{"value":"false","computed":false}},"disabled":{"required":false,"tsType":{"name":"boolean"},"description":"Whether the field is disabled","defaultValue":{"value":"false","computed":false}},"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the input\n@default 'medium'","defaultValue":{"value":"'medium'","computed":false}},"type":{"required":false,"tsType":{"name":"string"},"description":"The input type\n@default 'text'","defaultValue":{"value":"'text'","computed":false}},"value":{"required":false,"tsType":{"name":"union","raw":"string | number","elements":[{"name":"string"},{"name":"number"}]},"description":"The input value"},"defaultValue":{"required":false,"tsType":{"name":"union","raw":"string | number","elements":[{"name":"string"},{"name":"number"}]},"description":"Default value for uncontrolled input"},"onChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: React.ChangeEvent<HTMLInputElement>) => void","signature":{"arguments":[{"type":{"name":"ReactChangeEvent","raw":"React.ChangeEvent<HTMLInputElement>","elements":[{"name":"HTMLInputElement"}]},"name":"event"}],"return":{"name":"void"}}},"description":"Change handler"},"startAdornment":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"Start adornment (e.g., icon or prefix)"},"endAdornment":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"End adornment (e.g., icon or suffix)"},"fullWidth":{"required":false,"tsType":{"name":"boolean"},"description":"Whether input is full width","defaultValue":{"value":"false","computed":false}},"inputProps":{"required":false,"tsType":{"name":"ReactInputHTMLAttributes","raw":"React.InputHTMLAttributes<HTMLInputElement>","elements":[{"name":"HTMLInputElement"}]},"description":"Additional props for the input element"},"FormControlProps":{"required":false,"tsType":{"name":"ReactComponentProps","raw":"React.ComponentProps<typeof FormControl>","elements":[{"name":"FormControl"}]},"description":"Additional props for FormControl"},"FormLabelProps":{"required":false,"tsType":{"name":"ReactComponentProps","raw":"React.ComponentProps<typeof FormLabel>","elements":[{"name":"FormLabel"}]},"description":"Additional props for FormLabel"},"InputProps":{"required":false,"tsType":{"name":"ReactComponentProps","raw":"React.ComponentProps<typeof OutlinedInput>","elements":[{"name":"OutlinedInput"}]},"description":"Additional props for OutlinedInput"},"FormHelperTextProps":{"required":false,"tsType":{"name":"ReactComponentProps","raw":"React.ComponentProps<typeof FormHelperText>","elements":[{"name":"FormHelperText"}]},"description":"Additional props for FormHelperText"}}},"docs":{"ui-components-formfield--docs":{"id":"ui-components-formfield--docs","name":"Docs","path":"./src/stories/ui-components/FormField.mdx","title":"UI Components/FormField","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as FormFieldStories from './FormField.stories';\nimport { FormField } from '../../components/FormField';\n\n<Meta of={FormFieldStories} />\n\n# FormField\n\n## Overview\n\n`FormField` is the Signal Design System form input with external labels. It composes MUI `FormControl`, `FormLabel`, `OutlinedInput`, and `FormHelperText` — replacing MUI's floating-label pattern with a stable label positioned above the field.\n\n```tsx\nimport { FormField } from '@exotel-npm-dev/signal-design-system';\n```\n\n**Do not** use raw MUI `OutlinedInput` / `TextField` — use `FormField` for the external-label pattern (see UX Constitution → Form Inputs).\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Standard form inputs with external label, helper text, error, and adornments\n- Number, search, and password input types\n- Cases where `FormControl` + `OutlinedInput` is preferred over MUI `TextField`\n\n**When not to use**\n\n- Full MUI `TextField` features (multiline rows, select integration) → `EnhancedTextField`\n- Dropdown selection → `Select`\n- Typeahead → `Autocomplete`\n\n## Anatomy\n\n```\nFormControl\n├── FormLabel (optional)       ← label above input\n├── OutlinedInput              ← input with optional adornments\n└── FormHelperText (optional)  ← helperText below\n```\n\nAdornments wrap in MUI `InputAdornment` via `startAdornment` / `endAdornment` props.\n\n## Content guidelines\n\nRules for labels, placeholders, and helper text.\n\n### Label (`label` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Noun phrase | \"Email\", \"Quantity\", \"Search\", \"Amount\", \"Weight\" |\n| Sentence case | Consistent with ECC form standards |\n| Required | Use `required` prop for indicator |\n\n### Placeholder (`placeholder` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Input hint | \"Enter your email\", \"Search...\", \"0.00\" |\n| Not a substitute for label | Label remains visible above |\n\n### Helper text (`helperText` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Guidance | \"We'll never share your email\", \"Enter a number between 0 and 100\" |\n| Validation | \"Please enter a valid email address\" with `error={true}` |\n| Required note | \"This field is required\" |\n\n### Adornment content\n\n| Position | Examples from stories |\n|----------|----------------------|\n| `startAdornment` | `$`, `Icon name=\"search\"` |\n| `endAdornment` | `kg` |\n\n### Do and don't\n\n**Do**\n\n- \"Email\" + placeholder \"Enter your email\"\n- \"Quantity\" + helper \"Enter a number between 0 and 100\"\n- Currency prefix `$` as start adornment\n\n**Don't**\n\n- Long helper text paragraphs\n- Using placeholder as the only field identifier\n- Error without actionable helper message\n\n### Guidance for AI-generated form copy\n\n- `label` names the field; `placeholder` hints at expected input format.\n- Number fields: include range in helper when constrained (`inputProps.min`/`max`).\n- Search: `type=\"search\"` + search icon adornment per `SearchInput` story.\n- Password: helper states policy (\"Must be at least 8 characters\").\n\n## Props\n\n`FormFieldProps` is a standalone interface (does not extend MUI props directly).\n\n### Core props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `label` | `string` | — | Label above input | External label via `FormLabel` |\n| `placeholder` | `string` | — | Input placeholder | Hint text inside field |\n| `helperText` | `ReactNode` | — | Text below input | Help or validation message |\n| `error` | `boolean` | `false` | Error state | Red styling; pair with error helper |\n| `required` | `boolean` | `false` | Required field | Shows required indicator on label |\n| `disabled` | `boolean` | `false` | Disabled state | Non-editable input |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'medium'` | Input height | small 32px, medium 40px, large 44px |\n| `type` | `string` | `'text'` | HTML input type | `number`, `password`, `search` in stories |\n| `value` | `string \\| number` | — | Controlled value | Standard controlled pattern |\n| `defaultValue` | `string \\| number` | — | Uncontrolled default | `Error`, `Disabled` stories |\n| `onChange` | `function` | — | Change handler | Required for controlled inputs |\n| `startAdornment` | `ReactNode` | — | Leading adornment | Wrapped in `InputAdornment` |\n| `endAdornment` | `ReactNode` | — | Trailing adornment | Wrapped in `InputAdornment` |\n| `fullWidth` | `boolean` | `false` | Full container width | `SearchInput`, adornment stories |\n| `inputProps` | `object` | — | Native input attributes | `min`/`max` on number input |\n\n### Escape hatch props\n\n| Name | Type | Description |\n|------|------|-------------|\n| `FormControlProps` | `FormControl` props | Pass-through to `FormControl` |\n| `FormLabelProps` | `FormLabel` props | Label styling overrides |\n| `InputProps` | `OutlinedInput` props | Advanced input configuration |\n| `FormHelperTextProps` | `FormHelperText` props | Helper text overrides |\n\nSee the generated table below for the full API.\n\n<ArgTypes of={FormField} />\n\n## Variants\n\nFunctional variants via `type` and adornments:\n\n| Pattern | Props | Story |\n|---------|-------|-------|\n| Text | `type=\"text\"` (default) | `Basic` |\n| Number | `type=\"number\"`, `inputProps` min/max | `NumberInput` |\n| Search | `type=\"search\"` + search icon | `SearchInput` |\n| Password | `type=\"password\"` | `PasswordInput` |\n| Currency prefix | `startAdornment=\"$\"` | `WithStartAdornment` |\n| Unit suffix | `endAdornment=\"kg\"` | `WithEndAdornment` |\n\n## Sizes\n\n| Size | Height | Story |\n|------|--------|-------|\n| `small` | 32px | `Sizes` |\n| `medium` | 40px | `Sizes` (default) |\n| `large` | 44px | `Sizes` |\n\n<Canvas of={FormFieldStories.Sizes} />\n\n## States\n\n| State | How to apply | Story |\n|-------|--------------|-------|\n| Normal | Default props | `Basic`, `AllStates` |\n| With value | `defaultValue` or `value` | `AllStates` (\"With Value\") |\n| Error | `error` + helper | `Error`, `AllStates` |\n| Disabled | `disabled` | `Disabled`, `AllStates` |\n| Required | `required` + helper | `Required`, `AllStates` |\n| With helper | `helperText` | `WithHelperText`, `AllStates` |\n\n<Canvas of={FormFieldStories.AllStates} />\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| External label | `FormLabel` above `OutlinedInput` | All stories |\n| Number constraints | `inputProps={{ min, max }}` | `NumberInput` |\n| Icon search | `startAdornment` with `Icon` | `SearchInput` |\n| vs TextField | Side-by-side comparison | `Comparison` |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-form-field--basic`\n\n`label=\"Email\"`, `placeholder=\"Enter your email\"`.\n\n**Recommended usage:** Default text input with external label.\n\n<Canvas of={FormFieldStories.Basic} />\n\n### Sizes\n\n**Story ID:** `ui-components-form-field--sizes`\n\n`small`, `medium`, `large` at 32px / 40px / 44px.\n\n**Recommended usage:** Size selection for dense vs comfortable forms.\n\n<Canvas of={FormFieldStories.Sizes} />\n\n### WithHelperText\n\n**Story ID:** `ui-components-form-field--with-helper-text`\n\n`helperText=\"We'll never share your email\"`.\n\n**Recommended usage:** Non-error contextual help.\n\n<Canvas of={FormFieldStories.WithHelperText} />\n\n### Required\n\n**Story ID:** `ui-components-form-field--required`\n\n`required={true}`, `helperText=\"This field is required\"`.\n\n**Recommended usage:** Mandatory fields.\n\n<Canvas of={FormFieldStories.Required} />\n\n### Error\n\n**Story ID:** `ui-components-form-field--error`\n\n`error={true}`, `defaultValue=\"invalid-email\"`, `helperText=\"Please enter a valid email address\"`.\n\n**Recommended usage:** Validation failure.\n\n<Canvas of={FormFieldStories.Error} />\n\n### Disabled\n\n**Story ID:** `ui-components-form-field--disabled`\n\n`disabled={true}`, `defaultValue=\"disabled@example.com\"`.\n\n**Recommended usage:** Unavailable or read-only fields.\n\n<Canvas of={FormFieldStories.Disabled} />\n\n### NumberInput\n\n**Story ID:** `ui-components-form-field--number-input`\n\n`type=\"number\"`, `inputProps={{ min: 0, max: 100 }}`, range helper text.\n\n**Recommended usage:** Numeric quantity fields with bounds.\n\n<Canvas of={FormFieldStories.NumberInput} />\n\n### SearchInput\n\n**Story ID:** `ui-components-form-field--search-input`\n\n`type=\"search\"`, `startAdornment` with `Icon name=\"search\"`.\n\n**Recommended usage:** Search/filter fields.\n\n<Canvas of={FormFieldStories.SearchInput} />\n\n### PasswordInput\n\n**Story ID:** `ui-components-form-field--password-input`\n\n`type=\"password\"`, `helperText=\"Must be at least 8 characters\"`.\n\n**Recommended usage:** Password entry with policy hint.\n\n<Canvas of={FormFieldStories.PasswordInput} />\n\n### WithStartAdornment\n\n**Story ID:** `ui-components-form-field--with-start-adornment`\n\n`startAdornment=\"$\"` on Amount field.\n\n**Recommended usage:** Currency or unit prefix.\n\n<Canvas of={FormFieldStories.WithStartAdornment} />\n\n### WithEndAdornment\n\n**Story ID:** `ui-components-form-field--with-end-adornment`\n\n`endAdornment=\"kg\"` on Weight field.\n\n**Recommended usage:** Unit suffix.\n\n<Canvas of={FormFieldStories.WithEndAdornment} />\n\n### AllStates\n\n**Story ID:** `ui-components-form-field--all-states`\n\nNormal, with value, error, disabled, required, and helper states in one column.\n\n**Recommended usage:** Visual reference for all field states.\n\n<Canvas of={FormFieldStories.AllStates} />\n\n### Comparison\n\n**Story ID:** `ui-components-form-field--comparison`\n\n`FormField` (external label) vs `EnhancedTextField` (also external label via `FieldWrapper`) side by side.\n\n**Recommended usage:** Understanding label positioning approaches.\n\n<Canvas of={FormFieldStories.Comparison} />\n\n## Accessibility\n\n- `FormLabel` associates with input via `FormControl` semantics.\n- `required` and `error` propagate to `FormControl` for assistive technology.\n- `helperText` in `FormHelperText` is linked to the input.\n- `disabled` prevents interaction and greys out the field.\n- Search icon adornment should be decorative; the label \"Search\" names the field.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Provide `label` for every form field.\n- Pair `error` with specific, actionable `helperText`.\n- Use `size` consistently within a form section.\n- Use `fullWidth` in stacked form layouts.\n- Use `inputProps` for native constraints (`min`, `max`, `pattern`).\n- Choose `EnhancedTextField` when multiline or full TextField API is needed.\n\n## Anti-patterns\n\n- Omitting `label` and relying on placeholder alone.\n- Using `FormField` for multiline text — use `EnhancedTextField multiline`.\n- Using `FormField` for dropdowns — use `Select`.\n- Generic error messages without fix guidance.\n- Mixing floating-label `TextField` and `FormField` in the same form section without reason.\n\n## Guidance for AI Agents\n\n### When to choose `FormField`\n\n- Simple outlined input with external label\n- Number, search, password types with adornments\n- `FormControl`-level control over the input primitive\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Multiline / TextField features | `EnhancedTextField` |\n| Dropdown | `Select` |\n| Autocomplete list | `Autocomplete` |\n\n### Canonical prop combinations\n\n```tsx\n// Default — story: Basic\n<FormField label=\"Email\" placeholder=\"Enter your email\" />\n\n// Validation — story: Error\n<FormField label=\"Email\" error helperText=\"Please enter a valid email address\" defaultValue=\"invalid-email\" />\n\n// Number — story: NumberInput\n<FormField label=\"Quantity\" type=\"number\" defaultValue=\"0\" inputProps={{ min: 0, max: 100 }} helperText=\"Enter a number between 0 and 100\" />\n\n// Search — story: SearchInput\n<FormField label=\"Search\" type=\"search\" placeholder=\"Search...\" startAdornment={<Icon name=\"search\" size=\"sm\" style={{ color: 'inherit' }} />} fullWidth />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default field | `Basic` |\n| All visual states | `AllStates` |\n| Number input | `NumberInput` |\n| Search with icon | `SearchInput` |\n| Password | `PasswordInput` |\n| Currency adornment | `WithStartAdornment` |\n\n### Common mistakes to avoid\n\n- `multiline` — not supported; use `EnhancedTextField`.\n- `startIconProps` — use `startAdornment`.\n- Inventing sizes beyond `small`, `medium`, `large`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `EnhancedTextField` | TextField-based alternative with `FieldWrapper` |\n| `FieldWrapper` | Shared label primitive used by EnhancedTextField |\n| `Select` | Dropdown form control |\n| `FormControl` | Underlying MUI primitive |\n| `Icon` | Search adornment in `SearchInput` |\n"}}},"ui-components-grid":{"id":"ui-components-grid","name":"Grid","path":"./src/stories/ui-components/Grid.stories.tsx","stories":[{"id":"ui-components-grid--basic","name":"Basic","snippet":"const Basic = () => (\n  <Grid container spacing={2}>\n    <Grid item xs={6}><Paper sx={{ p: 2 }}>Item 1</Paper></Grid>\n    <Grid item xs={6}><Paper sx={{ p: 2 }}>Item 2</Paper></Grid>\n  </Grid>\n);","description":"Basic grid layout"},{"id":"ui-components-grid--responsive","name":"Responsive","snippet":"const Responsive = () => (\n  <Grid container spacing={2}>\n    <Grid item xs={12} sm={6} md={4}>\n      <Paper sx={{ p: 2 }}>\n        <Typography variant=\"h6\">Item 1</Typography>\n        <Typography variant=\"body2\">xs=12, sm=6, md=4</Typography>\n      </Paper>\n    </Grid>\n    <Grid item xs={12} sm={6} md={4}>\n      <Paper sx={{ p: 2 }}>\n        <Typography variant=\"h6\">Item 2</Typography>\n        <Typography variant=\"body2\">xs=12, sm=6, md=4</Typography>\n      </Paper>\n    </Grid>\n    <Grid item xs={12} sm={6} md={4}>\n      <Paper sx={{ p: 2 }}>\n        <Typography variant=\"h6\">Item 3</Typography>\n        <Typography variant=\"body2\">xs=12, sm=6, md=4</Typography>\n      </Paper>\n    </Grid>\n  </Grid>\n);","description":"Responsive grid"},{"id":"ui-components-grid--spacing","name":"Spacing","snippet":"const Spacing = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>\n    {[0, 1, 2, 4].map((spacing) => (\n      <div key={spacing}>\n        <Typography variant=\"caption\" gutterBottom>Spacing: {spacing}</Typography>\n        <Grid container spacing={spacing}>\n          <Grid item xs={4}><Paper sx={{ p: 2 }}>Item 1</Paper></Grid>\n          <Grid item xs={4}><Paper sx={{ p: 2 }}>Item 2</Paper></Grid>\n          <Grid item xs={4}><Paper sx={{ p: 2 }}>Item 3</Paper></Grid>\n        </Grid>\n      </div>\n    ))}\n  </div>\n);","description":"Different spacing"},{"id":"ui-components-grid--column-sizes","name":"Column Sizes","snippet":"const ColumnSizes = () => (\n  <Grid container spacing={2}>\n    <Grid item xs={12}><Paper sx={{ p: 2 }}>Full width (xs=12)</Paper></Grid>\n    <Grid item xs={6}><Paper sx={{ p: 2 }}>Half width (xs=6)</Paper></Grid>\n    <Grid item xs={6}><Paper sx={{ p: 2 }}>Half width (xs=6)</Paper></Grid>\n    <Grid item xs={4}><Paper sx={{ p: 2 }}>One third (xs=4)</Paper></Grid>\n    <Grid item xs={4}><Paper sx={{ p: 2 }}>One third (xs=4)</Paper></Grid>\n    <Grid item xs={4}><Paper sx={{ p: 2 }}>One third (xs=4)</Paper></Grid>\n  </Grid>\n);","description":"Grid with different column sizes"}],"import":"import { Grid, Paper, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Grid","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Grid/Grid.tsx","actualName":"Grid","exportName":"Grid","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-grid--docs":{"id":"ui-components-grid--docs","name":"Docs","path":"./src/stories/ui-components/Grid.mdx","title":"UI Components/Grid","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as GridStories from './Grid.stories';\nimport { Grid } from '../../components/Grid';\n\n<Meta of={GridStories} />\n\n# Grid\n\n## Overview\n\n`Grid` wraps MUI `Grid` (v2) for responsive column layouts.\n\n```tsx\nimport { Grid } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Responsive multi-column page layouts.\n**When not to use:** Simple vertical/horizontal stacking → `Stack`.\n\n## Stories\n\n`Basic`, `Responsive`, `Spacing`, `ColumnSizes`\n\n<Canvas of={GridStories.Basic} />\n<Canvas of={GridStories.Responsive} />\n\n## Related Components\n\n`Stack`, `Box`, `Container`\n"}}},"ui-components-icon":{"id":"ui-components-icon","name":"Icon","path":"./src/stories/ui-components/Icon.stories.tsx","stories":[{"id":"ui-components-icon--basic","name":"Basic","snippet":"const Basic = () => <Icon name=\"phone\" size=\"md\" weight=\"regular\" />;","description":"Basic icon"},{"id":"ui-components-icon--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Icon name=\"phone\" size=\"xs\" />\n    <Icon name=\"phone\" size=\"sm\" />\n    <Icon name=\"phone\" size=\"md\" />\n    <Icon name=\"phone\" size=\"lg\" />\n  </div>\n);","description":"Different sizes"},{"id":"ui-components-icon--weights","name":"Weights","snippet":"const Weights = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Icon name=\"warning\" weight=\"light\" />\n    <Icon name=\"warning\" weight=\"regular\" />\n    <Icon name=\"warning\" weight=\"bold\" />\n    <Icon name=\"warning\" weight=\"fill\" />\n  </div>\n);","description":"Different weights"},{"id":"ui-components-icon--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Icon name=\"check-circle\" color=\"#4caf50\" />\n    <Icon name=\"x-circle\" color=\"#d32f2f\" />\n    <Icon name=\"info\" color=\"#0288d1\" />\n    <Icon name=\"warning\" color=\"#ed6c02\" />\n  </div>\n);","description":"Different colors"},{"id":"ui-components-icon--common-icons","name":"Common Icons","snippet":"const CommonIcons = () => (\n  <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n    <Icon name=\"phone\" />\n    <Icon name=\"mail\" />\n    <Icon name=\"user\" />\n    <Icon name=\"settings\" />\n    <Icon name=\"search\" />\n    <Icon name=\"menu\" />\n    <Icon name=\"check\" />\n    <Icon name=\"x\" />\n    <Icon name=\"plus\" />\n    <Icon name=\"minus\" />\n    <Icon name=\"trash\" />\n    <Icon name=\"edit\" />\n  </div>\n);","description":"Common icons showcase"},{"id":"ui-components-icon--navigation-icons","name":"Navigation Icons","snippet":"const NavigationIcons = () => (\n  <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n    <Icon name=\"arrow-left\" />\n    <Icon name=\"arrow-right\" />\n    <Icon name=\"arrow-up\" />\n    <Icon name=\"arrow-down\" />\n    <Icon name=\"caret-left\" />\n    <Icon name=\"caret-right\" />\n    <Icon name=\"caret-up\" />\n    <Icon name=\"caret-down\" />\n  </div>\n);","description":"Navigation icons"},{"id":"ui-components-icon--interactive","name":"Interactive","snippet":"const Interactive = () => <Icon name=\"phone\" size=\"md\" weight=\"regular\" color={undefined} />;","description":"Interactive icon with all controls"}],"import":"import { Icon } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"description":"Icon component Renders Phosphor icons using a string-based name API. All Phosphor icon props are supported via prop spreading.","reactDocgen":{"description":"Icon component\n\nRenders Phosphor icons using a string-based name API.\nAll Phosphor icon props are supported via prop spreading.","methods":[],"displayName":"Icon","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Icon/Icon.tsx","actualName":"Icon","exportName":"Icon","props":{"name":{"required":true,"tsType":{"name":"unknown"},"description":"The name of the icon to display"},"size":{"required":false,"tsType":{"name":"union","raw":"IconSize | number","elements":[{"name":"union","raw":"'xs' | 'sm' | 'md' | 'lg'","elements":[{"name":"literal","value":"'xs'"},{"name":"literal","value":"'sm'"},{"name":"literal","value":"'md'"},{"name":"literal","value":"'lg'"}]},{"name":"number"}]},"description":"Size of the icon\n@default 'md'","defaultValue":{"value":"'md'","computed":false}},"weight":{"required":false,"tsType":{"name":"union","raw":"'regular' | 'bold' | 'fill' | 'light'","elements":[{"name":"literal","value":"'regular'"},{"name":"literal","value":"'bold'"},{"name":"literal","value":"'fill'"},{"name":"literal","value":"'light'"}]},"description":"Weight/style of the icon\n@default 'regular'","defaultValue":{"value":"'regular'","computed":false}},"color":{"required":false,"tsType":{"name":"string"},"description":"Color of the icon. Defaults to theme text color."}},"composes":["Omit"]},"docs":{"ui-components-icon--docs":{"id":"ui-components-icon--docs","name":"Docs","path":"./src/stories/ui-components/Icon.mdx","title":"UI Components/Icon","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as IconStories from './Icon.stories';\nimport { Icon } from '../../components/Icon';\n\n<Meta of={IconStories} />\n\n# Icon\n\n## Overview\n\n`Icon` renders [Phosphor Icons](https://phosphoricons.com/) via a string-based `name` registry (`IconName`). It is the standard way to display icons across Signal products.\n\n```tsx\nimport { Icon } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Icons inside buttons, tabs, lists, navigation, chips, and inline UI.\n**When not to use:** Clickable icon-only control → wrap in `IconButton`; labeled action → `Button` with `startIconProps`.\n\n## Anatomy\n\n```\nIcon  ← Phosphor icon from iconRegistry[name]\n```\n\nSingle element; no children.\n\n## Props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `name` | `IconName` | required | Registry icon key | Must exist in `iconRegistry` |\n| `size` | `'xs' \\| 'sm' \\| 'md' \\| 'lg' \\| number` | `'md'` | Size token or pixels | xs=16, sm=20, md=24, lg=32 |\n| `weight` | `'regular' \\| 'bold' \\| 'fill' \\| 'light'` | `'regular'` | Phosphor weight | `light` maps to Phosphor `thin` |\n| `color` | `string` | `'currentColor'` | Icon color | Inherit from parent for theme consistency |\n\n<ArgTypes of={Icon} />\n\n## Sizes\n\n| Token | Pixels | Story |\n|-------|--------|-------|\n| `xs` | 16 | `Sizes` |\n| `sm` | 20 | `Sizes`, tab/list icons |\n| `md` | 24 | `Basic`, default |\n| `lg` | 32 | `Sizes` |\n\n<Canvas of={IconStories.Sizes} />\n\n## Weights\n\n| Weight | Story |\n|--------|-------|\n| `light` | `Weights` |\n| `regular` | `Weights` |\n| `bold` | `Weights` |\n| `fill` | `Weights` |\n\n<Canvas of={IconStories.Weights} />\n\n## Stories\n\n### Basic — `ui-components-icon--basic`\n\nDefault `phone` icon, `md`, `regular`.\n\n<Canvas of={IconStories.Basic} />\n\n### Sizes — `ui-components-icon--sizes`\n\n### Weights — `ui-components-icon--weights`\n\n### Colors — `ui-components-icon--colors`\n\nHex colors on semantic icons (story demo only; prefer `currentColor` in product).\n\n<Canvas of={IconStories.Colors} />\n\n### CommonIcons — `ui-components-icon--common-icons`\n\nphone, mail, user, settings, search, menu, check, x, plus, minus, trash, edit.\n\n<Canvas of={IconStories.CommonIcons} />\n\n### NavigationIcons — `ui-components-icon--navigation-icons`\n\nArrows and carets.\n\n<Canvas of={IconStories.NavigationIcons} />\n\n### Interactive — `ui-components-icon--interactive`\n\n## Accessibility\n\n- Decorative icons inside labeled buttons: parent provides accessible name.\n- Standalone meaningful icons: ensure adjacent text or `aria-label` on parent control.\n- `color=\"currentColor\"` inherits theme text color for contrast context.\n- Storybook a11y: `test: 'todo'`.\n\n## Best Practices\n\n- Use `currentColor` (default) inside `Button`, `IconButton`, `ListItemIcon`.\n- Use valid `IconName` from registry — do not pass arbitrary strings.\n- Prefer `startIconProps` / `iconProps` on `Button` / `Tab` over embedding raw `Icon` when those APIs exist.\n- Size `sm` in dense lists and tabs; `md` for standalone toolbar icons.\n\n## Anti-patterns\n\n- Using `Icon` as a clickable element without `IconButton`.\n- Hardcoded hex in product code when semantic parent color suffices.\n- Inventing `name` values not in `IconName` registry.\n- Importing Phosphor icons directly — use Signal `Icon`.\n\n## Guidance for AI Agents\n\n### When to choose `Icon`\n\n- Visual affordance inside another component\n- Registry-based consistent icon set\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Clickable icon only | `IconButton` |\n| Icon + text action | `Button` + `startIconProps` |\n| Tab icon | `Tab` + `iconProps` |\n\n### Canonical patterns\n\n```tsx\n<Icon name=\"plus\" size=\"sm\" />\n<Icon name=\"trash\" size=\"md\" color=\"currentColor\" />\n// Button — prefer:\n<Button startIconProps={{ name: 'plus' }}>Add</Button>\n```\n\n### Canonical stories\n\n| Task | Story |\n|------|-------|\n| Default | `Basic` |\n| Size pick | `Sizes` |\n| Common set | `CommonIcons` |\n\n## Related Components\n\n`IconButton`, `Button`, `Tab`, `ListItemIcon`, `Chip`\n"}}},"ui-components-iconbutton":{"id":"ui-components-iconbutton","name":"IconButton","path":"./src/stories/ui-components/IconButton.stories.tsx","stories":[{"id":"ui-components-iconbutton--basic","name":"Basic","snippet":"const Basic = () => <IconButton><Icon name=\"trash\" /></IconButton>;"},{"id":"ui-components-iconbutton--shapes","name":"Shapes","snippet":"const Shapes = () => (\n  <Stack direction=\"row\" spacing={2} alignItems=\"center\">\n    <Stack alignItems=\"center\" spacing={1}>\n      <IconButton shape=\"square\">\n        <Icon name=\"gear\" />\n      </IconButton>\n      <Typography variant=\"caption\">Square (default)</Typography>\n    </Stack>\n    <Stack alignItems=\"center\" spacing={1}>\n      <IconButton shape=\"circle\">\n        <Icon name=\"gear\" />\n      </IconButton>\n      <Typography variant=\"caption\">Circle</Typography>\n    </Stack>\n  </Stack>\n);"},{"id":"ui-components-iconbutton--variants","name":"Variants","snippet":"const Variants = () => (\n  <Stack direction=\"row\" spacing={2} alignItems=\"center\">\n    <Stack alignItems=\"center\" spacing={1}>\n      <IconButton variant=\"text\">\n        <Icon name=\"gear\" />\n      </IconButton>\n      <Typography variant=\"caption\">Text (default)</Typography>\n    </Stack>\n    <Stack alignItems=\"center\" spacing={1}>\n      <IconButton variant=\"outlined\">\n        <Icon name=\"gear\" />\n      </IconButton>\n      <Typography variant=\"caption\">Outlined</Typography>\n    </Stack>\n    <Stack alignItems=\"center\" spacing={1}>\n      <IconButton variant=\"contained\">\n        <Icon name=\"gear\" />\n      </IconButton>\n      <Typography variant=\"caption\">Contained</Typography>\n    </Stack>\n  </Stack>\n);"},{"id":"ui-components-iconbutton--shape-with-variants","name":"Shape With Variants","snippet":"const ShapeWithVariants = () => (\n  <Stack spacing={3}>\n    <Stack spacing={1}>\n      <Typography variant=\"title2\">Square</Typography>\n      <Stack direction=\"row\" spacing={2}>\n        <IconButton shape=\"square\" variant=\"text\" color=\"primary\">\n          <Icon name=\"gear\" />\n        </IconButton>\n        <IconButton shape=\"square\" variant=\"outlined\" color=\"primary\">\n          <Icon name=\"gear\" />\n        </IconButton>\n        <IconButton shape=\"square\" variant=\"contained\" color=\"primary\">\n          <Icon name=\"gear\" />\n        </IconButton>\n      </Stack>\n    </Stack>\n    <Stack spacing={1}>\n      <Typography variant=\"title2\">Circle</Typography>\n      <Stack direction=\"row\" spacing={2}>\n        <IconButton shape=\"circle\" variant=\"text\" color=\"primary\">\n          <Icon name=\"gear\" />\n        </IconButton>\n        <IconButton shape=\"circle\" variant=\"outlined\" color=\"primary\">\n          <Icon name=\"gear\" />\n        </IconButton>\n        <IconButton shape=\"circle\" variant=\"contained\" color=\"primary\">\n          <Icon name=\"gear\" />\n        </IconButton>\n      </Stack>\n    </Stack>\n  </Stack>\n);"},{"id":"ui-components-iconbutton--color-variants","name":"Color Variants","snippet":"const ColorVariants = () => {\n  const colors = ['primary', 'secondary', 'error', 'warning', 'info', 'success'] as const;\n  return (\n    <Stack spacing={3}>\n      {(['text', 'outlined', 'contained'] as const).map((variant) => (\n        <Stack key={variant} spacing={1}>\n          <Typography variant=\"title2\" textTransform=\"capitalize\">{variant}</Typography>\n          <Stack direction=\"row\" spacing={2}>\n            {colors.map((color) => (\n              <IconButton key={color} variant={variant} color={color}>\n                <Icon name=\"gear\" />\n              </IconButton>\n            ))}\n          </Stack>\n        </Stack>\n      ))}\n    </Stack>\n  );\n};"},{"id":"ui-components-iconbutton--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <Stack spacing={3}>\n    {(['text', 'outlined', 'contained'] as const).map((variant) => (\n      <Stack key={variant} spacing={1}>\n        <Typography variant=\"title2\" textTransform=\"capitalize\">{variant}</Typography>\n        <Stack direction=\"row\" spacing={2} alignItems=\"center\">\n          {(['small', 'medium', 'large'] as const).map((size) => (\n            <Stack key={size} alignItems=\"center\" spacing={1}>\n              <IconButton variant={variant} size={size} color=\"primary\">\n                <Icon name=\"gear\" />\n              </IconButton>\n              <Typography variant=\"caption\">{size}</Typography>\n            </Stack>\n          ))}\n        </Stack>\n      </Stack>\n    ))}\n  </Stack>\n);"},{"id":"ui-components-iconbutton--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <Stack direction=\"row\" spacing={2} alignItems=\"center\">\n    <IconButton variant=\"text\" disabled>\n      <Icon name=\"gear\" />\n    </IconButton>\n    <IconButton variant=\"outlined\" disabled>\n      <Icon name=\"gear\" />\n    </IconButton>\n    <IconButton variant=\"contained\" disabled>\n      <Icon name=\"gear\" />\n    </IconButton>\n  </Stack>\n);"}],"import":"import { Icon, IconButton } from \"@exotel-npm-dev/signal-design-system\";\nimport { Stack, Typography } from \"@mui/material\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"IconButton","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/IconButton/IconButton.tsx","actualName":"IconButton","exportName":"IconButton","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""},"shape":{"required":false,"tsType":{"name":"union","raw":"'circle' | 'square'","elements":[{"name":"literal","value":"'circle'"},{"name":"literal","value":"'square'"}]},"description":"The shape of the icon button.\n@default 'square'","defaultValue":{"value":"'square'","computed":false}},"variant":{"required":false,"tsType":{"name":"union","raw":"'text' | 'outlined' | 'contained'","elements":[{"name":"literal","value":"'text'"},{"name":"literal","value":"'outlined'"},{"name":"literal","value":"'contained'"}]},"description":"The visual style variant of the icon button.\n@default 'text'","defaultValue":{"value":"'text'","computed":false}}},"composes":["Omit"]},"docs":{"ui-components-iconbutton--docs":{"id":"ui-components-iconbutton--docs","name":"Docs","path":"./src/stories/ui-components/IconButton.mdx","title":"UI Components/IconButton","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as IconButtonStories from './IconButton.stories';\nimport { IconButton } from '../../components/IconButton';\n\n<Meta of={IconButtonStories} />\n\n# IconButton\n\n## Overview\n\n`IconButton` wraps MUI `IconButton` with Signal `shape` (`square` | `circle`) and `variant` (`text` | `outlined` | `contained`). Sets `data-shape` and `data-variant` for theme styling.\n\nUse for icon-only actions without a text label. Always provide `aria-label`.\n\n```tsx\nimport { IconButton, Icon } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Toolbar actions, dismiss buttons, compact controls, menu triggers.\n**When not to use:** Labeled actions → `Button`; navigation URL → `Link`.\n\n## Anatomy\n\n```\nIconButton\n└── Icon (child)   ← Typically <Icon name=\"...\" />\n```\n\nOften wrapped by `Badge` for counts.\n\n## Props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `shape` | `'square' \\| 'circle'` | `'square'` | Button shape | `data-shape` on DOM |\n| `variant` | `'text' \\| 'outlined' \\| 'contained'` | `'text'` | Visual style | `data-variant` on DOM |\n| `color` | semantic palette | `'default'` | Semantic color | See `ColorVariants` |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'medium'` | Dimensions | `Sizes` story |\n| `disabled` | `boolean` | `false` | Disables interaction | `Disabled` story |\n| `children` | `ReactNode` | — | Icon content | Pass `<Icon name=\"...\" />` |\n\n<ArgTypes of={IconButton} />\n\n## Variants\n\n| variant | Story |\n|---------|-------|\n| `text` | `Variants` (default) |\n| `outlined` | `Variants` |\n| `contained` | `Variants` |\n\n## Shapes\n\n| shape | Story |\n|-------|-------|\n| `square` | `Shapes` (default) |\n| `circle` | `Shapes` |\n\n<Canvas of={IconButtonStories.Shapes} />\n\n## Stories\n\n### Basic — `ui-components-icon-button--basic`\n\nTrash icon, default shape/variant.\n\n<Canvas of={IconButtonStories.Basic} />\n\n### Shapes — `ui-components-icon-button--shapes`\n\n### Variants — `ui-components-icon-button--variants`\n\n### ShapeWithVariants — `ui-components-icon-button--shape-with-variants`\n\nSquare and circle across text/outlined/contained.\n\n<Canvas of={IconButtonStories.ShapeWithVariants} />\n\n### ColorVariants — `ui-components-icon-button--color-variants`\n\nAll semantic colors × three variants.\n\n<Canvas of={IconButtonStories.ColorVariants} />\n\n### Sizes — `ui-components-icon-button--sizes`\n\nsmall, medium, large per variant.\n\n<Canvas of={IconButtonStories.Sizes} />\n\n### Disabled — `ui-components-icon-button--disabled`\n\n<Canvas of={IconButtonStories.Disabled} />\n\n## Accessibility\n\n- **Required:** `aria-label` describing the action (e.g. `aria-label=\"Delete\"`, `aria-label=\"Notifications\"`).\n- Renders native `<button>`.\n- Keyboard: Enter and Space activate.\n- Do not rely on icon shape alone for meaning.\n- Storybook a11y: `test: 'todo'`.\n\n## Best Practices\n\n- Always set `aria-label`.\n- Use `Icon` child with `name` from registry.\n- Use `variant=\"text\"` for low-emphasis toolbar icons.\n- Use `Badge` wrapper for notification counts.\n- Match `shape=\"circle\"` for avatar-adjacent icon buttons when design requires.\n\n## Anti-patterns\n\n- Icon-only button without `aria-label`.\n- Using `IconButton` for primary labeled CTAs — use `Button`.\n- Inventing `shape` or `variant` values outside documented set.\n- Raw MUI icons instead of Signal `Icon`.\n\n## Guidance for AI Agents\n\n### When to choose `IconButton`\n\n- Single icon, no text label, click action\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Text label | `Button` |\n| Count overlay | `Badge` + `IconButton` |\n| Menu popup | `Menu` + `IconButton` trigger |\n\n### Canonical patterns\n\n```tsx\n<IconButton aria-label=\"Delete\" onClick={handleDelete}>\n  <Icon name=\"trash\" />\n</IconButton>\n\n<IconButton aria-label=\"Settings\" variant=\"outlined\" shape=\"circle\" color=\"primary\">\n  <Icon name=\"gear\" />\n</IconButton>\n```\n\n### Canonical stories\n\n| Task | Story |\n|------|-------|\n| Default | `Basic` |\n| Shape + variant matrix | `ShapeWithVariants` |\n| Colors | `ColorVariants` |\n\n## Related Components\n\n`Icon`, `Button`, `Badge`, `Tooltip`, `Menu`\n"}}},"ui-components-input":{"id":"ui-components-input","name":"Input","path":"./src/stories/ui-components/Input.stories.tsx","stories":[{"id":"ui-components-input--default","name":"Default","snippet":"const Default = () => <Input placeholder=\"Enter text...\" />;"},{"id":"ui-components-input--disabled","name":"Disabled","snippet":"const Disabled = () => <Input placeholder=\"Disabled input\" disabled />;"},{"id":"ui-components-input--error","name":"Error","snippet":"const Error = () => <Input placeholder=\"Error state\" error defaultValue=\"Invalid value\" />;"},{"id":"ui-components-input--full-width","name":"Full Width","snippet":"const FullWidth = () => <Input placeholder=\"Full width input\" fullWidth />;"},{"id":"ui-components-input--types","name":"Types","snippet":"const Types = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, width: 300 }}>\n    <Input placeholder=\"Text\" type=\"text\" />\n    <Input placeholder=\"Password\" type=\"password\" />\n    <Input placeholder=\"Email\" type=\"email\" />\n    <Input placeholder=\"Number\" type=\"number\" />\n  </Box>\n);"}],"import":"import { Box, Input } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Input","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Input/Input.tsx","actualName":"Input","exportName":"Input","props":{"value":{"required":false,"tsType":{"name":"union","raw":"string | number","elements":[{"name":"string"},{"name":"number"}]},"description":""}},"composes":["Omit"]},"docs":{"ui-components-input--docs":{"id":"ui-components-input--docs","name":"Docs","path":"./src/stories/ui-components/Input.mdx","title":"UI Components/Input","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as InputStories from './Input.stories';\nimport { Input } from '../../components/Input';\n\n<Meta of={InputStories} />\n\n# Input\n\n## Overview\n\n`Input` wraps MUI `Input` (underline variant). This is a thin pass-through wrapper for cases requiring the raw MUI underline input.\n\n```tsx\nimport { Input } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Rare cases needing MUI underline-style `Input` directly\n- Composing with `FormControl` for custom form layouts\n- Low-level input composition not covered by higher-level components\n\n**When not to use**\n\n- Standard Exotel forms → use `FormField` or `EnhancedTextField` (outlined, external label)\n- Searchable inputs → use `Autocomplete`\n- Select dropdowns → use `Select`\n\n## Props\n\n<ArgTypes of={Input} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `placeholder` | `string` | — | Placeholder text when input is empty |\n| `disabled` | `boolean` | `false` | If true, the input is disabled |\n| `error` | `boolean` | `false` | If true, displays in error state |\n| `fullWidth` | `boolean` | `false` | If true, takes full width of container |\n| `type` | `string` | `'text'` | HTML input type |\n| `value` | `string \\| number` | — | Controlled input value |\n\n## Stories\n\n### Default\n\nBasic input with placeholder text.\n\n<Canvas of={InputStories.Default} />\n\n### Disabled\n\nInput in disabled state.\n\n<Canvas of={InputStories.Disabled} />\n\n### Error\n\nInput displaying error styling.\n\n<Canvas of={InputStories.Error} />\n\n### FullWidth\n\nInput stretching to container width.\n\n<Canvas of={InputStories.FullWidth} />\n\n### Types\n\nVarious HTML input types (text, password, email, number).\n\n<Canvas of={InputStories.Types} />\n\n## Best Practices\n\n- Prefer `EnhancedTextField` or `FormField` for standard forms — they include labels and consistent styling.\n- Use `Input` only when you need the raw underline variant or are composing with `FormControl`.\n- Always wrap in `FormControl` with `InputLabel` and `FormHelperText` for accessible labels.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `FormField` | Preferred labeled input with outlined style |\n| `EnhancedTextField` | Full-featured input with external label via FieldWrapper |\n| `FormControl` | Context provider for error/disabled/required state |\n| `Autocomplete` | Searchable typeahead input |\n"}}},"ui-components-linearprogress":{"id":"ui-components-linearprogress","name":"LinearProgress","path":"./src/stories/ui-components/LinearProgress.stories.tsx","stories":[{"id":"ui-components-linearprogress--indeterminate","name":"Indeterminate","snippet":"const Indeterminate = () => <LinearProgress variant=\"indeterminate\" />;"},{"id":"ui-components-linearprogress--determinate","name":"Determinate","snippet":"const Determinate = () => <LinearProgress variant=\"determinate\" value={60} />;"},{"id":"ui-components-linearprogress--buffer","name":"Buffer","snippet":"const Buffer = () => <LinearProgress variant=\"buffer\" value={40} valueBuffer={70} />;"},{"id":"ui-components-linearprogress--colors","name":"Colors","snippet":"const Colors = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n    <LinearProgress color=\"primary\" />\n    <LinearProgress color=\"secondary\" />\n    <LinearProgress color=\"success\" />\n    <LinearProgress color=\"error\" />\n    <LinearProgress color=\"warning\" />\n    <LinearProgress color=\"info\" />\n  </Box>\n);"},{"id":"ui-components-linearprogress--with-label","name":"With Label","snippet":"const WithLabel = () => (\n  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>\n    <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n      <Typography variant=\"body2\" color=\"text.secondary\">Uploading...</Typography>\n      <Typography variant=\"body2\" color=\"text.secondary\">75%</Typography>\n    </Box>\n    <LinearProgress variant=\"determinate\" value={75} />\n  </Box>\n);"}],"import":"import { Box, LinearProgress, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"LinearProgress","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/LinearProgress/LinearProgress.tsx","actualName":"LinearProgress","exportName":"LinearProgress","composes":["Omit"]},"docs":{"ui-components-linearprogress--docs":{"id":"ui-components-linearprogress--docs","name":"Docs","path":"./src/stories/ui-components/LinearProgress.mdx","title":"UI Components/LinearProgress","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as LinearProgressStories from './LinearProgress.stories';\nimport { LinearProgress } from '../../components/LinearProgress';\n\n<Meta of={LinearProgressStories} />\n\n# LinearProgress\n\n## Overview\n\n`LinearProgress` wraps MUI `LinearProgress` for horizontal progress bars indicating loading state or completion percentage.\n\n```tsx\nimport { LinearProgress } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Known or indeterminate horizontal progress (upload, page load bar)\n- File upload progress indicators\n- Step completion in multi-step flows\n\n**When not to use**\n\n- Compact inline spinner → use `CircularProgress`\n- Skeleton loading states → use MUI Skeleton\n- Step navigation → use `Stepper`\n\n## Props\n\n<ArgTypes of={LinearProgress} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `variant` | `'indeterminate' \\| 'determinate' \\| 'buffer' \\| 'query'` | `'indeterminate'` | Progress bar behavior |\n| `value` | `number` | — | Value between 0–100 (for determinate/buffer) |\n| `valueBuffer` | `number` | — | Buffer bar value (buffer variant only) |\n| `color` | `'primary' \\| 'secondary' \\| 'error' \\| 'info' \\| 'success' \\| 'warning' \\| 'inherit'` | `'primary'` | The color of the progress bar |\n\n## Stories\n\n### Indeterminate\n\nContinuous animation indicating unknown progress duration.\n\n<Canvas of={LinearProgressStories.Indeterminate} />\n\n### Determinate\n\nProgress bar with a set value showing 60% completion.\n\n<Canvas of={LinearProgressStories.Determinate} />\n\n### Buffer\n\nBuffer variant showing loaded vs. played progress (e.g. video buffering).\n\n<Canvas of={LinearProgressStories.Buffer} />\n\n### Colors\n\nAll available color options demonstrated.\n\n<Canvas of={LinearProgressStories.Colors} />\n\n### WithLabel\n\nDeterminate progress bar paired with a percentage label.\n\n<Canvas of={LinearProgressStories.WithLabel} />\n\n## Best Practices\n\n- Use `indeterminate` when progress percentage is unknown.\n- Use `determinate` with a numeric `value` for file uploads, downloads, or known-duration tasks.\n- Pair with a `Typography` label showing percentage for determinate bars.\n- Use `color=\"success\"` on completion if desired.\n- Place at the top of a card or page for global loading state.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `CircularProgress` | Compact spinner for inline or centered loading |\n| `DataGrid` | Uses LinearProgress internally during loading |\n| `Stepper` | Step-based progress navigation |\n"}}},"ui-components-link":{"id":"ui-components-link","name":"Link","path":"./src/stories/ui-components/Link.stories.tsx","stories":[{"id":"ui-components-link--basic","name":"Basic","snippet":"const Basic = () => <Link href=\"#\">Link</Link>;"},{"id":"ui-components-link--underline-none","name":"Underline None","snippet":"const UnderlineNone = () => <Link href=\"#\" underline=\"none\">No underline</Link>;"}],"import":"import { Link } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Link","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Link/Link.tsx","actualName":"Link","exportName":"Link","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-link--docs":{"id":"ui-components-link--docs","name":"Docs","path":"./src/stories/ui-components/Link.mdx","title":"UI Components/Link","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as LinkStories from './Link.stories';\nimport { Link } from '../../components/Link';\n\n<Meta of={LinkStories} />\n\n# Link\n\n## Overview\n\n`Link` wraps MUI `Link` for navigation and external URLs within text or UI.\n\n```tsx\nimport { Link } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Inline navigation, external URLs, breadcrumb links.\n**When not to use:** Primary actions → `Button`; app routing may use framework `Link` with MUI styling.\n\n## Stories\n\n`Basic`, `UnderlineNone`\n\n<Canvas of={LinkStories.Basic} />\n\n## Related Components\n\n`Breadcrumbs`, `Button`, `Typography`\n"}}},"ui-components-list":{"id":"ui-components-list","name":"List","path":"./src/stories/ui-components/List.stories.tsx","stories":[{"id":"ui-components-list--basic","name":"Basic","snippet":"const Basic = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem>\n      <ListItemText primary=\"Inbox\" secondary=\"Jan 9, 2014\" />\n    </ListItem>\n    <ListItem>\n      <ListItemText primary=\"Drafts\" secondary=\"Jan 7, 2014\" />\n    </ListItem>\n    <ListItem>\n      <ListItemText primary=\"Trash\" secondary=\"Jan 1, 2014\" />\n    </ListItem>\n  </List>\n);","description":"Basic list"},{"id":"ui-components-list--with-icons","name":"With Icons","snippet":"const WithIcons = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"inbox\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Inbox\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"paper-plane\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Drafts\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"trash\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Trash\" />\n    </ListItem>\n  </List>\n);","description":"List with icons"},{"id":"ui-components-list--with-avatars","name":"With Avatars","snippet":"const WithAvatars = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem>\n      <ListItemAvatar>\n        <Avatar>A</Avatar>\n      </ListItemAvatar>\n      <ListItemText primary=\"Avatar A\" secondary=\"Secondary text\" />\n    </ListItem>\n    <ListItem>\n      <ListItemAvatar>\n        <Avatar>B</Avatar>\n      </ListItemAvatar>\n      <ListItemText primary=\"Avatar B\" secondary=\"Secondary text\" />\n    </ListItem>\n    <ListItem>\n      <ListItemAvatar>\n        <Avatar>C</Avatar>\n      </ListItemAvatar>\n      <ListItemText primary=\"Avatar C\" secondary=\"Secondary text\" />\n    </ListItem>\n  </List>\n);","description":"List with avatars"},{"id":"ui-components-list--with-buttons","name":"With Buttons","snippet":"const WithButtons = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem disablePadding>\n      <ListItemButton>\n        <ListItemIcon>\n          <Icon name=\"inbox\" size=\"sm\" />\n        </ListItemIcon>\n        <ListItemText primary=\"Inbox\" />\n      </ListItemButton>\n    </ListItem>\n    <ListItem disablePadding>\n      <ListItemButton>\n        <ListItemIcon>\n          <Icon name=\"paper-plane\" size=\"sm\" />\n        </ListItemIcon>\n        <ListItemText primary=\"Drafts\" />\n      </ListItemButton>\n    </ListItem>\n    <ListItem disablePadding>\n      <ListItemButton>\n        <ListItemIcon>\n          <Icon name=\"trash\" size=\"sm\" />\n        </ListItemIcon>\n        <ListItemText primary=\"Trash\" />\n      </ListItemButton>\n    </ListItem>\n  </List>\n);","description":"List with buttons"},{"id":"ui-components-list--with-secondary-actions","name":"With Secondary Actions","snippet":"const WithSecondaryActions = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"inbox\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Inbox\" secondary=\"Jan 9, 2014\" />\n      <ListItemSecondaryAction>\n        <IconButton edge=\"end\" aria-label=\"delete\">\n          <Icon name=\"trash\" size=\"sm\" />\n        </IconButton>\n      </ListItemSecondaryAction>\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"paper-plane\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Drafts\" secondary=\"Jan 7, 2014\" />\n      <ListItemSecondaryAction>\n        <IconButton edge=\"end\" aria-label=\"delete\">\n          <Icon name=\"trash\" size=\"sm\" />\n        </IconButton>\n      </ListItemSecondaryAction>\n    </ListItem>\n  </List>\n);","description":"List with secondary actions"},{"id":"ui-components-list--with-checkboxes","name":"With Checkboxes","snippet":"const WithCheckboxes = () => {\n  const [checked, setChecked] = useState([0]);\n  const handleToggle = (value: number) => () => {\n    const currentIndex = checked.indexOf(value);\n    const newChecked = [...checked];\n    if (currentIndex === -1) {\n      newChecked.push(value);\n    } else {\n      newChecked.splice(currentIndex, 1);\n    }\n    setChecked(newChecked);\n  };\n\n  return (\n    <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n      {[0, 1, 2, 3].map((value) => {\n        const labelId = `checkbox-list-label-${value}`;\n        return (\n          <ListItem\n            key={value}\n            disablePadding\n          >\n            <ListItemButton role={undefined} onClick={handleToggle(value)} dense>\n              <ListItemText id={labelId} primary={`Line item ${value + 1}`} />\n            </ListItemButton>\n            <ListItemSecondaryAction>\n              <Checkbox\n                edge=\"end\"\n                onChange={handleToggle(value)}\n                checked={checked.indexOf(value) !== -1}\n                inputProps={{ 'aria-labelledby': labelId }}\n              />\n            </ListItemSecondaryAction>\n          </ListItem>\n        );\n      })}\n    </List>\n  );\n};","description":"List with checkboxes"},{"id":"ui-components-list--dense","name":"Dense","snippet":"const Dense = () => (\n  <List dense sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"inbox\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Inbox\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"paper-plane\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Drafts\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"trash\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Trash\" />\n    </ListItem>\n  </List>\n);","description":"Dense list"},{"id":"ui-components-list--with-dividers","name":"With Dividers","snippet":"const WithDividers = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem>\n      <ListItemText primary=\"Inbox\" />\n    </ListItem>\n    <ListDivider />\n    <ListItem>\n      <ListItemText primary=\"Drafts\" />\n    </ListItem>\n    <ListDivider />\n    <ListItem>\n      <ListItemText primary=\"Trash\" />\n    </ListItem>\n  </List>\n);","description":"List with dividers"},{"id":"ui-components-list--with-subheaders","name":"With Subheaders","snippet":"const WithSubheaders = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListSubheader>Navigation</ListSubheader>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"inbox\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Inbox\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"paper-plane\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Drafts\" />\n    </ListItem>\n    <ListSubheader>Actions</ListSubheader>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"download\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Download\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"share\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Share\" />\n    </ListItem>\n  </List>\n);","description":"List with subheaders"},{"id":"ui-components-list--with-subheaders-and-dividers","name":"With Subheaders And Dividers","snippet":"const WithSubheadersAndDividers = () => (\n  <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListSubheader>Navigation</ListSubheader>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"inbox\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Inbox\" secondary=\"5 new messages\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"paper-plane\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Drafts\" secondary=\"2 drafts\" />\n    </ListItem>\n    <ListDivider />\n    <ListSubheader>Actions</ListSubheader>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"download\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Download\" />\n    </ListItem>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"share\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Share\" />\n    </ListItem>\n    <ListDivider />\n    <ListSubheader>Settings</ListSubheader>\n    <ListItem>\n      <ListItemIcon>\n        <Icon name=\"settings\" size=\"sm\" />\n      </ListItemIcon>\n      <ListItemText primary=\"Settings\" />\n    </ListItem>\n  </List>\n);","description":"List with subheaders and dividers"},{"id":"ui-components-list--with-selected","name":"With Selected","snippet":"const WithSelected = () => {\n  const [selectedIndex, setSelectedIndex] = useState(1);\n  return (\n    <List sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n      <ListItem \n        selected={selectedIndex === 0}\n        onClick={() => setSelectedIndex(0)}\n        sx={{ cursor: 'pointer' }}\n      >\n        <ListItemIcon>\n          <Icon name=\"inbox\" size=\"sm\" />\n        </ListItemIcon>\n        <ListItemText primary=\"Inbox\" />\n      </ListItem>\n      <ListItem \n        selected={selectedIndex === 1}\n        onClick={() => setSelectedIndex(1)}\n        sx={{ cursor: 'pointer' }}\n      >\n        <ListItemIcon>\n          <Icon name=\"paper-plane\" size=\"sm\" />\n        </ListItemIcon>\n        <ListItemText primary=\"Drafts\" />\n      </ListItem>\n      <ListItem \n        selected={selectedIndex === 2}\n        onClick={() => setSelectedIndex(2)}\n        sx={{ cursor: 'pointer' }}\n      >\n        <ListItemIcon>\n          <Icon name=\"trash\" size=\"sm\" />\n        </ListItemIcon>\n        <ListItemText primary=\"Trash\" />\n      </ListItem>\n    </List>\n  );\n};","description":"List with selected state"},{"id":"ui-components-list--interactive","name":"Interactive","snippet":"const Interactive = () => <List\n    dense={false}\n    disablePadding={false}\n    sx={{ width: '100%', maxWidth: 600, bgcolor: 'background.paper' }}>\n    <ListItem>\n        <ListItemText primary=\"Item One\" secondary=\"Secondary text\" />\n    </ListItem>\n    <ListItem>\n        <ListItemText primary=\"Item Two\" secondary=\"Secondary text\" />\n    </ListItem>\n    <ListItem>\n        <ListItemText primary=\"Item Three\" secondary=\"Secondary text\" />\n    </ListItem>\n</List>;","description":"Interactive list with all controls"}],"import":"import {\n    Avatar,\n    Checkbox,\n    Icon,\n    IconButton,\n    List,\n    ListDivider,\n    ListItem,\n    ListItemButton,\n    ListItemIcon,\n    ListItemSecondaryAction,\n    ListItemText,\n    ListSubheader,\n} from \"@exotel-npm-dev/signal-design-system\";\nimport ListItemAvatar from \"@mui/material/ListItemAvatar\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"List","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/List/List.tsx","actualName":"List","exportName":"List","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-list--docs":{"id":"ui-components-list--docs","name":"Docs","path":"./src/stories/ui-components/List.mdx","title":"UI Components/List","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ListStories from './List.stories';\nimport { List } from '../../components/List';\n\n<Meta of={ListStories} />\n\n# List\n\n## Overview\n\nSignal exports the MUI List suite: `List`, `ListItem`, `ListItemButton`, `ListItemIcon`, `ListItemText`, `ListItemSecondaryAction`, `ListSubheader`, `ListDivider`.\n\n```tsx\nimport {\n  List, ListItem, ListItemButton, ListItemIcon, ListItemText,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Vertical lists of items, settings rows, selectable lists.\n**When not to use:** Data tables → `DataGrid` or `Table`; dropdown menus → `Menu`.\n\n## Stories\n\n`Basic`, `WithIcons`, `WithAvatars`, `WithButtons`, `WithSecondaryActions`, `WithCheckboxes`, `Dense`, `WithDividers`, `WithSubheaders`, `WithSubheadersAndDividers`, `WithSelected`, `Interactive`\n\nSelected `ListItemButton` uses `palette.custom.highlight` in light theme.\n\n<Canvas of={ListStories.Basic} />\n<Canvas of={ListStories.WithSelected} />\n\n## Related Components\n\n`Menu`, `Checkbox`, `Avatar`, `Divider`\n"}}},"ui-components-menu":{"id":"ui-components-menu","name":"Menu","path":"./src/stories/ui-components/Menu.stories.tsx","stories":[{"id":"ui-components-menu--basic","name":"Basic","snippet":"const Basic = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Open Menu\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n      >\n        <MenuItem onClick={handleClose}>Profile</MenuItem>\n        <MenuItem onClick={handleClose}>My Account</MenuItem>\n        <MenuItem onClick={handleClose}>Logout</MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Basic menu triggered by Button"},{"id":"ui-components-menu--with-icon-button","name":"With Icon Button","snippet":"const WithIconButton = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <IconButton onClick={handleClick}>\n        <Icon name=\"more-vertical\" size=\"sm\" />\n      </IconButton>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n      >\n        <MenuItem onClick={handleClose}>Edit</MenuItem>\n        <MenuItem onClick={handleClose}>Duplicate</MenuItem>\n        <MenuItem onClick={handleClose}>Delete</MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Menu triggered by IconButton"},{"id":"ui-components-menu--with-icons","name":"With Icons","snippet":"const WithIcons = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <Button variant=\"outlined\" onClick={handleClick}>\n        Actions\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n      >\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"download\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Download</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"copy\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Copy</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"share\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Share</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"edit\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Edit</ListItemText>\n        </MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Menu with icons"},{"id":"ui-components-menu--with-disabled-items","name":"With Disabled Items","snippet":"const WithDisabledItems = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Options\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n      >\n        <MenuItem onClick={handleClose}>Available Option</MenuItem>\n        <MenuItem onClick={handleClose} disabled>\n          Disabled Option\n        </MenuItem>\n        <MenuItem onClick={handleClose}>Another Option</MenuItem>\n        <MenuItem onClick={handleClose} disabled>\n          Another Disabled\n        </MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Menu with disabled items"},{"id":"ui-components-menu--with-selected-item","name":"With Selected Item","snippet":"const WithSelectedItem = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const [selectedIndex, setSelectedIndex] = useState(1);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  const handleMenuItemClick = (index: number) => {\n    setSelectedIndex(index);\n    handleClose();\n  };\n\n  const options = ['Option 1', 'Option 2', 'Option 3'];\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Select: {options[selectedIndex]}\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n      >\n        {options.map((option, index) => (\n          <MenuItem\n            key={option}\n            selected={index === selectedIndex}\n            onClick={() => handleMenuItemClick(index)}\n          >\n            {option}\n          </MenuItem>\n        ))}\n      </Menu>\n    </>\n  );\n};","description":"Menu with selected item"},{"id":"ui-components-menu--with-dividers","name":"With Dividers","snippet":"const WithDividers = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Menu with Groups\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n      >\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"user\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Profile</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"settings\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Settings</ListItemText>\n        </MenuItem>\n        <Divider />\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"download\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Download</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"share\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Share</ListItemText>\n        </MenuItem>\n        <Divider />\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"trash\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Delete</ListItemText>\n        </MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Menu with dividers"},{"id":"ui-components-menu--placement-bottom-start","name":"Placement Bottom Start","snippet":"const PlacementBottomStart = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Bottom Start\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n        anchorOrigin={{\n          vertical: 'bottom',\n          horizontal: 'left',\n        }}\n        transformOrigin={{\n          vertical: 'top',\n          horizontal: 'left',\n        }}\n      >\n        <MenuItem onClick={handleClose}>Item 1</MenuItem>\n        <MenuItem onClick={handleClose}>Item 2</MenuItem>\n        <MenuItem onClick={handleClose}>Item 3</MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Menu placement - Bottom Start"},{"id":"ui-components-menu--placement-bottom-end","name":"Placement Bottom End","snippet":"const PlacementBottomEnd = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Bottom End\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n        anchorOrigin={{\n          vertical: 'bottom',\n          horizontal: 'right',\n        }}\n        transformOrigin={{\n          vertical: 'top',\n          horizontal: 'right',\n        }}\n      >\n        <MenuItem onClick={handleClose}>Item 1</MenuItem>\n        <MenuItem onClick={handleClose}>Item 2</MenuItem>\n        <MenuItem onClick={handleClose}>Item 3</MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Menu placement - Bottom End"},{"id":"ui-components-menu--placement-top-start","name":"Placement Top Start","snippet":"const PlacementTopStart = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <div style={{ marginTop: '200px' }}>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Top Start\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n        anchorOrigin={{\n          vertical: 'top',\n          horizontal: 'left',\n        }}\n        transformOrigin={{\n          vertical: 'bottom',\n          horizontal: 'left',\n        }}\n      >\n        <MenuItem onClick={handleClose}>Item 1</MenuItem>\n        <MenuItem onClick={handleClose}>Item 2</MenuItem>\n        <MenuItem onClick={handleClose}>Item 3</MenuItem>\n      </Menu>\n    </div>\n  );\n};","description":"Menu placement - Top Start"},{"id":"ui-components-menu--comprehensive","name":"Comprehensive","snippet":"const Comprehensive = () => {\n  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n\n  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={handleClick}>\n        Open Menu\n      </Button>\n      <Menu\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n      >\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"user\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Profile</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"settings\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Settings</ListItemText>\n        </MenuItem>\n        <Divider />\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"download\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Download</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"copy\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Copy</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose} disabled>\n          <ListItemIcon>\n            <Icon name=\"share\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Share (Disabled)</ListItemText>\n        </MenuItem>\n        <Divider />\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"edit\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Edit</ListItemText>\n        </MenuItem>\n        <MenuItem onClick={handleClose}>\n          <ListItemIcon>\n            <Icon name=\"trash\" size=\"sm\" />\n          </ListItemIcon>\n          <ListItemText>Delete</ListItemText>\n        </MenuItem>\n      </Menu>\n    </>\n  );\n};","description":"Comprehensive menu example"}],"import":"import { Button, Divider, Icon, IconButton, Menu } from \"@exotel-npm-dev/signal-design-system\";\nimport ListItemIcon from \"@mui/material/ListItemIcon\";\nimport ListItemText from \"@mui/material/ListItemText\";\nimport MenuItem from \"@mui/material/MenuItem\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Menu","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Menu/Menu.tsx","actualName":"Menu","exportName":"Menu","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-menu--docs":{"id":"ui-components-menu--docs","name":"Docs","path":"./src/stories/ui-components/Menu.mdx","title":"UI Components/Menu","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as MenuStories from './Menu.stories';\nimport { Menu } from '../../components/Menu';\n\n<Meta of={MenuStories} />\n\n# Menu\n\n## Overview\n\n`Menu` wraps MUI `Menu` for contextual dropdown action lists anchored to a trigger.\n\n```tsx\nimport { Menu, MenuItem } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Context menus, action dropdowns from buttons.\n**When not to use:** User account shell → `AvatarMenu`; product switcher → `AppLauncher`; rich panel → `Popover` / `Drawer`.\n\n## Stories\n\n`Basic`, `WithIconButton`, `WithIcons`, `WithDisabledItems`, `WithSelectedItem`, `WithDividers`, placement variants (`PlacementBottomStart`, etc.), `Comprehensive`\n\n<Canvas of={MenuStories.Basic} />\n<Canvas of={MenuStories.WithIcons} />\n\n## Related Components\n\n`IconButton`, `AvatarMenu`, `Popover`, `List`\n"}}},"ui-components-multiselect":{"id":"ui-components-multiselect","name":"MultiSelect","path":"./src/stories/ui-components/MultiSelect.stories.tsx","stories":[{"id":"ui-components-multiselect--disposition-filter","name":"Disposition Filter","snippet":"const DispositionFilter = () => {\n    const [selectedValues, setSelectedValues] = useState<string[]>([\n      'schedule.callback',\n      'callback',\n    ]);\n\n    return (\n        <Box sx={{ p: 2 }}>\n            <MultiSelect\n                label=\"Disposition\"\n                options={dispositionOptions}\n                placeholder=\"Select dispositions\"\n                showSelectAll\n                clearable\n                width={300}\n                maxDisplayItems={2}\n                value={selectedValues}\n                onChange={setSelectedValues} />\n        </Box>\n    );\n};","description":"Basic multi-select matching the image"},{"id":"ui-components-multiselect--simple-list","name":"Simple List","snippet":"const SimpleList = () => {\n    const [selectedValues, setSelectedValues] = useState<string[]>([]);\n\n    const simpleOptions: MultiSelectOption[] = [\n      { id: '1', label: 'Option 1', value: 'option-1' },\n      { id: '2', label: 'Option 2', value: 'option-2' },\n      { id: '3', label: 'Option 3', value: 'option-3' },\n      { id: '4', label: 'Option 4', value: 'option-4' },\n      { id: '5', label: 'Option 5', value: 'option-5' },\n    ];\n\n    return (\n        <Box sx={{ p: 2 }}>\n            <MultiSelect\n                label=\"Simple Select\"\n                placeholder=\"Select options\"\n                showSelectAll\n                clearable\n                width={280}\n                value={selectedValues}\n                onChange={setSelectedValues}\n                options={simpleOptions} />\n        </Box>\n    );\n};","description":"Simple flat list without groups"},{"id":"ui-components-multiselect--with-disabled-options","name":"With Disabled Options","snippet":"const WithDisabledOptions = () => {\n    const [selectedValues, setSelectedValues] = useState<string[]>(['active']);\n\n    const optionsWithDisabled: MultiSelectOption[] = [\n      { id: '1', label: 'Active', value: 'active' },\n      { id: '2', label: 'Inactive (Disabled)', value: 'inactive', disabled: true },\n      { id: '3', label: 'Pending', value: 'pending' },\n      { id: '4', label: 'Archived (Disabled)', value: 'archived', disabled: true },\n      { id: '5', label: 'Draft', value: 'draft' },\n    ];\n\n    return (\n        <Box sx={{ p: 2 }}>\n            <MultiSelect\n                label=\"Status\"\n                placeholder=\"Select status\"\n                showSelectAll\n                clearable\n                width={280}\n                value={selectedValues}\n                onChange={setSelectedValues}\n                options={optionsWithDisabled} />\n        </Box>\n    );\n};","description":"With disabled options"},{"id":"ui-components-multiselect--multiple-groups","name":"Multiple Groups","snippet":"const MultipleGroups = () => {\n    const [selectedValues, setSelectedValues] = useState<string[]>([]);\n\n    const groupedOptions: MultiSelectOption[] = [\n      { id: 'fruits', label: 'Fruits', value: 'fruits', isGroup: true },\n      { id: 'apple', label: 'Apple', value: 'apple', parentId: 'fruits' },\n      { id: 'banana', label: 'Banana', value: 'banana', parentId: 'fruits' },\n      { id: 'orange', label: 'Orange', value: 'orange', parentId: 'fruits' },\n      \n      { id: 'vegetables', label: 'Vegetables', value: 'vegetables', isGroup: true },\n      { id: 'carrot', label: 'Carrot', value: 'carrot', parentId: 'vegetables' },\n      { id: 'broccoli', label: 'Broccoli', value: 'broccoli', parentId: 'vegetables' },\n      { id: 'spinach', label: 'Spinach', value: 'spinach', parentId: 'vegetables' },\n      \n      { id: 'dairy', label: 'Dairy', value: 'dairy', isGroup: true },\n      { id: 'milk', label: 'Milk', value: 'milk', parentId: 'dairy' },\n      { id: 'cheese', label: 'Cheese', value: 'cheese', parentId: 'dairy' },\n      { id: 'yogurt', label: 'Yogurt', value: 'yogurt', parentId: 'dairy' },\n    ];\n\n    return (\n        <Box sx={{ p: 2 }}>\n            <MultiSelect\n                label=\"Food Categories\"\n                placeholder=\"Select items\"\n                showSelectAll\n                clearable\n                width={300}\n                value={selectedValues}\n                onChange={setSelectedValues}\n                options={groupedOptions} />\n        </Box>\n    );\n};","description":"Multiple groups"},{"id":"ui-components-multiselect--many-selected-items","name":"Many Selected Items","snippet":"const ManySelectedItems = () => {\n    const [selectedValues, setSelectedValues] = useState<string[]>([\n      'option-1',\n      'option-2',\n      'option-3',\n      'option-4',\n      'option-5',\n    ]);\n\n    const manyOptions: MultiSelectOption[] = Array.from({ length: 10 }, (_, i) => ({\n      id: `${i + 1}`,\n      label: `Option ${i + 1}`,\n      value: `option-${i + 1}`,\n    }));\n\n    return (\n        <Box sx={{ p: 2 }}>\n            <MultiSelect\n                label=\"Select Multiple\"\n                placeholder=\"Select options\"\n                showSelectAll\n                clearable\n                width={300}\n                maxDisplayItems={2}\n                value={selectedValues}\n                onChange={setSelectedValues}\n                options={manyOptions} />\n        </Box>\n    );\n};","description":"Many selected items"},{"id":"ui-components-multiselect--without-select-all","name":"Without Select All","snippet":"const WithoutSelectAll = () => {\n    const [selectedValues, setSelectedValues] = useState<string[]>([]);\n\n    const options: MultiSelectOption[] = [\n      { id: '1', label: 'Red', value: 'red' },\n      { id: '2', label: 'Blue', value: 'blue' },\n      { id: '3', label: 'Green', value: 'green' },\n      { id: '4', label: 'Yellow', value: 'yellow' },\n    ];\n\n    return (\n        <Box sx={{ p: 2 }}>\n            <MultiSelect\n                label=\"Colors\"\n                placeholder=\"Select colors\"\n                showSelectAll={false}\n                clearable\n                width={280}\n                value={selectedValues}\n                onChange={setSelectedValues}\n                options={options} />\n        </Box>\n    );\n};","description":"Without select all"},{"id":"ui-components-multiselect--disabled","name":"Disabled","snippet":"const Disabled = () => {\n    const [selectedValues, setSelectedValues] = useState<string[]>(['option-1', 'option-2']);\n\n    const options: MultiSelectOption[] = [\n      { id: '1', label: 'Option 1', value: 'option-1' },\n      { id: '2', label: 'Option 2', value: 'option-2' },\n      { id: '3', label: 'Option 3', value: 'option-3' },\n    ];\n\n    return (\n        <Box sx={{ p: 2 }}>\n            <MultiSelect\n                label=\"Disabled Select\"\n                placeholder=\"Select options\"\n                disabled\n                showSelectAll\n                clearable\n                width={280}\n                value={selectedValues}\n                onChange={setSelectedValues}\n                options={options} />\n        </Box>\n    );\n};","description":"Disabled state"},{"id":"ui-components-multiselect--in-form-layout","name":"In Form Layout","snippet":"const InFormLayout = (args) => {\n  const [disposition, setDisposition] = useState<string[]>(['callback']);\n  const [status, setStatus] = useState<string[]>(['open']);\n  const [priority, setPriority] = useState<string[]>([]);\n\n  return (\n    <Box sx={{ p: 2, display: 'flex', flexDirection: 'column', gap: 2, maxWidth: 400 }}>\n      <MultiSelect\n        label=\"Disposition\"\n        options={dispositionOptions}\n        value={disposition}\n        onChange={setDisposition}\n        placeholder=\"Select dispositions\"\n        width=\"100%\"\n      />\n      \n      <MultiSelect\n        label=\"Status\"\n        options={[\n          { id: '1', label: 'Open', value: 'open' },\n          { id: '2', label: 'In Progress', value: 'in-progress' },\n          { id: '3', label: 'Closed', value: 'closed' },\n          { id: '4', label: 'Pending', value: 'pending' },\n        ]}\n        value={status}\n        onChange={setStatus}\n        placeholder=\"Select status\"\n        width=\"100%\"\n      />\n      \n      <MultiSelect\n        label=\"Priority\"\n        options={[\n          { id: '1', label: 'Low', value: 'low' },\n          { id: '2', label: 'Medium', value: 'medium' },\n          { id: '3', label: 'High', value: 'high' },\n          { id: '4', label: 'Critical', value: 'critical' },\n        ]}\n        value={priority}\n        onChange={setPriority}\n        placeholder=\"Select priority\"\n        width=\"100%\"\n      />\n    </Box>\n  );\n};","description":"In a form layout"}],"import":"import { Box } from \"@mui/material\";\nimport { MultiSelect } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"MultiSelect","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/MultiSelect/MultiSelect.tsx","actualName":"MultiSelect","exportName":"MultiSelect","props":{"label":{"required":true,"tsType":{"name":"string"},"description":"Label for the select"},"options":{"required":true,"tsType":{"name":"Array","elements":[{"name":"MultiSelectOption"}],"raw":"MultiSelectOption[]"},"description":"Array of options"},"value":{"required":true,"tsType":{"name":"Array","elements":[{"name":"string"}],"raw":"string[]"},"description":"Selected values"},"onChange":{"required":true,"tsType":{"name":"signature","type":"function","raw":"(values: string[]) => void","signature":{"arguments":[{"type":{"name":"Array","elements":[{"name":"string"}],"raw":"string[]"},"name":"values"}],"return":{"name":"void"}}},"description":"Change handler"},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text"},"disabled":{"required":false,"tsType":{"name":"boolean"},"description":"Whether the select is disabled"},"width":{"required":false,"tsType":{"name":"union","raw":"number | string","elements":[{"name":"number"},{"name":"string"}]},"description":"Width of the component"},"showSelectAll":{"required":false,"tsType":{"name":"boolean"},"description":"Enable select all functionality"},"clearable":{"required":false,"tsType":{"name":"boolean"},"description":"Whether to show clear button"},"maxDisplayItems":{"required":false,"tsType":{"name":"number"},"description":"Maximum number of items to show in the field"},"showSelectedValuesInTrigger":{"required":false,"tsType":{"name":"boolean"},"description":"When false, the closed field always shows `label` only; selected values appear elsewhere (e.g. applied-filters chips).\n@default true"},"iconName":{"required":false,"tsType":{"name":"unknown"},"description":"Icon displayed at the start of the trigger field."},"useBottomSheet":{"required":false,"tsType":{"name":"boolean"},"description":"When true, options open in a bottom sheet instead of a popper (e.g. DataGrid compact toolbar)."}}},"docs":{"ui-components-multiselect--docs":{"id":"ui-components-multiselect--docs","name":"Docs","path":"./src/stories/ui-components/MultiSelect.mdx","title":"UI Components/MultiSelect","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as MultiSelectStories from './MultiSelect.stories';\nimport { MultiSelect } from '../../components/MultiSelect';\n\n<Meta of={MultiSelectStories} />\n\n# MultiSelect\n\n## Overview\n\n`MultiSelect` is a Signal Design System custom dropdown for multi-value selection. It supports grouped and nested options, select-all, checkboxes, clear button, truncated display text, optional start icon, and a mobile bottom-sheet mode.\n\nUse `MultiSelect` for filter toolbars and form fields where users pick multiple values from a structured option list without typeahead search. Do not use it when users need to search a large dynamic list.\n\n```tsx\nimport { MultiSelect, type MultiSelectOption } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Filter toolbars (disposition, status, category filters)\n- Multi-pick from grouped or nested option trees\n- Select-all / deselect-all patterns\n- DataGrid compact toolbar filters (`useBottomSheet`, `showSelectedValuesInTrigger={false}`)\n\n**When not to use**\n\n- Searchable typeahead → use `Autocomplete` with `multiple`\n- Single-value dropdown → use `Select`\n- Simple on/off or one-of-many → use `Switch` or `Radio`\n- Display-only filter chips → use `AppliedFilters`\n\n## Content guidelines\n\nRules for labels, placeholders, group headers, and option text.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Label names the filter | \"Disposition\", \"Status\", \"Priority\" |\n| Placeholder hints empty state | \"Select dispositions\", \"Select status\" |\n| Group headers are categories | \"System Defined\", \"Status\" — not interactive |\n| Options match data values | Use the same label as in APIs/reports (e.g. `schedule.callback`) |\n| Truncation is expected | Long selections show \"Item 1, Item 2 +3\" — keep base labels short |\n\n### Label patterns by context\n\n| Context | Label | Placeholder | Signal reference |\n|---------|-------|-------------|------------------|\n| ECC disposition filter | Disposition | Select dispositions | `DispositionFilter` |\n| Flat list | Simple Select | Select options | `SimpleList` |\n| Category picker | Food Categories | Select items | `MultipleGroups` |\n| Toolbar (chips elsewhere) | Disposition | — (label-only trigger) | DataGrid + `AppliedFilters` |\n\n### Do and don't\n\n**Do**\n\n- \"Disposition\" / \"Select dispositions\"\n- Group headers that match business taxonomy\n- Short option labels that survive truncation\n\n**Don't**\n\n- \"Click to select multiple dispositions\"\n- Interactive-looking group header text (\"Select System Defined\")\n- Overly long option labels when `maxDisplayItems` is low\n- Duplicate selected values in trigger and `AppliedFilters` chips\n\n### Select All row\n\n- Default label: \"Select All\" (hardcoded in component).\n- Shows indeterminate state when some but not all options are selected.\n- Omit with `showSelectAll={false}` when bulk select is inappropriate (`WithoutSelectAll`).\n\n## Anatomy\n\n```\nEnhancedTextField (read-only trigger)\n├── FieldWrapper label (when showSelectedValuesInTrigger)\n├── startAdornment: Icon (optional iconName)\n├── display text: placeholder | selected labels | label only\n└── endAdornment: clear (×) + caret-down\n\nPopper (desktop) or Drawer bottom sheet (useBottomSheet)\n└── Paper\n    └── List\n        ├── Select All row (showSelectAll)\n        ├── Divider\n        └── Options (flat or nested via parentId / isGroup)\n            ├── Group header (isGroup — Typography, non-interactive)\n            └── Selectable row (Checkbox + ListItemText)\n```\n\n## Props\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `label` | `string` | required | Field label | Shown above trigger when `showSelectedValuesInTrigger`; always used as display text when `showSelectedValuesInTrigger={false}`. |\n| `options` | `MultiSelectOption[]` | required | Flat or grouped option list | Use `isGroup` + `parentId` for tree structure. |\n| `value` | `string[]` | required | Selected option values | Controlled — must update via `onChange`. |\n| `onChange` | `(values: string[]) => void` | required | Selection change handler | Receives full array of selected values. |\n| `placeholder` | `string` | `'Select items'` | Text when nothing selected | Shown in trigger when `value` is empty and `showSelectedValuesInTrigger` is true. |\n| `disabled` | `boolean` | `false` | Disables interaction | See `Disabled` story. |\n| `width` | `number \\| string` | — | Trigger min width | Default `160px` when unset. Use `\"100%\"` in forms (`InFormLayout`). |\n| `showSelectAll` | `boolean` | `true` | Shows Select All row | Disable for small exclusive sets (`WithoutSelectAll`). |\n| `clearable` | `boolean` | `true` | Shows clear (×) button | Hidden when disabled or no selection. |\n| `maxDisplayItems` | `number` | `2` | Max labels before \"+N\" truncation | See `ManySelectedItems`. |\n| `showSelectedValuesInTrigger` | `boolean` | `true` | Show selections in trigger vs label only | Set `false` when `AppliedFilters` shows chips elsewhere. |\n| `iconName` | `IconName` | — | Leading icon in trigger | Optional filter affordance. |\n| `useBottomSheet` | `boolean` | `false` | Opens options in bottom `Drawer` | For mobile / DataGrid compact toolbar. |\n\n### MultiSelectOption shape\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | `string` | Unique identifier |\n| `label` | `string` | Display text |\n| `value` | `string` | Value stored in `value[]` |\n| `parentId` | `string` | Parent group id for nesting |\n| `isGroup` | `boolean` | Renders non-interactive group header |\n| `disabled` | `boolean` | Excludes from selection and select-all |\n| `children` | `MultiSelectOption[]` | Declared in type; grouping uses flat list + `parentId` |\n\n<ArgTypes of={MultiSelect} />\n\n## Variants\n\n`MultiSelect` has no visual `variant` prop. The trigger always uses `EnhancedTextField` at `size=\"small\"` with outlined styling and chip-border color on the outline.\n\n| Mode | Trigger | Panel |\n|------|---------|-------|\n| Default | Popper dropdown | Desktop dropdown below trigger |\n| Bottom sheet | Same trigger | `Drawer` anchor `bottom` when `useBottomSheet` |\n\n## Sizes\n\nThe trigger is fixed at `size=\"small\"` internally. Control width via the `width` prop.\n\n| Width | Use for |\n|-------|---------|\n| `160` (default min) | Compact toolbar filters |\n| `280`–`300` | Standard filter fields |\n| `\"100%\"` | Form layouts (`InFormLayout`) |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Empty | `value=[]` | Shows `placeholder` in trigger |\n| Partial selection | Some values in `value` | Select All shows indeterminate |\n| All selected | All selectable options in `value` | Select All checked |\n| Truncated display | `value.length > maxDisplayItems` | \"Label 1, Label 2 +N\" format |\n| Disabled option | `disabled: true` on option | Skipped by select-all; non-clickable |\n| Disabled field | `disabled={true}` | No open, no clear |\n| Label-only trigger | `showSelectedValuesInTrigger={false}` | Trigger always shows `label` |\n\n<Canvas of={MultiSelectStories.Disabled} />\n\n## Stories\n\n### DispositionFilter\n\n**Story ID:** `ui-components-multi-select--disposition-filter`\n\nCanonical ECC disposition filter with grouped options (`System Defined`, `Status`), pre-selected values, `maxDisplayItems: 2`, `width: 300`.\n\n**Recommended usage:** Primary reference for ECC filter toolbars and disposition pickers.\n\n<Canvas of={MultiSelectStories.DispositionFilter} />\n\n### SimpleList\n\n**Story ID:** `ui-components-multi-select--simple-list`\n\nFlat list of five options without groups.\n\n**Recommended usage:** Basic multi-select when options have no hierarchy.\n\n<Canvas of={MultiSelectStories.SimpleList} />\n\n### WithDisabledOptions\n\n**Story ID:** `ui-components-multi-select--with-disabled-options`\n\nFlat list with some options marked `disabled: true`.\n\n**Recommended usage:** When certain statuses or values must not be selectable.\n\n### MultipleGroups\n\n**Story ID:** `ui-components-multi-select--multiple-groups`\n\nThree groups (Fruits, Vegetables, Dairy) with nested children via `parentId`.\n\n**Recommended usage:** Category pickers with multiple group headers.\n\n<Canvas of={MultiSelectStories.MultipleGroups} />\n\n### ManySelectedItems\n\n**Story ID:** `ui-components-multi-select--many-selected-items`\n\nFive of ten options pre-selected with `maxDisplayItems: 2` — displays truncation.\n\n**Recommended usage:** Reference for truncated trigger text behavior.\n\n### WithoutSelectAll\n\n**Story ID:** `ui-components-multi-select--without-select-all`\n\n`showSelectAll={false}` — no bulk select row.\n\n**Recommended usage:** Small option sets where select-all is misleading (colors, priorities).\n\n### Disabled\n\n**Story ID:** `ui-components-multi-select--disabled`\n\n`disabled={true}` with pre-selected values.\n\n**Recommended usage:** Read-only filter state or unavailable fields.\n\n### InFormLayout\n\n**Story ID:** `ui-components-multi-select--in-form-layout`\n\nThree `MultiSelect` fields (Disposition, Status, Priority) stacked at `width=\"100%\"`.\n\n**Recommended usage:** Multi-filter form sections in drawers or settings panels.\n\n<Canvas of={MultiSelectStories.InFormLayout} />\n\n## Accessibility\n\n- Trigger is a read-only `EnhancedTextField` with `onClick` to open — not a native `<select>`.\n- Ensure `label` provides accessible naming; when `showSelectedValuesInTrigger={false}`, the label is the primary visible name.\n- Checkbox options reflect checked state; group headers are non-interactive `ListItem` rows.\n- Keyboard support depends on click-to-open pattern — consider focus management when embedding in toolbars.\n- `disabled` prevents open and clear actions.\n- Clear button uses `IconButton` with `x` icon — ensure sufficient touch target in mobile layouts.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Always control `value` and `onChange` — `MultiSelect` is fully controlled.\n- Use `isGroup` + `parentId` for hierarchical options (see `DispositionFilter`, `MultipleGroups`).\n- Set `showSelectedValuesInTrigger={false}` when pairing with `AppliedFilters` for chip display.\n- Use `useBottomSheet` in compact mobile or DataGrid toolbar contexts.\n- Set `width=\"100%\"` in vertical form layouts (`InFormLayout`).\n- Use `maxDisplayItems` to limit trigger text length; show full selection in `AppliedFilters`.\n- Disable `showSelectAll` for small mutually exclusive sets.\n- See **Content guidelines** for label and group copy rules.\n\n## Anti-patterns\n\n- Using `MultiSelect` for searchable dynamic lists → use `Autocomplete multiple`.\n- Using `MultiSelect` for single selection → use `Select`.\n- Showing selected values in both trigger and `AppliedFilters` chips — pick one display location.\n- Forgetting `onChange` — controlled `value` won't update.\n- Nesting options only via `children` without `parentId` — implementation uses flat list + `parentId`.\n- Importing a third-party multi-select — use Signal `MultiSelect` for ECC filter consistency.\n- Setting `disabled: true` on group headers — use `isGroup: true` instead.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `MultiSelect`\n\n- Multi-value filter from structured grouped options\n- Select-all / clear patterns in toolbars\n- ECC disposition/status filters\n- Mobile bottom-sheet option panel\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Searchable options | `Autocomplete` with `multiple` |\n| Single value | `Select` |\n| Chips display only | `AppliedFilters` |\n| Binary toggle | `Switch` |\n\n### Canonical prop combinations\n\n```tsx\n// Disposition filter — story: DispositionFilter\n<MultiSelect\n  label=\"Disposition\"\n  options={dispositionOptions}\n  value={selectedValues}\n  onChange={setSelectedValues}\n  placeholder=\"Select dispositions\"\n  showSelectAll\n  clearable\n  width={300}\n  maxDisplayItems={2}\n/>\n\n// Toolbar with chips elsewhere — DataGrid pattern\n<MultiSelect\n  label=\"Disposition\"\n  options={options}\n  value={value}\n  onChange={setValue}\n  showSelectedValuesInTrigger={false}\n  useBottomSheet\n/>\n\n// Form layout — story: InFormLayout\n<MultiSelect\n  label=\"Status\"\n  options={statusOptions}\n  value={status}\n  onChange={setStatus}\n  placeholder=\"Select status\"\n  width=\"100%\"\n/>\n\n// No select all — story: WithoutSelectAll\n<MultiSelect\n  label=\"Colors\"\n  options={colorOptions}\n  value={value}\n  onChange={setValue}\n  showSelectAll={false}\n/>\n```\n\n### Option data shape\n\n```tsx\nconst dispositionOptions: MultiSelectOption[] = [\n  { id: 'system-defined', label: 'System Defined', value: 'system-defined', isGroup: true },\n  { id: 'callback', label: 'Callback', value: 'callback', parentId: 'system-defined' },\n];\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| ECC disposition filter | `DispositionFilter` (`ui-components-multi-select--disposition-filter`) |\n| Flat option list | `SimpleList` |\n| Grouped options | `MultipleGroups` |\n| Truncated display | `ManySelectedItems` |\n| Form with multiple fields | `InFormLayout` |\n| Disabled state | `Disabled` |\n| Without select all | `WithoutSelectAll` |\n| Disabled options | `WithDisabledOptions` |\n\n### Common mistakes to avoid\n\n- Do not use uncontrolled mode — `value` and `onChange` are required.\n- Do not duplicate chip display when `showSelectedValuesInTrigger={false}`.\n- Group headers need `isGroup: true`; children need `parentId` matching group `id`.\n- `disabled` options are excluded from select-all count.\n- Trigger is always `size=\"small\"` — do not pass a size prop.\n\n### Composition guidance\n\n- Pair with `AppliedFilters` below the toolbar when `showSelectedValuesInTrigger={false}`.\n- Use in `DataGrid` toolbar filter rows with `useBottomSheet` on narrow viewports.\n- Stack multiple `MultiSelect` fields with `gap: 2` and `width=\"100%\"` in forms.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `EnhancedTextField` | Read-only trigger field |\n| `Checkbox` | Option and select-all checkboxes |\n| `AppliedFilters` | Displays selected filter chips when trigger is label-only |\n| `DataGrid` | Compact toolbar filter consumer |\n| `Select` | Single-value dropdown |\n| `Autocomplete` | Searchable multi-select alternative |\n| `Chip` | Individual filter chip display |\n| `Drawer` | Bottom sheet panel when `useBottomSheet` |\n"}}},"ui-components-navigation":{"id":"ui-components-navigation","name":"Navigation","path":"./src/stories/ui-components/Navigation.stories.tsx","stories":[{"id":"ui-components-navigation--default","name":"Default","snippet":"const Default = () => (\n  <Box sx={{ display: 'flex', height: '100vh', width: '100%' }}>\n    <Navigation items={dummyItems} />\n    <div style={{ flex: 1 }}>\n      <div style={{ height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n        <img style={{ width: '100%', height: '100%', objectFit: 'cover' }} src={tanjiroBgImage} alt=\"Content\" />\n      </div>\n    </div>\n  </Box>\n);"},{"id":"ui-components-navigation--narrow-width","name":"Narrow Width","snippet":"const NarrowWidth = () => (\n  <Box sx={{ height: '100vh', width: 240, backgroundColor: 'background.default' }}>\n    <Navigation items={dummyItems} />\n  </Box>\n);"}],"import":"import { Box, Navigation } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Navigation","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Navigation/components/Navigation.tsx","actualName":"Navigation","exportName":"Navigation","props":{"items":{"required":true,"tsType":{"name":"Array","elements":[{"name":"NavSectionProps"}],"raw":"NavSectionProps[]"},"description":""},"staticSidebar":{"required":false,"tsType":{"name":"boolean"},"description":""},"onNavigate":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(item: NavItemPayload) => void","signature":{"arguments":[{"type":{"name":"NavItemPayload"},"name":"item"}],"return":{"name":"void"}}},"description":"Single handler called when any leaf route is clicked, with full route info."}}},"docs":{"ui-components-navigation--docs":{"id":"ui-components-navigation--docs","name":"Docs","path":"./src/stories/ui-components/Navigation.mdx","title":"UI Components/Navigation","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as NavigationStories from './Navigation.stories';\nimport { Navigation } from '../../components/Navigation';\n\n<Meta of={NavigationStories} />\n\n# Navigation\n\n## Overview\n\n`Navigation` is the Exotel in-product side navigation shell. It provides a collapsible sidebar with search, pin/hover expand behavior, nested nav items (up to 3 levels), section subheaders, item pinning, and a built-in \"Customise Sidebar\" dialog for visibility and reordering.\n\n```tsx\nimport { Navigation } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe host supplies the full navigation tree via `items: NavSectionProps[]`. Routing, path matching, and click behavior are host-owned through `path` and `onClick` on each item.\n\n> **UX Constitution:** See **Application Layout → Navigation** (persistent left nav; 250px / 62px widths; not Dialog/Drawer).\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Persistent left-side navigation within a single Exotel product\n- Multi-section nav trees with icons, nested children, and search\n- Desktop layouts where agents need quick access to product areas\n\n**When not to use**\n\n- Application product switching → use `AppLauncher`\n- Temporary/mobile off-canvas nav → use `NavigationDrawer`\n- Simple flat link lists → use `List` with `ListItemButton`\n- Top application header → use `AppBar`\n- Arbitrary slide-out panel content → use `Drawer`\n\n## Anatomy\n\n```\nNavigation (aside, sticky)\n└── nav (collapsible, 62px ↔ 250px)\n    ├── NavToolbar                    ← search + pin toggle\n    ├── NavSections                   ← scrollable section list\n    │   └── NavSection[]              ← optional label subheader + NavItem[]\n    │       └── NavItem               ← icon, label, expand, pin, children\n    │           └── NavSection (nested) ← up to level 3\n    ├── Divider\n    └── NavFooter\n        └── NavCustomise              ← \"Customise Sidebar\" + StructuredDialog\n```\n\nInternal state is provided via `NavigationProvider` (search, pin, hover expand, current path, display config, pinned items).\n\n## Props\n\n### NavigationProps\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `items` | `NavSectionProps[]` | — (required) | Navigation sections and items | Host-owned tree; see shapes below |\n| `staticSidebar` | `boolean` | `false` | Always expanded sidebar | Use in `NavigationDrawer` or when collapse is not needed. Disables pin button. |\n\n### NavSectionProps\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `label` | `string` | no | Section subheader (shown when sidebar expanded) |\n| `items` | `Omit<NavItemProps, 'level'>[]` | yes | Top-level items in this section |\n| `level` | `number` | no | Internal nesting level (set by component) |\n\n### NavItemProps\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `id` | `string` | yes | Unique item identifier |\n| `label` | `string` | yes | Display label |\n| `iconName` | `IconName` | no | Phosphor icon (top-level items typically have icons) |\n| `path` | `string` | no | Route path for active-state matching |\n| `openNewPage` | `boolean` | yes | Shows external-link icon when `true` |\n| `onClick` | `() => void` | no | Click handler (leaf items); host handles routing |\n| `children` | `Omit<NavItemProps, 'level'>[]` | no | Nested sub-items (max depth: level 3) |\n| `showPin` | `boolean` | no | Enables pin button on hover |\n| `pinnedItem` | `boolean` | no | Item originates from pinned list |\n| `level` | `number` | no | Set internally during render |\n\n<ArgTypes of={Navigation} />\n\n## Variants\n\n| Mode | Props | Width | Behavior |\n|------|-------|-------|----------|\n| Collapsible (default) | `staticSidebar={false}` | 62px collapsed, 250px expanded | Expands on hover or pin |\n| Static expanded | `staticSidebar={true}` | 250px always | No pin button; used inside `NavigationDrawer` |\n| Narrow container | Same as default | Constrained by parent | See `NarrowWidth` story |\n\n## States\n\n| State | Condition | Notes |\n|-------|-----------|-------|\n| Collapsed | Default (not pinned, not hovered) | Icons only; labels hidden (`opacity: 0`) |\n| Expanded | `staticSidebar`, pinned, or hovered | Full labels, search field, pin button |\n| Active item | `path === currentPath` | `ListItemButton selected` styling |\n| Expanded parent | Active child or search match | Parent `Collapse` opens |\n| Pinned item | User pinned via pin button | Appears in footer pinned list |\n| Hidden item | Customise dialog unchecked | Filtered via `displayConfig` |\n| Search active | Text in toolbar search | Filters visible items; auto-expands matching branches |\n\n## Behavior\n\n- **Collapse/expand:** Sidebar width transitions `62px ↔ 250px` over 0.25s. Expanded when `staticSidebar || isPinned || isHovered`.\n- **Search:** Filters sections/items by label. Matching parent items auto-expand unless user manually toggled during search.\n- **Pin:** Pin button appears on hover for items with `showPin` or in pinned list. Pinned items render in footer area.\n- **Nested items:** Up to 3 levels (`NavSection` / `NavItem` throw if `level > 3`). Parent items toggle `Collapse`; leaf items set `currentPath` and call `onClick`.\n- **External links:** `openNewPage: true` shows `arrow-square-out` icon when expanded.\n- **Customise Sidebar:** Opens `StructuredDialog` with drag-reorder (within section), visibility checkboxes, search, Reset/Cancel/Apply footer.\n- **Active state:** Internal `currentPath` defaults to `'/home'` — host should integrate routing to sync active item (routing integration is host responsibility).\n- **Sticky positioning:** Outer `aside` uses `position: sticky`, `zIndex: 20`.\n\n## Stories\n\n### Default\n\n**Story ID:** `ui-components-navigation--default`\n\nFull navigation tree (`dummyItems`) beside main content area. Demonstrates collapsible sidebar, sections, nested items, and search.\n\n**Recommended usage:** Standard desktop in-product navigation layout.\n\n<Canvas of={NavigationStories.Default} />\n\n### NarrowWidth\n\n**Story ID:** `ui-components-navigation--narrow-width`\n\nNavigation in a 240px-wide container — demonstrates collapsed/icon-only behavior in constrained layouts.\n\n**Recommended usage:** Reference for narrow sidebar containers or embedded nav panels.\n\n<Canvas of={NavigationStories.NarrowWidth} />\n\n## Content guidelines\n\n### Section labels\n\n- Use uppercase section subheaders for grouping (e.g. `MONITOR`, `APPS`) — matches story data pattern.\n- Omit `label` for ungrouped top sections.\n\n### Item labels\n\n| Principle | Rule |\n|-----------|------|\n| Concise | Short product area names: \"Interactions\", \"Contacts\" |\n| Consistent | Match page titles and breadcrumbs where applicable |\n| Hierarchy | Child labels name sub-pages, not full paths |\n\n### Icons\n\n- Top-level items should include `iconName` for collapsed-mode recognition.\n- Nested children may omit icons (labels only when expanded).\n\n## Accessibility\n\n- Outer container: `<aside>` with inner `<nav aria-label=\"navigation-bar\">`.\n- Nav items use MUI `ListItemButton` — keyboard activatable.\n- Search field has associated `id` (`{id}-nav-toolbar-search`).\n- Collapsed mode hides labels visually but icons remain — ensure icons are distinct.\n- Customise dialog uses `StructuredDialog` with standard button footer.\n- Pin buttons are `IconButton` without explicit aria-label — consider host enhancement for production.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best practices\n\n- Supply stable unique `id` values on every nav item for customise/pin state.\n- Set `path` on items that correspond to routes for active highlighting.\n- Provide `onClick` for leaf items to trigger host routing/navigation.\n- Use `openNewPage: true` for links that open external products or new tabs.\n- Use `staticSidebar={true}` when embedding inside `NavigationDrawer`.\n- Structure deep trees with `children` rather than flat path strings.\n- Limit nesting to 3 levels (enforced by component).\n- Wrap the app in `ExotelThemeProvider`.\n\n## Anti-patterns\n\n- Nesting deeper than 3 levels — component throws an error.\n- Omitting `openNewPage` — it is required on every `NavItem`.\n- Expecting built-in router integration — host must wire `onClick` / `path` to the app router.\n- Using `Navigation` for product switching — use `AppLauncher`.\n- Using `Navigation` inside a modal — use `Menu` or `List` for short action lists.\n- Empty `items` array — renders toolbar and footer only.\n\n## Guidance for AI Agents\n\n**Read UX Constitution first** (Application Layout → Navigation).\n\n### When to choose `Navigation`\n\n- In-product left sidebar with sections, icons, search, and nested routes\n- Desktop layout with collapsible/pinnable sidebar\n- Needs \"Customise Sidebar\" visibility and reorder UX\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Mobile hamburger menu | `NavigationDrawer` |\n| Product/app switcher | `AppLauncher` |\n| Full app header | `AppBar` |\n| Simple link list | `List` + `ListItemButton` |\n| Off-canvas form/panel | `Drawer` |\n\n### Canonical prop combinations\n\n```tsx\n// Standard collapsible sidebar — story: Default\n<Box sx={{ display: 'flex', height: '100vh' }}>\n  <Navigation items={navSections} />\n  <Box component=\"main\" sx={{ flex: 1 }}>{children}</Box>\n</Box>\n\n// Always expanded (inside drawer) — story: NavigationDrawer Default\n<Navigation staticSidebar items={navSections} />\n\n// Nav section shape\nconst navSections: NavSectionProps[] = [\n  {\n    items: [\n      {\n        id: 'home',\n        iconName: 'house',\n        label: 'Home',\n        path: '/home',\n        openNewPage: false,\n        onClick: () => navigate('/home'),\n      },\n    ],\n  },\n  {\n    label: 'MONITOR',\n    items: [\n      {\n        id: 'analysis',\n        iconName: 'chart-line',\n        label: 'Analysis',\n        path: '/monitor/analysis',\n        openNewPage: false,\n        children: [\n          {\n            id: 'dashboard',\n            label: 'Dashboard',\n            path: '/monitor/analysis/dashboard',\n            openNewPage: false,\n          },\n        ],\n      },\n    ],\n  },\n];\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Full desktop layout | `Default` (`ui-components-navigation--default`) |\n| Narrow/collapsed container | `NarrowWidth` |\n| Sample nav data | `dummyItems` in `Navigation/dummyData.tsx` |\n\n### Common mistakes to avoid\n\n- Do not omit `openNewPage` on nav items — it is required.\n- Do not exceed 3 nesting levels.\n- Do not assume `currentPath` syncs with the browser URL automatically.\n- Do not use `Navigation` for the Exotel multi-product launcher.\n- Do not nest `Navigation` inside another scroll container without setting height (`height: 100%` on parent).\n\n### Composition guidance\n\n- Pair with `AppBar` for full application shell: `AppBar` on top, `Navigation` + main content below.\n- Use `NavigationDrawer` for mobile; `Navigation` with `staticSidebar` inside the drawer.\n- Leaf item `onClick` should invoke host router navigation matching `path`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `NavigationDrawer` | Wraps `Navigation` in a `Drawer` for mobile |\n| `Drawer` | Used by `NavigationDrawer` |\n| `List` / `ListItemButton` | Building blocks for nav items |\n| `Icon` | Nav item and toolbar icons |\n| `EnhancedTextField` | Toolbar search input |\n| `StructuredDialog` | Customise Sidebar dialog |\n| `AppBar` | Top header complement |\n| `PageHeader` | In-page title area below shell |\n"}}},"ui-components-navigationdrawer":{"id":"ui-components-navigationdrawer","name":"NavigationDrawer","path":"./src/stories/ui-components/NavigationDrawer.stories.tsx","stories":[{"id":"ui-components-navigationdrawer--default","name":"Default","snippet":"const Default = () => (\n  <Box sx={{ height: '100vh', width: 320, backgroundColor: 'background.default' }}>\n    <NavigationDrawer items={dummyItems} />\n  </Box>\n);"},{"id":"ui-components-navigationdrawer--with-content","name":"With Content","snippet":"const withContent = () => (\n  <Box sx={{ height: '100vh', backgroundColor: 'background.default' }}>\n    <Box component=\"header\" sx={{ display: 'flex', alignItems: 'center'}}>\n      <NavigationDrawer items={dummyItems} />\n    <Box component=\"h1\" sx={{ fontSize: 18, fontWeight: 600, color: 'text.primary', fontFamily: 'cursive' }}>My APP</Box>\n    </Box>\n    <Box component=\"main\">\n      <Box component=\"div\" style={{ height: '100%', backgroundColor: 'blue', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n        <img style={{ width: '100%', height: '100%', objectFit: 'cover' }} src={tanjiroBgImage} alt=\"Content\" />\n      </Box>\n    </Box>\n  </Box>\n);"}],"import":"import { Box, NavigationDrawer } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"NavigationDrawer","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/NavigationDrawer/components/NavigationDrawer.tsx","actualName":"NavigationDrawer","exportName":"NavigationDrawer","props":{"items":{"required":true,"tsType":{"name":"NavigationProps['items']","raw":"NavigationProps['items']"},"description":""}}},"docs":{"ui-components-navigationdrawer--docs":{"id":"ui-components-navigationdrawer--docs","name":"Docs","path":"./src/stories/ui-components/NavigationDrawer.mdx","title":"UI Components/NavigationDrawer","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as NavigationDrawerStories from './NavigationDrawer.stories';\nimport { NavigationDrawer } from '../../components/NavigationDrawer';\n\n<Meta of={NavigationDrawerStories} />\n\n# NavigationDrawer\n\n## Overview\n\n`NavigationDrawer` combines a menu `IconButton` trigger with MUI `Drawer` containing `Navigation` (`staticSidebar={true}`). It provides a slide-out navigation panel optimized for mobile and compact header layouts where a persistent sidebar is not practical.\n\n```tsx\nimport { NavigationDrawer } from '../../components/NavigationDrawer';\n// Note: not exported from package index.ts — import from component path or add barrel export\n```\n\nThe host supplies the same `items: NavSectionProps[]` tree used by `Navigation`. Open/close state is managed internally.\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Mobile or narrow layouts where navigation is hidden behind a hamburger menu\n- Header row with menu trigger + app title (see `withContent` story)\n- Temporary off-canvas access to the full nav tree\n\n**When not to use**\n\n- Persistent desktop sidebar → use `Navigation` directly\n- Form or detail panels → use `Drawer` with custom content\n- Product switching → use `AppLauncher`\n- Full application header → use `AppBar`\n\n## Anatomy\n\n```\nNavigationDrawer\n├── IconButton (trigger)           ← menu icon; opens drawer\n└── Drawer (internal state)\n    └── Navigation                   ← staticSidebar={true}, items={items}\n        ├── NavToolbar\n        ├── NavSections\n        └── NavFooter\n```\n\nUnlike `Navigation` alone, `NavigationDrawer` owns the open/close toggle — no external `open` prop is exposed.\n\n## Props\n\n### NavigationDrawerProps\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `items` | `NavSectionProps[]` | — (required) | Navigation tree forwarded to `Navigation` | Same shape as `Navigation` — see `Navigation` docs |\n\nNo additional props are exposed. Drawer open state is internal (`useState`).\n\n### Inherited nav item shapes\n\nSee **Navigation** documentation for `NavSectionProps` and `NavItemProps` field definitions.\n\n<ArgTypes of={NavigationDrawer} />\n\n## Variants\n\n| Layout | Story | Description |\n|--------|-------|-------------|\n| Standalone drawer trigger | `Default` | Menu button + drawer in a narrow column |\n| Header + content | `withContent` | Menu in app header row beside title, main content below |\n\nBoth use the same `dummyItems` navigation data from `Navigation/dummyData.tsx`.\n\n## States\n\n| State | Behavior |\n|-------|----------|\n| Closed (default) | Only hamburger `IconButton` visible |\n| Open | `Drawer` slides in with full expanded `Navigation` (`staticSidebar={true}`) |\n| Nav interaction | Search, expand, customise work inside drawer same as `Navigation` |\n\n## Behavior\n\n- Clicking the menu `IconButton` sets `isOpen` to `true`.\n- `Drawer onClose` sets `isOpen` to `false` (backdrop click, Escape — MUI Drawer defaults).\n- Inner `Navigation` always renders with `staticSidebar={true}` — sidebar is fully expanded inside the drawer; no collapse/pin behavior.\n- Trigger uses `Icon name=\"menu\" size=\"sm\"`.\n- Host does not control open state — consider wrapping or extending if programmatic open is needed.\n\n## Stories\n\n### Default\n\n**Story ID:** `ui-components-navigation-drawer--default`\n\nMenu trigger and drawer in a 320px-wide container. Click menu to open full navigation tree.\n\n**Recommended usage:** Mobile nav pattern in a narrow viewport or sidebar column.\n\n<Canvas of={NavigationDrawerStories.Default} />\n\n### withContent\n\n**Story ID:** `ui-components-navigation-drawer--with-content`\n\nNavigation drawer in a header row next to \"My APP\" title, with main content area below.\n\n**Recommended usage:** Mobile app shell with hamburger + page title + content.\n\n<Canvas of={NavigationDrawerStories.withContent} />\n\n## Accessibility\n\n- Menu trigger is an MUI `IconButton` — activatable via click and keyboard.\n- Drawer uses MUI `Drawer` focus trap and backdrop dismiss semantics when open.\n- Inner `Navigation` inherits nav accessibility (`aria-label=\"navigation-bar\"` on inner nav).\n- **Gap:** Trigger lacks explicit `aria-label` (e.g. \"Open navigation\") — add in host wrapper if needed for production.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best practices\n\n- Use for mobile breakpoints; pair with persistent `Navigation` on desktop.\n- Reuse the same `items` data structure as desktop `Navigation` for consistency.\n- Place the trigger in the app header row (see `withContent` story).\n- Wrap the app in `ExotelThemeProvider`.\n- Verify import path — component is **not** in package `index.ts` barrel export.\n\n## Anti-patterns\n\n- Using `NavigationDrawer` when a persistent sidebar fits — use `Navigation` directly.\n- Expecting external control of drawer open state — not exposed in current API.\n- Duplicating different nav trees for drawer vs desktop — share one `items` source.\n- Using for non-navigation drawer content (forms, filters) — use `Drawer` directly.\n- Assuming package root export — import from `NavigationDrawer` component path.\n\n## Guidance for AI Agents\n\n### When to choose `NavigationDrawer`\n\n- Mobile hamburger menu with full product navigation inside\n- Compact header that cannot fit a persistent sidebar\n- Same nav tree as desktop, presented off-canvas\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Persistent desktop sidebar | `Navigation` |\n| Full app header with logo and user menu | `AppBar` |\n| Custom drawer panel (not nav tree) | `Drawer` |\n| Product switching | `AppLauncher` |\n\n### Canonical prop combinations\n\n```tsx\n// Mobile header shell — story: withContent\n<Box component=\"header\" sx={{ display: 'flex', alignItems: 'center' }}>\n  <NavigationDrawer items={navSections} />\n  <Typography variant=\"title3\">My APP</Typography>\n</Box>\n<Box component=\"main\">{children}</Box>\n\n// Standalone — story: Default\n<NavigationDrawer items={navSections} />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Basic mobile drawer | `Default` (`ui-components-navigation-drawer--default`) |\n| Header + content layout | `withContent` |\n| Nav data reference | `dummyItems` in `Navigation/dummyData.tsx` |\n\n### Common mistakes to avoid\n\n- Do not import from `@exotel-npm-dev/signal-design-system` root unless barrel export is added — use component path.\n- Do not pass `staticSidebar` to `NavigationDrawer` — it sets this internally.\n- Do not expect `open` / `onOpenChange` props — not in current API.\n- Do not use for `AppBar` — different purpose (in-product nav vs app shell).\n\n### Composition guidance\n\n- Desktop: `<Navigation items={items} />` + main content.\n- Mobile: `<NavigationDrawer items={items} />` in header; hide desktop `Navigation` via responsive layout.\n- Share one `navSections` constant between both breakpoints.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Navigation` | Rendered inside drawer with `staticSidebar={true}` |\n| `Drawer` | Off-canvas container |\n| `IconButton` | Hamburger menu trigger |\n| `Icon` | Menu icon (`menu`) |\n| `AppBar` | Top shell header (different from in-product nav drawer) |\n| `PageHeader` | In-page title below shell |\n"}}},"ui-components-pageheader":{"id":"ui-components-pageheader","name":"PageHeader","path":"./src/stories/ui-components/PageHeader.stories.tsx","stories":[{"id":"ui-components-pageheader--default","name":"Default","snippet":"const Default = () => <PageHeader title=\"Channel Configuration\" />;"},{"id":"ui-components-pageheader--with-subtitle","name":"With Subtitle","snippet":"const WithSubtitle = () => <PageHeader\n    title=\"Channel Configuration\"\n    subtitle=\"Select communication channel and configure channel settings\" />;"},{"id":"ui-components-pageheader--with-actions","name":"With Actions","snippet":"const WithActions = () => <PageHeader\n    title=\"Channel Configuration\"\n    subtitle=\"Select communication channel and configure channel settings\"\n    actions={[\n      { id: 'export', children: 'Export', variant: 'outlined' },\n      { id: 'add', children: 'Add Contact', variant: 'contained' },\n    ]} />;"},{"id":"ui-components-pageheader--with-search","name":"With Search","snippet":"const WithSearch = () => <PageHeader\n    title=\"Channel Configuration\"\n    showSearch\n    searchType=\"basic\"\n    onBasicSearch={(v) => console.log('Search value:', v)} />;"},{"id":"ui-components-pageheader--with-search-and-actions","name":"With Search And Actions","snippet":"const WithSearchAndActions = () => <PageHeader\n    title=\"Channel Configuration\"\n    subtitle=\"Select communication channel and configure channel settings\"\n    showSearch\n    searchType=\"basic\"\n    onBasicSearch={(v) => console.log('Search value:', v)}\n    actions={[\n      { id: 'export', children: 'Export', variant: 'outlined' },\n      { id: 'add', children: 'Add Contact', variant: 'contained' },\n    ]} />;"},{"id":"ui-components-pageheader--with-icon-actions","name":"With Icon Actions","snippet":"const WithIconActions = () => <PageHeader\n    title=\"Channel Configuration\"\n    subtitle=\"Select communication channel and configure channel settings\"\n    showSearch\n    searchType=\"basic\"\n    onBasicSearch={(v) => console.log('Search value:', v)}\n    actions={[\n      { id: 'filter', children: 'Filter', variant: 'outlined', startIconProps: { name: 'funnel' } },\n      { id: 'create', children: 'Create Campaign', variant: 'contained', startIconProps: { name: 'plus' } },\n      { id: 'export', children: 'Export', variant: 'outlined', startIconProps: { name: 'export' } },\n      { id: 'import', children: 'Import', variant: 'outlined', startIconProps: { name: 'download-simple' } },\n    ]} />;"},{"id":"ui-components-pageheader--title-only","name":"Title Only","snippet":"const TitleOnly = () => <PageHeader title=\"Settings\" />;"},{"id":"ui-components-pageheader--with-toggle-button-group","name":"With Toggle Button Group","snippet":"const WithToggleButtonGroup = () => {\n  const [view, setView] = useState('list');\n  return (\n    <PageHeader\n      title=\"Campaigns (04)\"\n      showSearch\n      searchType=\"basic\"\n      onBasicSearch={(v) => console.log('Search:', v)}\n      toggleButtonGroup={{\n        value: view,\n        onChange: setView,\n        options: [\n          { value: 'list', iconName: 'list-bullets', ariaLabel: 'List view' },\n          { value: 'table', iconName: 'table', ariaLabel: 'Table view' },\n        ],\n      }}\n      actions={[\n        { id: 'new', children: 'New Campaign', variant: 'contained', startIconProps: { name: 'plus' } },\n      ]}\n    />\n  );\n};"},{"id":"ui-components-pageheader--with-toggle-and-overflow-actions","name":"With Toggle And Overflow Actions","snippet":"const WithToggleAndOverflowActions = () => {\n  const [view, setView] = useState('table');\n  return (\n    <PageHeader\n      title=\"Campaigns (04)\"\n      subtitle=\"Manage all your campaigns\"\n      showSearch\n      searchType=\"basic\"\n      onBasicSearch={(v) => console.log('Search:', v)}\n      toggleButtonGroup={{\n        value: view,\n        onChange: setView,\n        options: [\n          { value: 'list', iconName: 'list-bullets', ariaLabel: 'List view' },\n          { value: 'table', iconName: 'table', ariaLabel: 'Table view' },\n        ],\n      }}\n      actions={[\n        { id: 'new', children: 'New Campaign', variant: 'contained', startIconProps: { name: 'plus' } },\n        { id: 'export', children: 'Export', variant: 'outlined', startIconProps: { name: 'export' } },\n        { id: 'import', children: 'Import', variant: 'outlined', startIconProps: { name: 'download-simple' } },\n      ]}\n    />\n  );\n};"}],"import":"import { PageHeader } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"PageHeader","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/PageHeader/PageHeader.tsx","actualName":"PageHeader","exportName":"PageHeader","props":{"title":{"required":false,"tsType":{"name":"string"},"description":""},"subtitle":{"required":false,"tsType":{"name":"string"},"description":""},"actions":{"required":false,"tsType":{"name":"Array","elements":[{"name":"ButtonProps"}],"raw":"ButtonProps[]"},"description":""},"maxVisibleActions":{"required":false,"tsType":{"name":"number"},"description":""},"showSearch":{"required":false,"tsType":{"name":"boolean"},"description":""},"searchType":{"required":false,"tsType":{"name":"union","raw":"'basic' | 'advanced'","elements":[{"name":"literal","value":"'basic'"},{"name":"literal","value":"'advanced'"}]},"description":""},"onBasicSearch":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(search: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"search"}],"return":{"name":"void"}}},"description":""},"toggleButtonGroup":{"required":false,"tsType":{"name":"PageHeaderToggleGroupConfig"},"description":""}}},"docs":{"ui-components-pageheader--docs":{"id":"ui-components-pageheader--docs","name":"Docs","path":"./src/stories/ui-components/PageHeader.mdx","title":"UI Components/PageHeader","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as PageHeaderStories from './PageHeader.stories';\nimport { PageHeader } from '../../components/PageHeader';\n\n<Meta of={PageHeaderStories} />\n\n# PageHeader\n\n## Overview\n\n`PageHeader` renders an in-page title bar with optional subtitle, action buttons (with overflow menu), and optional basic search. It sits below the application shell (`AppBar`) and above page content.\n\n```tsx\nimport { PageHeader } from '@exotel-npm-dev/signal-design-system';\nimport type { ButtonProps } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe same props surface is reused by `DataGrid` via the `tableHeader` prop (`DataGridTableHeaderProps` extends `PageHeaderProps`).\n\n> **UX Constitution:** See **Table Pages → CTAs** and **Settings Pages → Save Model** (primary create CTAs, global Discard/Save, title with count via `DataGrid.tableHeader`).\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Page-level title and primary actions below `AppBar`\n- List/table views needing search + CTA buttons in one row\n- Channel configuration, campaign management, and similar ECC page headers\n\n**When not to use**\n\n- Application shell header with logo, launcher, notifications → use `AppBar`\n- Modal or dialog titles → use `StructuredDialog` or `Dialog`\n- Section headers within a form → use `Typography variant=\"title2\"`\n- DataGrid-only headers when `tableHeader` prop suffices → configure on `DataGrid`\n\n## Anatomy\n\n```\nPageHeader (surface.elevation1)\n├── Title block (flex column)\n│   ├── Typography title3           ← title\n│   └── Typography body2            ← subtitle (optional)\n└── Actions block (flex row)\n    ├── EnhancedTextField           ← when showSearch + searchType=\"basic\"\n    ├── IconButton (overflow)       ← when actions exceed maxVisibleActions\n    │   └── Menu                    ← overflow action items\n    └── Button[]                    ← visible actions (maxVisibleActions)\n```\n\n## Props\n\n### PageHeaderProps\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `title` | `string` | — | Page title | Rendered as `Typography variant=\"title3\"` |\n| `subtitle` | `string` | — | Subtitle below title | Rendered as `Typography variant=\"body2\"` |\n| `actions` | `ButtonProps[]` | — | Action buttons | Each action should include unique `id` for keys and overflow menu |\n| `maxVisibleActions` | `number` | `2` | Visible buttons before overflow | Excess actions move to \"More actions\" menu |\n| `showSearch` | `boolean` | — | Show search field | Requires `searchType` to render search UI |\n| `searchType` | `'basic' \\| 'advanced'` | — | Search mode | Only `'basic'` is implemented; `'advanced'` renders nothing |\n| `onBasicSearch` | `(search: string) => void` | — | Search change callback | Fires on each keystroke via `EnhancedTextField onChange` |\n\n### Action item shape (ButtonProps + id)\n\nEach entry in `actions` spreads onto Signal `Button`. Include:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `id` | `string` | yes (recommended) | Stable key for rendering and overflow menu |\n| `children` | `ReactNode` | yes | Button label |\n| `variant` | Button variant | no | `contained`, `outlined`, `text`, `tonal` |\n| `startIconProps` | `IconProps` | no | Leading icon (`{ name: 'plus' }`) |\n| `onClick` | `MouseEventHandler` | no | Click handler |\n\n<ArgTypes of={PageHeader} />\n\n## Variants\n\n| Configuration | Props | Story |\n|---------------|-------|-------|\n| Title only | `title` | `TitleOnly`, `Default` |\n| Title + subtitle | `title`, `subtitle` | `WithSubtitle` |\n| Title + actions | `title`, `subtitle`, `actions` | `WithActions` |\n| Title + search | `title`, `showSearch`, `searchType: 'basic'` | `WithSearch` |\n| Full header | title, subtitle, search, actions | `WithSearchAndActions` |\n| Icon actions + overflow | 4 actions, `maxVisibleActions: 2` (default) | `WithIconActions` |\n\n## States\n\n| State | Condition | Notes |\n|-------|-----------|-------|\n| Title only | No subtitle, search, or actions | Minimal header |\n| Overflow menu closed | `actions.length <= maxVisibleActions` | No kebab button |\n| Overflow menu open | Extra actions exist | `IconButton aria-label=\"More actions\"`, `aria-expanded` |\n| Search active | `showSearch && searchType === 'basic'` | Search field with magnifying-glass icon |\n| Advanced search | `searchType: 'advanced'` | Not implemented — no search UI renders |\n\n## Behavior\n\n- Layout: flex row with wrap; title block grows (`flex: 1 1 200px`); actions align trailing.\n- Background: `surface.elevation1` with padding `theme.spacing(1.5, 2)`.\n- **Action overflow:** First `maxVisibleActions` render as `Button`; remainder appear in overflow `Menu` triggered by `dots-three-vertical` `IconButton`.\n- Overflow menu items support `startIconProps` on actions; clicking an item invokes `onClick` and closes the menu.\n- **Search:** Only `searchType === 'basic'` renders `EnhancedTextField` with placeholder \"Search\" and `magnifying-glass` adornment.\n- `onBasicSearch` receives the current input string on each change event.\n- Visible action buttons use `size=\"medium\"`.\n\n## Stories\n\n### Default\n\n**Story ID:** `ui-components-page-header--default`\n\nTitle only: \"Channel Configuration\".\n\n**Recommended usage:** Simple page with a single heading and no actions.\n\n<Canvas of={PageHeaderStories.Default} />\n\n### WithSubtitle\n\n**Story ID:** `ui-components-page-header--with-subtitle`\n\nTitle + descriptive subtitle.\n\n**Recommended usage:** Pages needing context below the title.\n\n<Canvas of={PageHeaderStories.WithSubtitle} />\n\n### WithActions\n\n**Story ID:** `ui-components-page-header--with-actions`\n\nTitle, subtitle, and two actions: Export (outlined) + Add Contact (contained).\n\n**Recommended usage:** Standard page with primary and secondary CTAs.\n\n<Canvas of={PageHeaderStories.WithActions} />\n\n### WithSearch\n\n**Story ID:** `ui-components-page-header--with-search`\n\nTitle with basic search field.\n\n**Recommended usage:** List pages where inline search is needed in the header.\n\n<Canvas of={PageHeaderStories.WithSearch} />\n\n### WithSearchAndActions\n\n**Story ID:** `ui-components-page-header--with-search-and-actions`\n\nTitle, subtitle, search, and two action buttons — canonical full header pattern.\n\n**Recommended usage:** Table/list pages with search and CTAs.\n\n<Canvas of={PageHeaderStories.WithSearchAndActions} />\n\n### WithIconActions\n\n**Story ID:** `ui-components-page-header--with-icon-actions`\n\nFour icon actions (Filter, Create Campaign, Export, Import) — demonstrates overflow menu with default `maxVisibleActions: 2`.\n\n**Recommended usage:** Dense toolbars where only two buttons fit inline.\n\n<Canvas of={PageHeaderStories.WithIconActions} />\n\n### TitleOnly\n\n**Story ID:** `ui-components-page-header--title-only`\n\nMinimal \"Settings\" title.\n\n**Recommended usage:** Settings or simple content pages without actions.\n\n<Canvas of={PageHeaderStories.TitleOnly} />\n\n## Content guidelines\n\n### Title and subtitle\n\n| Element | Rule | Example |\n|---------|------|---------|\n| Title | Noun phrase naming the page | `Channel Configuration`, `Settings` |\n| Subtitle | One sentence describing scope or task | `Select communication channel and configure channel settings` |\n| Case | Sentence case for subtitle; title as product convention | Match ECC patterns in stories |\n\n### Action button labels\n\nFollow **Button** content guidelines — action-first, present tense, sentence case:\n\n| Action type | Label | Variant |\n|-------------|-------|---------|\n| Primary create | Add Contact, Create Campaign | `contained` + `primary` |\n| Secondary | Export, Filter | `outlined` |\n| With icon | Same labels + `startIconProps` | Reinforce verb with icon |\n\nPlace primary action as the trailing visible button (right in LTR).\n\n## Accessibility\n\n- Overflow trigger: `aria-label=\"More actions\"`, `aria-haspopup=\"true\"`, `aria-expanded` when open.\n- Search field has `id=\"search\"` on `EnhancedTextField`.\n- Action buttons inherit MUI `Button` semantics (native button, keyboard activation).\n- Overflow menu uses MUI `Menu` / `MenuItem` focus management.\n- Title uses semantic `Typography` — consider wrapping page in `<main>` with heading hierarchy in host layout.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best practices\n\n- Use one `contained` primary action in visible buttons; secondary actions as `outlined`.\n- Set unique `id` on each action for stable rendering and overflow menu keys.\n- Tune `maxVisibleActions` to available horizontal space (default `2`).\n- Use `startIconProps={{ name: '...' }}` for icon buttons — not deprecated `startIcon`.\n- Pair search with host-side filtering logic in `onBasicSearch`.\n- Use via `DataGrid` `tableHeader` when the header sits above a data grid.\n- Wrap the app in `ExotelThemeProvider`.\n\n## Anti-patterns\n\n- Using `PageHeader` as the application shell header — use `AppBar`.\n- Setting `searchType: 'advanced'` expecting UI — not implemented.\n- Omitting `id` on actions — causes unstable keys and poor overflow menu behavior.\n- More than one competing `contained` primary button in the visible set.\n- Using raw MUI `Button` in `actions` — use Signal `ButtonProps` patterns.\n- Placing `PageHeader` inside a dialog — use dialog title/footer instead.\n\n## Guidance for AI Agents\n\n**Read UX Constitution first** (Table Pages, Settings Pages, Page Layout Patterns).\n\n### When to choose `PageHeader`\n\n- In-page title + optional subtitle below `AppBar`\n- Page needs search and/or action buttons in one header row\n- DataGrid table header via `tableHeader` prop\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| App shell (logo, launcher, user menu) | `AppBar` |\n| Modal title and actions | `StructuredDialog` |\n| Floating page action | `Fab` |\n| Toolbar inside DataGrid only | `DataGrid` `tableHeader` |\n\n### Canonical prop combinations\n\n```tsx\n// Title + subtitle — story: WithSubtitle\n<PageHeader\n  title=\"Channel Configuration\"\n  subtitle=\"Select communication channel and configure channel settings\"\n/>\n\n// Actions — story: WithActions\n<PageHeader\n  title=\"Channel Configuration\"\n  subtitle=\"Select communication channel and configure channel settings\"\n  actions={[\n    { id: 'export', children: 'Export', variant: 'outlined' },\n    { id: 'add', children: 'Add Contact', variant: 'contained' },\n  ]}\n/>\n\n// Search + actions — story: WithSearchAndActions\n<PageHeader\n  title=\"Channel Configuration\"\n  subtitle=\"Select communication channel and configure channel settings\"\n  showSearch\n  searchType=\"basic\"\n  onBasicSearch={(value) => setSearch(value)}\n  actions={[\n    { id: 'export', children: 'Export', variant: 'outlined' },\n    { id: 'add', children: 'Add Contact', variant: 'contained' },\n  ]}\n/>\n\n// Icon actions with overflow — story: WithIconActions\n<PageHeader\n  title=\"Channel Configuration\"\n  subtitle=\"Select communication channel and configure channel settings\"\n  showSearch\n  searchType=\"basic\"\n  onBasicSearch={(v) => filterRows(v)}\n  actions={[\n    { id: 'filter', children: 'Filter', variant: 'outlined', startIconProps: { name: 'funnel' } },\n    { id: 'create', children: 'Create Campaign', variant: 'contained', startIconProps: { name: 'plus' } },\n    { id: 'export', children: 'Export', variant: 'outlined', startIconProps: { name: 'export' } },\n    { id: 'import', children: 'Import', variant: 'outlined', startIconProps: { name: 'download-simple' } },\n  ]}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Minimal title | `Default` or `TitleOnly` |\n| Title + subtitle | `WithSubtitle` |\n| With action buttons | `WithActions` |\n| With search | `WithSearch` |\n| Full header (search + actions) | `WithSearchAndActions` |\n| Overflow icon actions | `WithIconActions` |\n\n### Common mistakes to avoid\n\n- Do not use `searchType: 'advanced'` — no UI renders.\n- Do not omit `onBasicSearch` when `showSearch` is true — search will not filter.\n- Do not invent `maxVisibleActions` below 0 — clamped with `Math.max(0, maxVisibleActions)`.\n- Do not use `PageHeader` instead of `AppBar` for the top application bar.\n- Action labels: use \"Add Contact\", not bare \"Add\" (see Button content guidelines).\n\n### Composition guidance\n\n- Layout order: `AppBar` → `PageHeader` → page content (or `DataGrid`).\n- Primary CTA should be the rightmost visible button.\n- When using with `DataGrid`, prefer `tableHeader` prop to avoid duplicate headers.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Button` | Action buttons in header and overflow menu |\n| `IconButton` | Overflow \"More actions\" trigger |\n| `Menu` | Overflow action list |\n| `EnhancedTextField` | Basic search input |\n| `Icon` | Search and action icons |\n| `AppBar` | Application shell header above PageHeader |\n| `DataGrid` | Consumes same props via `tableHeader` |\n| `Typography` | Title and subtitle rendering |\n"}}},"ui-components-paper":{"id":"ui-components-paper","name":"Paper","path":"./src/stories/ui-components/Paper.stories.tsx","stories":[{"id":"ui-components-paper--basic","name":"Basic","snippet":"const Basic = () => (\n  <Paper sx={{ p: 2, minWidth: 300 }}>\n    <Typography variant=\"h6\" gutterBottom>\n      Paper Title\n    </Typography>\n    <Typography variant=\"body2\">\n      This is a basic paper component with some content.\n    </Typography>\n  </Paper>\n);","description":"Basic paper"},{"id":"ui-components-paper--elevations","name":"Elevations","snippet":"const Elevations = () => (\n  <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n    {[0, 1, 2, 4, 8, 16].map((elevation) => (\n      <Paper key={elevation} elevation={elevation} sx={{ p: 2, minWidth: 150 }}>\n        <Typography variant=\"body2\">Elevation {elevation}</Typography>\n      </Paper>\n    ))}\n  </div>\n);","description":"Different elevations"},{"id":"ui-components-paper--outlined","name":"Outlined","snippet":"const Outlined = () => (\n  <Paper variant=\"outlined\" sx={{ p: 2, minWidth: 300 }}>\n    <Typography variant=\"h6\" gutterBottom>\n      Outlined Paper\n    </Typography>\n    <Typography variant=\"body2\">\n      This paper uses the outlined variant instead of elevation.\n    </Typography>\n  </Paper>\n);","description":"Outlined variant"},{"id":"ui-components-paper--with-content","name":"With Content","snippet":"const WithContent = () => (\n  <Paper sx={{ p: 3, minWidth: 400 }}>\n    <Typography variant=\"h5\" gutterBottom>\n      Paper with Content\n    </Typography>\n    <Typography variant=\"body1\" paragraph>\n      This paper contains various types of content including headings, paragraphs, and buttons.\n    </Typography>\n    <div style={{ display: 'flex', gap: '8px', marginTop: '16px' }}>\n      <Button variant=\"contained\">Primary Action</Button>\n      <Button variant=\"outlined\">Secondary Action</Button>\n    </div>\n  </Paper>\n);","description":"Paper with interactive content"},{"id":"ui-components-paper--interactive","name":"Interactive","snippet":"const Interactive = () => <Paper\n    variant=\"elevation\"\n    elevation={1}\n    square={false}\n    sx={{ p: 2, minWidth: 300 }}>\n    <Typography variant=\"h6\" gutterBottom>Interactive Paper\n              </Typography>\n    <Typography variant=\"body2\">Use the controls to change variant, elevation, and square properties.\n              </Typography>\n</Paper>;","description":"Interactive paper with all controls"}],"import":"import { Button, Paper, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Paper","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Paper/Paper.tsx","actualName":"Paper","exportName":"Paper","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-paper--docs":{"id":"ui-components-paper--docs","name":"Docs","path":"./src/stories/ui-components/Paper.mdx","title":"UI Components/Paper","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as PaperStories from './Paper.stories';\nimport { Paper } from '../../components/Paper';\n\n<Meta of={PaperStories} />\n\n# Paper\n\n## Overview\n\n`Paper` wraps MUI `Paper` for elevated or outlined surfaces.\n\n```tsx\nimport { Paper } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Elevated panels, popover surfaces, toolbar backgrounds.\n**When not to use:** Structured content cards → `Card`.\n\n## Stories\n\n`Basic`, `Elevations`, `Outlined`, `WithContent`, `Interactive`\n\n<Canvas of={PaperStories.Basic} />\n\n## Related Components\n\n`Card`, `Box`, `Popover`\n"}}},"ui-components-popover":{"id":"ui-components-popover","name":"Popover","path":"./src/stories/ui-components/Popover.stories.tsx","stories":[{"id":"ui-components-popover--default","name":"Default","snippet":"const Default = () => {\n  const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);\n  const open = Boolean(anchorEl);\n\n  return (\n    <>\n      <Button variant=\"contained\" onClick={(e) => setAnchorEl(e.currentTarget)}>\n        Open Popover\n      </Button>\n      <Popover\n        open={open}\n        anchorEl={anchorEl}\n        onClose={() => setAnchorEl(null)}\n        anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}\n      >\n        <Box sx={{ p: 2, maxWidth: 280 }}>\n          <Typography variant=\"subtitle2\" gutterBottom>\n            Popover Content\n          </Typography>\n          <Typography variant=\"body2\" color=\"text.secondary\">\n            This is a simple popover anchored below the button.\n          </Typography>\n        </Box>\n      </Popover>\n    </>\n  );\n};"},{"id":"ui-components-popover--anchor-positions","name":"Anchor Positions","snippet":"const AnchorPositions = () => {\n  const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);\n  const [origin, setOrigin] = useState<'top' | 'bottom' | 'center'>('bottom');\n  const buttonRef = useRef<HTMLButtonElement>(null);\n\n  return (\n    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, alignItems: 'center' }}>\n      <Box sx={{ display: 'flex', gap: 1 }}>\n        {(['top', 'bottom', 'center'] as const).map((pos) => (\n          <Button\n            key={pos}\n            variant=\"outlined\"\n            size=\"small\"\n            onClick={(e) => {\n              setOrigin(pos);\n              setAnchorEl(e.currentTarget);\n            }}\n          >\n            {pos}\n          </Button>\n        ))}\n      </Box>\n      <Popover\n        open={Boolean(anchorEl)}\n        anchorEl={anchorEl}\n        onClose={() => setAnchorEl(null)}\n        anchorOrigin={{ vertical: origin, horizontal: 'center' }}\n        transformOrigin={{ vertical: origin === 'bottom' ? 'top' : 'bottom', horizontal: 'center' }}\n      >\n        <Box sx={{ p: 2 }}>\n          <Typography variant=\"body2\">Anchored at: {origin}</Typography>\n        </Box>\n      </Popover>\n    </Box>\n  );\n};"}],"import":"import { Box, Button, Popover, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Popover","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Popover/Popover.tsx","actualName":"Popover","exportName":"Popover","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-popover--docs":{"id":"ui-components-popover--docs","name":"Docs","path":"./src/stories/ui-components/Popover.mdx","title":"UI Components/Popover","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as PopoverStories from './Popover.stories';\nimport { Popover } from '../../components/Popover';\n\n<Meta of={PopoverStories} />\n\n# Popover\n\n## Overview\n\n`Popover` wraps MUI `Popover` for anchored overlay panels displayed on click or other interactions.\n\n```tsx\nimport { Popover } from '@exotel-npm-dev/signal-design-system';\n```\n\nUsed internally by `AppLauncher`, `AppliedFilters`, `MultiSelect`, and `ChatInputBox` mentions.\n\n**When to use**\n\n- Custom anchored panels with rich content\n- Overflow content display (e.g. applied filters detail)\n- Product launcher menus\n\n**When not to use**\n\n- Action lists → use `Menu`\n- Brief hover text → use `Tooltip`\n- Modal overlay → use `Dialog`\n- Side panel forms → use `Drawer`\n\n## Props\n\n<ArgTypes of={Popover} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `open` | `boolean` | — | Controls visibility of the popover |\n| `anchorEl` | `Element \\| null` | — | The element to anchor the popover to |\n| `onClose` | `() => void` | — | Callback when the popover should close |\n| `anchorOrigin` | `{ vertical, horizontal }` | `{ vertical: 'top', horizontal: 'left' }` | Anchor point on the reference element |\n| `transformOrigin` | `{ vertical, horizontal }` | — | Point on the popover that attaches to anchor |\n\n## Stories\n\n### Default\n\nBasic popover anchored below a button with text content.\n\n<Canvas of={PopoverStories.Default} />\n\n### AnchorPositions\n\nInteractive demo showing top, bottom, and center anchor positions.\n\n<Canvas of={PopoverStories.AnchorPositions} />\n\n## Guidance for AI Agents\n\n| Scenario | Component |\n|----------|-----------|\n| Menu actions (list of items) | `Menu` |\n| Rich click panel (form, info) | `Popover` |\n| Hover hint (single line) | `Tooltip` |\n\n```tsx\nconst [anchorEl, setAnchorEl] = useState(null);\n\n<Button onClick={(e) => setAnchorEl(e.currentTarget)}>Open</Button>\n<Popover\n  open={Boolean(anchorEl)}\n  anchorEl={anchorEl}\n  onClose={() => setAnchorEl(null)}\n  anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}\n>\n  <Box sx={{ p: 2 }}>Content here</Box>\n</Popover>\n```\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `Menu` | Popover-based action list with MenuItems |\n| `Tooltip` | Simple hover text; no interaction inside |\n| `AppLauncher` | Uses Popover internally for its grid panel |\n| `AppliedFilters` | Uses Popover for filter detail overflow |\n| `Dialog` | Full-screen modal; use for complex forms |\n"}}},"ui-components-radio":{"id":"ui-components-radio","name":"Radio","path":"./src/stories/ui-components/Radio.stories.tsx","stories":[{"id":"ui-components-radio--unchecked","name":"Unchecked","snippet":"const Unchecked = () => <Radio checked={false} />;","description":"Unchecked radio"},{"id":"ui-components-radio--checked","name":"Checked","snippet":"const Checked = () => <Radio checked />;","description":"Checked radio"},{"id":"ui-components-radio--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Radio checked color=\"default\" />\n    <Radio checked color=\"primary\" />\n    <Radio checked color=\"secondary\" />\n    <Radio checked color=\"success\" />\n    <Radio checked color=\"error\" />\n    <Radio checked color=\"info\" />\n    <Radio checked color=\"warning\" />\n  </div>\n);","description":"Different colors"},{"id":"ui-components-radio--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Radio checked size=\"small\" />\n    <Radio checked size=\"medium\" />\n  </div>\n);","description":"Different sizes"},{"id":"ui-components-radio--with-label","name":"With Label","snippet":"const WithLabel = (args) => (\n  <MuiRadioGroup defaultValue=\"female\" name=\"radio-buttons-group\">\n    <FormControlLabel value=\"female\" control={<Radio size={args.size} />} label=\"Female\" />\n    <FormControlLabel value=\"male\" control={<Radio size={args.size} />} label=\"Male\" />\n    <FormControlLabel value=\"other\" control={<Radio size={args.size} />} label=\"Other\" />\n  </MuiRadioGroup>\n);","description":"Radio group with labels"},{"id":"ui-components-radio--disabled","name":"Disabled","snippet":"const Disabled = (args) => (\n  <MuiRadioGroup defaultValue=\"checked\" name=\"disabled-radio-group\">\n    <FormControlLabel value=\"unchecked\" disabled control={<Radio size={args.size} />} label=\"Unchecked\" />\n    <FormControlLabel value=\"checked\" disabled control={<Radio size={args.size} />} label=\"Checked\" />\n  </MuiRadioGroup>\n);","description":"Disabled state"},{"id":"ui-components-radio--interactive","name":"Interactive","snippet":"const Interactive = () => {\n    const [checked, setChecked] = useState(args.checked);\n\n    return (\n        <Radio\n            color=\"primary\"\n            size=\"medium\"\n            disabled={false}\n            checked={checked}\n            onChange={(e) => setChecked(e.target.checked)} />\n    );\n};","description":"Interactive radio with all controls"}],"import":"import { FormControlLabel, RadioGroup as MuiRadioGroup } from \"@mui/material\";\nimport { Radio } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Radio","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Radio/Radio.tsx","actualName":"Radio","exportName":"Radio","props":{"checked":{"required":false,"tsType":{"name":"boolean"},"description":""},"disabled":{"required":false,"tsType":{"name":"boolean"},"description":""},"onChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => void","signature":{"arguments":[{"type":{"name":"ReactChangeEvent","raw":"React.ChangeEvent<HTMLInputElement>","elements":[{"name":"HTMLInputElement"}]},"name":"event"},{"type":{"name":"boolean"},"name":"checked"}],"return":{"name":"void"}}},"description":""}},"composes":["Omit"]},"docs":{"ui-components-radio--docs":{"id":"ui-components-radio--docs","name":"Docs","path":"./src/stories/ui-components/Radio.mdx","title":"UI Components/Radio","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as RadioStories from './Radio.stories';\nimport { Radio } from '../../components/Radio';\n\n<Meta of={RadioStories} />\n\n# Radio\n\n## Overview\n\n`Radio` is the Signal Design System wrapper around MUI `Radio`. It is a thin `forwardRef` pass-through with no custom logic. Use it inside a `RadioGroup` with `FormControlLabel` for exclusive single-choice selection among a visible set of options.\n\nUse `Radio` when users must pick exactly one option from a small set (typically 2–7) where all choices should be visible without opening a dropdown. Do not use it for multiple selections or binary toggles.\n\n```tsx\nimport { Radio, RadioGroup, FormControlLabel } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Mutually exclusive options displayed inline (gender, delivery method, view mode)\n- Settings where seeing all choices at once aids decision-making\n- Forms with 2–7 options where a dropdown would hide choices\n\n**When not to use**\n\n- Multiple selections from a list → use `Checkbox` or `MultiSelect`\n- Binary on/off settings → use `Switch`\n- Long option lists (8+) → use `Select` or `Autocomplete`\n- Immediate toggle without a grouped label context → use `Switch`\n\n## Content guidelines\n\nRules for radio option labels in Exotel ECC and other Signal products. Labels are set on `FormControlLabel`, not on `Radio` itself.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Options are parallel | Same grammatical structure: \"Female\", \"Male\", \"Other\" |\n| Mutually exclusive | Each label represents one distinct choice — no overlap |\n| Concise | One to three words per option |\n| Sentence case | \"In progress\" not \"In Progress\" unless proper noun |\n| Group label optional | Use `FormLabel` or fieldset legend when the group needs a name |\n\n### Option label patterns\n\n| Context | Group context | Option labels | Signal reference |\n|---------|---------------|---------------|------------------|\n| Demographic | — | Female, Male, Other | `WithLabel` story |\n| Disabled demo | — | Unchecked, Checked | `Disabled` story |\n| Status choice | Queue routing | Open, Closed, Pending | Compose in forms |\n\n### Do and don't\n\n**Do**\n\n- \"Female\", \"Male\", \"Other\"\n- Short, distinct option labels\n- `FormControlLabel` wrapping each `Radio` with a `value`\n\n**Don't**\n\n- \"Select female\" (verb in option label)\n- Overlapping options (\"Active\" and \"Currently active\")\n- Single `Radio` without `RadioGroup` for exclusive selection\n- Using `Radio` for multi-select\n\n## Anatomy\n\n```\nRadioGroup (MUI — name, value, onChange)\n└── FormControlLabel (per option)\n    ├── Radio                 ← Signal wrapper\n    └── label text\n```\n\n`Radio` alone is the control element. Always compose with `RadioGroup` + `FormControlLabel` for labeled exclusive selection.\n\n## Props\n\n`RadioProps` extends MUI `RadioProps` (minus `ref`). All MUI props pass through via spread.\n\n### Signal-specific props\n\n`Radio` adds no custom props. The wrapper explicitly documents:\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `checked` | `boolean` | `false` | Whether the radio is selected | Set by `RadioGroup` in grouped usage; manual for standalone demos. |\n| `disabled` | `boolean` | `false` | Disables interaction | Apply via `FormControlLabel disabled` or `Radio disabled`. |\n| `onChange` | `(event, checked: boolean) => void` | — | Change handler | Prefer `RadioGroup onChange` for groups. |\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `color` | `'default' \\| 'primary' \\| 'secondary' \\| 'success' \\| 'error' \\| 'info' \\| 'warning'` | `'primary'` | Semantic color | Use `primary` for standard forms. See `Colors` story. |\n| `size` | `'small' \\| 'medium'` | `'medium'` | Control dimensions | Use `small` in dense forms. See `Sizes` story. |\n| `value` | `string` | — | Option value | Set on `FormControlLabel value`, not directly on `Radio`. |\n| `name` | `string` | — | Native input name | Set on `RadioGroup name` for form submission. |\n\nAdditional standard MUI `RadioProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Radio} />\n\n## Variants\n\n`Radio` has no visual `variant` prop. Appearance is controlled by `color` and `size`.\n\n| Color | Use for |\n|-------|---------|\n| `primary` | Default form selection |\n| `secondary` | Secondary emphasis |\n| `error` | Destructive or invalid choice context |\n| `success` / `info` / `warning` | Status-driven selection |\n\n<Canvas of={RadioStories.Colors} />\n\n## Sizes\n\nTwo sizes are available.\n\n| Size | Use for |\n|------|---------|\n| `small` | Dense forms, table inline options |\n| `medium` | Default forms |\n\n<Canvas of={RadioStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Unchecked | Default / not selected in group | See `Unchecked` story |\n| Checked | `checked` or selected `RadioGroup` value | See `Checked` story |\n| Disabled (unchecked) | `disabled` on label or radio | See `Disabled` story |\n| Disabled (checked) | `disabled` with selected value | See `Disabled` story |\n| Hover / Focus | Automatic | MUI and theme styles |\n\n<Canvas of={RadioStories.Unchecked} />\n<Canvas of={RadioStories.Checked} />\n<Canvas of={RadioStories.Disabled} />\n\n## Stories\n\n### Unchecked\n\n**Story ID:** `ui-components-radio--unchecked`\n\nStandalone `Radio` with `checked={false}`.\n\n**Recommended usage:** Reference for default unchecked appearance. In production, use inside `RadioGroup`.\n\n### Checked\n\n**Story ID:** `ui-components-radio--checked`\n\nStandalone `Radio` with `checked={true}`.\n\n**Recommended usage:** Reference for selected appearance.\n\n### Colors\n\n**Story ID:** `ui-components-radio--colors`\n\nAll semantic colors on checked radios: `default`, `primary`, `secondary`, `success`, `error`, `info`, `warning`.\n\n**Recommended usage:** Semantic color selection reference.\n\n### Sizes\n\n**Story ID:** `ui-components-radio--sizes`\n\n`small` and `medium` checked radios side by side.\n\n**Recommended usage:** Size selection reference.\n\n### WithLabel\n\n**Story ID:** `ui-components-radio--with-label`\n\n`RadioGroup` with three `FormControlLabel` options: Female, Male, Other. `defaultValue=\"female\"`.\n\n**Recommended usage:** Canonical production pattern for labeled radio groups.\n\n<Canvas of={RadioStories.WithLabel} />\n\n### Disabled\n\n**Story ID:** `ui-components-radio--disabled`\n\n`RadioGroup` with disabled unchecked and disabled checked options.\n\n**Recommended usage:** Unavailable choices that remain visible for context.\n\n### Interactive\n\n**Story ID:** `ui-components-radio--interactive`\n\nStandalone controlled `Radio` with Storybook controls for `checked`, `color`, `size`, `disabled`.\n\n**Recommended usage:** Playground only; not a production pattern.\n\n## Accessibility\n\n- Renders a native `<input type=\"radio\">` via MUI (`forwardRef<HTMLButtonElement>` wraps the icon button; native input is present).\n- `RadioGroup` manages `role=\"radiogroup\"` and arrow-key navigation between options.\n- Each `FormControlLabel` associates label text with the radio input.\n- Only one option per `name` should be selected — enforce via `RadioGroup`.\n- `disabled` removes the option from interaction; use `FormControlLabel disabled` for the full row.\n- Set a group label via `FormLabel` + `FormControl` or a `fieldset`/`legend` for screen reader context.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Always wrap exclusive options in `RadioGroup` with a shared `name`.\n- Use `FormControlLabel` for each option — do not rely on click targets without labels.\n- Use `defaultValue` for uncontrolled groups, `value` + `onChange` for controlled.\n- Prefer `Radio` over `Select` when all options (≤7) should be visible.\n- Use `size=\"small\"` in dense layouts; `color=\"primary\"` by default.\n- Import `RadioGroup` and `FormControlLabel` from `@exotel-npm-dev/signal-design-system`.\n- See **Content guidelines** for option label copy rules.\n\n## Anti-patterns\n\n- Multiple standalone `Radio` elements without `RadioGroup` — selection won't be exclusive.\n- Using `Radio` for multi-select → use `Checkbox`.\n- Using `Radio` for on/off toggles → use `Switch`.\n- Long option lists as radio groups → use `Select`.\n- Importing `@mui/material/Radio` directly — import from `@exotel-npm-dev/signal-design-system`.\n- Setting different `name` on each radio in a group — breaks exclusivity.\n- Omitting visible labels — hurts accessibility and scanability.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `Radio`\n\n- Exactly one choice from 2–7 visible options\n- Mutually exclusive alternatives shown inline\n- Form field where dropdown would hide choices\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Multiple selections | `Checkbox`, `MultiSelect` |\n| Binary on/off | `Switch` |\n| Long option list | `Select`, `Autocomplete` |\n| Dropdown in compact space | `Select` |\n\n### Canonical prop combinations\n\n```tsx\n// Labeled group — story: WithLabel\n<RadioGroup defaultValue=\"female\" name=\"radio-buttons-group\">\n  <FormControlLabel value=\"female\" control={<Radio />} label=\"Female\" />\n  <FormControlLabel value=\"male\" control={<Radio />} label=\"Male\" />\n  <FormControlLabel value=\"other\" control={<Radio />} label=\"Other\" />\n</RadioGroup>\n\n// Controlled group\n<RadioGroup value={value} onChange={(e) => setValue(e.target.value)} name=\"status\">\n  <FormControlLabel value=\"open\" control={<Radio size=\"small\" />} label=\"Open\" />\n  <FormControlLabel value=\"closed\" control={<Radio size=\"small\" />} label=\"Closed\" />\n</RadioGroup>\n\n// Disabled options — story: Disabled\n<RadioGroup defaultValue=\"checked\" name=\"disabled-radio-group\">\n  <FormControlLabel value=\"unchecked\" disabled control={<Radio />} label=\"Unchecked\" />\n  <FormControlLabel value=\"checked\" disabled control={<Radio />} label=\"Checked\" />\n</RadioGroup>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Labeled radio group | `WithLabel` (`ui-components-radio--with-label`) |\n| Unchecked appearance | `Unchecked` |\n| Checked appearance | `Checked` |\n| Semantic colors | `Colors` |\n| Size selection | `Sizes` |\n| Disabled options | `Disabled` |\n\n### Option label copy\n\n| Context | Label pattern | Example |\n|---------|---------------|---------|\n| Demographic | `{Option}` | Female, Male, Other |\n| Status | `{Status}` | Open, Closed, Pending |\n| Delivery | `{Method}` | Email, SMS, Voice |\n\n### Common mistakes to avoid\n\n- Do not render exclusive radios without `RadioGroup`.\n- Do not use `Radio` for boolean settings — use `Switch`.\n- `value` goes on `FormControlLabel`, not on `Radio`.\n- Do not create more than one selected radio per group.\n- Import `RadioGroup`, `FormControlLabel` from the design system package.\n\n### Composition guidance\n\n- Wrap groups in `FormControl` with `FormLabel` when the group needs a visible heading.\n- Stack `FormControlLabel` rows vertically for forms; horizontal for 2–3 short options.\n- Use `size=\"small\"` when the group sits in a dense settings panel.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `RadioGroup` | Manages exclusive selection (MUI re-export) |\n| `FormControlLabel` | Pairs label text with `Radio` (MUI re-export) |\n| `FormControl` | Wrapper for group label and error state |\n| `Checkbox` | Multi-select from a list |\n| `Switch` | Binary on/off toggle |\n| `Select` | Single select from long dropdown list |\n| `FormField` | Higher-level labeled input patterns |\n"}}},"ui-components-secondarynavigation":{"id":"ui-components-secondarynavigation","name":"SecondaryNavigation","path":"./src/stories/ui-components/SecondaryNavigation.stories.tsx","stories":[{"id":"ui-components-secondarynavigation--default","name":"Default","snippet":"const Default = () => <SecondaryNavigation\n    title=\"Campaigns\"\n    icon=\"megaphone-simple\"\n    items={sampleItems}\n    selectedId=\"2\"\n    actionLabel=\"Create Campaign\"\n    actionIcon=\"plus\"\n    actionVariant=\"outlined\" />;"},{"id":"ui-components-secondarynavigation--collapsed","name":"Collapsed","snippet":"const Collapsed = () => <SecondaryNavigation collapsed />;"},{"id":"ui-components-secondarynavigation--interactive","name":"Interactive","snippet":"const Interactive = () => {\n  const [collapsed, setCollapsed] = useState(false);\n  const [selectedId, setSelectedId] = useState<string | number>('1');\n\n  return (\n    <SecondaryNavigation\n      title=\"Campaigns\"\n      icon=\"megaphone-simple\"\n      collapsed={collapsed}\n      onToggleCollapse={() => setCollapsed((prev) => !prev)}\n      actionLabel=\"Create Campaign\"\n      actionIcon=\"plus\"\n      actionVariant=\"outlined\"\n      onActionClick={() => alert('Create campaign clicked')}\n      items={sampleItems}\n      selectedId={selectedId}\n      onItemSelect={setSelectedId}\n    />\n  );\n};"},{"id":"ui-components-secondarynavigation--with-footer","name":"With Footer","snippet":"const WithFooter = () => <SecondaryNavigation\n    title=\"Queues\"\n    icon=\"queue\"\n    items={sampleItems.slice(0, 4)}\n    selectedId=\"1\"\n    actionLabel=\"Add Queue\"\n    actionIcon=\"plus\"\n    actionVariant=\"contained\"\n    footer={(<Box sx={{ px: 1, py: 0.5 }}>\n      <Typography variant=\"caption\" color=\"text.secondary\">\n        4 of 12 queues shown\n      </Typography>\n    </Box>)} />;"},{"id":"ui-components-secondarynavigation--empty-state","name":"Empty State","snippet":"const EmptyState = () => <SecondaryNavigation\n    title=\"Campaigns\"\n    icon=\"megaphone-simple\"\n    items={[]}\n    actionLabel=\"Create Campaign\"\n    actionIcon=\"plus\"\n    emptyMessage=\"No campaigns yet. Create one to get started.\" />;"},{"id":"ui-components-secondarynavigation--no-action","name":"No Action","snippet":"const NoAction = () => <SecondaryNavigation\n    title=\"Team Members\"\n    icon=\"users\"\n    items={sampleItems.slice(0, 3)}\n    selectedId=\"2\" />;"},{"id":"ui-components-secondarynavigation--custom-empty-message","name":"Custom Empty Message","snippet":"const CustomEmptyMessage = () => <SecondaryNavigation\n    title=\"Search Results\"\n    icon=\"magnifying-glass\"\n    items={[]}\n    emptyMessage=\"No results match your filters.\" />;"},{"id":"ui-components-secondarynavigation--custom-render-item","name":"Custom Render Item","snippet":"const CustomRenderItem = () => <SecondaryNavigation\n    title=\"Campaigns\"\n    icon=\"megaphone-simple\"\n    items={sampleItems.slice(0, 4)}\n    selectedId=\"2\"\n    renderItem={(item: NavigationItem, selected: boolean) => (\n      <Box\n        sx={{\n          px: 1.5,\n          py: 1,\n          borderRadius: '8px',\n          bgcolor: selected ? 'action.selected' : 'transparent',\n          '&:hover': { bgcolor: selected ? 'action.selected' : 'action.hover' },\n          cursor: 'pointer',\n        }}\n      >\n        <Typography variant=\"body2\" fontWeight={selected ? 600 : 400} color=\"text.primary\">\n          {item.label}\n        </Typography>\n        <Typography variant=\"caption\" color=\"text.secondary\">\n          ID: {item.id}\n        </Typography>\n      </Box>\n    )} />;"},{"id":"ui-components-secondarynavigation--many-items","name":"Many Items","snippet":"const ManyItems = () => <SecondaryNavigation\n    title=\"All Queues\"\n    icon=\"queue\"\n    items={Array.from({ length: 25 }, (_, i) => ({\n      id: String(i + 1),\n      label: `Queue ${i + 1}`,\n    }))}\n    selectedId=\"5\"\n    actionLabel=\"Add Queue\"\n    actionIcon=\"plus\"\n    actionVariant=\"outlined\" />;"}],"import":"import { Box, SecondaryNavigation, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"SecondaryNavigation","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/SecondaryNavigation/SecondaryNavigation.tsx","actualName":"SecondaryNavigation","exportName":"default","props":{"title":{"required":true,"tsType":{"name":"string"},"description":""},"icon":{"required":false,"tsType":{"name":"unknown"},"description":""},"collapsed":{"required":false,"tsType":{"name":"boolean"},"description":"","defaultValue":{"value":"false","computed":false}},"onToggleCollapse":{"required":false,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":""},"actionLabel":{"required":false,"tsType":{"name":"string"},"description":""},"actionIcon":{"required":false,"tsType":{"name":"unknown"},"description":""},"actionVariant":{"required":false,"tsType":{"name":"union","raw":"'outlined' | 'contained' | 'text'","elements":[{"name":"literal","value":"'outlined'"},{"name":"literal","value":"'contained'"},{"name":"literal","value":"'text'"}]},"description":""},"onActionClick":{"required":false,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":""},"items":{"required":true,"tsType":{"name":"Array","elements":[{"name":"NavigationItem"}],"raw":"NavigationItem[]"},"description":""},"selectedId":{"required":false,"tsType":{"name":"union","raw":"string | number | null","elements":[{"name":"string"},{"name":"number"},{"name":"null"}]},"description":""},"onItemSelect":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(id: string | number) => void","signature":{"arguments":[{"type":{"name":"union","raw":"string | number","elements":[{"name":"string"},{"name":"number"}]},"name":"id"}],"return":{"name":"void"}}},"description":""},"emptyMessage":{"required":false,"tsType":{"name":"string"},"description":""},"renderItem":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(item: NavigationItem, selected: boolean) => ReactNode","signature":{"arguments":[{"type":{"name":"NavigationItem"},"name":"item"},{"type":{"name":"boolean"},"name":"selected"}],"return":{"name":"ReactNode"}}},"description":""},"footer":{"required":false,"tsType":{"name":"ReactNode"},"description":""}}},"docs":{"ui-components-secondarynavigation--docs":{"id":"ui-components-secondarynavigation--docs","name":"Docs","path":"./src/stories/ui-components/SecondaryNavigation.mdx","title":"UI Components/SecondaryNavigation","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as SecondaryNavigationStories from './SecondaryNavigation.stories';\nimport { SecondaryNavigation } from '../../components/SecondaryNavigation';\n\n<Meta of={SecondaryNavigationStories} />\n\n# SecondaryNavigation\n\n## Overview\n\n`SecondaryNavigation` is a collapsible side panel that displays a list of selectable entities with an avatar, optional action button, and footer. Commonly used as a left-hand navigation list for campaigns, queues, or similar domain objects in workspace-style settings pages.\n\n```tsx\nimport { SecondaryNavigation } from '@exotel-npm-dev/signal-design-system';\nimport type { NavigationItem } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Left-hand entity navigation in workspace settings pages (UX Constitution § Settings — Workspace archetype)\n- Campaign, queue, or process lists that open detail views in the main panel\n- Any list where users select one entity from a fixed set\n\n**When not to use**\n\n- Primary app navigation → use `Navigation` (left sidebar)\n- Tab-based switching → use `Tabs`\n- Searchable / filterable data lists → use `DataGrid`\n- Tree-structured navigation → use `NavigationDrawer`\n\n## Anatomy\n\n```\nSecondaryNavigation                 ← Container (290px expanded / 59px collapsed)\n├── Header row                     ← Title + icon + collapse toggle\n├── SecondaryNavigationActions     ← Optional action button (e.g. \"Create Campaign\")\n├── SecondaryNavigationItems       ← Scrollable list of NavigationItem entries\n│   └── Item                       ← Avatar + label, highlight on selected\n└── SecondaryNavigationFooter      ← Optional footer content\n```\n\n## Props\n\n<ArgTypes of={SecondaryNavigation} />\n\n### Key props\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `title` | `string` | — | Panel header title |\n| `icon` | `IconName` | — | Icon displayed beside the title |\n| `collapsed` | `boolean` | `false` | Whether the panel is collapsed to icon-only width (59px) |\n| `onToggleCollapse` | `() => void` | — | Callback to toggle collapsed state; shows chevron button |\n| `items` | `NavigationItem[]` | — | Array of `{ id, label }` objects |\n| `selectedId` | `string \\| number \\| null` | — | Currently active item |\n| `onItemSelect` | `(id: string \\| number) => void` | — | Callback when an item is clicked |\n| `actionLabel` | `string` | — | Label for the action button |\n| `actionIcon` | `IconName` | — | Icon for the action button |\n| `actionVariant` | `'outlined' \\| 'contained' \\| 'text'` | `'outlined'` | Variant of the action button |\n| `onActionClick` | `() => void` | — | Callback when action button is clicked |\n| `emptyMessage` | `string` | `'No items found'` | Message shown when items list is empty |\n| `renderItem` | `(item, selected) => ReactNode` | — | Custom render function per item |\n| `footer` | `ReactNode` | — | Content rendered in the footer area |\n\n### NavigationItem type\n\n```tsx\ninterface NavigationItem {\n  id: string | number;\n  label: string;\n}\n```\n\n## Stories\n\n### Default\n\nExpanded panel with campaigns list, selected item, and action button.\n\n<Canvas of={SecondaryNavigationStories.Default} />\n\n### Collapsed\n\nPanel collapsed to icon-only width (59px). Items show avatars with tooltips on hover.\n\n<Canvas of={SecondaryNavigationStories.Collapsed} />\n\n### Interactive\n\nFull interactive demo with collapsible toggle and item selection state.\n\n<Canvas of={SecondaryNavigationStories.Interactive} />\n\n### WithFooter\n\nPanel with a footer showing item count metadata.\n\n<Canvas of={SecondaryNavigationStories.WithFooter} />\n\n### EmptyState\n\nEmpty list with a custom empty message.\n\n<Canvas of={SecondaryNavigationStories.EmptyState} />\n\n### CustomRenderItem\n\nCustom `renderItem` function rendering additional metadata per item.\n\n<Canvas of={SecondaryNavigationStories.CustomRenderItem} />\n\n### ManyItems\n\nScrollable list with 25 items demonstrating overflow behavior.\n\n<Canvas of={SecondaryNavigationStories.ManyItems} />\n\n## Behavior\n\n| Behavior | Detail |\n|----------|--------|\n| Collapsed width | 59px — shows only avatars with right-aligned tooltips |\n| Expanded width | 290px — full labels and action button text visible |\n| Transition | `all 0.2s ease` on width, padding, opacity |\n| Selected state | Primary-tinted background with primary border |\n| Hover state | `action.hover` background on non-selected items |\n| Overflow | Item list scrolls independently; header and footer remain fixed |\n\n## Accessibility\n\n- Items are clickable `Box` elements; consider adding `role=\"listbox\"` for screen readers in complex usage.\n- Collapse toggle uses `IconButton` with inherent button semantics.\n- Tooltips appear on collapsed items for label discovery.\n\n## Best Practices\n\n- Pair with a main content area that displays details of the selected entity.\n- Use `onToggleCollapse` to let users reclaim horizontal space.\n- Keep `actionLabel` concise (2–3 words: \"Create Campaign\", \"Add Queue\").\n- Use `footer` for summary counts or secondary actions.\n- Use `renderItem` only when you need extra metadata; the default avatar + label is preferred.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `Navigation` | Primary app nav (left sidebar); SecondaryNavigation sits inside the content area |\n| `NavigationDrawer` | Tree-structured navigation for hierarchical menus |\n| `DataGrid` | Filterable data tables when entity list needs search/sort/filter |\n| `Tabs` | Horizontal switching when entities are few and flat |\n| `Drawer` | Slide-out panel for editing selected entity details |\n"}}},"ui-components-select":{"id":"ui-components-select","name":"Select","path":"./src/stories/ui-components/Select.stories.tsx","stories":[{"id":"ui-components-select--basic","name":"Basic","snippet":"const Basic = () => {\n  const [value, setValue] = useState('');\n  return (\n    <Select\n      label=\"Age\"\n      value={value}\n      onChange={(e) => setValue(e.target.value)}\n      sx={{ minWidth: 200 }}\n    >\n      <MenuItem value={10}>Ten</MenuItem>\n      <MenuItem value={20}>Twenty</MenuItem>\n      <MenuItem value={30}>Thirty</MenuItem>\n    </Select>\n  );\n};","description":"Basic select with external label"},{"id":"ui-components-select--sizes","name":"Sizes","snippet":"const Sizes = () => {\n  const [value1, setValue1] = useState('');\n  const [value2, setValue2] = useState('');\n  const [value3, setValue3] = useState('');\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '300px' }}>\n      <Select\n        label=\"Small\"\n        size=\"small\"\n        value={value1}\n        onChange={(e) => setValue1(e.target.value)}\n      >\n        <MenuItem value={10}>Option 1</MenuItem>\n        <MenuItem value={20}>Option 2</MenuItem>\n      </Select>\n      <Select\n        label=\"Medium\"\n        size=\"medium\"\n        value={value2}\n        onChange={(e) => setValue2(e.target.value)}\n      >\n        <MenuItem value={10}>Option 1</MenuItem>\n        <MenuItem value={20}>Option 2</MenuItem>\n      </Select>\n      <Select\n        label=\"Large\"\n        size=\"large\"\n        value={value3}\n        onChange={(e) => setValue3(e.target.value)}\n      >\n        <MenuItem value={10}>Option 1</MenuItem>\n        <MenuItem value={20}>Option 2</MenuItem>\n      </Select>\n    </div>\n  );\n};","description":"Different sizes"},{"id":"ui-components-select--error","name":"Error","snippet":"const Error = () => {\n  const [value, setValue] = useState('');\n  return (\n    <Select\n      label=\"Age\"\n      value={value}\n      onChange={(e) => setValue(e.target.value)}\n      error\n      helperText=\"Please select an age\"\n      sx={{ minWidth: 200 }}\n    >\n      <MenuItem value={10}>Ten</MenuItem>\n      <MenuItem value={20}>Twenty</MenuItem>\n      <MenuItem value={30}>Thirty</MenuItem>\n    </Select>\n  );\n};","description":"Error state"},{"id":"ui-components-select--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <Select label=\"Age\" value={10} disabled sx={{ minWidth: 200 }}>\n    <MenuItem value={10}>Ten</MenuItem>\n    <MenuItem value={20}>Twenty</MenuItem>\n    <MenuItem value={30}>Thirty</MenuItem>\n  </Select>\n);","description":"Disabled state"},{"id":"ui-components-select--full-width","name":"Full Width","snippet":"const FullWidth = () => {\n  const [value, setValue] = useState('');\n  return (\n    <div style={{ width: '360px' }}>\n      <Select\n        label=\"Age\"\n        value={value}\n        onChange={(e) => setValue(e.target.value)}\n        fullWidth\n      >\n        <MenuItem value={10}>Ten</MenuItem>\n        <MenuItem value={20}>Twenty</MenuItem>\n        <MenuItem value={30}>Thirty</MenuItem>\n      </Select>\n    </div>\n  );\n};","description":"Full width"},{"id":"ui-components-select--with-placeholder","name":"With Placeholder","snippet":"const WithPlaceholder = () => {\n  const [value, setValue] = useState('');\n  return (\n    <Select\n      label=\"Status\"\n      placeholder=\"Choose a status\"\n      value={value}\n      onChange={(e) => setValue(e.target.value)}\n      sx={{ minWidth: 200 }}\n    >\n      <MenuItem value=\"open\">Open</MenuItem>\n      <MenuItem value=\"closed\">Closed</MenuItem>\n    </Select>\n  );\n};","description":"Custom placeholder"}],"import":"import { MenuItem } from \"@mui/material\";\nimport { Select } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Select","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Select/Select.tsx","actualName":"Select","exportName":"Select","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text when no value is selected. Derived from `label` when omitted.\nPass an empty string to disable the default placeholder."}},"composes":["Omit"]},"docs":{"ui-components-select--docs":{"id":"ui-components-select--docs","name":"Docs","path":"./src/stories/ui-components/Select.mdx","title":"UI Components/Select","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as SelectStories from './Select.stories';\nimport { Select } from '../../components/Select';\n\n<Meta of={SelectStories} />\n\n# Select\n\n## Overview\n\n`Select` is the Signal Design System wrapper for single-value dropdown selection. It applies Exotel field patterns: an external label via `FieldWrapper`, an outlined input via `EnhancedTextField`, and a default placeholder derived from the label.\n\nUse `Select` for fixed option lists where users pick exactly one value from a dropdown. Do not use it when users need to search or type ahead.\n\n```tsx\nimport { Select } from '@exotel-npm-dev/signal-design-system';\nimport { MenuItem } from '@mui/material';\n```\n\n**Do not** import MUI `Select` from `@mui/material` — use Signal `Select` (see UX Constitution → Form Inputs).\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Fixed option lists with single selection\n- Form fields with a known, finite set of choices (age range, status, priority)\n- Dropdowns where search is not needed\n\n**When not to use**\n\n- Searchable or typeahead lists → use `Autocomplete`\n- Multiple selections → use `MultiSelect` or `Autocomplete` with `multiple`\n- Plain text input → use `FormField` or `EnhancedTextField`\n- Binary on/off → use `Switch`\n- Exclusive visible options (2–7) → consider `Radio` group\n\n## Content guidelines\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Label names the field | Short noun phrase: \"Age\", \"Status\", \"Priority\" |\n| Options are parallel | Same grammatical form across all `MenuItem` children |\n| Placeholder hints action | \"Select status\" — derived from label when omitted |\n| Sentence case | \"In progress\" not \"In Progress\" unless a proper noun |\n| Empty state | Use `value=\"\"` for unselected; placeholder shows in the field |\n\n### Do and don't\n\n**Do**\n\n- \"Age\" with options \"Ten\", \"Twenty\", \"Thirty\"\n- Consistent option length and structure\n- `label` prop on `Select` for the external field label\n\n**Don't**\n\n- \"Please choose your age\"\n- Mixed option styles (\"Ten\" vs \"20 years\")\n- Duplicate label and placeholder text\n- Floating `InputLabel` — use the `label` prop instead\n\n### Form composition\n\n```tsx\n<Select label=\"Age\" value={value} onChange={handleChange} sx={{ minWidth: 200 }}>\n  <MenuItem value={10}>Ten</MenuItem>\n  <MenuItem value={20}>Twenty</MenuItem>\n</Select>\n```\n\n## Anatomy\n\n```\nFieldWrapper (external label)\n└── EnhancedTextField (select — outlined only)\n    └── MenuItem (children)\n```\n\nOnly the **outlined** variant is supported (via `EnhancedTextField`). There is no `variant` prop on `Select`.\n\n## Props\n\n`SelectProps` extends `EnhancedTextFieldProps` (minus `select` and `multiline`). All `TextField` props pass through, with `select` fixed to `true`.\n\n### Commonly used props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `label` | `ReactNode` | — | External label above the field | Required for labeled fields. |\n| `placeholder` | `string` | derived | Empty-state hint | Defaults to `Select {label}`; pass `\"\"` to disable. |\n| `children` | `ReactNode` | — | `MenuItem` option elements | Required for options. |\n| `value` | `unknown` | — | Current selected value | Controlled pattern; use `''` for empty. |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'medium'` | Field dimensions | See `Sizes` story. |\n| `disabled` | `boolean` | `false` | Disables interaction | See `Disabled` story. |\n| `error` | `boolean` | `false` | Error visual state | Pair with `helperText`. See `Error` story. |\n| `helperText` | `ReactNode` | — | Hint or error text below field | See `Error` story. |\n| `fullWidth` | `boolean` | `false` | Stretches to container width | See `FullWidth` story. |\n| `required` | `boolean` | `false` | Marks field as required | Shows asterisk on label. |\n| `onChange` | `(event) => void` | — | Fires when selection changes | Required for controlled usage. |\n\n<ArgTypes of={Select} />\n\n## Sizes\n\n| Size | Use for |\n|------|---------|\n| `small` | Dense toolbars, compact forms, table filters |\n| `medium` | Default form fields |\n| `large` | Prominent form fields |\n\n<Canvas of={SelectStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Empty | `value=\"\"` | Placeholder shown when derived or set |\n| Selected | `value` set to option value | Displays selected `MenuItem` text |\n| Error | `error` + `helperText` | See `Error` story |\n| Disabled | `disabled` on `Select` | See `Disabled` story |\n| Full width | `fullWidth` on `Select` | See `FullWidth` story |\n\n<Canvas of={SelectStories.Error} />\n<Canvas of={SelectStories.Disabled} />\n\n## Stories\n\n### Basic\n\nControlled select with external label \"Age\" and three `MenuItem` options.\n\n<Canvas of={SelectStories.Basic} />\n\n### With placeholder\n\nCustom placeholder overriding the default derived text.\n\n<Canvas of={SelectStories.WithPlaceholder} />\n\n### Full width\n\nSelect stretching to container width.\n\n<Canvas of={SelectStories.FullWidth} />\n\n## Accessibility\n\n- Renders a native select input with listbox semantics (MUI default).\n- External label associates with the field via `htmlFor` / `id` when provided.\n- Keyboard: Space/Enter to open, Arrow keys to navigate options, Enter to select, Escape to close.\n- Pair `error` with `helperText` describing the error for screen readers.\n\n## Best Practices\n\n- Use the `label` prop for external labels — do not compose with floating `InputLabel`.\n- Use controlled `value` + `onChange` in React forms.\n- Set `minWidth` or `fullWidth` to prevent layout collapse when empty.\n- Use `MenuItem` from `@mui/material` for option children.\n- See **Content guidelines** for label and option copy rules.\n\n## Anti-patterns\n\n- Using `Select` for searchable long lists → use `Autocomplete`.\n- Using `Select` for multi-value pick → use `MultiSelect`.\n- Composing with `FormControl` + `InputLabel` — use the `label` prop instead.\n- Importing `@mui/material/Select` directly — import from `@exotel-npm-dev/signal-design-system`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `MenuItem` | Option children (`@mui/material`) |\n| `MultiSelect` | Custom multi-value dropdown with groups |\n| `Autocomplete` | Searchable single or multi select |\n| `EnhancedTextField` | Underlying outlined field implementation |\n| `FormField` | Lower-level labeled input with helper text |\n"}}},"ui-components-slider":{"id":"ui-components-slider","name":"Slider","path":"./src/stories/ui-components/Slider.stories.tsx","stories":[{"id":"ui-components-slider--basic","name":"Basic","snippet":"const Basic = () => <Slider defaultValue={30} />;"},{"id":"ui-components-slider--disabled","name":"Disabled","snippet":"const Disabled = () => <Slider defaultValue={30} disabled />;"}],"import":"import { Slider } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Slider","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Slider/Slider.tsx","actualName":"Slider","exportName":"Slider","props":{"value":{"required":false,"tsType":{"name":"union","raw":"number | number[]","elements":[{"name":"number"},{"name":"Array","elements":[{"name":"number"}],"raw":"number[]"}]},"description":""},"onChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: Event, value: number | number[], activeThumb: number) => void","signature":{"arguments":[{"type":{"name":"Event"},"name":"event"},{"type":{"name":"union","raw":"number | number[]","elements":[{"name":"number"},{"name":"Array","elements":[{"name":"number"}],"raw":"number[]"}]},"name":"value"},{"type":{"name":"number"},"name":"activeThumb"}],"return":{"name":"void"}}},"description":""}},"composes":["Omit"]},"docs":{"ui-components-slider--docs":{"id":"ui-components-slider--docs","name":"Docs","path":"./src/stories/ui-components/Slider.mdx","title":"UI Components/Slider","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as SliderStories from './Slider.stories';\nimport { Slider } from '../../components/Slider';\n\n<Meta of={SliderStories} />\n\n# Slider\n\n## Overview\n\n`Slider` is the Signal Design System wrapper around MUI `Slider`. It is a thin `forwardRef` pass-through with no custom logic. Use it for selecting a numeric value or range along a continuous or stepped track.\n\nUse `Slider` when users need to adjust a value within a bounded range (volume, threshold, percentage). Do not use it for choosing among named discrete options.\n\n```tsx\nimport { Slider } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Continuous or stepped numeric ranges (0–100, min–max thresholds)\n- Settings where dragging conveys magnitude (volume, opacity, priority weight)\n- Range selection with `value` as `[min, max]` array (MUI built-in)\n\n**When not to use**\n\n- Named discrete choices (low/medium/high) → use `Select` or `Radio`\n- Binary on/off → use `Switch`\n- Exact numeric entry → use `EnhancedTextField` with `type=\"number\"`\n- Multiple unrelated booleans → use `Checkbox`\n\n## Content guidelines\n\nRules for slider labels and value annotations. MUI `Slider` does not include a built-in label — compose with `Typography`, `FormLabel`, or `FormControl`.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Label names the dimension | \"Volume\", \"Priority threshold\", \"Timeout (seconds)\" |\n| Show value when precision matters | Pair with `valueLabelDisplay=\"on\"` or adjacent text |\n| Units in label or value | \"Timeout (seconds)\" or \"50%\" — not ambiguous numbers |\n| Min/max context | Provide `min`, `max`, `step` that match label semantics |\n| Avoid bare slider | Always expose what the value controls |\n\n### Label patterns\n\n| Context | Label | Value range | Notes |\n|---------|-------|-------------|-------|\n| Percentage | Volume | 0–100, `step={1}` | Append `%` in display |\n| Duration | Timeout (seconds) | 0–60 | Unit in label |\n| Priority weight | Priority | 1–10 | Discrete steps via `step` |\n\n### Do and don't\n\n**Do**\n\n- \"Volume\" with 0–100 range\n- `aria-label=\"Volume\"` or visible `FormLabel` when no text label is shown\n- `step` aligned to meaningful increments\n\n**Don't**\n\n- Bare slider with no label or value context\n- `step={0.001}` on a 0–100 UI without decimal display\n- Using slider for 3-option enums (use `Radio`)\n\n## Anatomy\n\n```\nFormControl (optional)\n├── FormLabel / Typography (label — compose externally)\n└── Slider                    ← Signal wrapper (MUI Slider)\n    ├── Track\n    ├── Thumb(s)\n    └── Value label (optional, MUI valueLabelDisplay)\n```\n\n`Slider` is the track control only. Labels, helper text, and value readouts are composed externally.\n\n## Props\n\n`SliderProps` extends MUI `SliderProps` (minus `ref`). All MUI props pass through via spread.\n\n### Signal-specific props\n\n`Slider` adds no custom props. The wrapper explicitly documents:\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `value` | `number \\| number[]` | — | Controlled value(s) | Single number or `[min, max]` for range. |\n| `onChange` | `(event, value, activeThumb) => void` | — | Fires during drag | Use `onChangeCommitted` for final value only. |\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `defaultValue` | `number \\| number[]` | — | Uncontrolled initial value | See `Basic` story (`defaultValue: 30`). |\n| `min` | `number` | `0` | Minimum value | Set to domain minimum. |\n| `max` | `number` | `100` | Maximum value | Set to domain maximum. |\n| `step` | `number` | `1` | Increment step | Match precision needs. |\n| `disabled` | `boolean` | `false` | Disables interaction | See `Disabled` story. |\n| `marks` | `boolean \\| Mark[]` | `false` | Tick marks on track | Use for stepped discrete values. |\n| `valueLabelDisplay` | `'on' \\| 'auto' \\| 'off'` | `'off'` | Thumb value tooltip | Use `'on'` when value must always be visible. |\n| `orientation` | `'horizontal' \\| 'vertical'` | `'horizontal'` | Track direction | Vertical for compact panels. |\n| `size` | `'small' \\| 'medium'` | `'medium'` | Track thickness | MUI size prop. |\n| `color` | `'primary' \\| 'secondary' \\| ...` | `'primary'` | Track/thumb color | Semantic emphasis. |\n\nAdditional standard MUI `SliderProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Slider} />\n\n## Variants\n\n`Slider` has no visual `variant` prop. Use `color`, `size`, `marks`, and `valueLabelDisplay` for visual variation.\n\n| Configuration | Use for |\n|---------------|---------|\n| Default horizontal | Standard settings |\n| `marks` + `step` | Discrete stepped values |\n| `value` as `number[]` | Range selection (min–max) |\n| `orientation=\"vertical\"` | Compact side panels |\n\n## Sizes\n\nMUI supports `size=\"small\"` and `size=\"medium\"` on the track. No Signal-specific sizes.\n\n| Size | Use for |\n|------|---------|\n| `small` | Dense settings |\n| `medium` | Default |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Default | `defaultValue` or `value` | See `Basic` story |\n| Disabled | `disabled={true}` | See `Disabled` story |\n| Dragging | Automatic during interaction | `onChange` fires continuously |\n| Committed | `onChangeCommitted` | Fires on release |\n| Range | `value={[20, 80]}` | Two thumbs (MUI built-in) |\n\n<Canvas of={SliderStories.Basic} />\n<Canvas of={SliderStories.Disabled} />\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-slider--basic`\n\nUncontrolled slider with `defaultValue={30}`.\n\n**Recommended usage:** Default numeric range input when exact initial value is sufficient.\n\n<Canvas of={SliderStories.Basic} />\n\n### Disabled\n\n**Story ID:** `ui-components-slider--disabled`\n\n`defaultValue={30}` with `disabled={true}`.\n\n**Recommended usage:** Read-only or unavailable range settings that show current value position.\n\n<Canvas of={SliderStories.Disabled} />\n\n## Accessibility\n\n- Renders with `role=\"slider\"` semantics via MUI.\n- Keyboard: Arrow keys adjust value; Home/End jump to min/max (MUI default).\n- Provide `aria-label` or associated `FormLabel` — the Signal wrapper does not add a label.\n- `disabled` removes thumb from interaction.\n- When `valueLabelDisplay` is off, expose current value to assistive tech via `aria-valuetext` or visible text.\n- For range sliders, MUI manages two thumbs with appropriate focus order.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Always pair with a visible label or `aria-label` describing what the value controls.\n- Set explicit `min`, `max`, and `step` matching the label's unit and precision.\n- Use controlled `value` + `onChange` when the value drives other UI.\n- Use `onChangeCommitted` for expensive side effects (API calls) instead of `onChange`.\n- Use `marks` when only specific values are valid.\n- Prefer `Select` or `Radio` for ≤5 named discrete options without magnitude metaphor.\n- Wrap in `FormControl` with `FormLabel` for consistent form layout.\n\n## Anti-patterns\n\n- Bare slider without label or value readout.\n- Using `Slider` for enum selection (low/medium/high) → use `Radio` or `Select`.\n- Using `Slider` for boolean settings → use `Switch`.\n- Firing API calls on every `onChange` tick — use `onChangeCommitted`.\n- Importing `@mui/material/Slider` directly — import from `@exotel-npm-dev/signal-design-system`.\n- `step` that does not divide `(max - min)` evenly — last step may not reach `max`.\n- Omitting `min`/`max` when domain is not 0–100 — defaults may mislead users.\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `Slider`\n\n- Numeric value within a continuous or stepped range\n- Drag gesture helps users understand magnitude\n- Range selection between min and max bounds\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Named discrete options | `Select`, `Radio` |\n| Binary on/off | `Switch` |\n| Exact number typing | `EnhancedTextField` |\n| Multiple independent booleans | `Checkbox` |\n\n### Canonical prop combinations\n\n```tsx\n// Basic uncontrolled — story: Basic\n<Slider defaultValue={30} />\n\n// Disabled — story: Disabled\n<Slider defaultValue={30} disabled />\n\n// Controlled with label (compose)\n<FormControl fullWidth>\n  <FormLabel>Volume</FormLabel>\n  <Slider\n    value={volume}\n    onChange={(_e, v) => setVolume(v as number)}\n    min={0}\n    max={100}\n    step={1}\n    valueLabelDisplay=\"auto\"\n    aria-label=\"Volume\"\n  />\n</FormControl>\n\n// Range slider (MUI built-in)\n<Slider\n  value={[20, 80]}\n  onChange={(_e, v) => setRange(v as number[])}\n  min={0}\n  max={100}\n  valueLabelDisplay=\"on\"\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default slider | `Basic` (`ui-components-slider--basic`) |\n| Disabled state | `Disabled` |\n\n### Label copy\n\n| Context | Label pattern | Example |\n|---------|---------------|---------|\n| Percentage | `{Dimension}` | Volume |\n| Duration | `{Setting}` (seconds) | Timeout (seconds) |\n| Weight | `{Dimension}` | Priority |\n\n### Common mistakes to avoid\n\n- Do not render slider without accessible name (`aria-label` or `FormLabel`).\n- Do not use default 0–100 range when domain differs — set `min`/`max`.\n- Do not use `Slider` for 3-option enums.\n- Import from `@exotel-npm-dev/signal-design-system`.\n- Storybook only has `Basic` and `Disabled` — extend with `marks`, range, and labeled examples in app code following MUI patterns.\n\n### Composition guidance\n\n- Place label above slider in vertical form layouts.\n- Show current value adjacent to label when `valueLabelDisplay=\"off\"`.\n- Use `sx={{ width: '100%' }}` or `FormControl fullWidth` for responsive tracks.\n- Debounce or use `onChangeCommitted` for server-side updates.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `FormControl` | Wrapper for label and helper text |\n| `FormLabel` | Accessible label for the slider |\n| `Switch` | Binary toggle alternative |\n| `Select` | Discrete option selection |\n| `EnhancedTextField` | Exact numeric text entry |\n| `Radio` | Small discrete choice sets |\n"}}},"ui-components-snackbar":{"id":"ui-components-snackbar","name":"Snackbar","path":"./src/stories/ui-components/Snackbar.stories.tsx","stories":[{"id":"ui-components-snackbar--basic","name":"Basic","snippet":"const Basic = () => {\n  const [open, setOpen] = useState(true);\n  return (\n    <Snackbar open={open} autoHideDuration={6000} onClose={() => setOpen(false)}>\n      <Alert severity=\"success\" onClose={() => setOpen(false)}>\n        This is a success message!\n      </Alert>\n    </Snackbar>\n  );\n};"}],"import":"import { Alert, Snackbar } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{"deprecated":["Use ToastProvider instead."]},"description":"","reactDocgen":{"description":"@deprecated Use ToastProvider instead.","methods":[],"displayName":"Snackbar","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Snackbar/Snackbar.tsx","actualName":"Snackbar","exportName":"Snackbar","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-snackbar--docs":{"id":"ui-components-snackbar--docs","name":"Docs","path":"./src/stories/ui-components/Snackbar.mdx","title":"UI Components/Snackbar","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as SnackbarStories from './Snackbar.stories';\nimport { Snackbar } from '../../components/Snackbar';\n\n<Meta of={SnackbarStories} />\n\n# Snackbar\n\n## Overview\n\n`Snackbar` is the Signal Design System wrapper around MUI `Snackbar`. It displays brief, transient notifications anchored to the viewport — typically auto-dismissing after a timeout. In Signal stories and ECC patterns, `Snackbar` wraps an `Alert` child for semantic styling and dismiss control.\n\n```tsx\nimport { Snackbar, Alert } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Brief global feedback after a user action (save, delete, export)\n- Auto-dismissing success or info messages\n- Non-blocking notifications that do not require a dialog\n\n**When not to use**\n\n- Persistent inline messages within a page section → `Alert` alone\n- Blocking confirmation or forms → `Dialog` or `StructuredDialog`\n- Rich interactive content → `Popover` or `Drawer`\n- Critical errors requiring guaranteed attention → inline `Alert` or modal\n\n## Anatomy\n\n```\nSnackbar                    ← Signal wrapper (MUI Snackbar)\n└── Alert (child)           ← Semantic message + optional onClose\n    └── children            ← Message text\n```\n\nCanonical composition from `Basic` story:\n\n```tsx\n<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>\n  <Alert severity=\"success\" onClose={handleClose}>\n    This is a success message!\n  </Alert>\n</Snackbar>\n```\n\nParent controls `open` state. Both `Snackbar` and `Alert` receive `onClose` so backdrop/timer dismiss and alert close button both work.\n\n## Content guidelines\n\nRules for writing snackbar messages in Exotel products. Message text is set on `Alert` `children`; `Snackbar` handles timing and placement.\n\n### Message structure\n\n| Element | Guidance |\n|---------|----------|\n| Body (`Alert children`) | One short sentence stating the outcome |\n| Severity | Match `Alert severity` to outcome: `success`, `error`, `warning`, `info` |\n| Dismiss | Provide `Alert onClose` when user may dismiss before auto-hide |\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Lead with outcome | \"Campaign saved\" not \"Your campaign has been successfully saved to the system\" |\n| Be specific | Name the object when helpful: \"3 contacts imported\" |\n| Concise | One sentence; snackbars are transient |\n| Match severity | `success` for completion; `error` for failure; `warning` for caution; `info` for neutral |\n| Present tense | \"Settings updated\" not \"Settings were updated\" |\n| No blame | \"Unable to save changes\" not \"You failed to save\" |\n\n### Severity and tone\n\n| Severity | Tone | Example |\n|----------|------|---------|\n| `success` | Confident, brief | \"This is a success message!\" (Basic story) |\n| `error` | Direct, actionable | \"Unable to export report. Try again.\" |\n| `warning` | Cautionary | \"Connection unstable. Changes may not sync.\" |\n| `info` | Neutral | \"Sync will complete in the background.\" |\n\n### Duration and dismiss\n\n| Setting | Guidance |\n|---------|----------|\n| `autoHideDuration` | `6000` ms in Basic story — 4–8 seconds for most messages |\n| `onClose` on Snackbar | Required for timer and click-away dismiss |\n| `onClose` on Alert | Enables explicit close button on the alert surface |\n\n### Do and don't\n\n**Do**\n\n- \"This is a success message!\" (Basic story pattern)\n- One sentence per snackbar\n- `severity=\"success\"` for completed actions\n- Pair `Snackbar onClose` with `Alert onClose`\n\n**Don't**\n\n- Multi-paragraph explanations\n- Critical errors that users might miss when auto-hidden\n- \"OK\" or \"Done\" as message text — state what happened\n- Stacking many simultaneous snackbars without queueing\n- Using snackbar for validation errors on a form — use inline `Alert` or field errors\n\n### Guidance for AI-generated snackbar copy\n\n- Generate one sentence for `Alert children`.\n- Choose `severity` from outcome, not visual preference.\n- Use `autoHideDuration={6000}` unless UX requires longer (match Basic story).\n- Always wire parent `open` state and `onClose` handlers.\n- Do not invent `message` prop — message is `Alert` children.\n- For errors needing user action, prefer persistent inline `Alert` over auto-dismissing snackbar.\n\n## Props\n\n`SnackbarProps` extends MUI `SnackbarProps` (minus `ref`). All MUI props pass through via spread.\n\n### Core props (from Basic story)\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `open` | `boolean` | — | Controls visibility | Parent state; set `false` in `onClose` |\n| `autoHideDuration` | `number` | — | Ms before auto-dismiss | `6000` in Basic story; `null` to disable auto-hide |\n| `onClose` | `(event, reason?) => void` | — | Fires on timeout or click-away | Sync with `open` state |\n| `children` | `ReactNode` | — | Typically `Alert` | Provides message and severity styling |\n\n### Common MUI Snackbar props\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `anchorOrigin` | `{ vertical, horizontal }` | Viewport position | MUI default bottom-center; override per product |\n| `message` | `ReactNode` | MUI native message slot | Stories use `Alert` child instead — prefer `Alert` pattern |\n| `action` | `ReactNode` | Trailing action | Rare; `Alert` `onClose` preferred in Signal |\n| `ClickAwayListener` behavior | via `onClose` reason | `'clickaway'` | Handle in `onClose` if click-away should not dismiss |\n\nSee the generated table below for the full API.\n\n<ArgTypes of={Snackbar} />\n\n## Variants\n\n`Snackbar` has no Signal visual variants. Variation comes from the child `Alert`:\n\n| Pattern | Child configuration | Story |\n|---------|---------------------|-------|\n| Success toast | `Alert severity=\"success\"` | `Basic` |\n| Error toast | `Alert severity=\"error\"` | Not in stories — compose same pattern |\n| Warning toast | `Alert severity=\"warning\"` | Not in stories — compose same pattern |\n| Info toast | `Alert severity=\"info\"` | Not in stories — compose same pattern |\n\nOnly `Basic` is documented in stories. Other severities follow the same `Snackbar` + `Alert` composition.\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Hidden | `open={false}` | Default after dismiss |\n| Visible | `open={true}` | Basic story starts open |\n| Auto-dismissing | `autoHideDuration={6000}` | Timer calls `onClose` |\n| User dismissible | `Alert onClose={handleClose}` | Close button on alert |\n| Click-away dismiss | MUI `onClose` reason `clickaway` | Default MUI behavior |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Show on action | Parent sets `open` true after operation | `Basic` (starts `open={true}`) |\n| Auto-hide | `autoHideDuration` timer | `Basic` |\n| Manual dismiss | `Alert onClose` | `Basic` |\n| Snackbar-level close | `Snackbar onClose` | `Basic` |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-snackbar--basic`\n\n`open={true}`, `autoHideDuration={6000}`, child `Alert severity=\"success\"` with `onClose`. Message: \"This is a success message!\".\n\n**Recommended usage:** Canonical success toast after a completed action.\n\n<Canvas of={SnackbarStories.Basic} />\n\n## Accessibility\n\n- MUI `Snackbar` uses `role=\"presentation\"` on the root; the child `Alert` provides `role=\"alert\"` for message announcement.\n- Auto-dismiss may remove content before slow readers finish — keep messages very short.\n- `Alert onClose` close button has MUI accessible labeling.\n- Do not rely solely on snackbars for critical errors — screen reader users may miss timed dismissal.\n- Ensure `open` state changes trigger alert content in the accessibility tree.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Compose `Snackbar` + `Alert` as in `Basic` story.\n- Control `open` with React state; set `false` in `onClose`.\n- Use `autoHideDuration={6000}` for standard feedback.\n- Pass `onClose` to both `Snackbar` and `Alert`.\n- Match `Alert severity` to message intent.\n- Keep messages to one short sentence.\n- Import from `@exotel-npm-dev/signal-design-system`.\n\n## Anti-patterns\n\n- Putting raw text in `Snackbar` without `Alert` — loses semantic styling.\n- Long messages that overflow on mobile viewports.\n- Auto-dismissing critical error messages users must read.\n- Multiple concurrent snackbars without queue management.\n- Using `Snackbar` for form validation — use field-level errors or inline `Alert`.\n- Inventing a `severity` prop on `Snackbar` — severity is on `Alert`.\n- Omitting `onClose` so snackbar never clears state.\n\n## Guidance for AI Agents\n\n### When to choose `Snackbar`\n\n- Transient global feedback after successful or failed operations\n- Auto-dismissing notification with optional manual close\n- Child content is a short `Alert` message\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Persistent inline message | `Alert` |\n| Blocking confirmation | `StructuredDialog` or `Dialog` |\n| Field-level validation | `EnhancedTextField` / `FormField` with `error` |\n| Rich panel content | `Drawer` or `Popover` |\n\n### Canonical prop combinations\n\nCopy from `Basic` story. Do not invent alternatives.\n\n```tsx\nconst [open, setOpen] = useState(false);\n\nconst handleClose = () => setOpen(false);\n\n// After successful action:\nsetOpen(true);\n\n<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>\n  <Alert severity=\"success\" onClose={handleClose}>\n    This is a success message!\n  </Alert>\n</Snackbar>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Success toast | `Basic` (`ui-components-snackbar--basic`) |\n\n### Message copy patterns\n\n| Outcome | severity | Example message |\n|---------|----------|-----------------|\n| Save succeeded | `success` | \"This is a success message!\" |\n| Save succeeded (specific) | `success` | \"Campaign saved.\" |\n| Action failed | `error` | \"Unable to save changes. Try again.\" |\n| Background info | `info` | \"Sync will complete shortly.\" |\n\n### Common mistakes to avoid\n\n- `severity` on `Snackbar` — put it on `Alert`.\n- `message` prop with plain string — use `Alert` child per stories.\n- Forgetting to reset `open` to `false` in `onClose`.\n- Using snackbar inside a `Dialog` — prefer dialog feedback or post-close snackbar.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Alert` | Child component for message content and severity |\n| `Dialog` | Blocking modals; not for transient toast |\n| `StructuredDialog` | Confirmation before actions that trigger snackbars |\n| `EnhancedTextField` | Form fields validated before success snackbar |\n"}}},"ui-components-stack":{"id":"ui-components-stack","name":"Stack","path":"./src/stories/ui-components/Stack.stories.tsx","stories":[{"id":"ui-components-stack--basic","name":"Basic","snippet":"const Basic = () => (\n  <Stack spacing={2}>\n    <Paper sx={{ p: 2 }}>Item 1</Paper>\n    <Paper sx={{ p: 2 }}>Item 2</Paper>\n    <Paper sx={{ p: 2 }}>Item 3</Paper>\n  </Stack>\n);","description":"Basic vertical stack"},{"id":"ui-components-stack--horizontal","name":"Horizontal","snippet":"const Horizontal = () => (\n  <Stack direction=\"row\" spacing={2}>\n    <Button variant=\"contained\">Button 1</Button>\n    <Button variant=\"contained\">Button 2</Button>\n    <Button variant=\"contained\">Button 3</Button>\n  </Stack>\n);","description":"Horizontal stack"},{"id":"ui-components-stack--spacing","name":"Spacing","snippet":"const Spacing = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>\n    {[0, 1, 2, 4].map((spacing) => (\n      <div key={spacing}>\n        <div style={{ marginBottom: '8px', fontSize: '12px' }}>Spacing: {spacing}</div>\n        <Stack direction=\"row\" spacing={spacing}>\n          <Paper sx={{ p: 2 }}>Item 1</Paper>\n          <Paper sx={{ p: 2 }}>Item 2</Paper>\n          <Paper sx={{ p: 2 }}>Item 3</Paper>\n        </Stack>\n      </div>\n    ))}\n  </div>\n);","description":"Different spacing"},{"id":"ui-components-stack--alignment","name":"Alignment","snippet":"const Alignment = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>\n    <div>\n      <div style={{ marginBottom: '8px', fontSize: '12px' }}>alignItems: center</div>\n      <Stack direction=\"row\" spacing={2} alignItems=\"center\" sx={{ height: 100, border: '1px dashed #ccc' }}>\n        <Paper sx={{ p: 2, height: 40 }}>Item 1</Paper>\n        <Paper sx={{ p: 2, height: 60 }}>Item 2</Paper>\n        <Paper sx={{ p: 2, height: 80 }}>Item 3</Paper>\n      </Stack>\n    </div>\n    <div>\n      <div style={{ marginBottom: '8px', fontSize: '12px' }}>justifyContent: space-between</div>\n      <Stack direction=\"row\" spacing={2} justifyContent=\"space-between\" sx={{ width: 400, border: '1px dashed #ccc', p: 1 }}>\n        <Button variant=\"contained\">Button 1</Button>\n        <Button variant=\"contained\">Button 2</Button>\n        <Button variant=\"contained\">Button 3</Button>\n      </Stack>\n    </div>\n  </div>\n);","description":"Alignment options"},{"id":"ui-components-stack--interactive","name":"Interactive","snippet":"const Interactive = () => <Stack\n    direction=\"column\"\n    spacing={2}\n    alignItems=\"stretch\"\n    justifyContent=\"flex-start\"\n    sx={{ minWidth: 300 }}>\n    <Paper sx={{ p: 2 }}>Item 1</Paper>\n    <Paper sx={{ p: 2 }}>Item 2</Paper>\n    <Paper sx={{ p: 2 }}>Item 3</Paper>\n</Stack>;","description":"Interactive stack with all controls"}],"import":"import { Button, Paper, Stack } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Stack","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Stack/Stack.tsx","actualName":"Stack","exportName":"Stack","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-stack--docs":{"id":"ui-components-stack--docs","name":"Docs","path":"./src/stories/ui-components/Stack.mdx","title":"UI Components/Stack","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as StackStories from './Stack.stories';\nimport { Stack } from '../../components/Stack';\n\n<Meta of={StackStories} />\n\n# Stack\n\n## Overview\n\n`Stack` wraps MUI `Stack` for flex layouts with consistent `spacing` and `direction`.\n\n```tsx\nimport { Stack } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Vertical or horizontal stacks of components with gap.\n**When not to use:** Grid columns → `Grid`; generic container → `Box`.\n\n## Stories\n\n`Basic`, `Horizontal`, `Spacing`, `Alignment`, `Interactive`\n\n<Canvas of={StackStories.Basic} />\n\n## Related Components\n\n`Box`, `Grid`, `Divider`\n"}}},"ui-components-stepper":{"id":"ui-components-stepper","name":"Stepper","path":"./src/stories/ui-components/Stepper.stories.tsx","stories":[{"id":"ui-components-stepper--horizontal","name":"Horizontal","snippet":"const Horizontal = () => {\n  const [activeStep, setActiveStep] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Stepper activeStep={activeStep}>\n        {steps.map((label) => (\n          <MuiStep key={label}>\n            <MuiStepLabel>{label}</MuiStepLabel>\n          </MuiStep>\n        ))}\n      </Stepper>\n      <Box sx={{ mt: 4, display: 'flex', gap: 2 }}>\n        <Button\n          variant=\"contained\"\n          onClick={() => setActiveStep((prev) => Math.min(prev + 1, steps.length - 1))}\n          disabled={activeStep === steps.length - 1}\n        >\n          Next\n        </Button>\n        <Button\n          variant=\"outlined\"\n          onClick={() => setActiveStep((prev) => Math.max(prev - 1, 0))}\n          disabled={activeStep === 0}\n        >\n          Back\n        </Button>\n      </Box>\n    </Box>\n  );\n};","description":"Horizontal stepper"},{"id":"ui-components-stepper--vertical","name":"Vertical","snippet":"const Vertical = () => {\n  const [activeStep, setActiveStep] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Stepper activeStep={activeStep} orientation=\"vertical\">\n        {steps.map((step, index) => (\n          <MuiStep key={step}>\n            <MuiStepLabel>{step}</MuiStepLabel>\n            <MuiStepContent>\n              <Typography>Content for step {index + 1}</Typography>\n              <Box sx={{ mt: 2, display: 'flex', gap: 2 }}>\n                <Button\n                  variant=\"contained\"\n                  size=\"small\"\n                  onClick={() => setActiveStep((prev) => Math.min(prev + 1, steps.length - 1))}\n                >\n                  {index === steps.length - 1 ? 'Finish' : 'Continue'}\n                </Button>\n                <Button\n                  variant=\"outlined\"\n                  size=\"small\"\n                  onClick={() => setActiveStep((prev) => Math.max(prev - 1, 0))}\n                  disabled={index === 0}\n                >\n                  Back\n                </Button>\n              </Box>\n            </MuiStepContent>\n          </MuiStep>\n        ))}\n      </Stepper>\n    </Box>\n  );\n};","description":"Vertical stepper"},{"id":"ui-components-stepper--alternative-label","name":"Alternative Label","snippet":"const AlternativeLabel = () => {\n  const [activeStep, setActiveStep] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 800 }}>\n      <Stepper activeStep={activeStep} alternativeLabel>\n        {steps.map((label) => (\n          <MuiStep key={label}>\n            <MuiStepLabel>{label}</MuiStepLabel>\n          </MuiStep>\n        ))}\n      </Stepper>\n      <Box sx={{ mt: 4, display: 'flex', gap: 2, justifyContent: 'center' }}>\n        <Button\n          variant=\"contained\"\n          onClick={() => setActiveStep((prev) => Math.min(prev + 1, steps.length - 1))}\n          disabled={activeStep === steps.length - 1}\n        >\n          Next\n        </Button>\n        <Button\n          variant=\"outlined\"\n          onClick={() => setActiveStep((prev) => Math.max(prev - 1, 0))}\n          disabled={activeStep === 0}\n        >\n          Back\n        </Button>\n      </Box>\n    </Box>\n  );\n};","description":"Alternative label stepper"},{"id":"ui-components-stepper--non-linear","name":"Non Linear","snippet":"const NonLinear = () => {\n  const [activeStep, setActiveStep] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Stepper activeStep={activeStep} nonLinear>\n        {steps.map((label, index) => (\n          <MuiStep key={label} completed={index < activeStep}>\n            <MuiStepLabel onClick={() => setActiveStep(index)}>\n              {label}\n            </MuiStepLabel>\n          </MuiStep>\n        ))}\n      </Stepper>\n      <Box sx={{ mt: 4 }}>\n        <Typography>Active step: {activeStep + 1}</Typography>\n      </Box>\n    </Box>\n  );\n};","description":"Non-linear stepper"},{"id":"ui-components-stepper--interactive","name":"Interactive","snippet":"const Interactive = () => {\n    const [activeStep, setActiveStep] = useState(args.activeStep || 0);\n\n    return (\n        <Box sx={{ width: '100%', maxWidth: 600 }}>\n            <Stepper orientation=\"horizontal\" alternativeLabel={false} activeStep={activeStep}>\n                {steps.map((label) => (\n                  <MuiStep key={label}>\n                    <MuiStepLabel>{label}</MuiStepLabel>\n                  </MuiStep>\n                ))}\n            </Stepper>\n        </Box>\n    );\n};","description":"Interactive stepper with all controls"}],"import":"import { Box, Button, Stepper, Typography } from \"@exotel-npm-dev/signal-design-system\";\nimport MuiStep from \"@mui/material/Step\";\nimport MuiStepContent from \"@mui/material/StepContent\";\nimport MuiStepLabel from \"@mui/material/StepLabel\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Stepper","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Stepper/Stepper.tsx","actualName":"Stepper","exportName":"Stepper","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-stepper--docs":{"id":"ui-components-stepper--docs","name":"Docs","path":"./src/stories/ui-components/Stepper.mdx","title":"UI Components/Stepper","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as StepperStories from './Stepper.stories';\nimport { Stepper } from '../../components/Stepper';\n\n<Meta of={StepperStories} />\n\n# Stepper\n\n## Overview\n\n`Stepper` wraps MUI `Stepper` for sequential multi-step workflows. Compose with `Step`, `StepLabel`, `StepContent` (MUI re-exports).\n\n```tsx\nimport { Stepper, Step, StepLabel } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Wizards, onboarding flows, step-by-step processes.\n**When not to use:** Peer view switching → `Tabs`; collapsible sections → `Accordion`.\n\n## Stories\n\n`Horizontal`, `Vertical`, `AlternativeLabel`, `NonLinear`, `Interactive`\n\n<Canvas of={StepperStories.Horizontal} />\n\n## Guidance for AI Agents\n\n| Scenario | Component |\n|----------|-----------|\n| Sequential wizard | `Stepper` |\n| Parallel views | `Tabs` |\n| Optional collapsible sections | `Accordion` |\n\n## Related Components\n\n`Tabs`, `Accordion`, `Button`, `Dialog`\n"}}},"ui-components-structureddialog":{"id":"ui-components-structureddialog","name":"StructuredDialog","path":"./src/stories/ui-components/StructuredDialog.stories.tsx","stories":[{"id":"ui-components-structureddialog--basic","name":"Basic","snippet":"const Basic = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog</Button>\n      <StructuredDialog\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Heading\"\n        showFooter={true}\n        footerContent={\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Save and Dial\n          </Button>\n        }\n      >\n        <DialogBody>\n          <Typography variant=\"body2\">\n            This is the body content of the dialog. You can add any content here,\n            such as forms, lists, or other components.\n          </Typography>\n        </DialogBody>\n      </StructuredDialog>\n    </Box>\n  );\n};","description":"Basic StructuredDialog with header, body, and footer"},{"id":"ui-components-structureddialog--with-form","name":"With Form","snippet":"const WithForm = () => {\n  const [open, setOpen] = useState(false);\n  const [channel, setChannel] = useState('whatsapp');\n  const [number, setNumber] = useState('9876543210');\n  const [template, setTemplate] = useState('Hi {Customer name} can we connect ?');\n\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Form Dialog</Button>\n      <StructuredDialog\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Heading\"\n        showFooter={true}\n        footerContent={\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Save and Dial\n          </Button>\n        }\n      >\n        <DialogBody>\n          {/* Channel Selection */}\n          <Box sx={{ mb: 3 }}>\n            <Typography variant=\"body2\" sx={{ mb: 2, fontWeight: 500 }}>\n              Channel\n            </Typography>\n            <FormControl>\n              <RadioGroup\n                value={channel}\n                onChange={(e) => setChannel(e.target.value)}\n                row\n              >\n                <FormControlLabel value=\"call\" control={<Radio />} label=\"Call\" />\n                <FormControlLabel\n                  value=\"whatsapp\"\n                  control={<Radio />}\n                  label=\"WhatsApp Chat\"\n                />\n              </RadioGroup>\n            </FormControl>\n          </Box>\n\n          {/* Note */}\n          <Box\n            sx={{\n              p: 2,\n              mb: 3,\n              backgroundColor: 'action.hover',\n              borderRadius: 1,\n            }}\n          >\n            <Typography variant=\"body3\" color=\"text.secondary\">\n              Note : Please ensure the selected number is available on WhatsApp\n            </Typography>\n          </Box>\n\n          {/* Number Input */}\n          <Box sx={{ mb: 3 }}>\n            <TextField\n              fullWidth\n              label=\"Enter or select number\"\n              value={number}\n              onChange={(e) => setNumber(e.target.value)}\n            />\n          </Box>\n\n          {/* Template Text Area */}\n          <Box>\n            <TextField\n              fullWidth\n              label=\"Select Template\"\n              multiline\n              rows={4}\n              value={template}\n              onChange={(e) => setTemplate(e.target.value)}\n            />\n          </Box>\n        </DialogBody>\n      </StructuredDialog>\n    </Box>\n  );\n};","description":"Dialog with form content (matching Figma design)"},{"id":"ui-components-structureddialog--scrollable-body","name":"Scrollable Body","snippet":"const ScrollableBody = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Scrollable Dialog</Button>\n      <StructuredDialog\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Long Content Example\"\n        showFooter={true}\n        footerContent={\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Save\n          </Button>\n        }\n      >\n        <DialogBody>\n          {Array.from({ length: 50 }, (_, i) => (\n            <Typography key={i} variant=\"body2\" sx={{ mb: 2 }}>\n              This is paragraph {i + 1}. The body section should scroll when\n              content overflows, while the header and footer remain fixed.\n            </Typography>\n          ))}\n        </DialogBody>\n      </StructuredDialog>\n    </Box>\n  );\n};","description":"Dialog with long, scrollable body"},{"id":"ui-components-structureddialog--without-header","name":"Without Header","snippet":"const WithoutHeader = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog (No Header)</Button>\n      <StructuredDialog\n        open={open}\n        onClose={() => setOpen(false)}\n        showHeader={false}\n        showFooter={true}\n        footerContent={\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Continue\n          </Button>\n        }\n      >\n        <DialogBody>\n          <Typography variant=\"body2\">\n            This dialog does not have a header. The close button is not rendered\n            when the header is hidden. Users must use the footer action or click\n            outside to close.\n          </Typography>\n        </DialogBody>\n      </StructuredDialog>\n    </Box>\n  );\n};","description":"Dialog without header"},{"id":"ui-components-structureddialog--without-footer","name":"Without Footer","snippet":"const WithoutFooter = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog (No Footer)</Button>\n      <StructuredDialog\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Information Dialog\"\n        showFooter={false}\n      >\n        <DialogBody>\n          <Typography variant=\"body2\">\n            This dialog does not have a footer. It's useful for informational\n            dialogs where the only action is to close via the header close button\n            or backdrop click.\n          </Typography>\n        </DialogBody>\n      </StructuredDialog>\n    </Box>\n  );\n};","description":"Dialog without footer"},{"id":"ui-components-structureddialog--multiple-footer-actions","name":"Multiple Footer Actions","snippet":"const MultipleFooterActions = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Dialog (Multiple Actions)</Button>\n      <StructuredDialog\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Confirm Action\"\n        showFooter={true}\n        footerContent={\n          <>\n            <Button variant=\"outlined\" color=\"error\" onClick={() => setOpen(false)}>\n              Delete\n            </Button>\n            <Button variant=\"contained\" onClick={() => setOpen(false)}>\n              Save Changes\n            </Button>\n          </>\n        }\n      >\n        <DialogBody>\n          <Typography variant=\"body2\">\n            This dialog has multiple actions in the footer. Notice there's no\n            default Cancel button - the close (×) button is the primary dismissal\n            action.\n          </Typography>\n        </DialogBody>\n      </StructuredDialog>\n    </Box>\n  );\n};","description":"Dialog with multiple footer actions"},{"id":"ui-components-structureddialog--small-dialog","name":"Small Dialog","snippet":"const SmallDialog = () => {\n  const [open, setOpen] = useState(false);\n  return (\n    <Box>\n      <Button onClick={() => setOpen(true)}>Open Small Dialog</Button>\n      <StructuredDialog\n        open={open}\n        onClose={() => setOpen(false)}\n        title=\"Confirmation\"\n        showFooter={true}\n        footerContent={\n          <Button variant=\"contained\" onClick={() => setOpen(false)}>\n            Confirm\n          </Button>\n        }\n      >\n        <DialogBody>\n          <Typography variant=\"body2\">\n            Are you sure you want to proceed with this action?\n          </Typography>\n        </DialogBody>\n      </StructuredDialog>\n    </Box>\n  );\n};","description":"Small dialog with minimal content"},{"id":"ui-components-structureddialog--width-variants","name":"Width variants","snippet":"const WidthVariants = () => {\n  const [openWidth, setOpenWidth] = useState<DialogProps['maxWidth'] | null>(null);\n  return (\n    <Stack direction=\"row\" spacing={1} flexWrap=\"wrap\">\n      {WIDTH_OPTIONS.map((w) => (\n        <Button key={String(w)} variant=\"outlined\" onClick={() => setOpenWidth(w)}>\n          maxWidth=\"{String(w)}\"\n        </Button>\n      ))}\n\n      {WIDTH_OPTIONS.map((w) => (\n        <StructuredDialog\n          key={String(w)}\n          open={openWidth === w}\n          onClose={() => setOpenWidth(null)}\n          maxWidth={w}\n          title={`maxWidth=\"${String(w)}\"`}\n          showFooter\n          footerContent={\n            <Button variant=\"contained\" onClick={() => setOpenWidth(null)}>\n              Close\n            </Button>\n          }\n        >\n          <DialogBody>\n            <Typography variant=\"body2\" sx={{ mb: 1 }}>\n              This dialog uses <strong>maxWidth=\"{String(w)}\"</strong> with <strong>fullWidth</strong>.\n            </Typography>\n            <Typography variant=\"body2\" color=\"text.secondary\">\n              The dialog stretches to fill the available width up to the max-width\n              breakpoint. Resize your browser to see how each variant responds.\n            </Typography>\n          </DialogBody>\n        </StructuredDialog>\n      ))}\n    </Stack>\n  );\n};"}],"import":"import {\n    Box,\n    Button,\n    DialogBody,\n    FormControl,\n    Radio,\n    Stack,\n    StructuredDialog,\n    EnhancedTextField as TextField,\n    Typography,\n} from \"@exotel-npm-dev/signal-design-system\";\nimport { FormControlLabel, RadioGroup } from \"@mui/material\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"StructuredDialog","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Dialog/StructuredDialog.tsx","actualName":"StructuredDialog","exportName":"StructuredDialog","props":{"title":{"required":false,"tsType":{"name":"string"},"description":"Title displayed in the header"},"onClose":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: React.SyntheticEvent, reason?: 'backdropClick' | 'escapeKeyDown') => void","signature":{"arguments":[{"type":{"name":"ReactSyntheticEvent","raw":"React.SyntheticEvent"},"name":"event"},{"type":{"name":"union","raw":"'backdropClick' | 'escapeKeyDown'","elements":[{"name":"literal","value":"'backdropClick'"},{"name":"literal","value":"'escapeKeyDown'"}]},"name":"reason"}],"return":{"name":"void"}}},"description":"Callback fired when the close button is clicked"},"showHeader":{"required":false,"tsType":{"name":"boolean"},"description":"Whether to show the header section\n@default true","defaultValue":{"value":"true","computed":false}},"showFooter":{"required":false,"tsType":{"name":"boolean"},"description":"Whether to show the footer section\n@default false","defaultValue":{"value":"false","computed":false}},"children":{"required":false,"tsType":{"name":"ReactNode"},"description":"Main content to display in the body section"},"footerContent":{"required":false,"tsType":{"name":"ReactNode"},"description":"Footer content (actions) to display in the footer section"},"headerContent":{"required":false,"tsType":{"name":"ReactNode"},"description":"Custom header content (overrides title and default close button)"}},"composes":["Omit"]},"docs":{"ui-components-structureddialog--docs":{"id":"ui-components-structureddialog--docs","name":"Docs","path":"./src/stories/ui-components/StructuredDialog.mdx","title":"UI Components/StructuredDialog","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as StructuredDialogStories from './StructuredDialog.stories';\nimport { StructuredDialog } from '../../components/Dialog';\n\n<Meta of={StructuredDialogStories} />\n\n# StructuredDialog\n\n## Overview\n\n`StructuredDialog` is the Signal Design System structured modal built on MUI `Dialog`. It provides a fixed Header / scrollable Body / optional Footer layout with predictable scrolling, responsive `maxHeight` (90vh mobile/tablet, 80vh desktop), and Exotel theme styling.\n\nAlso exports `DialogBody` and `DialogFooter` as optional content wrappers. Stories wrap body content in `DialogBody`.\n\n```tsx\nimport {\n  StructuredDialog,\n  DialogBody,\n  Button,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Standard Exotel centered modal with title, scrollable body, and action footer\n- Create/edit flows, confirmations, and forms that match Drawer footer conventions\n- Cases where you want header close button and layout without manual MUI composition\n\n**When not to use**\n\n- Fully custom MUI dialog structure → use `Dialog` with `DialogTitle` / `DialogContent` / `DialogActions`\n- Off-canvas side panel → use `Drawer`\n- Brief auto-dismissing feedback → use `Snackbar` + `Alert`\n- Persistent inline messages → use `Alert`\n\n## Anatomy\n\n```\nStructuredDialog              ← Signal wrapper (maxWidth=\"sm\" fullWidth fixed)\n├── DialogTitle (internal)    ← Header: title + close IconButton (when showHeader)\n├── DialogContent (internal)  ← Scrollable body region\n│   └── DialogBody            ← Optional wrapper for children (stories)\n└── DialogActions (internal)  ← Footer when showFooter && footerContent\n```\n\nCanonical structure (from `Basic` story):\n\n```tsx\n<StructuredDialog\n  open={open}\n  onClose={handleClose}\n  title=\"Heading\"\n  showFooter={true}\n  footerContent={\n    <Button variant=\"contained\" onClick={handleClose}>\n      Save and Dial\n    </Button>\n  }\n>\n  <DialogBody>\n    <Typography variant=\"body2\">Body content</Typography>\n  </DialogBody>\n</StructuredDialog>\n```\n\n## Content guidelines\n\nRules for writing StructuredDialog copy in Exotel ECC and other Signal products.\n\n### Title (`title` prop)\n\n| Principle | Rule |\n|-----------|------|\n| Task-focused | Name the action or object: \"Create email settings\", \"Confirm action\" |\n| Concise | 1–5 words; sentence case |\n| No punctuation | Omit trailing periods in titles |\n\n**Canonical titles from stories:** \"Heading\", \"Long Content Example\", \"Confirm Action\", \"Confirmation\", \"Information Dialog\".\n\n### Body (`children` / `DialogBody`)\n\n| Principle | Rule |\n|-----------|------|\n| Lead with context | First sentence states purpose or decision |\n| Scannable sections | Section headings use `Typography variant=\"h6\"`; descriptions use `body3` + `text.secondary` |\n| Notes | Tinted `action.hover` boxes for contextual notes (see `WithForm`) |\n| Form labels | `EnhancedTextField` labels are nouns (\"Enter or select number\", \"Select Template\") |\n\n**Example note from `WithForm`:** \"Note : Please ensure the selected number is available on WhatsApp\"\n\n### Footer (`footerContent`)\n\n| Principle | Rule |\n|-----------|------|\n| Commit verb | Primary: \"Save\", \"Confirm\", \"Save and Dial\", \"Save Changes\" |\n| Dismiss | Header × handles dismiss when present; add explicit Cancel only when needed |\n| Destructive | `color=\"error\"` + `variant=\"outlined\"` for delete; commit stays `contained` |\n| Placement | Footer is `justifyContent: flex-end`; buttons render in DOM order left-to-right |\n\n**Canonical footer patterns from stories:**\n\n```\n[Save and Dial]              ← Basic, WithForm (single primary)\n[Save]                       ← ScrollableBody\n[Continue]                   ← WithoutHeader\n[Delete]  [Save Changes]     ← MultipleFooterActions\n[Confirm]                    ← SmallDialog\n```\n\n### Do and don't\n\n**Do**\n\n- \"Save and Dial\"\n- \"Save Changes\"\n- \"Confirm\"\n- Pair destructive `Delete` with a clear commit alternative\n\n**Don't**\n\n- Omit `showFooter={true}` when footer buttons are intended (`showFooter` defaults to `false`)\n- Rely on footer alone for dismiss when header is hidden — provide \"Continue\" or similar\n- Use generic \"OK\" / \"Submit\" when a specific verb is known\n- Put essential instructions only in `footerContent` — body carries context\n\n### Guidance for AI-generated dialog copy\n\n- Set `title` to a short task noun or phrase matching the workflow.\n- Wrap body in `DialogBody` for consistency with stories.\n- When `showHeader={true}` (default), header close (`aria-label=\"close dialog\"`) is the dismiss path — footer may be single-primary (`Basic`).\n- For `MultipleFooterActions`, document that × is primary dismiss; no separate Cancel.\n- Destructive: `Button variant=\"outlined\" color=\"error\"` before `Button variant=\"contained\"` commit.\n\n## Props\n\n`StructuredDialogProps` extends MUI `DialogProps` (minus `ref` and `children`).\n\n### Signal-specific props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `title` | `string` | — | Header title text | Rendered in `Typography variant=\"h6\"` when `showHeader` is true |\n| `onClose` | `(event, reason?) => void` | — | Close handler | Enables header close button and MUI backdrop/Escape dismiss |\n| `showHeader` | `boolean` | `true` | Show header section | Set `false` for headerless dialogs (`WithoutHeader`) |\n| `showFooter` | `boolean` | `false` | Show footer section | Must be `true` when using `footerContent` |\n| `footerContent` | `ReactNode` | — | Footer action buttons | Rendered in `DialogActions`; required when `showFooter` is true |\n| `headerContent` | `ReactNode` | — | Custom header | Overrides default title + close button layout |\n| `children` | `ReactNode` | — | Body content | Place inside `DialogBody` per stories |\n\n### Fixed implementation defaults\n\n| Behavior | Value | Notes |\n|----------|-------|-------|\n| `maxWidth` | `\"sm\"` | Hardcoded in `StructuredDialog.tsx`; not overridable via prop spread order |\n| `fullWidth` | `true` | Hardcoded |\n| Responsive `maxHeight` | `90vh` / `80vh` | Same as `Dialog` wrapper |\n\n### Props documented in stories argTypes\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `open` | `boolean` | `false` | Dialog visibility | Parent state required |\n| `title` | `string` | — | Header title | See Content guidelines |\n| `showHeader` | `boolean` | `true` | Toggle header | `WithoutHeader` sets `false` |\n| `showFooter` | `boolean` | `false` | Toggle footer | Must be `true` for footer buttons |\n\nAdditional MUI `DialogProps` pass through via `{...dialogProps}` (e.g. `disableEscapeKeyDown`). See the generated table below for the full API.\n\n<ArgTypes of={StructuredDialog} />\n\n## Variants\n\nLayout variants are controlled by `showHeader`, `showFooter`, and `footerContent`:\n\n| Pattern | Props | Story |\n|---------|-------|-------|\n| Full structure | `showHeader` + `showFooter` + `footerContent` | `Basic`, `WithForm`, `ScrollableBody` |\n| No header | `showHeader={false}` | `WithoutHeader` |\n| No footer | `showFooter={false}` | `WithoutFooter` |\n| Multiple footer actions | `footerContent` with fragment of Buttons | `MultipleFooterActions` |\n| Minimal confirmation | Short body + single Confirm | `SmallDialog` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Closed | `open={false}` | Default |\n| Open | `open={true}` | Focus trap via MUI |\n| Header visible | `showHeader={true}` (default) | Title + close button when `onClose` provided |\n| Header hidden | `showHeader={false}` | No close button; dismiss via footer or backdrop |\n| Footer visible | `showFooter={true}` + `footerContent` | Footer hidden when `showFooter` is false |\n| Footer hidden | `showFooter={false}` | Dismiss via header or backdrop (`WithoutFooter`) |\n| Scrollable body | Long `children` in `DialogContent` | Header/footer fixed (`ScrollableBody`) |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Open / close | Parent `useState` + `open` / `onClose` | All stories |\n| Header close | Built-in `IconButton` + `Icon name=\"x\"` | Default header |\n| Body scroll | Internal `DialogContent` with `overflowY: auto` | `ScrollableBody` |\n| Form content | `EnhancedTextField`, `RadioGroup`, sections | `WithForm` |\n| Custom header | `headerContent` prop | Not demonstrated in stories; overrides default |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-structured-dialog--basic`\n\n`title=\"Heading\"`, `showFooter={true}`, single \"Save and Dial\" in `footerContent`. Body wrapped in `DialogBody`.\n\n**Recommended usage:** Default Exotel structured modal with one primary action.\n\n<Canvas of={StructuredDialogStories.Basic} />\n\n### WithForm\n\n**Story ID:** `ui-components-structured-dialog--with-form`\n\nChannel `RadioGroup`, note box, number and template `EnhancedTextField` fields. Footer: \"Save and Dial\".\n\n**Recommended usage:** Multi-field modal workflows matching Figma ECC patterns.\n\n<Canvas of={StructuredDialogStories.WithForm} />\n\n### ScrollableBody\n\n**Story ID:** `ui-components-structured-dialog--scrollable-body`\n\n50 paragraphs in `DialogBody`. Footer: \"Save\".\n\n**Recommended usage:** Long content with fixed header and footer.\n\n<Canvas of={StructuredDialogStories.ScrollableBody} />\n\n### WithoutHeader\n\n**Story ID:** `ui-components-structured-dialog--without-header`\n\n`showHeader={false}`, footer \"Continue\". Body explains dismiss paths.\n\n**Recommended usage:** Simple prompts without a title bar.\n\n<Canvas of={StructuredDialogStories.WithoutHeader} />\n\n### WithoutFooter\n\n**Story ID:** `ui-components-structured-dialog--without-footer`\n\n`showFooter={false}`, title \"Information Dialog\". Dismiss via header × or backdrop.\n\n**Recommended usage:** Read-only informational modals.\n\n<Canvas of={StructuredDialogStories.WithoutFooter} />\n\n### MultipleFooterActions\n\n**Story ID:** `ui-components-structured-dialog--multiple-footer-actions`\n\n`footerContent` with `Delete` (outlined error) + `Save Changes` (contained). Header × is primary dismiss.\n\n**Recommended usage:** Destructive secondary + commit primary without Cancel.\n\n<Canvas of={StructuredDialogStories.MultipleFooterActions} />\n\n### SmallDialog\n\n**Story ID:** `ui-components-structured-dialog--small-dialog`\n\nTitle \"Confirmation\", short body question, single \"Confirm\" button.\n\n**Recommended usage:** Minimal confirmation dialogs.\n\n<Canvas of={StructuredDialogStories.SmallDialog} />\n\n## Accessibility\n\n- Inherits MUI `Dialog` semantics: `role=\"dialog\"`, `aria-modal=\"true\"`, focus trap.\n- Built-in close `IconButton` uses `aria-label=\"close dialog\"`.\n- `title` renders as `Typography component=\"h2\"` for accessible naming.\n- Footer `Button` children provide accessible names for actions.\n- When `showHeader={false}`, ensure footer or backdrop provides a keyboard-dismiss path.\n- No custom ARIA in Signal wrapper beyond MUI defaults.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Prefer `StructuredDialog` over manual `Dialog` composition for new ECC modals.\n- Set `showFooter={true}` whenever `footerContent` is provided.\n- Wrap body content in `DialogBody` for consistency with stories.\n- Provide `onClose` to enable header close and backdrop/Escape dismiss.\n- Match Drawer footer button conventions (`Cancel` + commit, or single primary with × dismiss).\n- Import from `@exotel-npm-dev/signal-design-system`.\n\n## Anti-patterns\n\n- Forgetting `showFooter={true}` — footer will not render (`showFooter` defaults to `false`).\n- Using `StructuredDialog` and also nesting `DialogTitle`/`DialogContent` manually.\n- Expecting to override `maxWidth` — implementation hardcodes `maxWidth=\"sm\" fullWidth`.\n- Multiple contained primaries without visual hierarchy.\n- Hiding header without a footer dismiss button (`WithoutHeader` includes \"Continue\").\n- Importing `StructuredDialog` from `@mui/material`.\n\n## Guidance for AI Agents\n\n### When to choose `StructuredDialog`\n\n- Standard Exotel modal with title, body, and footer\n- Same copy and footer patterns as `Drawer` but centered\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Custom MUI dialog sections | `Dialog` + `@mui/material` subcomponents |\n| Side panel | `Drawer` |\n| Toast feedback | `Snackbar` + `Alert` |\n\n### Canonical prop combinations\n\n```tsx\n// Default modal — story: Basic\n<StructuredDialog\n  open={open}\n  onClose={handleClose}\n  title=\"Heading\"\n  showFooter={true}\n  footerContent={\n    <Button variant=\"contained\" onClick={handleClose}>Save and Dial</Button>\n  }\n>\n  <DialogBody>{/* content */}</DialogBody>\n</StructuredDialog>\n\n// No header — story: WithoutHeader\n<StructuredDialog\n  open={open}\n  onClose={handleClose}\n  showHeader={false}\n  showFooter={true}\n  footerContent={\n    <Button variant=\"contained\" onClick={handleClose}>Continue</Button>\n  }\n>\n  <DialogBody>{/* content */}</DialogBody>\n</StructuredDialog>\n\n// Delete + save — story: MultipleFooterActions\nfooterContent={\n  <>\n    <Button variant=\"outlined\" color=\"error\" onClick={handleDelete}>Delete</Button>\n    <Button variant=\"contained\" onClick={handleSave}>Save Changes</Button>\n  </>\n}\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default structured modal | `Basic` |\n| Form modal | `WithForm` |\n| Scrollable content | `ScrollableBody` |\n| Headerless | `WithoutHeader` |\n| Informational (no footer) | `WithoutFooter` |\n| Destructive + commit | `MultipleFooterActions` |\n| Confirmation | `SmallDialog` |\n\n### Common mistakes to avoid\n\n- Omitting `showFooter={true}` when adding `footerContent`.\n- Not passing `onClose` (disables header close button).\n- Inventing `footerActions` prop — use `footerContent` (Drawer uses `footerActions`; StructuredDialog uses `footerContent`).\n- Skipping `DialogBody` wrapper when matching story patterns.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Dialog` | Lower-level MUI wrapper for custom composition |\n| `DialogBody` | Optional body wrapper exported alongside `StructuredDialog` |\n| `DialogFooter` | Optional footer wrapper (not used in current stories) |\n| `Drawer` | Same header/body/footer pattern, off-canvas |\n| `Button` | Footer actions |\n| `EnhancedTextField` | Form fields in modal body |\n| `Alert` / `Snackbar` | Non-blocking feedback |\n"}}},"ui-components-switch":{"id":"ui-components-switch","name":"Switch","path":"./src/stories/ui-components/Switch.stories.tsx","stories":[{"id":"ui-components-switch--unchecked","name":"Unchecked","snippet":"const Unchecked = () => <Switch checked={false} />;","description":"Unchecked switch"},{"id":"ui-components-switch--checked","name":"Checked","snippet":"const Checked = () => <Switch checked />;","description":"Checked switch"},{"id":"ui-components-switch--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Switch checked color=\"default\" />\n    <Switch checked color=\"primary\" />\n    <Switch checked color=\"secondary\" />\n    <Switch checked color=\"success\" />\n    <Switch checked color=\"error\" />\n    <Switch checked color=\"info\" />\n    <Switch checked color=\"warning\" />\n  </div>\n);","description":"Different colors"},{"id":"ui-components-switch--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Switch checked size=\"small\" />\n    <Switch checked size=\"medium\" />\n  </div>\n);","description":"Different sizes"},{"id":"ui-components-switch--with-label","name":"With Label","snippet":"const WithLabel = () => {\n  const [checked, setChecked] = useState(false);\n  return (\n    <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>\n      <Switch\n        checked={checked}\n        onChange={(e) => setChecked(e.target.checked)}\n      />\n      <span>Enable notifications</span>\n    </label>\n  );\n};","description":"With label"},{"id":"ui-components-switch--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n    <Switch disabled />\n    <Switch disabled checked />\n  </div>\n);","description":"Disabled state"},{"id":"ui-components-switch--interactive","name":"Interactive","snippet":"const Interactive = () => {\n    const [checked, setChecked] = useState(args.checked);\n\n    return (\n        <Switch\n            color=\"primary\"\n            size=\"medium\"\n            disabled={false}\n            checked={checked}\n            onChange={(e) => setChecked(e.target.checked)} />\n    );\n};","description":"Interactive switch with all controls"}],"import":"import { Switch } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Switch","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Switch/Switch.tsx","actualName":"Switch","exportName":"Switch","props":{"checked":{"required":false,"tsType":{"name":"boolean"},"description":""},"disabled":{"required":false,"tsType":{"name":"boolean"},"description":""},"onChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => void","signature":{"arguments":[{"type":{"name":"ReactChangeEvent","raw":"React.ChangeEvent<HTMLInputElement>","elements":[{"name":"HTMLInputElement"}]},"name":"event"},{"type":{"name":"boolean"},"name":"checked"}],"return":{"name":"void"}}},"description":""}},"composes":["Omit"]},"docs":{"ui-components-switch--docs":{"id":"ui-components-switch--docs","name":"Docs","path":"./src/stories/ui-components/Switch.mdx","title":"UI Components/Switch","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as SwitchStories from './Switch.stories';\nimport { Switch } from '../../components/Switch';\n\n<Meta of={SwitchStories} />\n\n# Switch\n\n## Overview\n\n`Switch` is the Signal Design System wrapper around MUI `Switch`. It is a thin `forwardRef` pass-through with no custom logic. Use it for binary on/off settings that take effect immediately.\n\nUse `Switch` when a setting has two opposing states (enabled/disabled, on/off) and the change applies without a separate save action. Do not use it for choosing among more than two options or for form submission checklists.\n\n```tsx\nimport { Switch, FormControlLabel } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Immediate toggle settings (enable notifications, dark mode, feature flags)\n- Binary preferences where on/off metaphor is clear\n- Settings panels where change applies in real time\n\n**When not to use**\n\n- Choosing one of three or more options → use `Radio` or `Select`\n- Multi-select from a list → use `Checkbox` or `MultiSelect`\n- Form submission consent with legal copy → use `Checkbox` with linked terms\n- Actions that trigger a process → use `Button`\n\n## Content guidelines\n\nRules for switch labels in Exotel ECC and other Signal products. Labels are placed adjacent to the switch, not as `children` of `Switch`.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Label describes the setting | \"Enable notifications\" — what is being turned on/off |\n| Positive framing | Describe the enabled state, not the negation (\"Enable X\" not \"Disable X off\") |\n| Concise | One short phrase; avoid full sentences |\n| Sentence case | \"Enable notifications\" not \"Enable Notifications\" |\n| No verb duplication | Label + switch state should not repeat (\"On: On\") |\n\n### Label patterns\n\n| Context | Label | Signal reference |\n|---------|-------|------------------|\n| Feature toggle | Enable notifications | `WithLabel` story |\n| Setting row | `{Verb} {feature}` | Compose with `FormControlLabel` |\n| Disabled demo | — (no label in `Disabled` story) | `Disabled` story |\n\n### Do and don't\n\n**Do**\n\n- \"Enable notifications\"\n- \"Auto-assign calls\"\n- \"Show closed tickets\"\n\n**Don't**\n\n- \"Turn switch on to enable notifications\"\n- \"Off\" as the only label\n- \"Disable notifications off\"\n- Using `Switch` for \"Accept terms and conditions\"\n\n### Label placement\n\nPreferred patterns:\n\n```tsx\n// FormControlLabel (MUI)\n<FormControlLabel\n  control={<Switch checked={checked} onChange={handleChange} />}\n  label=\"Enable notifications\"\n/>\n\n// Native label wrapper — story: WithLabel\n<label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n  <Switch checked={checked} onChange={handleChange} />\n  <span>Enable notifications</span>\n</label>\n```\n\n## Anatomy\n\n```\nFormControlLabel (recommended)\n├── Switch                    ← Signal wrapper (MUI Switch)\n└── label text\n\nor\n\n<label>\n├── Switch\n└── <span> label text\n```\n\n`Switch` is the toggle control only. Always pair with a visible label.\n\n## Props\n\n`SwitchProps` extends MUI `SwitchProps` (minus `ref`). All MUI props pass through via spread.\n\n### Signal-specific props\n\n`Switch` adds no custom props. The wrapper explicitly documents:\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `checked` | `boolean` | `false` | Whether the switch is on | Controlled via `checked` + `onChange`. |\n| `disabled` | `boolean` | `false` | Disables interaction | See `Disabled` story. |\n| `onChange` | `(event, checked: boolean) => void` | — | Fires when toggled | `checked` boolean is the second argument. |\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `color` | `'default' \\| 'primary' \\| 'secondary' \\| 'success' \\| 'error' \\| 'info' \\| 'warning'` | `'primary'` | Track/thumb semantic color | Use `primary` for standard settings. See `Colors` story. |\n| `size` | `'small' \\| 'medium'` | `'medium'` | Switch dimensions | Use `small` in dense settings lists. See `Sizes` story. |\n| `inputProps` | `object` | — | Native input attributes | Use for `aria-label` when no visible label (avoid if possible). |\n\nAdditional standard MUI `SwitchProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Switch} />\n\n## Variants\n\n`Switch` has no visual `variant` prop. Appearance is controlled by `color` and `size`.\n\n| Color | Use for |\n|-------|---------|\n| `primary` | Default settings toggles |\n| `secondary` | Secondary settings |\n| `error` | Destructive or high-risk enablement |\n| `success` | Confirmation of active healthy state |\n\n<Canvas of={SwitchStories.Colors} />\n\n## Sizes\n\nTwo sizes are available.\n\n| Size | Use for |\n|------|---------|\n| `small` | Dense settings panels, table row toggles |\n| `medium` | Default settings forms |\n\n<Canvas of={SwitchStories.Sizes} />\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Off (unchecked) | `checked={false}` or default | See `Unchecked` story |\n| On (checked) | `checked={true}` | See `Checked` story |\n| Disabled off | `disabled` without `checked` | See `Disabled` story |\n| Disabled on | `disabled checked` | See `Disabled` story |\n| Hover / Focus | Automatic | MUI and theme styles |\n\n<Canvas of={SwitchStories.Unchecked} />\n<Canvas of={SwitchStories.Checked} />\n<Canvas of={SwitchStories.Disabled} />\n\n## Stories\n\n### Unchecked\n\n**Story ID:** `ui-components-switch--unchecked`\n\nStandalone `Switch` with `checked={false}`.\n\n**Recommended usage:** Reference for default off appearance.\n\n### Checked\n\n**Story ID:** `ui-components-switch--checked`\n\nStandalone `Switch` with `checked={true}`.\n\n**Recommended usage:** Reference for on appearance.\n\n### Colors\n\n**Story ID:** `ui-components-switch--colors`\n\nAll semantic colors on checked switches.\n\n**Recommended usage:** Semantic color selection reference.\n\n### Sizes\n\n**Story ID:** `ui-components-switch--sizes`\n\n`small` and `medium` checked switches side by side.\n\n**Recommended usage:** Size selection reference.\n\n### WithLabel\n\n**Story ID:** `ui-components-switch--with-label`\n\nControlled switch inside a `<label>` with \"Enable notifications\" text. Toggles on click.\n\n**Recommended usage:** Canonical pattern for labeled toggle settings.\n\n<Canvas of={SwitchStories.WithLabel} />\n\n### Disabled\n\n**Story ID:** `ui-components-switch--disabled`\n\nDisabled off and disabled on switches side by side.\n\n**Recommended usage:** Unavailable settings that show current state.\n\n### Interactive\n\n**Story ID:** `ui-components-switch--interactive`\n\nControlled switch with Storybook controls for all props.\n\n**Recommended usage:** Playground only; not a production pattern.\n\n## Accessibility\n\n- Renders a native checkbox input with `role=\"switch\"` semantics via MUI.\n- `checked` maps to `aria-checked` on the switch input.\n- Keyboard: Space toggles the switch when focused.\n- Always provide a visible label via `FormControlLabel` or wrapping `<label>`.\n- `disabled` removes the switch from interaction.\n- Do not rely on color alone to convey on/off — label must describe the setting.\n- Storybook a11y addon is configured with `test: 'todo'` — accessibility is not CI-gated in the current Storybook setup.\n\n## Best Practices\n\n- Pair every `Switch` with a descriptive visible label.\n- Use controlled `checked` + `onChange` in React settings panels.\n- Use `FormControlLabel` for consistent label alignment in forms.\n- Apply changes immediately or show inline feedback — switches imply instant effect.\n- Use `size=\"small\"` in dense lists; `color=\"primary\"` by default.\n- Use `Switch` for settings, `Checkbox` for optional form fields and multi-select.\n- See **Content guidelines** for label copy rules.\n\n## Anti-patterns\n\n- Using `Switch` for mutually exclusive options among 3+ choices → use `Radio`.\n- Using `Switch` for \"I agree to terms\" → use `Checkbox`.\n- Switch without a visible label — accessibility failure.\n- Importing `@mui/material/Switch` directly — import from `@exotel-npm-dev/signal-design-system`.\n- Using `Switch` to trigger destructive actions without confirmation.\n- Multiple switches controlling the same setting without clear hierarchy.\n- Label phrased as negation of the off state (\"Disable notifications\" with confusing polarity).\n\n## Guidance for AI Agents\n\nThis section is optimized for Storybook MCP and AI code generation.\n\n### When to choose `Switch`\n\n- Binary on/off setting with immediate effect\n- Feature enablement toggle\n- Single boolean preference\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| 3+ exclusive options | `Radio`, `Select` |\n| Multi-select list | `Checkbox`, `MultiSelect` |\n| Legal consent / acknowledgment | `Checkbox` |\n| Trigger an action | `Button` |\n| Numeric range | `Slider` |\n\n### Canonical prop combinations\n\n```tsx\n// Labeled toggle — story: WithLabel\nconst [checked, setChecked] = useState(false);\n<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>\n  <Switch\n    checked={checked}\n    onChange={(e) => setChecked(e.target.checked)}\n  />\n  <span>Enable notifications</span>\n</label>\n\n// FormControlLabel pattern\n<FormControlLabel\n  control={\n    <Switch\n      checked={enabled}\n      onChange={(_e, checked) => setEnabled(checked)}\n      color=\"primary\"\n      size=\"small\"\n    />\n  }\n  label=\"Auto-assign calls\"\n/>\n\n// Disabled — story: Disabled\n<Switch disabled />\n<Switch disabled checked />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Labeled toggle | `WithLabel` (`ui-components-switch--with-label`) |\n| Off state | `Unchecked` |\n| On state | `Checked` |\n| Semantic colors | `Colors` |\n| Size selection | `Sizes` |\n| Disabled states | `Disabled` |\n\n### Label copy\n\n| Context | Label pattern | Example |\n|---------|---------------|---------|\n| Feature enable | `Enable {feature}` | Enable notifications |\n| Visibility | `Show {object}` | Show closed tickets |\n| Automation | `Auto-{verb} {object}` | Auto-assign calls |\n\n### Common mistakes to avoid\n\n- Do not use `Switch` for radio-group scenarios (pick one of many).\n- Do not omit labels — always use `FormControlLabel` or wrapping `<label>`.\n- `onChange` second argument is `checked: boolean` — use it for state updates.\n- Do not use `Switch` inside dialog footers as a submit control — use `Button`.\n- Import from `@exotel-npm-dev/signal-design-system`, not `@mui/material/Switch`.\n\n### Composition guidance\n\n- Place label to the right of the switch in LTR layouts (MUI `FormControlLabel` default).\n- In settings lists, align switches on the trailing edge with labels on the leading edge.\n- For high-risk toggles (`color=\"error\"`), add confirmation before applying destructive effects.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `FormControlLabel` | Pairs label with switch (MUI re-export) |\n| `Checkbox` | Multi-select and consent patterns |\n| `Radio` | Exclusive multi-option selection |\n| `FormControl` | Form wrapper for settings groups |\n| `Button` | Actions that commit or submit |\n"}}},"ui-components-table":{"id":"ui-components-table","name":"Table","path":"./src/stories/ui-components/Table.stories.tsx","stories":[{"id":"ui-components-table--default","name":"Default","snippet":"const Default = () => (\n  <TableContainer component={Paper} sx={{ maxWidth: 600 }}>\n    <Table>\n      <TableHead>\n        <TableRow>\n          <TableCell>Queue Name</TableCell>\n          <TableCell align=\"right\">Agents</TableCell>\n          <TableCell align=\"right\">Status</TableCell>\n        </TableRow>\n      </TableHead>\n      <TableBody>\n        {sampleRows.map((row) => (\n          <TableRow key={row.id}>\n            <TableCell>{row.name}</TableCell>\n            <TableCell align=\"right\">{row.agents}</TableCell>\n            <TableCell align=\"right\">\n              <Chip\n                label={row.status}\n                size=\"small\"\n                color={row.status === 'Active' ? 'success' : row.status === 'Paused' ? 'warning' : 'default'}\n                variant=\"tonal\"\n              />\n            </TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  </TableContainer>\n);"},{"id":"ui-components-table--small-size","name":"Small Size","snippet":"const SmallSize = () => (\n  <TableContainer component={Paper} sx={{ maxWidth: 600 }}>\n    <Table size=\"small\">\n      <TableHead>\n        <TableRow>\n          <TableCell>Queue Name</TableCell>\n          <TableCell align=\"right\">Agents</TableCell>\n          <TableCell align=\"right\">Status</TableCell>\n        </TableRow>\n      </TableHead>\n      <TableBody>\n        {sampleRows.map((row) => (\n          <TableRow key={row.id}>\n            <TableCell>{row.name}</TableCell>\n            <TableCell align=\"right\">{row.agents}</TableCell>\n            <TableCell align=\"right\">{row.status}</TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  </TableContainer>\n);"},{"id":"ui-components-table--sticky-header","name":"Sticky Header","snippet":"const StickyHeader = () => (\n  <TableContainer component={Paper} sx={{ maxWidth: 600, maxHeight: 200 }}>\n    <Table stickyHeader>\n      <TableHead>\n        <TableRow>\n          <TableCell>Queue Name</TableCell>\n          <TableCell align=\"right\">Agents</TableCell>\n          <TableCell align=\"right\">Status</TableCell>\n        </TableRow>\n      </TableHead>\n      <TableBody>\n        {[...sampleRows, ...sampleRows].map((row, idx) => (\n          <TableRow key={idx}>\n            <TableCell>{row.name}</TableCell>\n            <TableCell align=\"right\">{row.agents}</TableCell>\n            <TableCell align=\"right\">{row.status}</TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  </TableContainer>\n);"},{"id":"ui-components-table--borderless","name":"Borderless","snippet":"const Borderless = () => (\n  <Box sx={{ maxWidth: 600 }}>\n    <Typography variant=\"subtitle2\" sx={{ mb: 1 }}>Recent Activity</Typography>\n    <Table size=\"small\">\n      <TableBody>\n        {sampleRows.slice(0, 3).map((row) => (\n          <TableRow key={row.id} sx={{ '&:last-child td': { border: 0 } }}>\n            <TableCell sx={{ pl: 0 }}>{row.name}</TableCell>\n            <TableCell align=\"right\">{row.agents} agents</TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  </Box>\n);"}],"import":"import {\n    Box,\n    Chip,\n    Table,\n    TableBody,\n    TableCell,\n    TableContainer,\n    TableHead,\n    TableRow,\n    Typography,\n} from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Table","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Table/Table.tsx","actualName":"Table","exportName":"Table","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-table--docs":{"id":"ui-components-table--docs","name":"Docs","path":"./src/stories/ui-components/Table.mdx","title":"UI Components/Table","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as TableStories from './Table.stories';\nimport { Table } from '../../components/Table';\n\n<Meta of={TableStories} />\n\n# Table\n\n## Overview\n\n`Table` wraps MUI `Table` for simple static HTML tables. Compose with `TableHead`, `TableBody`, `TableRow`, `TableCell`, and `TableContainer` (all re-exported from MUI).\n\n```tsx\nimport {\n  Table, TableHead, TableBody, TableRow, TableCell, TableContainer, Paper,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Small static tables without sorting, filtering, or virtualization\n- Simple data presentation in cards, dialogs, or documentation\n- Borderless inline data lists\n\n**When not to use**\n\n- Advanced data grids with toolbar, filters, pagination → use `DataGrid` (preferred for Exotel product tables)\n- Editable tabular data → use `DataGrid`\n- Large datasets requiring virtualization → use `DataGrid`\n\n## Props\n\n<ArgTypes of={Table} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `size` | `'small' \\| 'medium'` | `'medium'` | Cell padding size |\n| `stickyHeader` | `boolean` | `false` | If true, header sticks to top on scroll |\n| `padding` | `'normal' \\| 'checkbox' \\| 'none'` | `'normal'` | Cell padding preset |\n\n## Stories\n\n### Default\n\nStandard table with header, body rows, and tonal status Chips.\n\n<Canvas of={TableStories.Default} />\n\n### SmallSize\n\nCompact table with `size=\"small\"` for denser layouts.\n\n<Canvas of={TableStories.SmallSize} />\n\n### StickyHeader\n\nScrollable table body with a fixed header using `stickyHeader`.\n\n<Canvas of={TableStories.StickyHeader} />\n\n### Borderless\n\nMinimal borderless table for inline data display.\n\n<Canvas of={TableStories.Borderless} />\n\n## Guidance for AI Agents\n\nDefault to `DataGrid` for product data tables with toolbar, filters, and pagination. Use `Table` only for simple presentational tables (< 10 rows, no interaction needed).\n\n```tsx\n<TableContainer component={Paper}>\n  <Table>\n    <TableHead>\n      <TableRow>\n        <TableCell>Name</TableCell>\n        <TableCell align=\"right\">Count</TableCell>\n      </TableRow>\n    </TableHead>\n    <TableBody>\n      <TableRow>\n        <TableCell>Item</TableCell>\n        <TableCell align=\"right\">42</TableCell>\n      </TableRow>\n    </TableBody>\n  </Table>\n</TableContainer>\n```\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `DataGrid` | Full-featured data table; preferred for product UIs |\n| `Paper` | Commonly used as `TableContainer` component prop |\n| `Chip` | Status indicators inside table cells |\n| `Typography` | Section titles above tables |\n"}}},"ui-components-tabs":{"id":"ui-components-tabs","name":"Tabs","path":"./src/stories/ui-components/Tabs.stories.tsx","stories":[{"id":"ui-components-tabs--basic","name":"Basic","snippet":"const Basic = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Tabs value={value} onChange={(e, newValue) => setValue(newValue as number)}>\n        <MuiTab label=\"Item One\" />\n        <MuiTab label=\"Item Two\" />\n        <MuiTab label=\"Item Three\" />\n      </Tabs>\n      <TabPanel value={value} index={0}>\n        <Typography>Content for Item One</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={1}>\n        <Typography>Content for Item Two</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={2}>\n        <Typography>Content for Item Three</Typography>\n      </TabPanel>\n    </Box>\n  );\n};","description":"Basic tabs"},{"id":"ui-components-tabs--scrollable","name":"Scrollable","snippet":"const Scrollable = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 400 }}>\n      <Tabs\n        value={value}\n        onChange={(e, newValue) => setValue(newValue as number)}\n        variant=\"scrollable\"\n        scrollButtons=\"auto\"\n      >\n        {['Tab 1', 'Tab 2', 'Tab 3', 'Tab 4', 'Tab 5', 'Tab 6', 'Tab 7'].map((label, index) => (\n          <MuiTab key={index} label={label} />\n        ))}\n      </Tabs>\n    </Box>\n  );\n};","description":"Scrollable tabs"},{"id":"ui-components-tabs--full-width","name":"Full Width","snippet":"const FullWidth = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Tabs\n        value={value}\n        onChange={(e, newValue) => setValue(newValue as number)}\n        variant=\"fullWidth\"\n      >\n        <MuiTab label=\"Item One\" />\n        <MuiTab label=\"Item Two\" />\n        <MuiTab label=\"Item Three\" />\n      </Tabs>\n    </Box>\n  );\n};","description":"Full width tabs"},{"id":"ui-components-tabs--vertical","name":"Vertical","snippet":"const Vertical = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ display: 'flex', width: '100%', maxWidth: 600, height: 300 }}>\n      <Tabs\n        value={value}\n        onChange={(e, newValue) => setValue(newValue as number)}\n        orientation=\"vertical\"\n        variant=\"scrollable\"\n      >\n        <MuiTab label=\"Item One\" />\n        <MuiTab label=\"Item Two\" />\n        <MuiTab label=\"Item Three\" />\n        <MuiTab label=\"Item Four\" />\n      </Tabs>\n      <Box sx={{ p: 3, flex: 1 }}>\n        <TabPanel value={value} index={0}>\n          <Typography>Content for Item One</Typography>\n        </TabPanel>\n        <TabPanel value={value} index={1}>\n          <Typography>Content for Item Two</Typography>\n        </TabPanel>\n        <TabPanel value={value} index={2}>\n          <Typography>Content for Item Three</Typography>\n        </TabPanel>\n        <TabPanel value={value} index={3}>\n          <Typography>Content for Item Four</Typography>\n        </TabPanel>\n      </Box>\n    </Box>\n  );\n};","description":"Vertical tabs"},{"id":"ui-components-tabs--with-icons","name":"With Icons","snippet":"const WithIcons = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Tabs value={value} onChange={(e, newValue) => setValue(newValue as number)}>\n        <Tab iconProps={{ name: \"chart-bar\", size: \"sm\" }} label=\"Dashboard\" iconPosition=\"start\" />\n        <Tab iconProps={{ name: \"envelope\", size: \"sm\" }} label=\"Messages\" iconPosition=\"start\" />\n        <Tab iconProps={{ name: \"gear\", size: \"sm\" }} label=\"Settings\" iconPosition=\"start\" />\n      </Tabs>\n    </Box>\n  );\n};","description":"Tabs with icons"},{"id":"ui-components-tabs--interactive","name":"Interactive","snippet":"const Interactive = () => {\n    const [value, setValue] = useState(0);\n    const isVertical = args.orientation === 'vertical';\n\n    const tabs: { label: string; icon: IconName; content: string }[] = [\n      { label: 'Dashboard', icon: 'chart-bar', content: 'Dashboard overview with key metrics and charts.' },\n      { label: 'Messages', icon: 'envelope', content: 'Your inbox — 3 unread messages.' },\n      { label: 'Settings', icon: 'gear', content: 'Account preferences and configuration.' },\n      { label: 'Billing', icon: 'credit-card', content: 'Invoices and payment methods.' },\n      { label: 'Team', icon: 'users', content: 'Manage team members and roles.' },\n    ];\n\n    return (\n        <Box\n            sx={{\n              width: '100%',\n              maxWidth: 650,\n              ...(isVertical && { display: 'flex', height: 300 }),\n            }}>\n            <Tabs\n                tabStyle=\"default\"\n                variant=\"standard\"\n                orientation=\"horizontal\"\n                scrollButtons=\"auto\"\n                value={value}\n                onChange={(_e, newValue) => setValue(newValue as number)}>\n                {tabs.map((tab) => (\n                  <Tab\n                    key={tab.label}\n                    label={tab.label}\n                    iconProps={{ name: tab.icon, size: \"sm\" }}\n                    iconPosition=\"start\"\n                  />\n                ))}\n            </Tabs>\n            <Box sx={{ flex: 1 }}>\n                {tabs.map((tab, idx) => (\n                  <TabPanel key={tab.label} value={value} index={idx}>\n                    <Typography>{tab.content}</Typography>\n                  </TabPanel>\n                ))}\n            </Box>\n        </Box>\n    );\n};","description":"Interactive tabs with all controls — use the Storybook controls panel to switch between `tabStyle`, `variant`, `orientation`, and `scrollButtons`."},{"id":"ui-components-tabs--button-tabs-fixed-width","name":"Button Tabs Fixed Width","snippet":"const ButtonTabsFixedWidth = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%' }}>\n      <Tabs\n        tabStyle=\"button\"\n        value={value}\n        onChange={(e, newValue) => setValue(newValue as number)}\n      >\n        <MuiTab label=\"My Details\" />\n        <MuiTab label=\"Profile\" />\n        <MuiTab label=\"Password\" />\n        <MuiTab label=\"Team\" />\n        <MuiTab label=\"Plan\" />\n        <MuiTab label=\"Billing\" />\n        <MuiTab label=\"Email\" />\n        <MuiTab label=\"Notification\" />\n      </Tabs>\n      <TabPanel value={value} index={0}>\n        <Typography>My Details content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={1}>\n        <Typography>Profile content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={2}>\n        <Typography>Password content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={3}>\n        <Typography>Team content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={4}>\n        <Typography>Plan content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={5}>\n        <Typography>Billing content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={6}>\n        <Typography>Email content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={7}>\n        <Typography>Notification content</Typography>\n      </TabPanel>\n    </Box>\n  );\n};","description":"Button tabs — segmented control / pill style (fixed width)"},{"id":"ui-components-tabs--button-tabs-fill","name":"Button Tabs Fill","snippet":"const ButtonTabsFill = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Tabs\n        tabStyle=\"button\"\n        variant=\"fullWidth\"\n        value={value}\n        onChange={(e, newValue) => setValue(newValue as number)}\n      >\n        <MuiTab label=\"My Details\" />\n        <MuiTab label=\"Profile\" />\n        <MuiTab label=\"CRM\" />\n        <MuiTab label=\"Plan\" />\n      </Tabs>\n      <TabPanel value={value} index={0}>\n        <Typography>My Details content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={1}>\n        <Typography>Profile content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={2}>\n        <Typography>CRM content</Typography>\n      </TabPanel>\n      <TabPanel value={value} index={3}>\n        <Typography>Plan content</Typography>\n      </TabPanel>\n    </Box>\n  );\n};","description":"Button tabs — segmented control / pill style (fill / equal width)"},{"id":"ui-components-tabs--with-top-icons","name":"With Top Icons","snippet":"const WithTopIcons = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Tabs tabStyle=\"topIcon\" value={value} onChange={(e, newValue) => setValue(newValue as number)}>\n        <Tab iconProps={{ name: \"airplane\", size: \"md\" }} label=\"Flights\" />\n        <Tab iconProps={{ name: \"suitcase\", size: \"md\" }} label=\"Trips\" />\n        <Tab iconProps={{ name: \"compass\", size: \"md\" }} label=\"Explore\" />\n      </Tabs>\n    </Box>\n  );\n};","description":"Tabs with top icons — icons positioned above the label text with a bottom indicator"},{"id":"ui-components-tabs--button-tabs-with-badges","name":"Button Tabs With Badges","snippet":"const ButtonTabsWithBadges = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%' }}>\n      <Tabs\n        tabStyle=\"button\"\n        value={value}\n        onChange={(e, newValue) => setValue(newValue as number)}\n      >\n        <Tab label=\"My Details\" />\n        <Tab label=\"Profile\" />\n        <Tab label=\"Password\" />\n        <Tab label=\"Team\" />\n        <Tab label=\"Plan\" />\n        <Tab label=\"Billing\" />\n        <Tab label=\"Email\" />\n        <Tab label=\"Notification\" badge={3} />\n      </Tabs>\n    </Box>\n  );\n};","description":"Button tabs with badges"},{"id":"ui-components-tabs--button-tabs-with-icons","name":"Button Tabs With Icons","snippet":"const ButtonTabsWithIcons = () => {\n  const [value, setValue] = useState(0);\n  return (\n    <Box sx={{ width: '100%', maxWidth: 600 }}>\n      <Tabs\n        tabStyle=\"button\"\n        value={value}\n        onChange={(e, newValue) => setValue(newValue as number)}\n      >\n        <Tab iconProps={{ name: \"chart-bar\", size: \"sm\" }} label=\"Dashboard\" iconPosition=\"start\" />\n        <Tab iconProps={{ name: \"envelope\", size: \"sm\" }} label=\"Messages\" iconPosition=\"start\" />\n        <Tab iconProps={{ name: \"gear\", size: \"sm\" }} label=\"Settings\" iconPosition=\"start\" />\n      </Tabs>\n    </Box>\n  );\n};","description":"Button tabs with icons"}],"import":"import { Box, Tab, Tabs, Typography } from \"@exotel-npm-dev/signal-design-system\";\nimport MuiTab from \"@mui/material/Tab\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Tabs","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Tabs/Tabs.tsx","actualName":"Tabs","exportName":"Tabs","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""},"value":{"required":false,"tsType":{"name":"union","raw":"string | number","elements":[{"name":"string"},{"name":"number"}]},"description":""},"onChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(event: React.SyntheticEvent, newValue: string | number) => void","signature":{"arguments":[{"type":{"name":"ReactSyntheticEvent","raw":"React.SyntheticEvent"},"name":"event"},{"type":{"name":"union","raw":"string | number","elements":[{"name":"string"},{"name":"number"}]},"name":"newValue"}],"return":{"name":"void"}}},"description":""},"tabStyle":{"required":false,"tsType":{"name":"union","raw":"'default' | 'button' | 'topIcon'","elements":[{"name":"literal","value":"'default'"},{"name":"literal","value":"'button'"},{"name":"literal","value":"'topIcon'"}]},"description":"Visual style of the tabs. \"button\" renders a segmented-control / pill appearance. \"topIcon\" renders icon-above-label tabs with a rounded, content-width indicator.","defaultValue":{"value":"'default'","computed":false}}},"composes":["Omit"]},"docs":{"ui-components-tabs--docs":{"id":"ui-components-tabs--docs","name":"Docs","path":"./src/stories/ui-components/Tabs.mdx","title":"UI Components/Tabs","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as TabsStories from './Tabs.stories';\nimport { Tabs } from '../../components/Tabs';\n\n<Meta of={TabsStories} />\n\n# Tabs\n\n## Overview\n\n`Tabs` is the Signal Design System wrapper around MUI `Tabs`. It adds a Signal `tabStyle` prop (`default`, `button`, `topIcon`) for segmented-control and icon-above-label appearances. Pair with Signal `Tab` (supports `iconProps` and `badge`) or MUI `Tab` for labels.\n\nUse `Tabs` to switch between peer views or sections where only one panel is visible at a time. Do not use for sequential step-by-step workflows or collapsible optional detail.\n\n```tsx\nimport { Tabs, Tab } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Switching between related views on the same page (settings categories, dashboard sections)\n- Segmented control / pill-style toggles (`tabStyle=\"button\"`)\n- Icon-labeled navigation tabs (`tabStyle=\"topIcon\"` or `iconProps` on `Tab`)\n\n**When not to use**\n\n- Collapsible optional sections → use `Accordion`\n- Sequential wizard or multi-step flow → use `Stepper`\n- Dropdown action list from a button → use `Menu`\n- Off-canvas panel → use `Drawer`\n\n## Anatomy\n\nSignal does not provide `TabPanel`. Stories use a local `TabPanel` wrapper or conditional content below `Tabs`.\n\n```\nTabs                           ← Signal wrapper (tabStyle → data-variant)\n├── Tab (Signal) or MuiTab     ← One per tab; Signal Tab supports iconProps, badge\n└── (app-owned panel content)  ← Shown when value matches; not a DS component\n```\n\nCanonical controlled pattern from `Basic`:\n\n```tsx\nconst [value, setValue] = useState(0);\n\n<Tabs value={value} onChange={(_e, v) => setValue(v as number)}>\n  <Tab label=\"Item One\" />\n  <Tab label=\"Item Two\" />\n</Tabs>\n{value === 0 && <Typography>Content for Item One</Typography>}\n```\n\nSignal `Tab` with icon:\n\n```tsx\n<Tab iconProps={{ name: 'chart-bar', size: 'sm' }} label=\"Dashboard\" iconPosition=\"start\" />\n```\n\n## Content guidelines\n\nTab labels are set via `label` on each `Tab`.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Short | 1–3 words: \"Dashboard\", \"Messages\", \"Settings\" |\n| Noun or section name | Name the view, not an action |\n| Sentence case | Match product tone; stories use sentence case |\n| Consistent length | Avoid one very long tab among short peers |\n\n### Do and don't\n\n**Do:** \"My Details\", \"Profile\", \"Billing\", \"Team\"\n\n**Don't:** \"Click here to view settings\", full sentences, duplicate icons that repeat the label meaning\n\n## Props\n\n### Signal-specific props (`Tabs`)\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `tabStyle` | `'default' \\| 'button' \\| 'topIcon'` | `'default'` | Visual style | `button` = segmented pills; `topIcon` = icon above label. Sets `data-variant` on DOM when not `default`. |\n| `value` | `string \\| number` | — | Selected tab index or id | Required for controlled usage in stories |\n| `onChange` | `(event, newValue) => void` | — | Selection handler | Update parent state |\n\n### Signal-specific props (`Tab`)\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `iconProps` | `IconProps` | — | Design-system `Icon` props | Preferred over deprecated `icon`. Renders when `iconProps.name` is set. |\n| `icon` | `ReactElement` | — | **Deprecated** raw icon node | Use `iconProps` instead |\n| `badge` | `ReactNode` | — | Inline count next to label | Wraps label in `Badge` `color=\"error\"`. See `ButtonTabsWithBadges`. |\n| `label` | `ReactNode` | — | Tab text | Primary accessible name |\n| `iconPosition` | `'top' \\| 'bottom' \\| 'start' \\| 'end'` | — | Icon placement | `start` in `WithIcons`; `topIcon` tabStyle uses top layout |\n\n### Commonly used inherited props (`Tabs`)\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `variant` | `'standard' \\| 'scrollable' \\| 'fullWidth'` | `'standard'` | Layout | `scrollable` for many tabs; `fullWidth` distributes width |\n| `orientation` | `'horizontal' \\| 'vertical'` | `'horizontal'` | Tab bar direction | `Vertical` story |\n| `scrollButtons` | `'auto' \\| true \\| false` | `'auto'` | Scroll arrows when scrollable | Used with `variant=\"scrollable\"` |\n\n<ArgTypes of={Tabs} />\n\n## Variants\n\n### `tabStyle` (Signal)\n\n| tabStyle | Description | Story |\n|----------|-------------|-------|\n| `default` | Standard MUI underline tabs | `Basic`, `WithIcons` |\n| `button` | Segmented control / pills | `ButtonTabsFixedWidth`, `ButtonTabsFill`, `ButtonTabsWithBadges`, `ButtonTabsWithIcons` |\n| `topIcon` | Icon above label, rounded indicator | `WithTopIcons` |\n\n### MUI `variant`\n\n| variant | Story |\n|---------|-------|\n| `standard` | `Basic` |\n| `scrollable` | `Scrollable`, `Vertical` |\n| `fullWidth` | `FullWidth`, `ButtonTabsFill` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Selected | `value` matches tab index | MUI sets `aria-selected` |\n| Unselected | Other tab indices | Inactive styling via theme |\n| Scrollable overflow | `variant=\"scrollable\"` | `Scrollable` story with 7 tabs |\n| With badge | `badge={n}` on Signal `Tab` | `ButtonTabsWithBadges` |\n\n## Behavior\n\n- Controlled: parent owns `value` and `onChange` in all stories.\n- `tabStyle !== 'default'` sets `data-variant={tabStyle}` on `Tabs` root.\n- Signal `Tab` resolves `iconProps.name` to `<Icon {...iconProps} />`.\n- `badge` on `Tab` wraps `label` in `<Badge badgeContent={badge} color=\"error\">`.\n- Panel content is **not** built into `Tabs` — app implements show/hide (see `TabPanel` in stories).\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-tabs--basic`\n\nThree tabs with `TabPanel` content areas.\n\n**Recommended usage:** Default horizontal tabs with controlled state.\n\n<Canvas of={TabsStories.Basic} />\n\n### Scrollable\n\n**Story ID:** `ui-components-tabs--scrollable`\n\nSeven tabs with `variant=\"scrollable\"` and `scrollButtons=\"auto\"`.\n\n**Recommended usage:** Many tabs in a narrow container.\n\n<Canvas of={TabsStories.Scrollable} />\n\n### FullWidth\n\n**Story ID:** `ui-components-tabs--full-width`\n\n`variant=\"fullWidth\"` distributes tab width evenly.\n\n<Canvas of={TabsStories.FullWidth} />\n\n### Vertical\n\n**Story ID:** `ui-components-tabs--vertical`\n\n`orientation=\"vertical\"` with content panel beside tab list.\n\n<Canvas of={TabsStories.Vertical} />\n\n### WithIcons\n\n**Story ID:** `ui-components-tabs--with-icons`\n\nSignal `Tab` with `iconProps` and `iconPosition=\"start\"`.\n\n<Canvas of={TabsStories.WithIcons} />\n\n### Interactive\n\n**Story ID:** `ui-components-tabs--interactive`\n\nPlayground for `tabStyle`, `variant`, `orientation`, `scrollButtons`.\n\n### ButtonTabsFixedWidth\n\n**Story ID:** `ui-components-tabs--button-tabs-fixed-width`\n\n`tabStyle=\"button\"` with eight settings-style tabs.\n\n<Canvas of={TabsStories.ButtonTabsFixedWidth} />\n\n### ButtonTabsFill\n\n**Story ID:** `ui-components-tabs--button-tabs-fill`\n\n`tabStyle=\"button\"` + `variant=\"fullWidth\"` for equal-width pills.\n\n<Canvas of={TabsStories.ButtonTabsFill} />\n\n### WithTopIcons\n\n**Story ID:** `ui-components-tabs--with-top-icons`\n\n`tabStyle=\"topIcon\"` with `iconProps` size `md`.\n\n<Canvas of={TabsStories.WithTopIcons} />\n\n### ButtonTabsWithBadges\n\n**Story ID:** `ui-components-tabs--button-tabs-with-badges`\n\n`tabStyle=\"button\"` with `badge={3}` on Notification tab.\n\n<Canvas of={TabsStories.ButtonTabsWithBadges} />\n\n### ButtonTabsWithIcons\n\n**Story ID:** `ui-components-tabs--button-tabs-with-icons`\n\n`tabStyle=\"button\"` with leading `iconProps`.\n\n<Canvas of={TabsStories.ButtonTabsWithIcons} />\n\n## Accessibility\n\n- MUI `Tabs` provides `role=\"tablist\"`; each `Tab` has `role=\"tab\"` and `aria-selected`.\n- Keyboard: arrow keys move between tabs; activation follows MUI focus management.\n- Tab panels in stories use `role=\"tabpanel\"`, `hidden`, and `aria-labelledby` — replicate in product code.\n- `badge` on `Tab` wraps label in `Badge`; ensure tab accessible name still includes label text.\n- Storybook a11y addon: `test: 'todo'`.\n\n## Best Practices\n\n- Keep one `value` state in the parent; update via `onChange`.\n- Use Signal `Tab` with `iconProps` instead of raw MUI icon nodes.\n- Use `tabStyle=\"button\"` for settings-style segmented navigation.\n- Use `variant=\"scrollable\"` when tab count exceeds container width.\n- Implement panel visibility with consistent `id` / `aria-labelledby` linkage.\n- Import `Tabs` and `Tab` from `@exotel-npm-dev/signal-design-system`.\n\n## Anti-patterns\n\n- Using `Tabs` for a linear wizard — use `Stepper`.\n- Using `Tabs` for collapsible FAQ sections — use `Accordion`.\n- Omitting `onChange` in controlled mode.\n- Deprecated `icon` prop on `Tab` when `iconProps` is available.\n- Inventing `tabStyle` values beyond `default`, `button`, `topIcon`.\n- Expecting built-in `TabPanel` — implement panel region in the app.\n\n## Guidance for AI Agents\n\n### When to choose `Tabs`\n\n- Peer views on one page (settings, dashboard sections)\n- Segmented pill control (`tabStyle=\"button\"`)\n- Icon-labeled section switcher\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Collapsible sections | `Accordion` |\n| Sequential steps | `Stepper` |\n| Action dropdown | `Menu` |\n| Side overlay | `Drawer` |\n\n### Canonical prop combinations\n\n```tsx\n// Default — story: Basic\n<Tabs value={value} onChange={(_e, v) => setValue(v as number)}>\n  <Tab label=\"Item One\" />\n</Tabs>\n\n// Icons — story: WithIcons\n<Tab iconProps={{ name: 'chart-bar', size: 'sm' }} label=\"Dashboard\" iconPosition=\"start\" />\n\n// Button pills — story: ButtonTabsFixedWidth\n<Tabs tabStyle=\"button\" value={value} onChange={handleChange}>\n  <Tab label=\"Profile\" />\n</Tabs>\n\n// Top icon — story: WithTopIcons\n<Tabs tabStyle=\"topIcon\" value={value} onChange={handleChange}>\n  <Tab iconProps={{ name: 'airplane', size: 'md' }} label=\"Flights\" />\n</Tabs>\n\n// Badge on tab — story: ButtonTabsWithBadges\n<Tab label=\"Notification\" badge={3} />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default tabs | `Basic` |\n| Many tabs | `Scrollable` |\n| Segmented pills | `ButtonTabsFixedWidth` |\n| Equal-width pills | `ButtonTabsFill` |\n| Icon tabs | `WithIcons` |\n| Top icon layout | `WithTopIcons` |\n| Tab with count | `ButtonTabsWithBadges` |\n\n### Common mistakes to avoid\n\n- Inventing `TabPanel` as a DS export — build panel visibility in app code.\n- Using MUI `Tab` `icon` JSX instead of `iconProps`.\n- Mixing uncontrolled and controlled `value` on the same instance.\n- Using `Accordion` for view switching — use `Tabs`.\n\n### Composition guidance\n\n- Place `Tabs` above the panel content region.\n- For vertical tabs, use flex row: `Tabs` + content `Box` (`Vertical` story).\n- Pair `tabStyle=\"button\"` with short noun labels.\n- Use `badge` sparingly for unread/count on a single tab.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Tab` | Signal tab with `iconProps` and `badge` |\n| `Accordion` | Alternative for collapsible sections |\n| `Stepper` | Alternative for sequential flows |\n| `Icon` | Via `Tab` `iconProps` |\n| `Badge` | Via `Tab` `badge` prop |\n| `Box` | Layout wrapper for panels |\n| `Typography` | Panel content |\n"}}},"ui-components-themeprovider":{"id":"ui-components-themeprovider","name":"ExotelThemeProvider","path":"./src/stories/ui-components/ThemeProvider.stories.tsx","stories":[{"id":"ui-components-themeprovider--with-theme","name":"With Theme","snippet":"const WithTheme = () => (\n  <ExotelThemeProvider>\n    <Card sx={{ padding: 3, minWidth: 400 }}>\n      <Typography variant=\"h5\" gutterBottom>\n        Exotel Theme Applied\n      </Typography>\n      <Typography variant=\"body1\" paragraph>\n        This card and all components below are using the Exotel design system theme.\n      </Typography>\n      <div style={{ display: 'flex', gap: '8px', marginTop: '16px' }}>\n        <Button variant=\"contained\" color=\"primary\">\n          Primary\n        </Button>\n        <Button variant=\"contained\" color=\"secondary\">\n          Secondary\n        </Button>\n        <Button variant=\"outlined\" color=\"primary\">\n          Outlined\n        </Button>\n      </div>\n    </Card>\n  </ExotelThemeProvider>\n);","description":"Theme provider in action This demonstrates that the theme is applied correctly. All components use the Exotel theme colors and styling."},{"id":"ui-components-themeprovider--theme-colors","name":"Theme Colors","snippet":"const ThemeColors = () => (\n  <ExotelThemeProvider>\n    <Card sx={{ padding: 3, minWidth: 500 }}>\n      <Typography variant=\"h5\" gutterBottom>\n        Theme Colors\n      </Typography>\n      <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', marginTop: '16px' }}>\n        <Button variant=\"contained\" color=\"primary\" fullWidth>\n          Primary\n        </Button>\n        <Button variant=\"contained\" color=\"secondary\" fullWidth>\n          Secondary\n        </Button>\n        <Button variant=\"contained\" color=\"success\" fullWidth>\n          Success\n        </Button>\n        <Button variant=\"contained\" color=\"error\" fullWidth>\n          Error\n        </Button>\n        <Button variant=\"contained\" color=\"info\" fullWidth>\n          Info\n        </Button>\n        <Button variant=\"contained\" color=\"warning\" fullWidth>\n          Warning\n        </Button>\n      </div>\n    </Card>\n  </ExotelThemeProvider>\n);","description":"Theme colors demonstration Shows all available theme colors from the Exotel design system."},{"id":"ui-components-themeprovider--font-switcher","name":"Font Switcher","snippet":"const FontSwitcher = () => (\n  <ExotelThemeProvider>\n    <FontSwitcherDemo />\n  </ExotelThemeProvider>\n);","description":"Runtime font switching Toggle between **Noto Sans** and **IBM Plex Sans** at runtime. The choice is persisted in `localStorage` and survives page refreshes."}],"import":"import { Box, Stack, ToggleButton, ToggleButtonGroup, Typography } from \"@mui/material\";\nimport { Button, Card, ExotelThemeProvider } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"ExotelThemeProvider","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/ThemeProvider/ThemeProvider.tsx","actualName":"ExotelThemeProvider","exportName":"ExotelThemeProvider","props":{"children":{"required":true,"tsType":{"name":"ReactNode"},"description":""},"defaultMode":{"required":false,"tsType":{"name":"union","raw":"\"light\" | \"dark\" | \"system\"","elements":[{"name":"literal","value":"\"light\""},{"name":"literal","value":"\"dark\""},{"name":"literal","value":"\"system\""}]},"description":"The initial color mode applied on first visit (before any user toggle).\n- `'light'`  — start in light mode (default)\n- `'dark'`   — start in dark mode\n- `'system'` — follow the user's OS preference\n\nAfter the user changes the mode via `useThemeMode().setMode()`,\ntheir choice is persisted and takes priority over this value.","defaultValue":{"value":"\"light\"","computed":false}},"defaultFont":{"required":false,"tsType":{"name":"union","raw":"keyof typeof FONT_OPTIONS","elements":[{"name":"literal","value":"\"noto-sans\""},{"name":"literal","value":"\"ibm-plex-sans\""}]},"description":"Initial font. Defaults to `\"noto-sans\"`.\nCan be changed at runtime via `useFont().setFont()`.","defaultValue":{"value":"\"noto-sans\"","computed":false}},"adapterLocale":{"required":false,"tsType":{"name":"string"},"description":"Locale string passed to the dayjs date adapter (e.g. \"en\", \"de\", \"ja\").\nControls formatting for all date/time picker components."},"themeOverrides":{"required":false,"tsType":{"name":"ThemeOptions"},"description":"Partial theme overrides deep-merged on top of the base Exotel theme.\nUse this to extend palette colors, add component overrides, or\nadjust typography without forking the design system theme."},"contextData":{"required":false,"tsType":{"name":"Record","elements":[{"name":"string"},{"name":"unknown"}],"raw":"Record<string, unknown>"},"description":"Arbitrary data accessible anywhere via `useSignal().data`.\nUse this to pass global app-level context (tenant info, feature flags,\npermissions, etc.) without creating additional providers.","defaultValue":{"value":"{}","computed":false}}}},"docs":{"ui-components-themeprovider--docs":{"id":"ui-components-themeprovider--docs","name":"Docs","path":"./src/stories/ui-components/ThemeProvider.mdx","title":"UI Components/ThemeProvider","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ThemeProviderStories from './ThemeProvider.stories';\nimport { ExotelThemeProvider } from '../../components/ThemeProvider';\n\n<Meta of={ThemeProviderStories} />\n\n# ThemeProvider\n\n## Overview\n\n`ExotelThemeProvider` wraps the app with MUI `ThemeProvider`, `CssBaseline`, Dayjs `LocalizationProvider`, and theme mode persistence.\n\n```tsx\nimport {\n  ExotelThemeProvider,\n  useThemeMode,\n  useFont,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\n**Required** at app root for all Signal components, pickers, and correct light/dark tokens.\n\n## Props\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `defaultMode` | `'light' \\| 'dark' \\| 'system'` | `'light'` | Initial color mode |\n| `modeStorageKey` | `string` | `'exotel-mode'` | localStorage key for mode |\n| `adapterLocale` | `string` | — | Dayjs locale for pickers |\n\n## Hooks\n\n| Hook | Returns |\n|------|---------|\n| `useThemeMode()` | `{ mode, setMode, toggleMode }` |\n| `useFont()` | `{ fontKey, setFont }` — `noto-sans`, `ibm-plex-sans`, etc. |\n| `useLoadDataByTheme()` | Theme-aware asset loading |\n\nDark mode uses `colorSchemeSelector: \"class\"` on `<html>`.\n\n## Stories\n\n`WithTheme`, `ThemeColors`, `FontSwitcher`\n\n<Canvas of={ThemeProviderStories.WithTheme} />\n\n## Guidance for AI Agents\n\nAlways wrap generated UI in `ExotelThemeProvider`. Date/time pickers require this provider for `LocalizationProvider`.\n\n## Related Components\n\n`AvatarMenu` (theme submenu), all UI components\n"}}},"ui-components-toast":{"id":"ui-components-toast","name":"ToastProvider","path":"./src/stories/ui-components/Toast.stories.tsx","stories":[{"id":"ui-components-toast--severities","name":"Severities","snippet":"const Severities = () => (\n  <ToastProvider>\n    <SeverityDemo />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--with-title","name":"With title","snippet":"const WithTitle = () => (\n  <ToastProvider>\n    <WithTitleDemo />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--slide-transition","name":"Transition — Slide","snippet":"const SlideTransition = () => (\n  <ToastProvider transition=\"slide\">\n    <TransitionDemo transition=\"slide\" />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--grow-transition","name":"Transition — Grow","snippet":"const GrowTransition = () => (\n  <ToastProvider transition=\"grow\">\n    <TransitionDemo transition=\"grow\" />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--positions","name":"Anchor positions","snippet":"const Positions = () => (\n  <ToastProvider>\n    <PositionDemo />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--offset","name":"Relative offset (300px from bottom)","snippet":"const Offset = () => (\n  <ToastProvider offset={300}>\n    <OffsetDemo />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--persistent","name":"Persistent (no auto-hide)","snippet":"const Persistent = () => (\n  <ToastProvider>\n    <PersistDemo />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--stacked","name":"Stacked (max 3)","snippet":"const Stacked = () => (\n  <ToastProvider maxToasts={3}>\n    <StackedDemo />\n  </ToastProvider>\n);"},{"id":"ui-components-toast--playground","name":"Playground (interactive)","snippet":"const Playground = ({\n  maxToasts,\n  vertical,\n  horizontal,\n  transition,\n  autoHideDuration,\n  dense,\n  offset,\n  toastOffset,\n  severity,\n  title,\n  message,\n  persist,\n}) => (\n  <ToastProvider\n    key={`${vertical}-${horizontal}-${transition}-${maxToasts}-${offset}-${dense}-${autoHideDuration}`}\n    maxToasts={maxToasts}\n    anchorOrigin={{ vertical, horizontal }}\n    transition={transition}\n    autoHideDuration={autoHideDuration}\n    dense={dense}\n    offset={offset}\n  >\n    <PlaygroundDemo\n      severity={severity}\n      title={title}\n      message={message}\n      persist={persist}\n      toastOffset={toastOffset}\n    />\n  </ToastProvider>\n);"}],"import":"import { Box, Button, Stack, ToastProvider, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"ToastProvider","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Toast/ToastProvider.tsx","actualName":"ToastProvider","exportName":"ToastProvider","props":{"children":{"required":true,"tsType":{"name":"ReactNode"},"description":""},"maxToasts":{"required":false,"tsType":{"name":"number"},"description":"Maximum toasts visible at once. @default 3","defaultValue":{"value":"3","computed":false}},"anchorOrigin":{"required":false,"tsType":{"name":"ToastOrigin"},"description":"Default screen anchor for all toasts. @default { vertical: 'bottom', horizontal: 'right' }","defaultValue":{"value":"{ vertical: 'bottom', horizontal: 'right' }","computed":false}},"transition":{"required":false,"tsType":{"name":"union","raw":"'slide' | 'grow'","elements":[{"name":"literal","value":"'slide'"},{"name":"literal","value":"'grow'"}]},"description":"Default transition for all toasts. @default 'slide'","defaultValue":{"value":"'slide'","computed":false}},"autoHideDuration":{"required":false,"tsType":{"name":"union","raw":"number | null","elements":[{"name":"number"},{"name":"null"}]},"description":"Default auto-hide duration in ms. @default 5000","defaultValue":{"value":"5000","computed":false}},"dense":{"required":false,"tsType":{"name":"boolean"},"description":"Denser spacing (useful on mobile). @default false","defaultValue":{"value":"false","computed":false}},"offset":{"required":false,"tsType":{"name":"union","raw":"number | string | ToastOffset","elements":[{"name":"number"},{"name":"string"},{"name":"ToastOffset"}]},"description":"Distance of the toast container from the viewport edges, letting you\nposition the widget relative to its anchor. A number/string is applied to\nthe anchored vertical edge (e.g. `offset={300}` with a bottom anchor lifts\ntoasts to 300px above the bottom). Pass an object to control each edge\nindependently (e.g. `{ bottom: 300, right: 24 }`)."}}},"docs":{"ui-components-toast--docs":{"id":"ui-components-toast--docs","name":"Docs","path":"./src/stories/ui-components/Toast.mdx","title":"UI Components/Toast","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ToastStories from './Toast.stories';\nimport { ToastProvider } from '../../components/Toast';\n\n<Meta of={ToastStories} />\n\n# Toast\n\n## Overview\n\n`Toast` is a notification system powered by notistack. Wrap your app in `<ToastProvider>`, then call `useToast()` from any component to show success, error, warning, or info toasts with configurable position, transitions, and auto-dismiss behavior.\n\n```tsx\nimport { ToastProvider, useToast } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use**\n\n- Brief, non-blocking feedback after user actions (save, delete, submit)\n- System notifications (update available, connection lost)\n- Confirmation of background processes completing\n\n**When not to use**\n\n- Persistent status messages that require action → use `Alert`\n- Inline field validation errors → use form `helperText`\n- Critical confirmations (delete, discard) → use `Dialog`\n- Long-form messages → use `Snackbar` with action button\n\n## Setup\n\nWrap your application (or a subtree) in `ToastProvider`:\n\n```tsx\nimport { ToastProvider } from '@exotel-npm-dev/signal-design-system';\n\nfunction App() {\n  return (\n    <ExotelThemeProvider>\n      <ToastProvider>\n        <YourApp />\n      </ToastProvider>\n    </ExotelThemeProvider>\n  );\n}\n```\n\nThen consume from any child component:\n\n```tsx\nimport { useToast } from '@exotel-npm-dev/signal-design-system';\n\nfunction SaveButton() {\n  const { showSuccess, showError } = useToast();\n\n  const handleSave = async () => {\n    try {\n      await save();\n      showSuccess('Changes saved successfully.');\n    } catch {\n      showError('Failed to save changes.', { title: 'Error' });\n    }\n  };\n\n  return <Button onClick={handleSave}>Save</Button>;\n}\n```\n\n## Provider Props\n\n<ArgTypes of={ToastProvider} />\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `maxToasts` | `number` | `3` | Maximum toasts visible at once |\n| `anchorOrigin` | `ToastOrigin` | `{ vertical: 'bottom', horizontal: 'right' }` | Default screen anchor |\n| `transition` | `'slide' \\| 'grow'` | `'slide'` | Default enter/exit animation |\n| `autoHideDuration` | `number \\| null` | `5000` | Milliseconds before auto-dismiss; `null` to persist |\n| `dense` | `boolean` | `false` | Denser spacing between stacked toasts |\n| `offset` | `number \\| string \\| ToastOffset` | — | Distance from viewport edges |\n\n## useToast API\n\n| Method | Signature | Description |\n|--------|-----------|-------------|\n| `showToast` | `(message, options?) => ToastKey` | Show a toast with any severity |\n| `showSuccess` | `(message, options?) => ToastKey` | Shorthand for `severity: 'success'` |\n| `showError` | `(message, options?) => ToastKey` | Shorthand for `severity: 'error'` |\n| `showWarning` | `(message, options?) => ToastKey` | Shorthand for `severity: 'warning'` |\n| `showInfo` | `(message, options?) => ToastKey` | Shorthand for `severity: 'info'` |\n| `closeToast` | `(key?) => void` | Close by key, or all if no key passed |\n\n### ToastOptions\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `title` | `ReactNode` | — | Bold title above the message |\n| `severity` | `'success' \\| 'error' \\| 'warning' \\| 'info'` | `'info'` | Alert color and icon |\n| `autoHideDuration` | `number \\| null` | `5000` | Override per-toast auto-dismiss |\n| `anchorOrigin` | `ToastOrigin` | Provider default | Override per-toast position |\n| `offset` | `number \\| string \\| ToastOffset` | — | Per-toast additional offset |\n| `transition` | `'slide' \\| 'grow'` | Provider default | Override per-toast animation |\n| `key` | `ToastKey` | auto | Unique key for deduplication/dismissal |\n| `persist` | `boolean` | `false` | Keep until explicitly dismissed |\n\n## Stories\n\n### Severities\n\nAll four severity levels with shorthand methods.\n\n<Canvas of={ToastStories.Severities} />\n\n### With title\n\nToasts with a bold title above the message body.\n\n<Canvas of={ToastStories.WithTitle} />\n\n### Transition — Slide\n\nSlide animation (default) from the anchored edge.\n\n<Canvas of={ToastStories.SlideTransition} />\n\n### Transition — Grow\n\nGrow animation expanding from the anchor point.\n\n<Canvas of={ToastStories.GrowTransition} />\n\n### Anchor positions\n\nAll six anchor positions demonstrated interactively.\n\n<Canvas of={ToastStories.Positions} />\n\n### Offset\n\nProvider-level offset lifting toasts 300px from the bottom edge.\n\n<Canvas of={ToastStories.Offset} />\n\n### Persistent\n\nToast that remains until explicitly dismissed via `closeToast(key)`.\n\n<Canvas of={ToastStories.Persistent} />\n\n### Stacked\n\nMultiple toasts stacking with `maxToasts={3}` limit.\n\n<Canvas of={ToastStories.Stacked} />\n\n### Playground\n\nInteractive controls for all provider and toast options.\n\n<Canvas of={ToastStories.Playground} />\n\n## Best Practices\n\n- Place `ToastProvider` near the root of your app (after `ExotelThemeProvider`).\n- Keep toast messages under 2 lines; use `title` for a bold headline.\n- Use `showSuccess` / `showError` shorthands for the most common cases.\n- Set `persist: true` only for critical notifications that require acknowledgment.\n- Use `key` to prevent duplicate toasts for the same event.\n- Set `offset` on the provider when toasts overlap with a bottom navigation bar or FAB.\n\n## Accessibility\n\n- Toasts use MUI `Alert` internally with appropriate ARIA roles.\n- Auto-dismiss ensures screen reader announcements are transient.\n- Persistent toasts include a close button for keyboard dismissal.\n- Avoid placing critical-only information in auto-dismissing toasts.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `Snackbar` | Lower-level MUI snackbar; Toast builds on notistack for stacking |\n| `Alert` | Inline persistent alert; use when toast auto-dismiss isn't appropriate |\n| `Dialog` | Modal confirmation for destructive actions |\n"}}},"ui-components-tooltip":{"id":"ui-components-tooltip","name":"Tooltip","path":"./src/stories/ui-components/Tooltip.stories.tsx","stories":[{"id":"ui-components-tooltip--basic","name":"Basic","snippet":"const Basic = () => (\n  <Tooltip title=\"This is a tooltip\">\n    <Button>Hover me</Button>\n  </Tooltip>\n);"}],"import":"import { Button, Tooltip } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Tooltip","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Tooltip/Tooltip.tsx","actualName":"Tooltip","exportName":"Tooltip","props":{"children":{"required":true,"tsType":{"name":"ReactReactElement","raw":"React.ReactElement"},"description":""},"title":{"required":true,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-tooltip--docs":{"id":"ui-components-tooltip--docs","name":"Docs","path":"./src/stories/ui-components/Tooltip.mdx","title":"UI Components/Tooltip","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as TooltipStories from './Tooltip.stories';\nimport { Tooltip } from '../../components/Tooltip';\n\n<Meta of={TooltipStories} />\n\n# Tooltip\n\n## Overview\n\n`Tooltip` is the Signal Design System wrapper around MUI `Tooltip`. It displays brief supplementary text on hover or keyboard focus of a single child element.\n\n```tsx\nimport { Tooltip, Button } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Icon-only control labels (`IconButton` with no visible text)\n- Truncated text expansion on hover\n- Short definitions of unfamiliar terms or metrics\n- Supplementary hints that repeat visible context for clarity\n\n**When not to use**\n\n- Essential information available only in the tooltip → expose in visible UI\n- Rich or interactive content → `Popover`\n- Persistent status messages → `Alert`\n- Navigation menus → `Menu`\n- Mobile-primary interactions without hover → use visible labels\n\n## Anatomy\n\n```\nTooltip\n├── title (prop)              ← Brief supplementary text\n└── children (single element) ← Trigger that accepts ref (Button, IconButton, etc.)\n```\n\nCanonical structure from `Basic` story:\n\n```tsx\n<Tooltip title=\"This is a tooltip\">\n  <Button>Hover me</Button>\n</Tooltip>\n```\n\n`children` must be a single React element that forwards ref to a DOM node (MUI requirement).\n\n## Content guidelines\n\nRules for writing tooltip copy in Exotel products. Text is set via the `title` prop.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Brief | A few words to one short phrase — not sentences or paragraphs |\n| Supplementary | Adds context to visible UI; does not replace labels |\n| Sentence case | \"This is a tooltip\" — not Title Case Every Word |\n| No punctuation | Omit trailing periods for short phrases |\n| Describe function | For icon buttons: name the action (\"Close\", \"Delete\", \"Filter\") |\n| Not redundant | Do not repeat visible button text verbatim |\n\n### Content by trigger type\n\n| Trigger | title pattern | Example |\n|---------|---------------|---------|\n| Icon-only button | Action verb or noun | \"Close\", \"Export\", \"More options\" |\n| Truncated text | Full untruncated string | Full email or name |\n| Abbreviation | Expanded term | \"Average handle time\" for \"AHT\" |\n| Disabled control | Why disabled (if space allows) | \"Save unavailable until form is valid\" |\n\n### Do and don't\n\n**Do**\n\n- \"This is a tooltip\" (Basic story)\n- Name icon-only actions clearly\n- Keep under ~60 characters when possible\n\n**Don't**\n\n- Put instructions that exist only in the tooltip\n- Multi-sentence help text\n- \"Click here\" or \"Hover for more\"\n- Duplicate the child element's visible label\n- Critical warnings users must see without hovering\n\n### Guidance for AI-generated tooltip copy\n\n- `title` = 1–6 words for icon buttons; slightly longer for truncated text expansion.\n- If the child has visible text (\"Hover me\"), `title` should add new information or be omitted.\n- For `IconButton`, always provide `title` matching `aria-label` intent.\n- Do not generate placeholder lorem ipsum.\n- Do not use tooltip as the only accessible name — child must have visible text or `aria-label`.\n\n## Props\n\n`TooltipProps` extends MUI `TooltipProps` (minus `ref`) with required `title` and `children`.\n\n### Required props\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `title` | `ReactNode` | Tooltip content | Brief supplementary text |\n| `children` | `React.ReactElement` | Single trigger element | Must forward ref (`Button`, `IconButton`, `span`, etc.) |\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `placement` | MUI placement | `'bottom'` | Tooltip position relative to child | Adjust to avoid viewport clipping |\n| `arrow` | `boolean` | `false` | Show pointer arrow | Optional emphasis |\n| `disableHoverListener` | `boolean` | `false` | Disable hover trigger | Use for focus-only or controlled patterns |\n| `disableFocusListener` | `boolean` | `false` | Disable focus trigger | Do not disable without alternative accessible name |\n| `enterDelay` / `leaveDelay` | `number` | MUI defaults | Show/hide timing | Increase `enterDelay` to reduce accidental triggers |\n| `describeChild` | `boolean` | `false` | Use tooltip as accessible description | Rare; prefer explicit `aria-label` on icon buttons |\n\nAdditional MUI `TooltipProps` pass through. See the generated table below for the full API.\n\n<ArgTypes of={Tooltip} />\n\n## Variants\n\n`Tooltip` has no Signal visual variants. MUI supports `placement` and `arrow` options (not demonstrated in stories).\n\n| Option | Description |\n|--------|-------------|\n| `placement` | `top`, `bottom`, `left`, `right`, and aligned variants |\n| `arrow` | Pointer arrow on tooltip popper |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Hidden | Default | Shows on hover/focus of child |\n| Visible | Hover or focus on child | MUI manages popper |\n| Disabled child | Tooltip on disabled elements | Wrap disabled control in `<span>` (MUI pattern; not in stories) |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Hover reveal | Mouse over child | `Basic` |\n| Focus reveal | Keyboard focus on child | `Basic` (MUI default) |\n| Single child | One `ReactElement` child | `Basic` with `Button` |\n\n## Stories\n\n### Basic\n\n**Story ID:** `ui-components-tooltip--basic`\n\n`title=\"This is a tooltip\"` on a `Button` child with text \"Hover me\".\n\n**Recommended usage:** Default tooltip on a focusable/hoverable control.\n\n<Canvas of={TooltipStories.Basic} />\n\n## Accessibility\n\n- MUI `Tooltip` shows on hover and focus by default — keyboard users can access content.\n- Tooltip text supplements visible labels; it must not be the sole accessible name for icon-only buttons.\n- For `IconButton`, pair `Tooltip title` with `aria-label` on the button (same string is acceptable).\n- `title` content is exposed to assistive technology via `aria-describedby` when appropriate (MUI behavior).\n- Disabled elements do not fire events — wrap in `<span>` if tooltip needed on disabled control (MUI docs pattern).\n- Do not put essential instructions only in tooltips.\n- Storybook a11y addon is configured with `test: 'todo'`.\n\n## Best Practices\n\n- Keep `title` to a few words.\n- Use on icon-only controls where visible label is absent.\n- Ensure child is a single element that forwards ref.\n- Match `title` and `aria-label` intent on `IconButton` triggers.\n- Prefer visible labels over tooltips when space allows.\n- Import from `@exotel-npm-dev/signal-design-system`.\n\n## Anti-patterns\n\n- Multi-line instructions in `title`.\n- Tooltip as only label for icon buttons without `aria-label`.\n- Multiple children inside `Tooltip` — must be exactly one element.\n- Non-ref-forwarding custom components as children (tooltip will not attach).\n- Using tooltip for error messages — use `Alert` or field `helperText`.\n- Using tooltip on mobile-only flows where hover does not exist.\n- Importing `@mui/material/Tooltip` directly in consumer apps.\n\n## Guidance for AI Agents\n\n### When to choose `Tooltip`\n\n- Short hover/focus hint on a button, icon button, or truncated text\n- Child is a single ref-forwarding element\n- Information is supplementary, not essential-only\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Click-open rich content | `Popover` |\n| Icon-only action (primary naming) | `IconButton` with `aria-label` |\n| Persistent help text | `Typography` or `Alert` |\n| Menu of actions | `Menu` |\n| Form field format hint | `helperText` on `EnhancedTextField` / `FormField` |\n\n### Canonical prop combinations\n\n```tsx\n// Default — story: Basic\n<Tooltip title=\"This is a tooltip\">\n  <Button>Hover me</Button>\n</Tooltip>\n\n// Icon button pattern (not in stories; standard ECC pattern)\n<Tooltip title=\"Close\">\n  <IconButton aria-label=\"Close\">\n    <Icon name=\"x\" size=\"sm\" />\n  </IconButton>\n</Tooltip>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Default tooltip | `Basic` (`ui-components-tooltip--basic`) |\n\n### Copy patterns\n\n| Context | title example |\n|---------|---------------|\n| Generic demo | \"This is a tooltip\" |\n| Close icon | \"Close\" |\n| Delete icon | \"Delete\" |\n| Truncated name | Full untruncated string |\n\n### Common mistakes to avoid\n\n- Multiple children: `<Tooltip><Button/><Icon/></Tooltip>` — invalid.\n- Empty `title` — tooltip has no purpose.\n- Long `title` strings — use `Popover` or inline help.\n- `title` as only `aria-label` source without `aria-label` on icon-only buttons — provide both.\n- Wrapping non-interactive blocks without focusable child.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `IconButton` | Common tooltip trigger for icon-only actions |\n| `Button` | Demonstrated trigger in `Basic` story |\n| `Icon` | Used inside icon button triggers |\n| `Popover` | Click-triggered richer overlays |\n| `Typography` | Visible text; tooltip supplements truncation |\n| `Menu` | Action lists; not hover hints |\n"}}},"ui-components-typography":{"id":"ui-components-typography","name":"Typography","path":"./src/stories/ui-components/Typography.stories.tsx","stories":[{"id":"ui-components-typography--typography-system","name":"Typography System","snippet":"const TypographySystem = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '24px', maxWidth: '800px' }}>\n    <section>\n      <Typography variant=\"h3\" gutterBottom>Headings</Typography>\n      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', paddingLeft: '16px' }}>\n        <Typography variant=\"h1\">Heading 1 - 60px / Bold (700)</Typography>\n        <Typography variant=\"h2\">Heading 2 - 48px / Bold (700)</Typography>\n        <Typography variant=\"h3\">Heading 3 - 32px / Bold (700)</Typography>\n        <Typography variant=\"h4\">Heading 4 - 24px / Bold (700)</Typography>\n        <Typography variant=\"h5\">Heading 5 - 20px / Bold (700)</Typography>\n        <Typography variant=\"h6\">Heading 6 - 16px / Bold (700)</Typography>\n      </div>\n    </section>\n\n    <section>\n      <Typography variant=\"h3\" gutterBottom>Titles</Typography>\n      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', paddingLeft: '16px' }}>\n        <Typography variant=\"title3\">Title 3 - 16px / SemiBold (600)</Typography>\n        <Typography variant=\"title2\">Title 2 - 14px / SemiBold (600)</Typography>\n        <Typography variant=\"title1\">Title 1 - 12px / SemiBold (600)</Typography>\n      </div>\n    </section>\n\n    <section>\n      <Typography variant=\"h3\" gutterBottom>Labels</Typography>\n      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', paddingLeft: '16px' }}>\n        <Typography variant=\"label3\">Label 3 - 16px / Medium (500)</Typography>\n        <Typography variant=\"label2\">Label 2 - 14px / Medium (500)</Typography>\n        <Typography variant=\"label1\">Label 1 - 12px / Medium (500)</Typography>\n      </div>\n    </section>\n\n    <section>\n      <Typography variant=\"h3\" gutterBottom>Body Text</Typography>\n      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', paddingLeft: '16px' }}>\n        <Typography variant=\"body1\">Body 1 - 16px / Regular (400)</Typography>\n        <Typography variant=\"body2\">Body 2 - 14px / Regular (400)</Typography>\n        <Typography variant=\"body3\">Body 3 - 12px / Regular (400)</Typography>\n      </div>\n    </section>\n\n    <section>\n      <Typography variant=\"h3\" gutterBottom>Caption &amp; Overline</Typography>\n      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', paddingLeft: '16px' }}>\n        <Typography variant=\"caption\">Caption - 12px / Regular (400)</Typography>\n        <Typography variant=\"overline\">Overline - 12px / Regular (400) / Uppercase</Typography>\n      </div>\n    </section>\n\n  </div>\n);"},{"id":"ui-components-typography--all-variants","name":"All Variants","snippet":"const AllVariants = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n    <Typography variant=\"h1\">Heading 1</Typography>\n    <Typography variant=\"h2\">Heading 2</Typography>\n    <Typography variant=\"h3\">Heading 3</Typography>\n    <Typography variant=\"h4\">Heading 4</Typography>\n    <Typography variant=\"h5\">Heading 5</Typography>\n    <Typography variant=\"h6\">Heading 6</Typography>\n    <Typography variant=\"title3\">Title 3</Typography>\n    <Typography variant=\"title2\">Title 2</Typography>\n    <Typography variant=\"title1\">Title 1</Typography>\n    <Typography variant=\"label3\">Label 3</Typography>\n    <Typography variant=\"label2\">Label 2</Typography>\n    <Typography variant=\"label1\">Label 1</Typography>\n    <Typography variant=\"body1\">Body 1</Typography>\n    <Typography variant=\"body2\">Body 2</Typography>\n    <Typography variant=\"body3\">Body 3</Typography>\n    <Typography variant=\"caption\">Caption</Typography>\n    <Typography variant=\"overline\">Overline</Typography>\n  </div>\n);"},{"id":"ui-components-typography--colors","name":"Colors","snippet":"const Colors = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n    <Typography color=\"text.primary\">Primary text</Typography>\n    <Typography color=\"text.secondary\">Secondary text</Typography>\n    <Typography color=\"text.disabled\">Disabled text</Typography>\n    <Typography color=\"primary\">Primary color</Typography>\n    <Typography color=\"secondary\">Secondary color</Typography>\n    <Typography color=\"error\">Error color</Typography>\n  </div>\n);"},{"id":"ui-components-typography--alignment","name":"Alignment","snippet":"const Alignment = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '300px' }}>\n    <Typography align=\"left\">Left aligned text</Typography>\n    <Typography align=\"center\">Center aligned text</Typography>\n    <Typography align=\"right\">Right aligned text</Typography>\n    <Typography align=\"justify\">\n      Justified text that spreads across the full width of the container.\n    </Typography>\n  </div>\n);"},{"id":"ui-components-typography--headings","name":"Headings","snippet":"const Headings = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n    <Typography variant=\"h1\">Heading 1 - 60px / Bold</Typography>\n    <Typography variant=\"h2\">Heading 2 - 48px / Bold</Typography>\n    <Typography variant=\"h3\">Heading 3 - 32px / Bold</Typography>\n    <Typography variant=\"h4\">Heading 4 - 24px / Bold</Typography>\n    <Typography variant=\"h5\">Heading 5 - 20px / Bold</Typography>\n    <Typography variant=\"h6\">Heading 6 - 16px / Bold</Typography>\n  </div>\n);"},{"id":"ui-components-typography--titles","name":"Titles","snippet":"const Titles = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n    <Typography variant=\"title3\">Title 3 - 16px / SemiBold (600)</Typography>\n    <Typography variant=\"title2\">Title 2 - 14px / SemiBold (600)</Typography>\n    <Typography variant=\"title1\">Title 1 - 12px / SemiBold (600)</Typography>\n  </div>\n);"},{"id":"ui-components-typography--labels","name":"Labels","snippet":"const Labels = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n    <Typography variant=\"label3\">Label 3 - 16px / Medium (500)</Typography>\n    <Typography variant=\"label2\">Label 2 - 14px / Medium (500)</Typography>\n    <Typography variant=\"label1\">Label 1 - 12px / Medium (500)</Typography>\n  </div>\n);"},{"id":"ui-components-typography--body-text","name":"Body Text","snippet":"const BodyText = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '600px' }}>\n    <Typography variant=\"body1\">\n      Body 1 (16px / Regular) - This is the default body text style. Use for paragraphs and general content.\n    </Typography>\n    <Typography variant=\"body2\">\n      Body 2 (14px / Regular) - This is a smaller body text style. Use for secondary content or compact layouts.\n    </Typography>\n    <Typography variant=\"body3\">\n      Body 3 (12px / Regular) - This is the smallest body text. Use sparingly for very compact content.\n    </Typography>\n  </div>\n);"},{"id":"ui-components-typography--interactive","name":"Interactive","snippet":"const Interactive = () => <Typography\n    variant=\"body1\"\n    color=\"text.primary\"\n    align=\"inherit\"\n    gutterBottom={false}\n    noWrap={false}>Typography text</Typography>;"}],"import":"import { Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"Typography","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/Typography/Typography.tsx","actualName":"Typography","exportName":"Typography","props":{"children":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":""}},"composes":["Omit"]},"docs":{"ui-components-typography--docs":{"id":"ui-components-typography--docs","name":"Docs","path":"./src/stories/ui-components/Typography.mdx","title":"UI Components/Typography","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as TypographyStories from './Typography.stories';\nimport { Typography } from '../../components/Typography';\n\n<Meta of={TypographyStories} />\n\n# Typography\n\n## Overview\n\n`Typography` wraps MUI `Typography` with Exotel theme tokens: custom variants `title1`–`title3`, `label1`–`label3`, `body1`–`body3`, plus standard MUI `h1`–`h6`, `caption`, and `overline`.\n\nUse `Typography` for all text rendering in Signal products. Do not use raw `<p>` or `<span>` with ad-hoc font sizes when a theme variant exists.\n\n```tsx\nimport { Typography } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct font family and variant styles.\n\n**When to use**\n\n- Page titles, section headings, labels, body copy, captions\n- Semantic text hierarchy via `variant`\n- Secondary or disabled text via `color=\"text.secondary\"` / `text.disabled`\n\n**When not to use**\n\n- Clickable navigation → use `Link` (may wrap `Typography` styling)\n- Button labels → use `Button` `children`\n- Form field labels → use `FormField` / `FieldWrapper` / `EnhancedTextField` label props\n\n## Content guidelines\n\nTypography content is set via `children`.\n\n### Writing principles\n\n| Principle | Rule |\n|-----------|------|\n| Match variant to hierarchy | `title2` for section titles, `body2` for default paragraphs |\n| Sentence case | Product copy uses sentence case unless `overline` |\n| Concise titles | Page titles: few words; subtitles: one line when possible |\n| Semantic color | `text.secondary` for supporting text, not smaller arbitrary fonts |\n\n### Variant selection for AI-generated copy\n\n| Content type | Variant |\n|--------------|---------|\n| Page title | `title2` or `h4`–`h5` |\n| Section title | `title3` or `h6` |\n| Form label | `label2` |\n| Body paragraph | `body1` or `body2` |\n| Helper text | `body3` or `caption` + `color=\"text.secondary\"` |\n| Error text | `body2` + `color=\"error\"` |\n\n## Props\n\n### Custom Exotel variants (theme)\n\n| Variant | Size / weight (from stories) | Use for |\n|---------|------------------------------|---------|\n| `title3` | 16px / SemiBold (600) | Largest title token |\n| `title2` | 14px / SemiBold (600) | Section titles |\n| `title1` | 12px / SemiBold (600) | Small titles |\n| `label3` | 16px / Medium (500) | Large labels |\n| `label2` | 14px / Medium (500) | Default labels |\n| `label1` | 12px / Medium (500) | Compact labels |\n| `body1` | 16px / Regular (400) | Default body |\n| `body2` | 14px / Regular (400) | Secondary body |\n| `body3` | 12px / Regular (400) | Compact body |\n\nFont family (theme): `\"Noto Sans\", \"Inter\", \"Roboto\", sans-serif`.\n\n### Commonly used inherited props\n\n| Name | Type | Default | Description | Usage guidance |\n|------|------|---------|-------------|----------------|\n| `variant` | see argTypes | `'body1'` | Typography style token | Prefer Exotel tokens over raw `fontSize` |\n| `color` | palette path | `'text.primary'` | Text color | `text.secondary`, `text.disabled`, `error`, etc. |\n| `align` | `'inherit' \\| 'left' \\| 'center' \\| 'right' \\| 'justify'` | `'inherit'` | Text alignment | `Alignment` story |\n| `gutterBottom` | `boolean` | `false` | Bottom margin | Section spacing |\n| `noWrap` | `boolean` | `false` | Single line ellipsis | Truncation in dense UI |\n| `component` | element type | maps from variant | Semantic HTML element | Override when needed for a11y |\n\n<ArgTypes of={Typography} />\n\n## Variants\n\nStories document two groups:\n\n1. **MUI headings** `h1`–`h6` — marketing-style large headings (`Headings`, `TypographySystem`)\n2. **Signal tokens** `title*`, `label*`, `body*` — product UI (`Titles`, `Labels`, `BodyText`)\n\n<Canvas of={TypographyStories.TypographySystem} />\n\n## States\n\n| State | How to apply | Story |\n|-------|--------------|-------|\n| Primary text | `color=\"text.primary\"` (default) | `Colors` |\n| Secondary | `color=\"text.secondary\"` | `Colors` |\n| Disabled | `color=\"text.disabled\"` | `Colors` |\n| Semantic | `color=\"primary\"`, `error`, etc. | `Colors` |\n| Aligned | `align` prop | `Alignment` |\n\n## Stories\n\n### TypographySystem\n\n**Story ID:** `ui-components-typography--typography-system`\n\nFull type scale reference: headings, titles, labels, body, caption, overline.\n\n<Canvas of={TypographyStories.TypographySystem} />\n\n### AllVariants\n\n**Story ID:** `ui-components-typography--all-variants`\n\nAll variants in one column.\n\n<Canvas of={TypographyStories.AllVariants} />\n\n### Colors\n\n**Story ID:** `ui-components-typography--colors`\n\n`text.primary`, `text.secondary`, `text.disabled`, `primary`, `secondary`, `error`.\n\n<Canvas of={TypographyStories.Colors} />\n\n### Alignment\n\n**Story ID:** `ui-components-typography--alignment`\n\n`left`, `center`, `right`, `justify`.\n\n<Canvas of={TypographyStories.Alignment} />\n\n### Headings\n\n**Story ID:** `ui-components-typography--headings`\n\n`h1` through `h6` with documented sizes.\n\n<Canvas of={TypographyStories.Headings} />\n\n### Titles\n\n**Story ID:** `ui-components-typography--titles`\n\n`title3`, `title2`, `title1`.\n\n<Canvas of={TypographyStories.Titles} />\n\n### Labels\n\n**Story ID:** `ui-components-typography--labels`\n\n`label3`, `label2`, `label1`.\n\n<Canvas of={TypographyStories.Labels} />\n\n### BodyText\n\n**Story ID:** `ui-components-typography--body-text`\n\n`body1`, `body2`, `body3` with usage notes in copy.\n\n<Canvas of={TypographyStories.BodyText} />\n\n### Interactive\n\n**Story ID:** `ui-components-typography--interactive`\n\nStorybook controls playground.\n\n## Accessibility\n\n- Renders semantic elements based on `variant` (e.g. `h1` for `variant=\"h1\"`).\n- Use appropriate heading levels for document outline — do not skip levels for styling; use `variant` with `component` if needed.\n- `color=\"text.secondary\"` alone is not sufficient for critical information — ensure contrast meets WCAG.\n- Storybook a11y addon: `test: 'todo'`.\n\n## Best Practices\n\n- Use theme variants instead of inline `fontSize` / `fontWeight`.\n- Use `title2` / `title3` for in-app section headers; reserve `h1`–`h6` for marketing or sparse hero layouts.\n- Use `body2` as default dense UI copy; `body1` for comfortable reading areas.\n- Use `label2` for form-adjacent labels when not using `FormField`.\n- Set `gutterBottom` on headings above body blocks.\n\n## Anti-patterns\n\n- Hardcoded `sx={{ fontSize: 14 }}` when `variant=\"body2\"` exists.\n- Using `h1` for every section title in app UI — use `title2`/`title3`.\n- Putting navigation behavior on `Typography` without `Link` — use `Link` component.\n- Importing `@mui/material/Typography` directly in consumer apps.\n\n## Guidance for AI Agents\n\n### When to choose `Typography`\n\n- Any static text: titles, labels, descriptions, helper text\n- Semantic hierarchy via `variant`\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Clickable text / URL | `Link` |\n| Button label | `Button` children |\n| External form label | `FormField` / `EnhancedTextField` label |\n\n### Canonical patterns\n\n```tsx\n<Typography variant=\"title2\">Section title</Typography>\n<Typography variant=\"body2\" color=\"text.secondary\">Supporting description</Typography>\n<Typography variant=\"label2\">Field label</Typography>\n<Typography variant=\"body2\" color=\"error\">Error message</Typography>\n```\n\n### Canonical stories\n\n| Task | Story |\n|------|-------|\n| Full type scale | `TypographySystem` |\n| Pick variant | `AllVariants` |\n| Text colors | `Colors` |\n| Section titles | `Titles` |\n| Body copy | `BodyText` |\n\n### Common mistakes\n\n- Inventing variants beyond theme set.\n- Using `Typography` for button text outside `Button`.\n- Omitting `ExotelThemeProvider`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|----------------|\n| `Link` | Navigable text |\n| `Button` | Action labels |\n| `PageHeader` | Uses `Typography` for title/subtitle |\n| `FormField` | External labels |\n"}}},"ai-suite-beta-agenticcard":{"id":"ai-suite-beta-agenticcard","name":"AgenticCard","path":"./src/stories/ui-components/AgenticCard.stories.tsx","stories":[{"id":"ai-suite-beta-agenticcard--campaign-blueprint","name":"Campaign Blueprint","snippet":"const CampaignBlueprint = () => (\n  <AgenticCard\n    title=\"Campaign Blueprint\"\n    actions={\n      <Button variant=\"contained\" size=\"medium\">\n        Start Building The Journey\n      </Button>\n    }\n  >\n    <Typography variant=\"body2\" fontWeight=\"bold\" gutterBottom>\n      1. Core Parameters &amp; Targets\n    </Typography>\n    <ul>\n      <li>Primary Objective: Drive application conversion from 12% baseline to ≥20%.</li>\n      <li>Audience Segmentation: 45,736 validated leads synced from Salesforce CRM.</li>\n      <li>DND Safeguard: 3,156 active DND users isolated strictly to transactional-only routes.</li>\n      <li>\n        Campaign Lifespan: 7-day sprint max per lead, with an automated return to the nurture pool\n        on Day 8.\n      </li>\n    </ul>\n    <Typography variant=\"body2\" fontWeight=\"bold\" gutterBottom sx={{ mt: 2 }}>\n      2. Omnichannel Flow Execution Steps\n    </Typography>\n    <ul>\n      <li>Day 0 (SMS): Send personalized reminder with an app deep-link.</li>\n      <li>Day 1 (WhatsApp Multi-Path):</li>\n      <ul>\n        <li>Branch A: If drop-off stage is KYC Upload → Send video tutorial link + \"Upload KYC\" CTA.</li>\n        <li>Branch B: For all other drop-offs → Send step-by-step text onboarding guide.</li>\n        <li>\n          Fallback Track: Leads without active WhatsApp tokens automatically receive an SMS\n          fallback.\n        </li>\n      </ul>\n      <li>\n        Day 3 (Voicebot): Trigger an interactive Exotel outbound call to capture intent and drop\n        an instant text link.\n      </li>\n      <li>Day 5 (Preview Dialer): Pass remaining high-priority leads to live human agents.</li>\n      <li>\n        Exit Condition: Instantly drop a lead from the journey the moment an account opening is\n        confirmed.\n      </li>\n    </ul>\n    <Typography variant=\"body2\" fontWeight=\"bold\" gutterBottom sx={{ mt: 2 }}>\n      3. Budget &amp; Financial Guardrails\n    </Typography>\n    <ul>\n      <li>\n        Cost Efficiency Check: Blended journey cost optimized at ₹1.49 per lead (~₹68,200 total\n        campaign spend).\n      </li>\n      <li>Budget Ceiling: Operating safely within your ₹8.00 per lead maximum limit.</li>\n    </ul>\n    <Typography variant=\"body2\" sx={{ mt: 2 }}>\n      All background assets including Meta WhatsApp formats, DLT text blocks, and conversational\n      voicebot scripts are fully staged.\n    </Typography>\n    <Typography variant=\"body2\" sx={{ mt: 2 }}>\n      How would you like to proceed?\n    </Typography>\n  </AgenticCard>\n);","description":"Campaign Blueprint — rich text body with a primary CTA button. Matches the first Figma screen (node 30-4664)."},{"id":"ai-suite-beta-agenticcard--with-image-preview","name":"With Image Preview","snippet":"const WithImagePreview = () => (\n  <AgenticCard\n    title=\"Lead Conversion — Demat Account Opening Business Journey\"\n    imageSrc=\"https://placehold.co/684x210/f8f8f8/ccc?text=Business+Journey+Preview\"\n    imageAlt=\"Business journey flow preview\"\n    actions={\n      <Button variant=\"contained\" size=\"medium\">\n        Open Business Journey\n      </Button>\n    }\n  />\n);","description":"Business Journey — image preview with a primary CTA button. Matches the second Figma screen (node 40-9323)."},{"id":"ai-suite-beta-agenticcard--with-edit-action","name":"With Edit Action","snippet":"const WithEditAction = () => (\n  <AgenticCard\n    title=\"Campaign Blueprint\"\n    actions={\n      <Button variant=\"outlined\" color=\"inherit\" size=\"medium\" startIconProps={{ name: 'note-pencil', size: 'sm' }}>\n        Edit\n      </Button>\n    }\n  >\n    <Typography variant=\"body2\" fontWeight=\"bold\" gutterBottom>\n      1. Core Parameters &amp; Targets\n    </Typography>\n    <ul>\n      <li>Primary Objective: Drive application conversion from 12% baseline to ≥20%.</li>\n      <li>Audience Segmentation: 45,736 validated leads synced from Salesforce CRM.</li>\n      <li>DND Safeguard: 3,156 active DND users isolated strictly to transactional-only routes.</li>\n      <li>\n        Campaign Lifespan: 7-day sprint max per lead, with an automated return to the nurture pool\n        on Day 8.\n      </li>\n    </ul>\n    <Typography variant=\"body2\" sx={{ mt: 2 }}>\n      How would you like to proceed?\n    </Typography>\n  </AgenticCard>\n);","description":"With Edit action — outlined button footer. Matches the third Figma screen (node 37-8951)."},{"id":"ai-suite-beta-agenticcard--with-header-action","name":"With Header Action","snippet":"const WithHeaderAction = () => (\n  <AgenticCard\n    title=\"Sandbox Test Results\"\n    headerAction={\n      <Button\n        variant=\"outlined\"\n        size=\"small\"\n        sx={{\n          backgroundColor: 'surface.elevation1',\n          color: 'text.primary',\n        }}\n        startIconProps={{ name: 'clipboard-text', size: 'sm' }}\n      >\n        Detailed Report\n      </Button>\n    }\n  >\n    <Typography variant=\"body2\" fontWeight=\"bold\" gutterBottom>\n      1. Pathway Simulation Diagnostics\n    </Typography>\n    <ul>\n      <li>\n        Path 1: Standard SMS Execution (Day 0): 100% PASS | Micro-link tokenization and dynamic\n        name variables parsed correctly.\n      </li>\n      <li>\n        Path 2: WhatsApp Segmented Routing (Day 1): 100% PASS | KYC-delayed profiles correctly\n        received the localized video tutorial.\n      </li>\n      <li>\n        Path 3: Multi-Channel Fallback Loop: 100% PASS | Profiles without verified WhatsApp\n        records seamlessly switched to alternate SMS tracks.\n      </li>\n      <li>\n        Path 4: Smart Outbound Voicebot (Day 3): 100% PASS | Dual-language triggers executed based\n        on the user profile preference field.\n      </li>\n      <li>\n        Path 5: Live Escalation Queue (Day 5): 100% PASS | Premium profiles cleanly injected into\n        the active HSL_Premium_Sales_Team preview dialer list.\n      </li>\n    </ul>\n    <Typography variant=\"body2\" fontWeight=\"bold\" gutterBottom sx={{ mt: 2 }}>\n      2. Compliance &amp; Error Gate Assertions\n    </Typography>\n    <ul>\n      <li>\n        TRAI DND Enforcement Check: Passed. Zero promotional materials were dispatched to\n        DND-registered test vectors.\n      </li>\n      <li>\n        Quiet Hours Hold Check: Passed. Timers calculated to fire between 8 PM and 9 AM were\n        automatically paused and batched for release at exactly 09:00 AM IST.\n      </li>\n      <li>\n        Absolute Journey Exit Rule: Passed. Synced conversion signals successfully terminated all\n        pending downstream communications for converted mock profiles instantly.\n      </li>\n    </ul>\n  </AgenticCard>\n);","description":"With header action button — outlined button in the header. Matches the Figma screen (node 52-14262) \"Sandbox Test Results\"."},{"id":"ai-suite-beta-agenticcard--minimal","name":"Minimal","snippet":"const Minimal = () => <AgenticCard\n    title=\"Generated Report\"\n    actions={\n      <Button variant=\"contained\" size=\"medium\">\n        Download Report\n      </Button>\n    } />;","description":"Minimal — title and actions only, no body content."},{"id":"ai-suite-beta-agenticcard--content-only","name":"Content Only","snippet":"const ContentOnly = () => (\n  <AgenticCard title=\"Analysis Summary\">\n    <Typography variant=\"body2\">\n      The analysis identified 3 high-priority segments for immediate outreach, with a projected\n      15% improvement in conversion rates.\n    </Typography>\n  </AgenticCard>\n);","description":"Content only — no actions footer."},{"id":"ai-suite-beta-agenticcard--with-iframe-preview","name":"With Iframe Preview","snippet":"const WithIframePreview = () => (\n  <AgenticCard\n    title=\"Live Campaign Dashboard\"\n    iframeSrc=\"https://www.wikipedia.org\"\n    iframeTitle=\"Campaign dashboard preview\"\n    actions={\n      <Button variant=\"contained\" size=\"medium\">\n        Open Full Dashboard\n      </Button>\n    }\n  />\n);","description":"Iframe preview — non-interactive preview that opens fullscreen on click. The inline preview shows a \"Click to interact\" overlay. Clicking it opens a fullscreen overlay covering the entire window where the user can interact with the iframe content."},{"id":"ai-suite-beta-agenticcard--iframe-with-body","name":"Iframe With Body","snippet":"const IframeWithBody = () => (\n  <AgenticCard\n    title=\"Journey Flow Preview\"\n    iframeSrc=\"https://www.wikipedia.org\"\n    iframeTitle=\"Journey flow diagram\"\n    iframePreviewHeight={180}\n  >\n    <Typography variant=\"body2\">\n      This is the auto-generated journey flow based on your campaign blueprint. Click the preview\n      above to interact with the diagram, zoom in, or inspect individual nodes.\n    </Typography>\n  </AgenticCard>\n);","description":"Iframe with body content — iframe preview above rich text body."},{"id":"ai-suite-beta-agenticcard--iframe-with-header-action","name":"Iframe With Header Action","snippet":"const IframeWithHeaderAction = () => (\n  <AgenticCard\n    title=\"Analytics Report\"\n    iframeSrc=\"https://www.wikipedia.org\"\n    iframeTitle=\"Analytics report\"\n    iframePreviewHeight={260}\n    headerAction={\n      <Button\n        variant=\"outlined\"\n        size=\"small\"\n        sx={{\n          backgroundColor: 'surface.elevation1',\n          color: 'text.primary',\n        }}\n        startIconProps={{ name: 'arrow-square-out', size: 'sm' }}\n      >\n        Open in New Tab\n      </Button>\n    }\n  />\n);","description":"Iframe with header action — taller preview with a header button."}],"import":"import { AgenticCard, Box, Button, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"description":"AgenticCard — a structured content card used in agentic chat flows. Renders a bordered card with a gray title header, a body area for rich content or images, and an optional action footer with buttons. ```tsx <AgenticCard title=\"Campaign Blueprint\" actions={ <Button variant=\"contained\">Start Building The Journey</Button> } > <Typography variant=\"body2\">Plan details here…</Typography> </AgenticCard> ```","reactDocgen":{"description":"AgenticCard — a structured content card used in agentic chat flows.\n\nRenders a bordered card with a gray title header, a body area for\nrich content or images, and an optional action footer with buttons.\n\n```tsx\n<AgenticCard\n  title=\"Campaign Blueprint\"\n  actions={\n    <Button variant=\"contained\">Start Building The Journey</Button>\n  }\n>\n  <Typography variant=\"body2\">Plan details here…</Typography>\n</AgenticCard>\n```","methods":[],"displayName":"AgenticCard","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/AgenticCard/AgenticCard.tsx","actualName":"AgenticCard","exportName":"AgenticCard","props":{"title":{"required":true,"tsType":{"name":"string"},"description":"Title displayed in the gray header bar."},"children":{"required":false,"tsType":{"name":"ReactNode"},"description":"Body content — rich text, images, or any React node."},"headerAction":{"required":false,"tsType":{"name":"ReactNode"},"description":"Action element rendered to the right of the title in the header.\nTypically a small outlined button (e.g. \"Detailed Report\")."},"actions":{"required":false,"tsType":{"name":"ReactNode"},"description":"Action buttons rendered right-aligned in the footer.\nWhen provided, a divider separates the footer from the body."},"imageSrc":{"required":false,"tsType":{"name":"string"},"description":"Image source rendered between the header and body/footer.\nUse for visual previews such as journey flow diagrams."},"imageAlt":{"required":false,"tsType":{"name":"string"},"description":"Alt text for the image.\n@default ''","defaultValue":{"value":"''","computed":false}},"iframeSrc":{"required":false,"tsType":{"name":"string"},"description":"URL for an iframe rendered between the header and body/footer.\nShows a non-interactive preview by default; the user can expand\nit to interact with the iframe content."},"iframeTitle":{"required":false,"tsType":{"name":"string"},"description":"Title attribute for the iframe (accessibility).\n@default ''","defaultValue":{"value":"''","computed":false}},"iframePreviewHeight":{"required":false,"tsType":{"name":"number"},"description":"Height of the iframe preview in collapsed mode.\nExpanding opens a fullscreen overlay covering the entire window.\n@default 200","defaultValue":{"value":"200","computed":false}},"sx":{"required":false,"tsType":{"name":"SxProps","elements":[{"name":"Theme"}],"raw":"SxProps<Theme>"},"description":"Override styles for the root container."}}},"docs":{"ai-suite-beta-agenticcard--docs":{"id":"ai-suite-beta-agenticcard--docs","name":"Docs","path":"./src/stories/ui-components/AgenticCard.mdx","title":"AI-SUITE (Beta)/AgenticCard","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AgenticCardStories from './AgenticCard.stories';\nimport { AgenticCard } from '../../components/AgenticCard';\n\n<Meta of={AgenticCardStories} />\n\n# AgenticCard\n\n## Overview\n\n`AgenticCard` is a Signal Design System component purpose-built for agentic chat flows. It renders a structured content card with a gray title header, an optional body area for rich content or images, an optional footer with action buttons, and an optional message-actions bar (copy / thumbs-up / thumbs-down).\n\n```tsx\nimport {\n  AgenticCard,\n  MessageActions,\n  Button,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n`MessageActions` is a companion component exported from the same module. It can be used standalone below any agent message, or it is rendered automatically by `AgenticCard` when feedback callbacks are supplied.\n\n**When to use**\n\n- Displaying structured agent output (blueprints, test results, checklists) inside a chat thread\n- Cards with a clear title, rich body content, and optional call-to-action buttons\n- Visual previews (image) with associated actions (e.g. \"Open Business Journey\")\n- Any agent response that needs copy / thumbs-up / thumbs-down feedback actions\n\n**When not to use**\n\n- Simple inline text responses → render plain `Typography`\n- Collapsible thinking/processing steps → use `AgenticSteps`\n- Interactive clarification prompts with quick-reply options → use `MessageComposer`\n- General-purpose UI cards → use `Card`\n- Editable form content → use `Drawer` or page layout\n\n## Anatomy\n\n```\nAgenticCard (root)\n├── Card container (bordered, shadowed, rounded)\n│   ├── Header (gray bg, title + optional headerAction)\n│   ├── Image (optional, full-width)\n│   ├── Body (optional, rich content via children)\n│   └── Footer (optional, divider + right-aligned actions)\n└── MessageActions (optional, copy / thumbs-up / thumbs-down)\n```\n\n## Props\n\n### AgenticCardProps\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `title` | `string` | — | **Required.** Title displayed in the gray header bar. |\n| `children` | `ReactNode` | — | Body content — rich text, images, or any React node. |\n| `headerAction` | `ReactNode` | — | Action element rendered to the right of the title in the header. Typically a small outlined `Button`. |\n| `actions` | `ReactNode` | — | Footer buttons rendered right-aligned below a divider. |\n| `imageSrc` | `string` | — | Full-width image rendered between header and body. |\n| `imageAlt` | `string` | `''` | Alt text for the image. |\n| `onCopy` | `() => void` | — | When provided, renders a copy icon button below the card. |\n| `onThumbsUp` | `() => void` | — | When provided, renders a thumbs-up icon button below the card. |\n| `onThumbsDown` | `() => void` | — | When provided, renders a thumbs-down icon button below the card. |\n| `sx` | `SxProps<Theme>` | — | Override styles for the root container. |\n\n### MessageActionsProps\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `onCopy` | `() => void` | — | Called when copy is clicked. |\n| `onThumbsUp` | `() => void` | — | Called when thumbs-up is clicked. |\n| `onThumbsDown` | `() => void` | — | Called when thumbs-down is clicked. |\n| `sx` | `SxProps<Theme>` | — | Override styles. |\n\n<ArgTypes of={AgenticCard} />\n\n## Variants\n\n| Variant | Key props | Story |\n|---------|-----------|-------|\n| Rich text with CTA | `title`, `children`, `actions` (contained `Button`) | `CampaignBlueprint` |\n| Image preview with CTA | `title`, `imageSrc`, `actions` | `WithImagePreview` |\n| Edit action | `title`, `children`, `actions` (outlined `Button` with icon) | `WithEditAction` |\n| Header action | `title`, `headerAction`, `children` | `WithHeaderAction` |\n| Title + actions only | `title`, `actions` | `Minimal` |\n| Content only | `title`, `children` | `ContentOnly` |\n| With feedback strip | `title`, `children`, `actions`, `onCopy`, `onThumbsUp`, `onThumbsDown` | `WithMessageActions` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Default | Provide `title` | Card always shows header |\n| With body | Provide `children` | Rich text, lists, or any React node |\n| With image | Provide `imageSrc` | Full-width image below header |\n| With footer | Provide `actions` | Divider + right-aligned buttons |\n| With header button | Provide `headerAction` | Inline button next to title |\n| With feedback | Provide `onCopy` / `onThumbsUp` / `onThumbsDown` | Icon bar below card |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| CTA action | `actions` slot with `Button` | `CampaignBlueprint` |\n| Header-level action | `headerAction` slot with small `Button` | `WithHeaderAction` |\n| Visual preview | `imageSrc` for image, `actions` for navigation | `WithImagePreview` |\n| Feedback collection | `onCopy`, `onThumbsUp`, `onThumbsDown` callbacks | `WithMessageActions` |\n| Standalone feedback | `MessageActions` component outside of card | `StandaloneMessageActions` |\n\nThe card does not manage any internal state. All interactions (button clicks, feedback) are controlled via callback props.\n\n## Stories\n\n### CampaignBlueprint\n\n**Story ID:** `ui-components-agenticcard--campaign-blueprint`\n\nRich text body with structured headings and bullet lists, and a primary \"Start Building The Journey\" button in the footer.\n\n**Recommended usage:** Agent-generated blueprints, plans, or structured analysis output.\n\n<Canvas of={AgenticCardStories.CampaignBlueprint} />\n\n### WithImagePreview\n\n**Story ID:** `ui-components-agenticcard--with-image-preview`\n\nImage preview between header and footer with a primary CTA button.\n\n**Recommended usage:** Visual previews such as journey flow diagrams or generated assets.\n\n<Canvas of={AgenticCardStories.WithImagePreview} />\n\n### WithEditAction\n\n**Story ID:** `ui-components-agenticcard--with-edit-action`\n\nRich text body with an outlined \"Edit\" button (with icon) in the footer.\n\n**Recommended usage:** Previously generated content that the user can revise.\n\n<Canvas of={AgenticCardStories.WithEditAction} />\n\n### WithHeaderAction\n\n**Story ID:** `ui-components-agenticcard--with-header-action`\n\nSmall outlined button in the header alongside the title. Body shows test results.\n\n**Recommended usage:** Secondary actions scoped to the card header (e.g. \"Detailed Report\", \"Export\").\n\n<Canvas of={AgenticCardStories.WithHeaderAction} />\n\n### Minimal\n\n**Story ID:** `ui-components-agenticcard--minimal`\n\nTitle header and footer actions only, no body content.\n\n**Recommended usage:** Generated artifacts that only require a download or navigation action.\n\n### ContentOnly\n\n**Story ID:** `ui-components-agenticcard--content-only`\n\nTitle and body content, no footer or header actions.\n\n**Recommended usage:** Informational agent output with no required user action.\n\n### WithMessageActions\n\n**Story ID:** `ui-components-agenticcard--with-message-actions`\n\nCard with copy, thumbs-up, and thumbs-down feedback icons below.\n\n**Recommended usage:** Any agent-generated card where feedback collection is enabled.\n\n### StandaloneMessageActions\n\n**Story ID:** `ui-components-agenticcard--standalone-message-actions`\n\n`MessageActions` used independently below plain text (outside of `AgenticCard`).\n\n**Recommended usage:** Feedback strip below simple text agent responses.\n\n## Accessibility\n\n- The card container uses semantic `Box` elements. Add `role=\"region\"` and `aria-label` if the card represents a distinct content landmark.\n- Header title is rendered as `Typography variant=\"subtitle2\"` — consider wrapping in a heading element for screen readers in complex pages.\n- Footer and header action buttons inherit standard MUI `Button` accessibility (focusable, keyboard-operable).\n- `MessageActions` icon buttons include `aria-label` attributes (\"Copy\", \"Thumbs up\", \"Thumbs down\").\n- Images include `alt` text via the `imageAlt` prop.\n\n## Best Practices\n\n- Use `title` to clearly identify the card content (e.g. \"Campaign Blueprint\", \"Sandbox Test Results\").\n- Provide a single primary CTA in `actions` — avoid overloading the footer with many buttons.\n- Use `headerAction` for secondary, context-specific actions (e.g. export, detailed report).\n- Use `imageSrc` for meaningful visual previews, not decorative images.\n- Supply `imageAlt` when `imageSrc` is provided.\n- Use feedback callbacks (`onCopy`, `onThumbsUp`, `onThumbsDown`) consistently across all agent cards.\n- Use `MessageActions` standalone when feedback is needed on plain text messages.\n- Import from `@exotel-npm-dev/signal-design-system`, not from internal paths.\n\n## Anti-patterns\n\n- Using `AgenticCard` for interactive forms — use `Drawer` or page layouts.\n- Nesting `AgenticCard` inside `AgenticCard`.\n- Using `AgenticCard` for collapsible thinking steps — use `AgenticSteps`.\n- Hardcoding card widths — let the parent container control width.\n- Omitting `title` — the header is always rendered.\n- Using raw MUI `Card` for agentic chat content — use `AgenticCard` for consistent styling.\n\n## Guidance for AI Agents\n\n### When to choose `AgenticCard`\n\n- Structured agent output (blueprints, checklists, test results) in a chat thread\n- Visual preview cards (images + CTA buttons) for generated assets\n- Any card requiring copy / thumbs-up / thumbs-down feedback\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Collapsible thinking/processing steps | `AgenticSteps` |\n| Quick-reply clarification prompt | `MessageComposer` |\n| General-purpose card | `Card` |\n| Plain text agent message | `Typography` |\n| Editable form in an overlay | `Drawer` |\n\n### Preferred composition patterns\n\n```tsx\n// Rich text with CTA — story: CampaignBlueprint\n<AgenticCard\n  title=\"Campaign Blueprint\"\n  actions={<Button variant=\"contained\">Start Building The Journey</Button>}\n>\n  <Typography variant=\"body2\" fontWeight=\"bold\">1. Core Parameters</Typography>\n  <ul><li>Primary Objective: ...</li></ul>\n</AgenticCard>\n\n// Image preview — story: WithImagePreview\n<AgenticCard\n  title=\"Business Journey\"\n  imageSrc=\"/preview.png\"\n  imageAlt=\"Journey flow\"\n  actions={<Button variant=\"contained\">Open Business Journey</Button>}\n/>\n\n// Header action — story: WithHeaderAction\n<AgenticCard\n  title=\"Sandbox Test Results\"\n  headerAction={\n    <Button variant=\"outlined\" size=\"small\" startIconProps={{ name: 'clipboard-text', size: 'sm' }}>\n      Detailed Report\n    </Button>\n  }\n>\n  {/* test results */}\n</AgenticCard>\n\n// With feedback — story: WithMessageActions\n<AgenticCard\n  title=\"Analysis\"\n  onCopy={() => copyToClipboard()}\n  onThumbsUp={() => sendFeedback('positive')}\n  onThumbsDown={() => sendFeedback('negative')}\n>\n  <Typography variant=\"body2\">Content here</Typography>\n</AgenticCard>\n\n// Standalone feedback strip\n<Typography variant=\"body2\">Plain agent response text</Typography>\n<MessageActions onCopy={handleCopy} onThumbsUp={handleUp} onThumbsDown={handleDown} />\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Rich text + CTA | `CampaignBlueprint` |\n| Image preview | `WithImagePreview` |\n| Edit action footer | `WithEditAction` |\n| Header button | `WithHeaderAction` |\n| Title + action only | `Minimal` |\n| Content only | `ContentOnly` |\n| Feedback bar | `WithMessageActions` |\n| Standalone feedback | `StandaloneMessageActions` |\n\n### Common mistakes to avoid\n\n- Importing `Card` from `@mui/material` for agentic content — use `AgenticCard`.\n- Forgetting to use `startIconProps` instead of the deprecated `startIcon` on Signal `Button`.\n- Omitting `ExotelThemeProvider` in app setup.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|-------------|\n| `MessageActions` | Companion feedback strip (copy / thumbs-up / thumbs-down) |\n| `AgenticSteps` | Collapsible processing steps (thinking/analysis) |\n| `MessageComposer` | Inline clarification prompt with quick replies |\n| `ChatInputBox` | Text input composer for agentic chat |\n| `Button` | Used in `actions`, `headerAction` slots |\n| `Typography` | Used for body content |\n| `Card` | General-purpose card (not for agentic flows) |\n"}}},"ai-suite-beta-agenticsteps":{"id":"ai-suite-beta-agenticsteps","name":"AgenticSteps","path":"./src/stories/ui-components/AgenticSteps.stories.tsx","stories":[{"id":"ai-suite-beta-agenticsteps--loading","name":"Loading","snippet":"const Loading = () => (\n  <Box sx={{ width: 684 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Thinking\" status=\"loading\" defaultExpanded={false} />\n    </AgenticSteps>\n  </Box>\n);","description":"Loading state — StepHeader shows animated dots, collapsed with no visible steps. Matches the Figma \"Thinking\" initial state."},{"id":"ai-suite-beta-agenticsteps--loading-with-steps","name":"Loading With Steps","snippet":"const LoadingWithSteps = () => (\n  <Box sx={{ width: 684 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Thinking\" status=\"loading\">\n        <AgenticStep id=\"step-1\" title=\"Analysing Request\" status=\"loading\" />\n      </StepHeader>\n    </AgenticSteps>\n  </Box>\n);","description":"Loading with steps — StepHeader expanded, showing steps in progress. Matches the Figma expanded \"Thinking\" with \"Analysing Request\" step."},{"id":"ai-suite-beta-agenticsteps--step-with-result-content","name":"Step With Result Content","snippet":"const StepWithResultContent = () => (\n  <Box sx={{ width: 684 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Thinking\" status=\"loading\">\n        <AgenticStep\n          id=\"step-1\"\n          title=\"Analysing Request\"\n          status=\"success\"\n          defaultExpanded\n          resultContent={\n            <>\n              <p>Evaluating core business objectives, guardrails, and scope boundaries...</p>\n              <ul>\n                <li>\n                  Goal Extraction: Funnel recovery for HDFC Securities Demat Account opening.\n                </li>\n                <li>\n                  Performance Baseline: Current conversion: 12% → Target conversion: 20% (+8% Lift\n                  target).\n                </li>\n                <li>Financial Constraints: Absolute budget ceiling allocated at ₹8 per lead.</li>\n                <li>\n                  Regulatory Boundaries: TRAI compliance — strict filter required for National\n                  Consumer Preference Register (NCPR) DND records on promotional SMS pathways.\n                  <ul>\n                    <li>\n                      Operational timing windows: Voice restricted to 09:00 AM - 07:00 PM IST;\n                      Digital (SMS/WhatsApp) restricted to 09:00 AM - 08:00 PM IST.\n                    </li>\n                  </ul>\n                </li>\n                <li>\n                  Missing Parameters Detected: Journey exit timeout duration not specified for\n                  cold/unresponsive cohorts.\n                </li>\n              </ul>\n              <p>\n                Analysis concluded. Handing off to orchestrator for clarification prompt\n                generation...\n              </p>\n            </>\n          }\n        />\n        <AgenticStep id=\"step-2\" title=\"Building Execution Plan\" status=\"loading\" />\n      </StepHeader>\n    </AgenticSteps>\n  </Box>\n);","description":"Step with expanded result content — the step shows detailed analysis output. Matches the Figma design with bullet-point analysis results."},{"id":"ai-suite-beta-agenticsteps--success","name":"Success","snippet":"const Success = () => (\n  <Box sx={{ width: 684 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Thinking\" status=\"success\" defaultExpanded={false} />\n    </AgenticSteps>\n  </Box>\n);","description":"Success state — StepHeader shows a green check icon, collapsed. Matches the Figma \"Thinking\" completed state."},{"id":"ai-suite-beta-agenticsteps--success-expanded","name":"Success Expanded","snippet":"const SuccessExpanded = () => (\n  <Box sx={{ width: 684 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Thinking\" status=\"success\">\n        <AgenticStep\n          id=\"step-1\"\n          title=\"Analysing Request\"\n          status=\"success\"\n          resultContent={\n            <>\n              <p>Evaluating core business objectives, guardrails, and scope boundaries...</p>\n              <ul>\n                <li>Goal Extraction: Funnel recovery for Demat Account opening.</li>\n                <li>Performance Baseline: Current conversion: 12% → Target: 20%.</li>\n                <li>Financial Constraints: Budget ceiling at ₹8 per lead.</li>\n              </ul>\n              <p>Analysis concluded.</p>\n            </>\n          }\n        />\n        <AgenticStep\n          id=\"step-2\"\n          title=\"Building Execution Plan\"\n          status=\"success\"\n          resultContent={\n            <p>\n              Execution plan generated with 3 stages: SMS outreach → WhatsApp follow-up → Voice\n              callback.\n            </p>\n          }\n        />\n      </StepHeader>\n    </AgenticSteps>\n  </Box>\n);","description":"Success with all steps completed and expanded."},{"id":"ai-suite-beta-agenticsteps--failure","name":"Failure","snippet":"const Failure = () => (\n  <Box sx={{ width: 684 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Thinking\" status=\"failure\" defaultExpanded={false} />\n    </AgenticSteps>\n  </Box>\n);","description":"Failure state — StepHeader shows an error icon."},{"id":"ai-suite-beta-agenticsteps--failure-with-steps","name":"Failure With Steps","snippet":"const FailureWithSteps = () => (\n  <Box sx={{ width: 684 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Thinking\" status=\"failure\">\n        <AgenticStep\n          id=\"step-1\"\n          title=\"Analysing Request\"\n          status=\"success\"\n          resultContent={<p>Analysis completed successfully.</p>}\n        />\n        <AgenticStep\n          id=\"step-2\"\n          title=\"Building Execution Plan\"\n          status=\"failure\"\n          defaultExpanded\n          resultContent={\n            <Typography color=\"error\" variant=\"body2\">\n              Failed to generate execution plan. Insufficient data for audience segmentation.\n            </Typography>\n          }\n        />\n      </StepHeader>\n    </AgenticSteps>\n  </Box>\n);","description":"Failure with step detail — one step failed while another succeeded."},{"id":"ai-suite-beta-agenticsteps--interactive","name":"Interactive","snippet":"const Interactive = () => {\n  const [headerStatus, setHeaderStatus] = useState<'loading' | 'success' | 'failure'>('loading');\n  const [step1Status, setStep1Status] = useState<'loading' | 'success' | 'failure'>('loading');\n  const [step2Status, setStep2Status] = useState<'loading' | 'success' | 'failure'>('loading');\n\n  return (\n    <Box sx={{ width: 684, display: 'flex', flexDirection: 'column', gap: 3 }}>\n      <Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>\n        <Typography variant=\"body2\" sx={{ width: '100%', fontWeight: 600 }}>\n          Header Status:\n        </Typography>\n        <Button\n          size=\"small\"\n          variant={headerStatus === 'loading' ? 'contained' : 'outlined'}\n          onClick={() => setHeaderStatus('loading')}\n        >\n          Loading\n        </Button>\n        <Button\n          size=\"small\"\n          variant={headerStatus === 'success' ? 'contained' : 'outlined'}\n          color=\"success\"\n          onClick={() => setHeaderStatus('success')}\n        >\n          Success\n        </Button>\n        <Button\n          size=\"small\"\n          variant={headerStatus === 'failure' ? 'contained' : 'outlined'}\n          color=\"error\"\n          onClick={() => setHeaderStatus('failure')}\n        >\n          Failure\n        </Button>\n      </Box>\n      <Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>\n        <Typography variant=\"body2\" sx={{ width: '100%', fontWeight: 600 }}>\n          Step 1 Status:\n        </Typography>\n        <Button\n          size=\"small\"\n          variant={step1Status === 'loading' ? 'contained' : 'outlined'}\n          onClick={() => setStep1Status('loading')}\n        >\n          Loading\n        </Button>\n        <Button\n          size=\"small\"\n          variant={step1Status === 'success' ? 'contained' : 'outlined'}\n          color=\"success\"\n          onClick={() => setStep1Status('success')}\n        >\n          Success\n        </Button>\n        <Button\n          size=\"small\"\n          variant={step1Status === 'failure' ? 'contained' : 'outlined'}\n          color=\"error\"\n          onClick={() => setStep1Status('failure')}\n        >\n          Failure\n        </Button>\n      </Box>\n      <Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>\n        <Typography variant=\"body2\" sx={{ width: '100%', fontWeight: 600 }}>\n          Step 2 Status:\n        </Typography>\n        <Button\n          size=\"small\"\n          variant={step2Status === 'loading' ? 'contained' : 'outlined'}\n          onClick={() => setStep2Status('loading')}\n        >\n          Loading\n        </Button>\n        <Button\n          size=\"small\"\n          variant={step2Status === 'success' ? 'contained' : 'outlined'}\n          color=\"success\"\n          onClick={() => setStep2Status('success')}\n        >\n          Success\n        </Button>\n        <Button\n          size=\"small\"\n          variant={step2Status === 'failure' ? 'contained' : 'outlined'}\n          color=\"error\"\n          onClick={() => setStep2Status('failure')}\n        >\n          Failure\n        </Button>\n      </Box>\n\n      <AgenticSteps>\n        <StepHeader title=\"Thinking\" status={headerStatus}>\n          <AgenticStep\n            id=\"step-1\"\n            title=\"Analysing Request\"\n            status={step1Status}\n            resultContent={\n              <>\n                <p>Evaluating core business objectives, guardrails, and scope boundaries...</p>\n                <ul>\n                  <li>Goal Extraction: Funnel recovery for Demat Account opening.</li>\n                  <li>Performance Baseline: 12% → 20% target conversion.</li>\n                  <li>Budget ceiling: ₹8 per lead.</li>\n                </ul>\n                <p>Analysis concluded.</p>\n              </>\n            }\n          />\n          <AgenticStep\n            id=\"step-2\"\n            title=\"Building Execution Plan\"\n            status={step2Status}\n            resultContent={\n              <p>\n                3-stage execution plan: SMS outreach → WhatsApp follow-up → Voice callback for\n                high-intent leads.\n              </p>\n            }\n          />\n        </StepHeader>\n      </AgenticSteps>\n    </Box>\n  );\n};","description":"Interactive demo — toggle step status and expand/collapse states."},{"id":"ai-suite-beta-agenticsteps--multiple-headers","name":"Multiple Headers","snippet":"const MultipleHeaders = () => (\n  <Box sx={{ width: 684, display: 'flex', flexDirection: 'column', gap: 2 }}>\n    <AgenticSteps>\n      <StepHeader title=\"Understanding Requirements\" status=\"success\" defaultExpanded={false} />\n    </AgenticSteps>\n    <AgenticSteps>\n      <StepHeader title=\"Building Campaign\" status=\"loading\">\n        <AgenticStep\n          id=\"step-1\"\n          title=\"Selecting Channels\"\n          status=\"success\"\n          resultContent={<p>SMS + WhatsApp selected based on budget and reach analysis.</p>}\n        />\n        <AgenticStep id=\"step-2\" title=\"Generating Templates\" status=\"loading\" />\n      </StepHeader>\n    </AgenticSteps>\n  </Box>\n);","description":"Multiple headers — shows multiple sequential thinking phases."}],"import":"import { AgenticStep, AgenticSteps, Box, Button, StepHeader, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"description":"AgenticSteps — container for StepHeader + AgenticStep components. Renders a bordered, rounded card that groups a collapsible header (showing overall status) with individual processing steps. ```tsx <AgenticSteps> <StepHeader title=\"Thinking\" status=\"loading\"> <AgenticStep id=\"1\" title=\"Analysing Request\" status=\"loading\" /> <AgenticStep id=\"2\" title=\"Building Plan\" status=\"success\" resultContent={<p>Done</p>} /> </StepHeader> </AgenticSteps> ```","reactDocgen":{"description":"AgenticSteps — container for StepHeader + AgenticStep components.\n\nRenders a bordered, rounded card that groups a collapsible header\n(showing overall status) with individual processing steps.\n\n```tsx\n<AgenticSteps>\n  <StepHeader title=\"Thinking\" status=\"loading\">\n    <AgenticStep id=\"1\" title=\"Analysing Request\" status=\"loading\" />\n    <AgenticStep id=\"2\" title=\"Building Plan\" status=\"success\" resultContent={<p>Done</p>} />\n  </StepHeader>\n</AgenticSteps>\n```","methods":[],"displayName":"AgenticSteps","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/AgenticSteps/AgenticSteps.tsx","actualName":"AgenticSteps","exportName":"AgenticSteps","props":{"sx":{"required":false,"tsType":{"name":"SxProps","elements":[{"name":"Theme"}],"raw":"SxProps<Theme>"},"description":"Override styles for the root container"},"children":{"required":false,"tsType":{"name":"ReactNode"},"description":"Child StepHeader and Step components"}}},"docs":{"ai-suite-beta-agenticsteps--docs":{"id":"ai-suite-beta-agenticsteps--docs","name":"Docs","path":"./src/stories/ui-components/AgenticSteps.mdx","title":"AI-SUITE (Beta)/AgenticSteps","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as AgenticStepsStories from './AgenticSteps.stories';\nimport { AgenticSteps } from '../../components/AgenticSteps';\n\n<Meta of={AgenticStepsStories} />\n\n# AgenticSteps\n\n## Overview\n\n`AgenticSteps` displays AI processing stages in agentic chat flows. It renders a bordered, rounded card that groups a collapsible `StepHeader` (showing overall status) with individual `AgenticStep` components — each supporting loading, success, and failure states.\n\n```tsx\nimport {\n  AgenticSteps,\n  StepHeader,\n  AgenticStep,\n} from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n`StepHeader` and `AgenticStep` are companion components exported from the same module. They are designed to be composed as children of `AgenticSteps`.\n\n**When to use**\n\n- Showing AI \"thinking\" or processing progress in a chat thread\n- Multi-step analysis or plan generation with per-step status indicators\n- Collapsible result content for completed processing steps\n- Sequential agent operations where users need visibility into progress\n\n**When not to use**\n\n- Structured output cards with body content and CTA buttons → use `AgenticCard`\n- Sequential user-driven workflows (wizards) → use `Stepper`\n- Quick-reply clarification prompts → use `MessageComposer`\n- Simple loading indicators → use `CircularProgress` or `LinearProgress`\n\n## Anatomy\n\n```\nAgenticSteps (root container — bordered, rounded)\n└── StepHeader (collapsible header with status icon + title)\n    ├── AgenticStep (individual step row with status + collapsible result)\n    ├── AgenticStep\n    └── ...\n```\n\nMultiple `AgenticSteps` can be stacked vertically to represent sequential processing phases (e.g. \"Understanding Requirements\" followed by \"Building Campaign\").\n\n## Props\n\n### AgenticStepsProps\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `children` | `ReactNode` | — | Child `StepHeader` and `AgenticStep` components. |\n| `sx` | `SxProps<Theme>` | — | Override styles for the root container. |\n\n### StepHeaderProps\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `title` | `string` | — | **Required.** Title displayed in the header (e.g. \"Thinking\"). |\n| `status` | `'loading' \\| 'success' \\| 'failure'` | `'loading'` | Current status. Controls the icon: spinner (loading), green check (success), red X (failure). |\n| `defaultExpanded` | `boolean` | `true` | Whether child steps are visible on mount (uncontrolled). |\n| `expanded` | `boolean` | — | Controlled expanded state. |\n| `onExpandChange` | `(expanded: boolean) => void` | — | Callback when expand state changes. |\n| `children` | `ReactNode` | — | Child `AgenticStep` components. |\n| `sx` | `SxProps<Theme>` | — | Override styles. |\n\n### AgenticStepProps\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `id` | `string` | — | **Required.** Unique identifier for the step. |\n| `title` | `string` | — | **Required.** Title displayed in the step row. |\n| `status` | `'loading' \\| 'success' \\| 'failure'` | `'loading'` | Current status. Controls the icon: spinner, check, or X. |\n| `defaultExpanded` | `boolean` | `false` | Whether result content is visible on mount (uncontrolled). |\n| `expanded` | `boolean` | — | Controlled expanded state. |\n| `onExpandChange` | `(expanded: boolean) => void` | — | Callback when expand state changes. |\n| `resultContent` | `ReactNode` | — | Content shown when the step is expanded. When absent, the step is not expandable. |\n| `sx` | `SxProps<Theme>` | — | Override styles. |\n\n<ArgTypes of={AgenticSteps} />\n\n## Variants\n\n| Variant | Key props | Story |\n|---------|-----------|-------|\n| Loading header only | `StepHeader` with `status=\"loading\"` | `Loading` |\n| Loading with steps | `StepHeader` + `AgenticStep` children | `LoadingWithSteps` |\n| Step with result content | `AgenticStep` with `resultContent` + `defaultExpanded` | `StepWithResultContent` |\n| All success | `status=\"success\"` on header and all steps | `SuccessExpanded` |\n| Failure | `status=\"failure\"` on header | `Failure` |\n| Partial failure | Mixed step statuses | `FailureWithSteps` |\n| Multiple sequential phases | Multiple `AgenticSteps` stacked | `MultipleHeaders` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Loading | `status=\"loading\"` | Spinner icon, animated dots in header |\n| Success | `status=\"success\"` | Green check icon |\n| Failure | `status=\"failure\"` | Red X icon |\n| Collapsed | `defaultExpanded={false}` or user click | Steps hidden |\n| Expanded | `defaultExpanded={true}` or user click | Steps visible |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Collapsed thinking | `StepHeader` with `defaultExpanded={false}` | `Loading` |\n| Expanded with steps | `StepHeader` with child `AgenticStep` components | `LoadingWithSteps` |\n| Expandable result | `AgenticStep` with `resultContent` — click to expand/collapse | `StepWithResultContent` |\n| Controlled status | Pass `status` to update in real time as processing progresses | `Interactive` |\n| Sequential phases | Stack multiple `AgenticSteps` containers | `MultipleHeaders` |\n\nSteps without `resultContent` are not expandable — clicking has no effect. The caret-down icon only appears when `resultContent` is present.\n\n`StepHeader` defaults to `defaultExpanded={true}` so child steps are visible during processing. Set `defaultExpanded={false}` for completed phases that should collapse.\n\n## Stories\n\n### Loading\n\n**Story ID:** `ui-components-agenticsteps--loading`\n\nSingle `StepHeader` with `status=\"loading\"` and no child steps. Collapsed view.\n\n**Recommended usage:** Initial \"Thinking\" state before any steps begin.\n\n<Canvas of={AgenticStepsStories.Loading} />\n\n### LoadingWithSteps\n\n**Story ID:** `ui-components-agenticsteps--loading-with-steps`\n\n`StepHeader` expanded with one `AgenticStep` in loading state.\n\n**Recommended usage:** Active processing with one or more steps visible.\n\n<Canvas of={AgenticStepsStories.LoadingWithSteps} />\n\n### StepWithResultContent\n\n**Story ID:** `ui-components-agenticsteps--step-with-result-content`\n\nOne step completed (success) with expanded bullet-point analysis, another step still loading.\n\n**Recommended usage:** Showing detailed analysis output for a completed step alongside in-progress steps.\n\n<Canvas of={AgenticStepsStories.StepWithResultContent} />\n\n### Success\n\n**Story ID:** `ui-components-agenticsteps--success`\n\n`StepHeader` with `status=\"success\"`, collapsed.\n\n**Recommended usage:** Completed thinking phase, collapsed to save space.\n\n<Canvas of={AgenticStepsStories.Success} />\n\n### SuccessExpanded\n\n**Story ID:** `ui-components-agenticsteps--success-expanded`\n\nAll steps completed (success) with result content visible.\n\n**Recommended usage:** Completed phase with results the user can review.\n\n### Failure\n\n**Story ID:** `ui-components-agenticsteps--failure`\n\n`StepHeader` with `status=\"failure\"`, collapsed.\n\n**Recommended usage:** Failed processing phase indicator.\n\n### FailureWithSteps\n\n**Story ID:** `ui-components-agenticsteps--failure-with-steps`\n\nOne step succeeded, another step failed with an error message.\n\n**Recommended usage:** Partial failure where the user needs to see which step failed.\n\n<Canvas of={AgenticStepsStories.FailureWithSteps} />\n\n### Interactive\n\n**Story ID:** `ui-components-agenticsteps--interactive`\n\nButtons to toggle header and step statuses. Demonstrates controlled state.\n\n**Recommended usage:** Testing and prototyping status transitions.\n\n### MultipleHeaders\n\n**Story ID:** `ui-components-agenticsteps--multiple-headers`\n\nTwo stacked `AgenticSteps` containers representing sequential phases.\n\n**Recommended usage:** Multi-phase agent processing (e.g. \"Understanding Requirements\" → \"Building Campaign\").\n\n<Canvas of={AgenticStepsStories.MultipleHeaders} />\n\n## Accessibility\n\n- `StepHeader` and `AgenticStep` headers are clickable `Box` elements. They receive `cursor: pointer` when expandable.\n- Status icons convey meaning via color (spinner = loading, green check = success, red X = failure). Pair with text labels for color-blind users.\n- `Collapse` transition uses MUI `Collapse` with `unmountOnExit` to remove hidden content from the DOM.\n- The expand/collapse caret icon rotates 180° as a visual indicator.\n- Consider adding `aria-expanded` and `role=\"button\"` to clickable headers for enhanced screen reader support.\n\n## Best Practices\n\n- Use descriptive step titles (e.g. \"Analysing Request\", \"Building Execution Plan\") instead of generic labels.\n- Update `status` in real time as processing progresses — don't wait until all steps complete.\n- Use `resultContent` to show meaningful analysis output, not just \"Done\".\n- Collapse completed phases (`defaultExpanded={false}`) to keep the chat thread readable.\n- Stack multiple `AgenticSteps` for sequential agent phases rather than nesting.\n- Use `Typography` with `color=\"error\"` in `resultContent` for failure details.\n\n## Anti-patterns\n\n- Nesting `AgenticSteps` inside `AgenticSteps`.\n- Using `AgenticSteps` for structured output with CTA buttons — use `AgenticCard`.\n- Omitting `id` on `AgenticStep` — it is required.\n- Using `AgenticSteps` for user-driven wizard flows — use `Stepper`.\n- Hardcoding status values — drive from real-time processing state.\n- Using `CircularProgress` directly in chat threads — use `AgenticSteps` for structured step progress.\n\n## Guidance for AI Agents\n\n### When to choose `AgenticSteps`\n\n- AI \"thinking\" or processing progress indicators\n- Multi-step analysis, plan generation, or data processing\n- Collapsible result content for completed steps\n- Sequential agent operations with per-step visibility\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Structured output card with CTA | `AgenticCard` |\n| Clarification prompt with options | `MessageComposer` |\n| User-driven wizard steps | `Stepper` |\n| Simple loading spinner | `CircularProgress` |\n| Simple progress bar | `LinearProgress` |\n\n### Preferred composition patterns\n\n```tsx\n// Basic thinking — story: Loading\n<AgenticSteps>\n  <StepHeader title=\"Thinking\" status=\"loading\" defaultExpanded={false} />\n</AgenticSteps>\n\n// Active processing — story: LoadingWithSteps\n<AgenticSteps>\n  <StepHeader title=\"Thinking\" status=\"loading\">\n    <AgenticStep id=\"1\" title=\"Analysing Request\" status=\"loading\" />\n  </StepHeader>\n</AgenticSteps>\n\n// With result content — story: StepWithResultContent\n<AgenticSteps>\n  <StepHeader title=\"Thinking\" status=\"loading\">\n    <AgenticStep\n      id=\"1\"\n      title=\"Analysing Request\"\n      status=\"success\"\n      defaultExpanded\n      resultContent={\n        <>\n          <p>Analysis results...</p>\n          <ul><li>Finding 1</li><li>Finding 2</li></ul>\n        </>\n      }\n    />\n    <AgenticStep id=\"2\" title=\"Building Plan\" status=\"loading\" />\n  </StepHeader>\n</AgenticSteps>\n\n// Multiple phases — story: MultipleHeaders\n<AgenticSteps>\n  <StepHeader title=\"Understanding Requirements\" status=\"success\" defaultExpanded={false} />\n</AgenticSteps>\n<AgenticSteps>\n  <StepHeader title=\"Building Campaign\" status=\"loading\">\n    <AgenticStep id=\"1\" title=\"Selecting Channels\" status=\"success\" />\n    <AgenticStep id=\"2\" title=\"Generating Templates\" status=\"loading\" />\n  </StepHeader>\n</AgenticSteps>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Initial thinking state | `Loading` |\n| Active steps | `LoadingWithSteps` |\n| Results with analysis | `StepWithResultContent` |\n| Completed phase | `Success` / `SuccessExpanded` |\n| Error state | `Failure` / `FailureWithSteps` |\n| Sequential phases | `MultipleHeaders` |\n| Status toggling | `Interactive` |\n\n### Common mistakes to avoid\n\n- Using `AgenticStep` outside of `StepHeader` — steps must be children of `StepHeader`.\n- Omitting `id` on `AgenticStep`.\n- Using `AgenticSteps` for output cards — use `AgenticCard`.\n- Importing from `@mui/material` — use `@exotel-npm-dev/signal-design-system`.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|-------------|\n| `StepHeader` | Collapsible header with status icon (companion) |\n| `AgenticStep` | Individual step row with status and result content (companion) |\n| `AgenticCard` | Structured output card for agentic flows |\n| `MessageComposer` | Inline clarification prompt |\n| `ChatInputBox` | Text input composer for agentic chat |\n| `Stepper` | User-driven sequential wizard |\n| `CircularProgress` | Simple loading spinner |\n"}}},"ai-suite-beta-chatinputbox":{"id":"ai-suite-beta-chatinputbox","name":"ChatInputBox","path":"./src/stories/ui-components/ChatInputBox.stories.tsx","stories":[{"id":"ai-suite-beta-chatinputbox--default","name":"Default","snippet":"const Default = () => <ChatInputBox\n    placeholder=\"Type @ to select processes, campaigns and queues you want to configure\"\n    maxLength={200} />;"},{"id":"ai-suite-beta-chatinputbox--with-mention-search","name":"With Mention Search","snippet":"const WithMentionSearch = () => {\n  const Demo = () => {\n    const [value, setValue] = useState('');\n    const [suggestions, setSuggestions] = useState<MentionSuggestion[]>([]);\n    const [loading, setLoading] = useState(false);\n\n    const handleMentionSearch = useCallback((query: string) => {\n      setLoading(true);\n      setTimeout(() => {\n        const filtered = allMembers.filter(\n          (m) => m.label.toLowerCase().includes(query.toLowerCase())\n        );\n        setSuggestions(filtered);\n        setLoading(false);\n      }, 300);\n    }, []);\n\n    const handleMentionSelect = useCallback((suggestion: MentionSuggestion) => {\n      console.log('Mention selected:', suggestion);\n    }, []);\n\n    return (\n      <ChatInputBox\n        value={value}\n        onChange={setValue}\n        mentionSuggestions={suggestions}\n        onMentionSearch={handleMentionSearch}\n        onMentionSelect={handleMentionSelect}\n        mentionLoading={loading}\n        onSend={(text, _atts, mentionsList) => {\n          console.log('Sent:', { text, mentions: mentionsList });\n        }}\n        maxLength={200}\n        placeholder=\"Type @ to mention someone...\"\n      />\n    );\n  };\n  return <Demo />;\n};"},{"id":"ai-suite-beta-chatinputbox--with-attachments","name":"With Attachments","snippet":"const WithAttachments = () => {\n  const Demo = () => {\n    const [attachments, setAttachments] = useState<ChatInputAttachment[]>([\n      { id: '1', name: 'campaign-config.json', type: 'application/json', size: 2400 },\n      { id: '2', name: 'agent-list.csv', type: 'text/csv', size: 15600 },\n    ]);\n\n    return (\n      <ChatInputBox\n        attachments={attachments}\n        onAttach={(files) => {\n          const newAttachments = files.map((file) => ({\n            id: String(Date.now()) + file.name,\n            name: file.name,\n            type: file.type,\n            size: file.size,\n            file,\n          }));\n          setAttachments((prev) => [...prev, ...newAttachments]);\n        }}\n        onRemoveAttachment={(id) => setAttachments((prev) => prev.filter((a) => a.id !== id))}\n        onSend={(text, atts) => {\n          console.log('Sent:', { text, attachments: atts });\n          console.log('Files ready for upload:', atts.map((a) => a.file).filter(Boolean));\n        }}\n        maxLength={200}\n      />\n    );\n  };\n  return <Demo />;\n};"},{"id":"ai-suite-beta-chatinputbox--interactive","name":"Interactive","snippet":"const Interactive = () => {\n  const Demo = () => {\n    const [value, setValue] = useState('');\n    const [attachments, setAttachments] = useState<ChatInputAttachment[]>([]);\n    const [suggestions, setSuggestions] = useState<MentionSuggestion[]>([]);\n    const [loading, setLoading] = useState(false);\n\n    const handleMentionSearch = useCallback((query: string) => {\n      setLoading(true);\n      setTimeout(() => {\n        setSuggestions(\n          allMembers.filter((m) => m.label.toLowerCase().includes(query.toLowerCase()))\n        );\n        setLoading(false);\n      }, 300);\n    }, []);\n\n    const handleMentionSelect = useCallback((suggestion: MentionSuggestion) => {\n      console.log('Mention selected:', suggestion);\n    }, []);\n\n    return (\n      <ChatInputBox\n        value={value}\n        onChange={setValue}\n        attachments={attachments}\n        onAttach={(files) => {\n          const newAttachments = files.map((file) => ({\n            id: String(Date.now()) + file.name,\n            name: file.name,\n            type: file.type,\n            size: file.size,\n            file,\n          }));\n          setAttachments((prev) => [...prev, ...newAttachments]);\n        }}\n        onRemoveAttachment={(id) => setAttachments((prev) => prev.filter((a) => a.id !== id))}\n        mentionSuggestions={suggestions}\n        onMentionSearch={handleMentionSearch}\n        onMentionSelect={handleMentionSelect}\n        mentionLoading={loading}\n        onSend={(text, atts, mentionsList) => {\n          alert(\n            `Sent!\\nText: ${text}\\nAttachments: ${atts.map((a) => a.name).join(', ')}\\nMentions: ${mentionsList.map((m) => m.label).join(', ')}`\n          );\n        }}\n        maxLength={200}\n        placeholder=\"Type @ to mention someone...\"\n      />\n    );\n  };\n  return <Demo />;\n};"},{"id":"ai-suite-beta-chatinputbox--with-voice-input","name":"With Voice Input","snippet":"const WithVoiceInput = () => <ChatInputBox\n    showVoiceInput\n    placeholder=\"Build or ask anything. Type / for commands\"\n    maxLength={200} />;"},{"id":"ai-suite-beta-chatinputbox--disabled","name":"Disabled","snippet":"const Disabled = () => <ChatInputBox disabled placeholder=\"This input is disabled\" maxLength={200} />;"},{"id":"ai-suite-beta-chatinputbox--with-label","name":"With Label","snippet":"const WithLabel = () => <ChatInputBox\n    label=\"Thinking...\"\n    placeholder=\"Build or ask anything. Type / for commands\"\n    maxLength={200}\n    showVoiceInput />;"}],"import":"import { Box, ChatInputBox } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"ChatInputBox","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/ChatInputBox/ChatInputBox.tsx","actualName":"ChatInputBox","exportName":"ChatInputBox","props":{"value":{"required":false,"tsType":{"name":"string"},"description":""},"onChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(value: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"value"}],"return":{"name":"void"}}},"description":""},"onSend":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(value: string, attachments: ChatInputAttachment[], mentions: ChatInputMention[]) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"value"},{"type":{"name":"Array","elements":[{"name":"ChatInputAttachment"}],"raw":"ChatInputAttachment[]"},"name":"attachments"},{"type":{"name":"Array","elements":[{"name":"ChatInputMention"}],"raw":"ChatInputMention[]"},"name":"mentions"}],"return":{"name":"void"}}},"description":""},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"","defaultValue":{"value":"'Type @ to select processes, campaigns and queues you want to configure'","computed":false}},"maxLength":{"required":false,"tsType":{"name":"number"},"description":"","defaultValue":{"value":"200","computed":false}},"attachments":{"required":false,"tsType":{"name":"Array","elements":[{"name":"ChatInputAttachment"}],"raw":"ChatInputAttachment[]"},"description":"","defaultValue":{"value":"[]","computed":false}},"onAttach":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(files: File[]) => void","signature":{"arguments":[{"type":{"name":"Array","elements":[{"name":"File"}],"raw":"File[]"},"name":"files"}],"return":{"name":"void"}}},"description":""},"acceptFileTypes":{"required":false,"tsType":{"name":"string"},"description":""},"allowMultipleFiles":{"required":false,"tsType":{"name":"boolean"},"description":"","defaultValue":{"value":"true","computed":false}},"onRemoveAttachment":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(id: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"id"}],"return":{"name":"void"}}},"description":""},"mentionSuggestions":{"required":false,"tsType":{"name":"Array","elements":[{"name":"MentionSuggestion"}],"raw":"MentionSuggestion[]"},"description":"","defaultValue":{"value":"[]","computed":false}},"onMentionSearch":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(query: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"query"}],"return":{"name":"void"}}},"description":""},"onMentionSelect":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(suggestion: MentionSuggestion) => void","signature":{"arguments":[{"type":{"name":"MentionSuggestion"},"name":"suggestion"}],"return":{"name":"void"}}},"description":""},"mentionLoading":{"required":false,"tsType":{"name":"boolean"},"description":"","defaultValue":{"value":"false","computed":false}},"mentionEmptyText":{"required":false,"tsType":{"name":"string"},"description":"","defaultValue":{"value":"'No results found'","computed":false}},"sendDisabled":{"required":false,"tsType":{"name":"boolean"},"description":""},"disabled":{"required":false,"tsType":{"name":"boolean"},"description":"","defaultValue":{"value":"false","computed":false}},"showVoiceInput":{"required":false,"tsType":{"name":"boolean"},"description":"","defaultValue":{"value":"false","computed":false}},"label":{"required":false,"tsType":{"name":"string"},"description":"Label text displayed above the input box (e.g. status like \"Thinking...\" or \"Live Sandbox Testing...\")"}}},"docs":{"ai-suite-beta-chatinputbox--docs":{"id":"ai-suite-beta-chatinputbox--docs","name":"Docs","path":"./src/stories/ui-components/ChatInputBox.mdx","title":"AI-SUITE (Beta)/ChatInputBox","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ChatInputBoxStories from './ChatInputBox.stories';\nimport { ChatInputBox } from '../../components/ChatInputBox';\n\n<Meta of={ChatInputBoxStories} />\n\n# ChatInputBox\n\n## Overview\n\n`ChatInputBox` is an Exotel-specific composite input for chat-style messaging and configuration flows. It supports multiline text, file attachment chips, `@` mention search with a suggestion popover, character count, and send action.\n\n```tsx\nimport { ChatInputBox } from '@exotel-npm-dev/signal-design-system';\nimport type { ChatInputAttachment, ChatInputMention, MentionSuggestion } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Chat or message compose UIs\n- Mention-based configuration (`@` processes, campaigns, queues, users)\n- Sending text with optional file attachments\n\n**When not to use**\n\n- Standard single-line form fields → `FormField` or `EnhancedTextField`\n- Search-only input without send → `EnhancedTextField` with search adornment\n- Rich text editor → not supported by this component\n\n## Anatomy\n\n```\nChatInputBox (maxWidth 700)\n├── Attachment chips (optional)     ← From attachments[] above textarea\n├── Textarea + @ mention popover   ← Popper with MentionSuggestion list\n├── Character count (maxLength)     ← Shown when maxLength set\n├── Voice input IconButton          ← Shown when showVoiceInput is true\n└── Send IconButton                 ← onSend; disabled when sendDisabled/disabled\n```\n\n## Props\n\n| Name | Type | Description | Usage guidance |\n|------|------|-------------|----------------|\n| `value` | `string` | Controlled text | Pair with `onChange` |\n| `onChange` | `(value: string) => void` | Text change | Parent owns state |\n| `onSend` | `(text, attachments, mentions) => void` | Send handler | Receives final text, attachment list, mention list |\n| `placeholder` | `string` | Placeholder | See stories for ECC copy |\n| `maxLength` | `number` | Character limit | `Default` uses 200 |\n| `attachments` | `ChatInputAttachment[]` | Attachment chips | `{ id, name, size?, type?, file? }` |\n| `onAttach` | `(files: File[]) => void` | File picker callback | Map to `attachments` in parent |\n| `onRemoveAttachment` | `(id: string) => void` | Remove attachment chip | |\n| `acceptFileTypes` | `string` | File input accept | Optional filter |\n| `allowMultipleFiles` | `boolean` | Multi-file attach | |\n| `mentionSuggestions` | `MentionSuggestion[]` | Popover options | Parent filters via `onMentionSearch` |\n| `onMentionSearch` | `(query: string) => void` | Search as user types after `@` | Host/backend filtering |\n| `onMentionSelect` | `(suggestion) => void` | Selection callback | |\n| `mentionLoading` | `boolean` | Loading in popover | |\n| `mentionEmptyText` | `string` | Empty state copy | |\n| `sendDisabled` | `boolean` | Disable send only | |\n| `disabled` | `boolean` | Disable entire input | `Disabled` story |\n| `showVoiceInput` | `boolean` | Show microphone button beside send | `WithVoiceInput` story; default `false` |\n\n### MentionSuggestion shape\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | `string` | Unique id |\n| `label` | `string` | Display name |\n| `secondary` | `string` | Subtitle (email, type) |\n| `avatar` | `string` | Optional avatar URL |\n\n<ArgTypes of={ChatInputBox} />\n\n## Behavior\n\n- Type `@` in the textarea to open mention popover; query passed to `onMentionSearch`.\n- Selected mentions inserted as highlighted inline text; tracked for `onSend` third argument.\n- Attachments render as chips above the textarea; removable via `onRemoveAttachment`.\n- Send button calls `onSend(value, attachments, mentions)`.\n- Stories use 608px wrapper width in decorator.\n\n## Content guidelines\n\n### Placeholder copy (from stories)\n\n| Context | Example |\n|---------|---------|\n| Configuration | `Type @ to select processes, campaigns and queues you want to configure` |\n| Mentions | `Type @ to mention someone...` |\n| Disabled | `This input is disabled` |\n\n### Writing principles\n\n- Placeholder explains `@` affordance when mentions are enabled.\n- Keep placeholders one sentence; sentence case.\n- Do not use placeholder as the only label for required actions.\n\n## Stories\n\n### Default\n\n**Story ID:** `ui-components-chat-input-box--default`\n\n`placeholder`, `maxLength: 200`.\n\n<Canvas of={ChatInputBoxStories.Default} />\n\n### WithMentionSearch\n\n**Story ID:** `ui-components-chat-input-box--with-mention-search`\n\nControlled value; `onMentionSearch` filters `allMembers` with 300ms simulated delay; `mentionLoading` during fetch.\n\n<Canvas of={ChatInputBoxStories.WithMentionSearch} />\n\n### WithAttachments\n\n**Story ID:** `ui-components-chat-input-box--with-attachments`\n\nPre-loaded JSON and CSV attachment chips; `onAttach` / `onRemoveAttachment`.\n\n<Canvas of={ChatInputBoxStories.WithAttachments} />\n\n### Interactive\n\n**Story ID:** `ui-components-chat-input-box--interactive`\n\nFull features: text, attachments, mentions, send alert.\n\n<Canvas of={ChatInputBoxStories.Interactive} />\n\n### WithVoiceInput\n\n**Story ID:** `ui-components-chat-input-box--with-voice-input`\n\n`showVoiceInput: true` — displays a microphone button beside the send button.\n\n<Canvas of={ChatInputBoxStories.WithVoiceInput} />\n\n### Disabled\n\n**Story ID:** `ui-components-chat-input-box--disabled`\n\n`disabled: true`.\n\n<Canvas of={ChatInputBoxStories.Disabled} />\n\n## Accessibility\n\n- Send `IconButton` needs descriptive context — ensure compose region has accessible name via surrounding layout or `aria-label` on send if exposed separately.\n- Mention popover uses list interaction; keyboard support from MUI Popper/List patterns in implementation.\n- Disabled state blocks interaction on textarea and send.\n- Storybook a11y: `test: 'todo'`.\n\n## Best Practices\n\n- Parent owns `value`, `attachments`, and filtered `mentionSuggestions`.\n- Implement `onMentionSearch` for server or client filter — do not pass full unfiltered huge lists without search.\n- Wire `onSend` to post message API with attachments and mention metadata.\n- Set realistic `maxLength` (200 in stories).\n- Use domain-specific mention labels (users, campaigns, queues per stories).\n\n## Anti-patterns\n\n- Using `ChatInputBox` for simple email/password fields.\n- Omitting `onMentionSearch` when `@` mentions are enabled.\n- Expecting built-in file upload to server — parent handles `file` from attachments.\n- Inventing props not in `ChatInputBoxProps`.\n\n## Guidance for AI Agents\n\n### When to choose `ChatInputBox`\n\n- Chat compose with optional mentions and attachments\n- ECC configuration flows referencing campaigns/queues via `@`\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Standard text field | `FormField` / `EnhancedTextField` |\n| Tag input only | `Autocomplete` multiple |\n\n### Canonical pattern (from WithMentionSearch)\n\n```tsx\nconst [value, setValue] = useState('');\nconst [suggestions, setSuggestions] = useState<MentionSuggestion[]>([]);\n\n<ChatInputBox\n  value={value}\n  onChange={setValue}\n  mentionSuggestions={suggestions}\n  onMentionSearch={(query) => filterAndSetSuggestions(query)}\n  onMentionSelect={(s) => console.log(s)}\n  onSend={(text, attachments, mentions) => { /* post */ }}\n  maxLength={200}\n  placeholder=\"Type @ to mention someone...\"\n/>\n```\n\n### Canonical stories\n\n| Task | Story |\n|------|-------|\n| Minimal | `Default` |\n| Mentions | `WithMentionSearch` |\n| Files | `WithAttachments` |\n| Voice input | `WithVoiceInput` |\n| Full demo | `Interactive` |\n\n## Related Components\n\n`Icon`, `IconButton`, `Chip`, `CircularProgress`, `EnhancedTextField`\n"}}},"ai-suite-beta-messagecomposer":{"id":"ai-suite-beta-messagecomposer","name":"MessageComposer","path":"./src/stories/ui-components/MessageComposer.stories.tsx","stories":[{"id":"ai-suite-beta-messagecomposer--default","name":"Default","snippet":"const Default = () => (\n  <Box sx={{ width: 684 }}>\n    <MessageComposer\n      question=\"What is your preferred maximum journey duration per lead?\"\n      options={OPTIONS}\n      currentIndex={1}\n      totalCount={1}\n      onClose={() => {}}\n    />\n  </Box>\n);","description":"Default — matches the Figma \"Message Composer\" with three options, pagination header, free-text input, and keyboard hints."},{"id":"ai-suite-beta-messagecomposer--options-only","name":"Options Only","snippet":"const OptionsOnly = () => (\n  <Box sx={{ width: 684 }}>\n    <MessageComposer\n      question=\"Which channel should we prioritise for follow-ups?\"\n      options={[\n        { id: 'sms', label: 'SMS' },\n        { id: 'wa', label: 'WhatsApp' },\n        { id: 'voice', label: 'Voice callback' },\n      ]}\n      showInput={false}\n      onClose={() => {}}\n    />\n  </Box>\n);","description":"Without the free-text input — options only."},{"id":"ai-suite-beta-messagecomposer--paginated","name":"Paginated","snippet":"const Paginated = () => {\n  const prompts = [\n    {\n      question: 'What is your preferred maximum journey duration per lead?',\n      options: OPTIONS,\n    },\n    {\n      question: 'What is the absolute budget ceiling per lead?',\n      options: [\n        { id: '5', label: '₹5 per lead' },\n        { id: '8', label: '₹8 per lead' },\n        { id: 'ai', label: 'Let AI optimise within ₹10' },\n      ],\n    },\n  ];\n  const [index, setIndex] = useState(0);\n  const current = prompts[index];\n\n  return (\n    <Box sx={{ width: 684 }}>\n      <MessageComposer\n        key={index}\n        question={current.question}\n        options={current.options}\n        currentIndex={index + 1}\n        totalCount={prompts.length}\n        onPrev={index > 0 ? () => setIndex((i) => i - 1) : undefined}\n        onNext={index < prompts.length - 1 ? () => setIndex((i) => i + 1) : undefined}\n        onClose={() => {}}\n      />\n    </Box>\n  );\n};","description":"Multi-step sequence — pagination controls let the user move between prompts."},{"id":"ai-suite-beta-messagecomposer--interactive","name":"Interactive","snippet":"const Interactive = () => {\n  const [result, setResult] = useState<string>('No response yet');\n\n  return (\n    <Box sx={{ width: 684, display: 'flex', flexDirection: 'column', gap: 2 }}>\n      <MessageComposer\n        question=\"What is your preferred maximum journey duration per lead?\"\n        options={OPTIONS}\n        currentIndex={1}\n        totalCount={1}\n        onSelect={(option) => setResult(`Selected: ${option.label}`)}\n        onSubmit={(text) => setResult(`Submitted: ${text}`)}\n        onClose={() => setResult('Dismissed')}\n      />\n      <Typography variant=\"body2\" sx={{ color: 'text.secondary' }}>\n        {result}\n      </Typography>\n    </Box>\n  );\n};","description":"Interactive — logs selection and free-text submission."}],"import":"import { Box, MessageComposer, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"description":"MessageComposer — an inline clarification prompt used in agentic flows. Shows a question, a list of lettered quick-reply options, an optional free-text input, and a keyboard-hint footer. Options can be navigated with the arrow keys and chosen with Enter; typing in the input and pressing Enter submits free text instead. ```tsx <MessageComposer question=\"What is your preferred maximum journey duration per lead?\" options={[ { id: 'a', label: \"Let's do a compressed 7-day sprint\" }, { id: 'b', label: 'Stick to the standard 10-day window' }, { id: 'c', label: 'Let AI Decide' }, ]} currentIndex={1} totalCount={1} onSelect={(option) => console.log(option)} onSubmit={(text) => console.log(text)} /> ```","reactDocgen":{"description":"MessageComposer — an inline clarification prompt used in agentic flows.\n\nShows a question, a list of lettered quick-reply options, an optional\nfree-text input, and a keyboard-hint footer. Options can be navigated with\nthe arrow keys and chosen with Enter; typing in the input and pressing Enter\nsubmits free text instead.\n\n```tsx\n<MessageComposer\n  question=\"What is your preferred maximum journey duration per lead?\"\n  options={[\n    { id: 'a', label: \"Let's do a compressed 7-day sprint\" },\n    { id: 'b', label: 'Stick to the standard 10-day window' },\n    { id: 'c', label: 'Let AI Decide' },\n  ]}\n  currentIndex={1}\n  totalCount={1}\n  onSelect={(option) => console.log(option)}\n  onSubmit={(text) => console.log(text)}\n/>\n```","methods":[],"displayName":"MessageComposer","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/MessageComposer/MessageComposer.tsx","actualName":"MessageComposer","exportName":"MessageComposer","props":{"question":{"required":true,"tsType":{"name":"string"},"description":"The question / prompt shown in the header"},"options":{"required":true,"tsType":{"name":"Array","elements":[{"name":"MessageComposerOption"}],"raw":"MessageComposerOption[]"},"description":"Selectable quick-reply options. Each option is rendered with a\nsequential letter key cap (A, B, C…)."},"defaultActiveOptionId":{"required":false,"tsType":{"name":"string"},"description":"Initial highlighted option. Defaults to the first option."},"onActiveOptionChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(id: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"id"}],"return":{"name":"void"}}},"description":"Called when the highlighted option changes (keyboard or hover)."},"onSelect":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(option: MessageComposerOption) => void","signature":{"arguments":[{"type":{"name":"MessageComposerOption"},"name":"option"}],"return":{"name":"void"}}},"description":"Called when an option is selected (click or Enter)."},"defaultInputValue":{"required":false,"tsType":{"name":"string"},"description":"Initial value of the free-text input.","defaultValue":{"value":"''","computed":false}},"onInputChange":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(value: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"value"}],"return":{"name":"void"}}},"description":"Called when the free-text input value changes."},"onSubmit":{"required":false,"tsType":{"name":"signature","type":"function","raw":"(value: string) => void","signature":{"arguments":[{"type":{"name":"string"},"name":"value"}],"return":{"name":"void"}}},"description":"Called when free text is submitted (Enter with non-empty input)."},"inputPlaceholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder for the free-text input.\n@default 'Type something'","defaultValue":{"value":"'Type something'","computed":false}},"showInput":{"required":false,"tsType":{"name":"boolean"},"description":"Whether to render the free-text input row.\n@default true","defaultValue":{"value":"true","computed":false}},"currentIndex":{"required":false,"tsType":{"name":"number"},"description":"1-based index of the current prompt, shown as `{current} of {total}`."},"totalCount":{"required":false,"tsType":{"name":"number"},"description":"Total number of prompts in the sequence."},"onPrev":{"required":false,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":"Called when the previous-prompt control is clicked."},"onNext":{"required":false,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":"Called when the next-prompt control is clicked."},"onClose":{"required":false,"tsType":{"name":"signature","type":"function","raw":"() => void","signature":{"arguments":[],"return":{"name":"void"}}},"description":"Called when the close (×) control is clicked. When omitted the close\nbutton is hidden."},"showFooterHints":{"required":false,"tsType":{"name":"boolean"},"description":"Whether to render the keyboard-hint footer.\n@default true","defaultValue":{"value":"true","computed":false}},"sx":{"required":false,"tsType":{"name":"SxProps","elements":[{"name":"Theme"}],"raw":"SxProps<Theme>"},"description":"Override styles for the root container."}}},"docs":{"ai-suite-beta-messagecomposer--docs":{"id":"ai-suite-beta-messagecomposer--docs","name":"Docs","path":"./src/stories/ui-components/MessageComposer.mdx","title":"AI-SUITE (Beta)/MessageComposer","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as MessageComposerStories from './MessageComposer.stories';\nimport { MessageComposer } from '../../components/MessageComposer';\n\n<Meta of={MessageComposerStories} />\n\n# MessageComposer\n\n## Overview\n\n`MessageComposer` is a Signal Design System component for inline clarification prompts in agentic flows. It renders a question, lettered quick-reply options (A, B, C…), an optional free-text input, and a keyboard-hint footer. Users navigate with arrow keys and Enter, or type a custom response.\n\n```tsx\nimport { MessageComposer } from '@exotel-npm-dev/signal-design-system';\nimport type { MessageComposerOption } from '@exotel-npm-dev/signal-design-system';\n```\n\nThe app must be wrapped in `ExotelThemeProvider` for correct styling.\n\n**When to use**\n\n- Inline clarification prompts where the agent needs a decision from the user\n- Quick-reply option selection (single choice from a predefined list)\n- Multi-step prompt sequences with pagination\n- Optional free-text input alongside structured options\n\n**When not to use**\n\n- Displaying agent output (structured cards, test results) → use `AgenticCard`\n- Showing processing steps or thinking state → use `AgenticSteps`\n- Full-featured chat text input → use `ChatInputBox`\n- Form fields in a page layout → use `EnhancedTextField`, `Select`, or `Autocomplete`\n- Confirmation dialogs → use `Dialog` or `StructuredDialog`\n\n## Anatomy\n\n```\nMessageComposer (root)\n├── Header bar\n│   ├── Question text (left)\n│   ├── Pagination (\"1 of 2\") + prev/next arrows (center-right)\n│   └── Close button (right)\n├── Options list\n│   ├── Option row (letter keycap + label) × N\n│   └── Active option has highlighted background\n├── Free-text input row (optional, controlled by showInput)\n│   └── Text input with placeholder\n└── Footer keyboard hints (optional, controlled by showFooterHints)\n    └── \"↑↓ Navigate  ↵ Select  Esc Close\"\n```\n\n## Props\n\n### MessageComposerOption\n\n| Name | Type | Description |\n|------|------|-------------|\n| `id` | `string` | **Required.** Unique identifier for the option. |\n| `label` | `string` | **Required.** Display text for the option. |\n\n### MessageComposerProps\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `question` | `string` | — | **Required.** The question or prompt shown in the header. |\n| `options` | `MessageComposerOption[]` | — | **Required.** Quick-reply options. Each rendered with a sequential letter (A, B, C…). |\n| `defaultActiveOptionId` | `string` | First option | Initially highlighted option. |\n| `onActiveOptionChange` | `(id: string) => void` | — | Called when the highlighted option changes (keyboard or hover). |\n| `onSelect` | `(option: MessageComposerOption) => void` | — | Called when an option is selected (click or Enter). |\n| `defaultInputValue` | `string` | `''` | Initial value of the free-text input. |\n| `onInputChange` | `(value: string) => void` | — | Called when the free-text input value changes. |\n| `onSubmit` | `(value: string) => void` | — | Called when free text is submitted (Enter with non-empty input). |\n| `inputPlaceholder` | `string` | `'Type something'` | Placeholder for the free-text input. |\n| `showInput` | `boolean` | `true` | Whether to render the free-text input row. |\n| `currentIndex` | `number` | — | 1-based index of the current prompt (shown as \"1 of 2\"). |\n| `totalCount` | `number` | — | Total number of prompts in the sequence. |\n| `onPrev` | `() => void` | — | Called when the previous-prompt arrow is clicked. Hidden when absent. |\n| `onNext` | `() => void` | — | Called when the next-prompt arrow is clicked. Hidden when absent. |\n| `onClose` | `() => void` | — | Called when the close (×) button is clicked. Button hidden when absent. |\n| `showFooterHints` | `boolean` | `true` | Whether to render the keyboard-hint footer. |\n| `sx` | `SxProps<Theme>` | — | Override styles for the root container. |\n\n<ArgTypes of={MessageComposer} />\n\n## Variants\n\n| Variant | Key props | Story |\n|---------|-----------|-------|\n| Full prompt | `question`, `options`, `showInput`, pagination | `Default` |\n| Options only | `showInput={false}` | `OptionsOnly` |\n| Paginated sequence | `currentIndex`, `totalCount`, `onPrev`, `onNext` | `Paginated` |\n| Interactive | `onSelect`, `onSubmit`, `onClose` | `Interactive` |\n\n## States\n\n| State | How to apply | Notes |\n|-------|--------------|-------|\n| Default | Provide `question` and `options` | First option highlighted |\n| Option active | Keyboard ↑↓ or hover | Active option gets highlighted background |\n| Option selected | Click or Enter on active option | Fires `onSelect` |\n| Text input mode | Focus text input, type, Enter | Fires `onSubmit` |\n| No text input | `showInput={false}` | Input row hidden |\n| No footer hints | `showFooterHints={false}` | Keyboard hints hidden |\n\n## Behavior\n\n| Pattern | Mechanism | Story |\n|---------|-----------|-------|\n| Quick selection | Click or Enter on highlighted option → `onSelect` | `Interactive` |\n| Keyboard navigation | ↑↓ arrow keys cycle through options | `Default` |\n| Free-text response | Type in input, press Enter → `onSubmit` | `Interactive` |\n| Dismiss | Click × or press Escape → `onClose` | `Interactive` |\n| Multi-step prompts | `onPrev` / `onNext` paginate through questions | `Paginated` |\n\nThe component manages active-option state internally (uncontrolled by default). Use `defaultActiveOptionId` to set the initial active option. Use `onActiveOptionChange` to track the active option externally.\n\n## Stories\n\n### Default\n\n**Story ID:** `ui-components-messagecomposer--default`\n\nThree quick-reply options with pagination header, free-text input, and keyboard hints.\n\n**Recommended usage:** Standard clarification prompt in an agentic chat flow.\n\n<Canvas of={MessageComposerStories.Default} />\n\n### OptionsOnly\n\n**Story ID:** `ui-components-messagecomposer--options-only`\n\nThree options with `showInput={false}` — no free-text input.\n\n**Recommended usage:** When the agent needs a strict choice from predefined options with no free-text alternative.\n\n<Canvas of={MessageComposerStories.OptionsOnly} />\n\n### Paginated\n\n**Story ID:** `ui-components-messagecomposer--paginated`\n\nTwo-step prompt sequence with prev/next pagination controls.\n\n**Recommended usage:** Multi-question clarification flows where the agent needs several decisions.\n\n<Canvas of={MessageComposerStories.Paginated} />\n\n### Interactive\n\n**Story ID:** `ui-components-messagecomposer--interactive`\n\nLogs selections and free-text submissions to demonstrate callback behavior.\n\n**Recommended usage:** Testing and prototyping prompt interactions.\n\n<Canvas of={MessageComposerStories.Interactive} />\n\n## Accessibility\n\n- Options are rendered as clickable list items. Arrow keys navigate between options.\n- Enter key selects the highlighted option or submits free-text input.\n- Escape key fires `onClose` to dismiss the prompt.\n- Letter keycaps (A, B, C…) provide visual keyboard shortcuts.\n- Keyboard hints in the footer guide users on available interactions.\n- The close button has appropriate interactive affordance.\n- Consider adding `role=\"listbox\"` and `role=\"option\"` for enhanced screen reader support.\n\n## Best Practices\n\n- Write clear, concise questions that explain what the agent needs to proceed.\n- Provide 2–5 options — avoid overwhelming the user with too many choices.\n- Include a \"Let AI Decide\" option when appropriate to reduce decision fatigue.\n- Use `showInput={false}` when free-text responses are not meaningful.\n- Use pagination (`currentIndex`, `totalCount`, `onPrev`, `onNext`) for multi-step clarification.\n- Always provide `onClose` so the user can dismiss the prompt.\n- Keep option labels short and scannable (one sentence or less).\n\n## Anti-patterns\n\n- Using `MessageComposer` for displaying agent output — use `AgenticCard`.\n- Using `MessageComposer` for full chat text input — use `ChatInputBox`.\n- Providing more than 7 options — consider a `Select` or `Autocomplete` instead.\n- Omitting `onClose` — users should always be able to dismiss.\n- Using `MessageComposer` for form fields — use Signal form components.\n- Nesting `MessageComposer` inside `AgenticCard`.\n\n## Guidance for AI Agents\n\n### When to choose `MessageComposer`\n\n- Agent needs a clarification decision from the user before proceeding\n- Quick-reply selection from 2–5 predefined options\n- Optional free-text alternative alongside structured choices\n- Multi-step prompt sequences\n\n### When to choose another component\n\n| Scenario | Component |\n|----------|-----------|\n| Structured output card | `AgenticCard` |\n| Processing/thinking steps | `AgenticSteps` |\n| Full chat input | `ChatInputBox` |\n| Form field (dropdown) | `Select` or `Autocomplete` |\n| Yes/No confirmation | `Dialog` or `StructuredDialog` |\n\n### Preferred composition patterns\n\n```tsx\n// Basic prompt — story: Default\n<MessageComposer\n  question=\"What is your preferred maximum journey duration per lead?\"\n  options={[\n    { id: 'a', label: 'Compressed 7-day sprint' },\n    { id: 'b', label: 'Standard 10-day window' },\n    { id: 'c', label: 'Let AI Decide' },\n  ]}\n  currentIndex={1}\n  totalCount={1}\n  onSelect={(option) => handleSelection(option)}\n  onSubmit={(text) => handleFreeText(text)}\n  onClose={() => dismissPrompt()}\n/>\n\n// Options only — story: OptionsOnly\n<MessageComposer\n  question=\"Which channel should we prioritise?\"\n  options={[\n    { id: 'sms', label: 'SMS' },\n    { id: 'wa', label: 'WhatsApp' },\n    { id: 'voice', label: 'Voice callback' },\n  ]}\n  showInput={false}\n  onClose={() => {}}\n/>\n\n// Paginated — story: Paginated\n<MessageComposer\n  question={currentPrompt.question}\n  options={currentPrompt.options}\n  currentIndex={index + 1}\n  totalCount={prompts.length}\n  onPrev={index > 0 ? () => setIndex(i => i - 1) : undefined}\n  onNext={index < prompts.length - 1 ? () => setIndex(i => i + 1) : undefined}\n  onClose={() => {}}\n/>\n```\n\n### Canonical stories for code generation\n\n| Task | Reference story |\n|------|-----------------|\n| Standard clarification | `Default` |\n| Strict option choice | `OptionsOnly` |\n| Multi-step prompts | `Paginated` |\n| Callback testing | `Interactive` |\n\n### Common mistakes to avoid\n\n- Using `MessageComposer` for chat text input — use `ChatInputBox`.\n- Providing zero options — at least one option is expected.\n- Omitting `onClose` — always allow dismissal.\n- Importing from `@mui/material` — use `@exotel-npm-dev/signal-design-system`.\n- Omitting `ExotelThemeProvider` in app setup.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|-------------|\n| `AgenticCard` | Structured output card for agentic flows |\n| `AgenticSteps` | Collapsible processing steps |\n| `ChatInputBox` | Full-featured chat text input |\n| `Select` | Dropdown selection (form context) |\n| `Autocomplete` | Searchable selection (form context) |\n| `Dialog` / `StructuredDialog` | Modal confirmation |\n"}}},"date-time-pickers-datepicker":{"id":"date-time-pickers-datepicker","name":"DatePicker","path":"./src/stories/ui-components/DatePicker.stories.tsx","stories":[{"id":"date-time-pickers-datepicker--basic","name":"Basic","snippet":"const Basic = () => <DatePicker label=\"Select date\" />;","description":"Basic date picker with a label."},{"id":"date-time-pickers-datepicker--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 300 }}>\n    <DatePicker label=\"Small\" size=\"small\" />\n    <DatePicker label=\"Medium\" size=\"medium\" />\n    <DatePicker label=\"Large\" size=\"large\" />\n  </div>\n);","description":"All three sizes — small (32px), medium (40px), and large (50px) — matching EnhancedTextField."},{"id":"date-time-pickers-datepicker--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [value, setValue] = useState<Dayjs | null>(dayjs());\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 300 }}>\n      <DatePicker label=\"Date\" value={value} onChange={(newValue) => setValue(newValue)} />\n      <div style={{ fontSize: 14, color: '#666' }}>\n        Selected: {value ? value.format('MMMM D, YYYY') : 'None'}\n      </div>\n    </div>\n  );\n};","description":"Controlled date picker with React state."},{"id":"date-time-pickers-datepicker--without-label","name":"Without Label","snippet":"const WithoutLabel = () => <DatePicker />;","description":"Without an external label."},{"id":"date-time-pickers-datepicker--disabled","name":"Disabled","snippet":"const Disabled = () => <DatePicker label=\"Disabled\" disabled defaultValue={dayjs()} />;","description":"Date picker in disabled state."},{"id":"date-time-pickers-datepicker--read-only","name":"Read Only","snippet":"const ReadOnly = () => <DatePicker label=\"Read only\" readOnly defaultValue={dayjs()} />;","description":"Read-only date picker."},{"id":"date-time-pickers-datepicker--disable-past","name":"Disable Past","snippet":"const DisablePast = () => <DatePicker label=\"Future dates only\" disablePast />;","description":"Only future dates are selectable."},{"id":"date-time-pickers-datepicker--disable-future","name":"Disable Future","snippet":"const DisableFuture = () => <DatePicker label=\"Past dates only\" disableFuture />;","description":"Only past dates are selectable."},{"id":"date-time-pickers-datepicker--min-max-date","name":"Min Max Date","snippet":"const MinMaxDate = () => (\n  <DatePicker\n    label=\"This month only\"\n    minDate={dayjs().startOf('month')}\n    maxDate={dayjs().endOf('month')}\n  />\n);","description":"Custom date range using minDate and maxDate."},{"id":"date-time-pickers-datepicker--month-year-only","name":"Month Year Only","snippet":"const MonthYearOnly = () => (\n  <DatePicker label=\"Select month\" views={['month', 'year']} openTo=\"month\" />\n);","description":"Month and year views only (no day picker)."},{"id":"date-time-pickers-datepicker--year-only","name":"Year Only","snippet":"const YearOnly = () => <DatePicker label=\"Select year\" views={['year']} openTo=\"year\" />;","description":"Year picker only."},{"id":"date-time-pickers-datepicker--custom-format","name":"Custom Format","snippet":"const CustomFormat = () => <DatePicker label=\"DD/MM/YYYY format\" format=\"DD/MM/YYYY\" />;","description":"Custom format display."},{"id":"date-time-pickers-datepicker--action-bar","name":"Action Bar","snippet":"const ActionBar = () => (\n  <DatePicker\n    label=\"With action bar\"\n    slotProps={{\n      actionBar: {\n        actions: ['clear', 'cancel', 'today', 'accept'],\n      },\n    }}\n  />\n);","description":"Default action bar with Clear, Cancel, Today, and Accept actions."},{"id":"date-time-pickers-datepicker--interactive","name":"Interactive","snippet":"const Interactive = () => <DatePicker\n    label=\"Pick a date\"\n    size=\"medium\"\n    disabled={false}\n    readOnly={false}\n    disableFuture={false}\n    disablePast={false} />;","description":"Interactive playground with all controls."}],"import":"import { DatePicker } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"DatePicker","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/DatePicker/DatePicker.tsx","actualName":"DatePicker","exportName":"DatePicker","props":{"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the picker input. Matches EnhancedTextField sizes."},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted.\nPass an empty string to disable the default placeholder."}},"composes":["Omit"]},"docs":{"date-time-pickers-datepicker--docs":{"id":"date-time-pickers-datepicker--docs","name":"Docs","path":"./src/stories/ui-components/DatePicker.mdx","title":"Date & Time Pickers/DatePicker","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DatePickerStories from './DatePicker.stories';\nimport { DatePicker } from '../../components/DatePicker';\n\n<Meta of={DatePickerStories} />\n\n# DatePicker\n\n## Overview\n\n`DatePicker` wraps MUI X `DatePicker` with external `FieldWrapper` label and `size` prop. **Requires `ExotelThemeProvider`** (Dayjs adapter).\n\n```tsx\nimport { DatePicker } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Single date selection.\n**When not to use:** Date range → `DateRangePicker`; date+time → `DateTimePicker`.\n\n## Props\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `label` | `ReactNode` | — | External label |\n| `size` | `'small' \\| 'medium' \\| 'large'` | `'medium'` | Input size |\n\nPlus MUI X DatePicker props (`value`, `onChange`, `disabled`, `readOnly`, `disablePast`, `minDate`, `maxDate`, `views`, `format`, etc.).\n\n## Stories\n\n`Basic`, `Sizes`, `Controlled`, `WithoutLabel`, `Disabled`, `ReadOnly`, `DisablePast`, `DisableFuture`, `MinMaxDate`, `MonthYearOnly`, `YearOnly`, `CustomFormat`, `ActionBar`, `Interactive`\n\n<Canvas of={DatePickerStories.Basic} />\n\n## Related Components\n\n`DateRangePicker`, `DateTimePicker`, `ExotelThemeProvider`, `EnhancedTextField`\n"}}},"date-time-pickers-daterangepicker":{"id":"date-time-pickers-daterangepicker","name":"DateRangePicker","path":"./src/stories/ui-components/DateRangePicker.stories.tsx","stories":[{"id":"date-time-pickers-daterangepicker--basic","name":"Basic","snippet":"const Basic = () => <DateRangePicker label=\"Select date range\" />;","description":"Basic date range picker with a label."},{"id":"date-time-pickers-daterangepicker--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: 16, minWidth: 500 }}>\n    <DateRangePicker label=\"Small\" size=\"small\" />\n    <DateRangePicker label=\"Medium\" size=\"medium\" />\n    <DateRangePicker label=\"Large\" size=\"large\" />\n  </div>\n);","description":"All three sizes — small (32px), medium (40px), and large (50px) — matching EnhancedTextField."},{"id":"date-time-pickers-daterangepicker--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [value, setValue] = useState<DateRange<Dayjs>>([null, null]);\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, minWidth: 500 }}>\n      <DateRangePicker label=\"Date range\" value={value} onChange={(newValue) => setValue(newValue)} />\n      <div style={{ fontSize: 14, color: '#666' }}>\n        Start: {value[0] ? value[0].format('MMMM D, YYYY') : 'None'}\n        {' — '}\n        End: {value[1] ? value[1].format('MMMM D, YYYY') : 'None'}\n      </div>\n    </div>\n  );\n};","description":"Controlled date range picker with React state."},{"id":"date-time-pickers-daterangepicker--without-label","name":"Without Label","snippet":"const WithoutLabel = () => <DateRangePicker />;","description":"Without an external label."},{"id":"date-time-pickers-daterangepicker--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <DateRangePicker\n    label=\"Disabled\"\n    disabled\n    defaultValue={[dayjs(), dayjs().add(7, 'day')]}\n  />\n);","description":"Disabled state."},{"id":"date-time-pickers-daterangepicker--read-only","name":"Read Only","snippet":"const ReadOnly = () => (\n  <DateRangePicker\n    label=\"Read only\"\n    readOnly\n    defaultValue={[dayjs(), dayjs().add(7, 'day')]}\n  />\n);","description":"Read-only state."},{"id":"date-time-pickers-daterangepicker--disable-past","name":"Disable Past","snippet":"const DisablePast = () => <DateRangePicker label=\"Future dates only\" disablePast />;","description":"Only future dates are selectable."},{"id":"date-time-pickers-daterangepicker--single-calendar","name":"Single Calendar","snippet":"const SingleCalendar = () => <DateRangePicker label=\"Single calendar\" calendars={1} />;","description":"Single calendar instead of the default two."},{"id":"date-time-pickers-daterangepicker--min-max-date","name":"Min Max Date","snippet":"const MinMaxDate = () => (\n  <DateRangePicker\n    label=\"This month only\"\n    minDate={dayjs().startOf('month')}\n    maxDate={dayjs().endOf('month')}\n  />\n);","description":"Restrict to a specific date window."},{"id":"date-time-pickers-daterangepicker--without-shortcuts","name":"Without Shortcuts","snippet":"const WithoutShortcuts = () => (\n  <DateRangePicker label=\"Without shortcuts\" shortcuts={false} />\n);","description":"With built-in default shortcuts panel (Today, Yesterday, Last 7 Days, etc.). Simply pass `shortcuts` to enable."},{"id":"date-time-pickers-daterangepicker--with-custom-shortcuts","name":"With Custom Shortcuts","snippet":"const WithCustomShortcuts = () => {\n  const customShortcuts: DateRangeShortcut[] = [\n    { label: 'Today', getValue: () => [dayjs().startOf('day'), dayjs().endOf('day')] },\n    { label: 'This week', getValue: () => [dayjs().startOf('week'), dayjs().endOf('week')] },\n    { label: 'This month', getValue: () => [dayjs().startOf('month'), dayjs().endOf('month')] },\n  ];\n  return (\n    <DateRangePicker label=\"With custom shortcuts\" shortcuts={customShortcuts} />\n  );\n};","description":"With custom shortcuts array for full control over the shortcuts panel."},{"id":"date-time-pickers-daterangepicker--action-bar","name":"Action Bar","snippet":"const ActionBar = () => (\n  <DateRangePicker\n    label=\"With action bar\"\n    slotProps={{\n      actionBar: {\n        actions: ['clear', 'cancel', 'accept'],\n      },\n    }}\n  />\n);","description":"Default action bar with Cancel and Accept actions."},{"id":"date-time-pickers-daterangepicker--interactive","name":"Interactive","snippet":"const Interactive = () => <DateRangePicker\n    label=\"Pick a range\"\n    size=\"medium\"\n    disabled={false}\n    readOnly={false}\n    disableFuture={false}\n    disablePast={false}\n    calendars={2} />;","description":"Interactive playground with all controls."}],"import":"import { DateRangePicker } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"DateRangePicker","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/DateRangePicker/DateRangePicker.tsx","actualName":"DateRangePicker","exportName":"DateRangePicker","props":{"label":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"External label rendered above the picker."},"shortcuts":{"required":false,"tsType":{"name":"union","raw":"boolean | DateRangeShortcut[]","elements":[{"name":"boolean"},{"name":"Array","elements":[{"name":"PickersShortcutsItem","elements":[{"name":"DateRange","elements":[{"name":"Dayjs"}],"raw":"DateRange<Dayjs>"}],"raw":"PickersShortcutsItem<DateRange<Dayjs>>"}],"raw":"DateRangeShortcut[]"}]},"description":"Enable the shortcuts panel for quick date range selection.\n- `true` uses the built-in default shortcuts (Today, Yesterday, Last 7 Days, etc.)\n- Pass a custom array of `DateRangeShortcut` items for full control.\n- `false` / `undefined` disables shortcuts.\n@default true"},"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the picker input. Matches EnhancedTextField sizes."},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted."}},"composes":["Omit"]},"docs":{"date-time-pickers-daterangepicker--docs":{"id":"date-time-pickers-daterangepicker--docs","name":"Docs","path":"./src/stories/ui-components/DateRangePicker.mdx","title":"Date & Time Pickers/DateRangePicker","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DateRangePickerStories from './DateRangePicker.stories';\nimport { DateRangePicker } from '../../components/DateRangePicker';\n\n<Meta of={DateRangePickerStories} />\n\n# DateRangePicker\n\n## Overview\n\n`DateRangePicker` wraps MUI X date range picker with Exotel field label pattern. Exports `DEFAULT_DATE_RANGE_SHORTCUTS`.\n\n```tsx\nimport { DateRangePicker, DEFAULT_DATE_RANGE_SHORTCUTS } from '@exotel-npm-dev/signal-design-system';\n```\n\n**Requires `ExotelThemeProvider`.**\n\n**When to use:** Start/end date filters, report date ranges.\n**When not to use:** Single date → `DatePicker`; date+time range → `DateTimeRangePicker`.\n\n## Stories\n\n`Basic`, `Sizes`, `Controlled`, `WithoutLabel`, `Disabled`, `ReadOnly`, `DisablePast`, `SingleCalendar`, `MinMaxDate`, `WithoutShortcuts`, `WithCustomShortcuts`, `ActionBar`, `Interactive`\n\n<Canvas of={DateRangePickerStories.Basic} />\n<Canvas of={DateRangePickerStories.WithCustomShortcuts} />\n\n## Related Components\n\n`DatePicker`, `DataGrid` (date-range toolbar filter), `AppliedFilters`\n"}}},"date-time-pickers-datetimepicker":{"id":"date-time-pickers-datetimepicker","name":"DateTimePicker","path":"./src/stories/ui-components/DateTimePicker.stories.tsx","stories":[{"id":"date-time-pickers-datetimepicker--basic","name":"Basic","snippet":"const Basic = () => <DateTimePicker label=\"Select date & time\" />;","description":"Basic date-time picker with a label."},{"id":"date-time-pickers-datetimepicker--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 300 }}>\n    <DateTimePicker label=\"Small\" size=\"small\" />\n    <DateTimePicker label=\"Medium\" size=\"medium\" />\n    <DateTimePicker label=\"Large\" size=\"large\" />\n  </div>\n);","description":"All three sizes — small (32px), medium (40px), and large (50px) — matching EnhancedTextField."},{"id":"date-time-pickers-datetimepicker--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [value, setValue] = useState<Dayjs | null>(dayjs());\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 300 }}>\n      <DateTimePicker label=\"Date & time\" value={value} onChange={(newValue) => setValue(newValue)} />\n      <div style={{ fontSize: 14, color: '#666' }}>\n        Selected: {value ? value.format('MMMM D, YYYY hh:mm A') : 'None'}\n      </div>\n    </div>\n  );\n};","description":"Controlled date-time picker with React state."},{"id":"date-time-pickers-datetimepicker--without-label","name":"Without Label","snippet":"const WithoutLabel = () => <DateTimePicker />;","description":"Without an external label."},{"id":"date-time-pickers-datetimepicker--disabled","name":"Disabled","snippet":"const Disabled = () => <DateTimePicker label=\"Disabled\" disabled defaultValue={dayjs()} />;","description":"Disabled state."},{"id":"date-time-pickers-datetimepicker--read-only","name":"Read Only","snippet":"const ReadOnly = () => <DateTimePicker label=\"Read only\" readOnly defaultValue={dayjs()} />;","description":"Read-only state."},{"id":"date-time-pickers-datetimepicker--disable-past","name":"Disable Past","snippet":"const DisablePast = () => <DateTimePicker label=\"Future only\" disablePast />;","description":"Only future dates are selectable."},{"id":"date-time-pickers-datetimepicker--twenty-four-hour","name":"Twenty Four Hour","snippet":"const TwentyFourHour = () => <DateTimePicker label=\"24-hour format\" ampm={false} />;","description":"24-hour format (no AM/PM)."},{"id":"date-time-pickers-datetimepicker--custom-format","name":"Custom Format","snippet":"const CustomFormat = () => <DateTimePicker label=\"Custom format\" format=\"DD/MM/YYYY HH:mm\" ampm={false} />;","description":"Custom display format."},{"id":"date-time-pickers-datetimepicker--action-bar","name":"Action Bar","snippet":"const ActionBar = () => (\n  <DateTimePicker\n    label=\"With action bar\"\n    slotProps={{\n      actionBar: {\n        actions: ['clear', 'cancel', 'today', 'accept'],\n      },\n    }}\n  />\n);","description":"Default action bar with Clear, Cancel, Today, and Accept actions."},{"id":"date-time-pickers-datetimepicker--interactive","name":"Interactive","snippet":"const Interactive = () => <DateTimePicker\n    label=\"Pick date & time\"\n    size=\"medium\"\n    disabled={false}\n    readOnly={false}\n    disableFuture={false}\n    disablePast={false}\n    ampm />;","description":"Interactive playground with all controls."}],"import":"import { DateTimePicker } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"DateTimePicker","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/DateTimePicker/DateTimePicker.tsx","actualName":"DateTimePicker","exportName":"DateTimePicker","props":{"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the picker input. Matches EnhancedTextField sizes."},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted."}},"composes":["Omit"]},"docs":{"date-time-pickers-datetimepicker--docs":{"id":"date-time-pickers-datetimepicker--docs","name":"Docs","path":"./src/stories/ui-components/DateTimePicker.mdx","title":"Date & Time Pickers/DateTimePicker","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DateTimePickerStories from './DateTimePicker.stories';\nimport { DateTimePicker } from '../../components/DateTimePicker';\n\n<Meta of={DateTimePickerStories} />\n\n# DateTimePicker\n\n## Overview\n\n`DateTimePicker` wraps MUI X `DateTimePicker` with external label and size. **Requires `ExotelThemeProvider`.**\n\n```tsx\nimport { DateTimePicker } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Combined date and time selection in one field.\n**When not to use:** Date only → `DatePicker`; time only → `TimePicker`.\n\n## Stories\n\n`Basic`, `Sizes`, `Controlled`, `WithoutLabel`, `Disabled`, `ReadOnly`, `DisablePast`, `TwentyFourHour`, `CustomFormat`, `ActionBar`, `Interactive`\n\n<Canvas of={DateTimePickerStories.Basic} />\n\n## Related Components\n\n`DatePicker`, `TimePicker`, `DateTimeRangePicker`\n"}}},"date-time-pickers-datetimerangepicker":{"id":"date-time-pickers-datetimerangepicker","name":"DateTimeRangePicker","path":"./src/stories/ui-components/DateTimeRangePicker.stories.tsx","stories":[{"id":"date-time-pickers-datetimerangepicker--basic","name":"Basic","snippet":"const Basic = () => <DateTimeRangePicker label=\"Select date-time range\" />;","description":"Basic date-time range picker with a label."},{"id":"date-time-pickers-datetimerangepicker--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: 16, minWidth: 600 }}>\n    <DateTimeRangePicker label=\"Small\" size=\"small\" />\n    <DateTimeRangePicker label=\"Medium\" size=\"medium\" />\n    <DateTimeRangePicker label=\"Large\" size=\"large\" />\n  </div>\n);","description":"All three sizes — small (32px), medium (40px), and large (50px) — matching EnhancedTextField."},{"id":"date-time-pickers-datetimerangepicker--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [value, setValue] = useState<DateRange<Dayjs>>([null, null]);\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, minWidth: 600 }}>\n      <DateTimeRangePicker\n        label=\"Date-time range\"\n        value={value}\n        onChange={(newValue) => setValue(newValue)}\n      />\n      <div style={{ fontSize: 14, color: '#666' }}>\n        Start: {value[0] ? value[0].format('MMM D, YYYY hh:mm A') : 'None'}\n        {' — '}\n        End: {value[1] ? value[1].format('MMM D, YYYY hh:mm A') : 'None'}\n      </div>\n    </div>\n  );\n};","description":"Controlled date-time range picker with React state."},{"id":"date-time-pickers-datetimerangepicker--without-label","name":"Without Label","snippet":"const WithoutLabel = () => <DateTimeRangePicker />;","description":"Without an external label."},{"id":"date-time-pickers-datetimerangepicker--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <DateTimeRangePicker\n    label=\"Disabled\"\n    disabled\n    defaultValue={[dayjs(), dayjs().add(3, 'day').hour(17).minute(0)]}\n  />\n);","description":"Disabled state."},{"id":"date-time-pickers-datetimerangepicker--read-only","name":"Read Only","snippet":"const ReadOnly = () => (\n  <DateTimeRangePicker\n    label=\"Read only\"\n    readOnly\n    defaultValue={[dayjs(), dayjs().add(3, 'day').hour(17).minute(0)]}\n  />\n);","description":"Read-only state."},{"id":"date-time-pickers-datetimerangepicker--disable-past","name":"Disable Past","snippet":"const DisablePast = () => <DateTimeRangePicker label=\"Future only\" disablePast />;","description":"Only future dates are selectable."},{"id":"date-time-pickers-datetimerangepicker--twenty-four-hour","name":"Twenty Four Hour","snippet":"const TwentyFourHour = () => <DateTimeRangePicker label=\"24-hour format\" ampm={false} />;","description":"24-hour format (no AM/PM)."},{"id":"date-time-pickers-datetimerangepicker--min-max-date","name":"Min Max Date","snippet":"const MinMaxDate = () => (\n  <DateTimeRangePicker\n    label=\"This month only\"\n    minDateTime={dayjs().startOf('month')}\n    maxDateTime={dayjs().endOf('month')}\n  />\n);","description":"Restrict to a specific date window."},{"id":"date-time-pickers-datetimerangepicker--without-shortcuts","name":"Without Shortcuts","snippet":"const WithoutShortcuts = () => <DateTimeRangePicker label=\"Without shortcuts\" shortcuts={false} />;","description":"With built-in default shortcuts panel (Today, Yesterday, Last 7 Days, etc.)."},{"id":"date-time-pickers-datetimerangepicker--action-bar","name":"Action Bar","snippet":"const ActionBar = () => (\n  <DateTimeRangePicker\n    label=\"With action bar\"\n    slotProps={{\n      actionBar: {\n        actions: ['clear', 'cancel', 'accept'],\n      },\n    }}\n  />\n);","description":"Default action bar with Cancel and Accept actions."},{"id":"date-time-pickers-datetimerangepicker--interactive","name":"Interactive","snippet":"const Interactive = () => <DateTimeRangePicker\n    label=\"Pick a date-time range\"\n    size=\"medium\"\n    disabled={false}\n    readOnly={false}\n    disableFuture={false}\n    disablePast={false}\n    ampm />;","description":"Interactive playground with all controls."}],"import":"import { DateTimeRangePicker } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"DateTimeRangePicker","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/DateTimeRangePicker/DateTimeRangePicker.tsx","actualName":"DateTimeRangePicker","exportName":"DateTimeRangePicker","props":{"label":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"External label rendered above the picker."},"shortcuts":{"required":false,"tsType":{"name":"union","raw":"boolean | DateRangeShortcut[]","elements":[{"name":"boolean"},{"name":"Array","elements":[{"name":"PickersShortcutsItem","elements":[{"name":"DateRange","elements":[{"name":"Dayjs"}],"raw":"DateRange<Dayjs>"}],"raw":"PickersShortcutsItem<DateRange<Dayjs>>"}],"raw":"DateRangeShortcut[]"}]},"description":"Enable the shortcuts panel for quick date range selection.\n- `true` uses the built-in default shortcuts (Today, Yesterday, Last 7 Days, etc.)\n- Pass a custom array of `DateRangeShortcut` items for full control.\n- `false` / `undefined` disables shortcuts (default)."},"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the picker input. Matches EnhancedTextField sizes."},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted."}},"composes":["Omit"]},"docs":{"date-time-pickers-datetimerangepicker--docs":{"id":"date-time-pickers-datetimerangepicker--docs","name":"Docs","path":"./src/stories/ui-components/DateTimeRangePicker.mdx","title":"Date & Time Pickers/DateTimeRangePicker","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as DateTimeRangePickerStories from './DateTimeRangePicker.stories';\nimport { DateTimeRangePicker } from '../../components/DateTimeRangePicker';\n\n<Meta of={DateTimeRangePickerStories} />\n\n# DateTimeRangePicker\n\n## Overview\n\n`DateTimeRangePicker` wraps MUI X date-time range picker. **Requires `ExotelThemeProvider`.**\n\n```tsx\nimport { DateTimeRangePicker } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Filter/report ranges including time component.\n\n## Stories\n\n`Basic`, `Sizes`, `Controlled`, `WithoutLabel`, `Disabled`, `ReadOnly`, `DisablePast`, `TwentyFourHour`, `MinMaxDate`, `WithoutShortcuts`, `ActionBar`, `Interactive`\n\n<Canvas of={DateTimeRangePickerStories.Basic} />\n\n## Related Components\n\n`DateRangePicker`, `DateTimePicker`, `TimeRangePicker`\n"}}},"date-time-pickers-timepicker":{"id":"date-time-pickers-timepicker","name":"TimePicker","path":"./src/stories/ui-components/TimePicker.stories.tsx","stories":[{"id":"date-time-pickers-timepicker--basic","name":"Basic","snippet":"const Basic = () => <TimePicker label=\"Select time\" />;","description":"Basic time picker with a label."},{"id":"date-time-pickers-timepicker--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 300 }}>\n    <TimePicker label=\"Small\" size=\"small\" />\n    <TimePicker label=\"Medium\" size=\"medium\" />\n    <TimePicker label=\"Large\" size=\"large\" />\n  </div>\n);","description":"All three sizes — small (32px), medium (40px), and large (50px) — matching EnhancedTextField."},{"id":"date-time-pickers-timepicker--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [value, setValue] = useState<Dayjs | null>(dayjs());\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 300 }}>\n      <TimePicker label=\"Time\" value={value} onChange={(newValue) => setValue(newValue)} />\n      <div style={{ fontSize: 14, color: '#666' }}>\n        Selected: {value ? value.format('hh:mm A') : 'None'}\n      </div>\n    </div>\n  );\n};","description":"Controlled time picker with React state."},{"id":"date-time-pickers-timepicker--without-label","name":"Without Label","snippet":"const WithoutLabel = () => <TimePicker />;","description":"Without an external label."},{"id":"date-time-pickers-timepicker--disabled","name":"Disabled","snippet":"const Disabled = () => <TimePicker label=\"Disabled\" disabled defaultValue={dayjs()} />;","description":"Time picker in disabled state."},{"id":"date-time-pickers-timepicker--read-only","name":"Read Only","snippet":"const ReadOnly = () => <TimePicker label=\"Read only\" readOnly defaultValue={dayjs()} />;","description":"Read-only time picker."},{"id":"date-time-pickers-timepicker--twenty-four-hour","name":"Twenty Four Hour","snippet":"const TwentyFourHour = () => <TimePicker label=\"24-hour format\" ampm={false} />;","description":"24-hour format (no AM/PM)."},{"id":"date-time-pickers-timepicker--with-seconds","name":"With Seconds","snippet":"const WithSeconds = () => (\n  <TimePicker label=\"Include seconds\" views={['hours', 'minutes', 'seconds']} format=\"hh:mm:ss A\" />\n);","description":"With seconds visible."},{"id":"date-time-pickers-timepicker--min-max-time","name":"Min Max Time","snippet":"const MinMaxTime = () => (\n  <TimePicker\n    label=\"Business hours (9 AM – 5 PM)\"\n    minTime={dayjs().hour(9).minute(0)}\n    maxTime={dayjs().hour(17).minute(0)}\n  />\n);","description":"Restrict to specific time range."},{"id":"date-time-pickers-timepicker--action-bar","name":"Action Bar","snippet":"const ActionBar = () => (\n  <TimePicker\n    label=\"With action bar\"\n    slotProps={{\n      actionBar: {\n        actions: ['clear', 'cancel', 'accept'],\n      },\n    }}\n  />\n);","description":"Default action bar with Clear, Cancel, and Accept actions."},{"id":"date-time-pickers-timepicker--interactive","name":"Interactive","snippet":"const Interactive = () => <TimePicker label=\"Pick a time\" size=\"medium\" disabled={false} readOnly={false} ampm />;","description":"Interactive playground with all controls."}],"import":"import { TimePicker } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"TimePicker","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/TimePicker/TimePicker.tsx","actualName":"TimePicker","exportName":"TimePicker","props":{"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the picker input. Matches EnhancedTextField sizes."},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted."}},"composes":["Omit"]},"docs":{"date-time-pickers-timepicker--docs":{"id":"date-time-pickers-timepicker--docs","name":"Docs","path":"./src/stories/ui-components/TimePicker.mdx","title":"Date & Time Pickers/TimePicker","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as TimePickerStories from './TimePicker.stories';\nimport { TimePicker } from '../../components/TimePicker';\n\n<Meta of={TimePickerStories} />\n\n# TimePicker\n\n## Overview\n\n`TimePicker` wraps MUI X `TimePicker` with external label. **Requires `ExotelThemeProvider`.**\n\n```tsx\nimport { TimePicker } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Time-of-day selection.\n**When not to use:** Date+time → `DateTimePicker`; time range → `TimeRangePicker`.\n\n## Stories\n\n`Basic`, `Sizes`, `Controlled`, `WithoutLabel`, `Disabled`, `ReadOnly`, `TwentyFourHour`, `WithSeconds`, `MinMaxTime`, `ActionBar`, `Interactive`\n\n<Canvas of={TimePickerStories.Basic} />\n\n## Related Components\n\n`DateTimePicker`, `TimeRangePicker`\n"}}},"date-time-pickers-timerangepicker":{"id":"date-time-pickers-timerangepicker","name":"TimeRangePicker","path":"./src/stories/ui-components/TimeRangePicker.stories.tsx","stories":[{"id":"date-time-pickers-timerangepicker--basic","name":"Basic","snippet":"const Basic = () => <TimeRangePicker label=\"Select time range\" />;","description":"Basic time range picker with a label."},{"id":"date-time-pickers-timerangepicker--sizes","name":"Sizes","snippet":"const Sizes = () => (\n  <div style={{ display: 'flex', flexDirection: 'column', gap: 16, minWidth: 500 }}>\n    <TimeRangePicker label=\"Small\" size=\"small\" />\n    <TimeRangePicker label=\"Medium\" size=\"medium\" />\n    <TimeRangePicker label=\"Large\" size=\"large\" />\n  </div>\n);","description":"All three sizes — small (32px), medium (40px), and large (50px) — matching EnhancedTextField."},{"id":"date-time-pickers-timerangepicker--controlled","name":"Controlled","snippet":"const Controlled = () => {\n  const [value, setValue] = useState<DateRange<Dayjs>>([null, null]);\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, minWidth: 500 }}>\n      <TimeRangePicker label=\"Time range\" value={value} onChange={(newValue) => setValue(newValue)} />\n      <div style={{ fontSize: 14, color: '#666' }}>\n        Start: {value[0] ? value[0].format('hh:mm A') : 'None'}\n        {' — '}\n        End: {value[1] ? value[1].format('hh:mm A') : 'None'}\n      </div>\n    </div>\n  );\n};","description":"Controlled time range picker with React state."},{"id":"date-time-pickers-timerangepicker--without-label","name":"Without Label","snippet":"const WithoutLabel = () => <TimeRangePicker />;","description":"Without an external label."},{"id":"date-time-pickers-timerangepicker--disabled","name":"Disabled","snippet":"const Disabled = () => (\n  <TimeRangePicker\n    label=\"Disabled\"\n    disabled\n    defaultValue={[dayjs().hour(9).minute(0), dayjs().hour(17).minute(0)]}\n  />\n);","description":"Disabled state."},{"id":"date-time-pickers-timerangepicker--read-only","name":"Read Only","snippet":"const ReadOnly = () => (\n  <TimeRangePicker\n    label=\"Read only\"\n    readOnly\n    defaultValue={[dayjs().hour(9).minute(0), dayjs().hour(17).minute(0)]}\n  />\n);","description":"Read-only state."},{"id":"date-time-pickers-timerangepicker--twenty-four-hour","name":"Twenty Four Hour","snippet":"const TwentyFourHour = () => <TimeRangePicker label=\"24-hour format\" ampm={false} />;","description":"24-hour format (no AM/PM)."},{"id":"date-time-pickers-timerangepicker--business-hours","name":"Business Hours","snippet":"const BusinessHours = () => (\n  <TimeRangePicker\n    label=\"Business hours\"\n    defaultValue={[dayjs().hour(9).minute(0), dayjs().hour(17).minute(0)]}\n  />\n);","description":"Pre-filled business hours range."},{"id":"date-time-pickers-timerangepicker--action-bar","name":"Action Bar","snippet":"const ActionBar = () => (\n  <TimeRangePicker\n    label=\"With action bar\"\n    slotProps={{\n      actionBar: {\n        actions: ['clear', 'cancel', 'accept'],\n      },\n    }}\n  />\n);","description":"Default action bar with Cancel and Accept actions."},{"id":"date-time-pickers-timerangepicker--interactive","name":"Interactive","snippet":"const Interactive = () => <TimeRangePicker\n    label=\"Pick a time range\"\n    size=\"medium\"\n    disabled={false}\n    readOnly={false}\n    ampm />;","description":"Interactive playground with all controls."}],"import":"import { TimeRangePicker } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"reactDocgen":{"description":"","methods":[],"displayName":"TimeRangePicker","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/TimeRangePicker/TimeRangePicker.tsx","actualName":"TimeRangePicker","exportName":"TimeRangePicker","props":{"label":{"required":false,"tsType":{"name":"ReactReactNode","raw":"React.ReactNode"},"description":"External label rendered above the picker."},"size":{"required":false,"tsType":{"name":"union","raw":"'small' | 'medium' | 'large'","elements":[{"name":"literal","value":"'small'"},{"name":"literal","value":"'medium'"},{"name":"literal","value":"'large'"}]},"description":"The size of the picker input. Matches EnhancedTextField sizes."},"placeholder":{"required":false,"tsType":{"name":"string"},"description":"Placeholder text inside the input. Derived from `label` when omitted."}},"composes":["Omit"]},"docs":{"date-time-pickers-timerangepicker--docs":{"id":"date-time-pickers-timerangepicker--docs","name":"Docs","path":"./src/stories/ui-components/TimeRangePicker.mdx","title":"Date & Time Pickers/TimeRangePicker","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as TimeRangePickerStories from './TimeRangePicker.stories';\nimport { TimeRangePicker } from '../../components/TimeRangePicker';\n\n<Meta of={TimeRangePickerStories} />\n\n# TimeRangePicker\n\n## Overview\n\n`TimeRangePicker` wraps MUI X time range picker. **Requires `ExotelThemeProvider`.**\n\n```tsx\nimport { TimeRangePicker } from '@exotel-npm-dev/signal-design-system';\n```\n\n**When to use:** Start/end time windows (business hours, schedules).\n\n## Stories\n\n`Basic`, `Sizes`, `Controlled`, `WithoutLabel`, `Disabled`, `ReadOnly`, `TwentyFourHour`, `BusinessHours`, `ActionBar`, `Interactive`\n\n<Canvas of={TimeRangePickerStories.Basic} />\n\n## Related Components\n\n`TimePicker`, `DateTimeRangePicker`\n"}}},"flow-builder-flowbuilder":{"id":"flow-builder-flowbuilder","name":"FlowBuilder","path":"./src/stories/ui-components/FlowBuilder.stories.tsx","stories":[{"id":"flow-builder-flowbuilder--basic","name":"Basic","snippet":"const Basic = () => {\n    const flow = useFlowBuilder({\n      initialNodes: sampleNodes,\n      initialEdges: sampleEdges,\n    });\n    return <FlowBuilder showMinimap={false} showControls showBackground {...flow} />;\n};"},{"id":"flow-builder-flowbuilder--with-minimap","name":"With Minimap","snippet":"const WithMinimap = () => {\n    const flow = useFlowBuilder({\n      initialNodes: sampleNodes,\n      initialEdges: sampleEdges,\n    });\n    return <FlowBuilder showMinimap showControls showBackground {...flow} />;\n};"},{"id":"flow-builder-flowbuilder--with-toolbar","name":"With Toolbar","snippet":"const WithToolbar = () => {\n  const flow = useFlowBuilder({\n    initialNodes: sampleNodes,\n    initialEdges: sampleEdges,\n  });\n\n  const addNode = useCallback(() => {\n    const id = `new-${Date.now()}`;\n    flow.setNodes((prev) => [\n      ...prev,\n      {\n        id,\n        type: 'action',\n        position: { x: Math.random() * 400, y: Math.random() * 400 },\n        data: { label: 'New Node', description: 'Added via toolbar' },\n      },\n    ]);\n  }, [flow.setNodes]);\n\n  return (\n    <FlowBuilder {...flow} showMinimap>\n      <FlowToolbar>\n        <button onClick={addNode} style={{ cursor: 'pointer', padding: '4px 12px', borderRadius: 6, border: '1px solid #ccc', background: '#fff' }}>\n          + Add Node\n        </button>\n      </FlowToolbar>\n    </FlowBuilder>\n  );\n};"},{"id":"flow-builder-flowbuilder--read-only","name":"Read Only","snippet":"const ReadOnly = () => {\n  const flow = useFlowBuilder({\n    initialNodes: sampleNodes,\n    initialEdges: sampleEdges,\n  });\n  return (\n    <FlowBuilder\n      {...flow}\n      nodesDraggable={false}\n      nodesConnectable={false}\n      elementsSelectable={false}\n      showControls={false}\n    />\n  );\n};"},{"id":"flow-builder-flowbuilder--node-showcase","name":"Node Showcase","snippet":"const NodeShowcase = () => {\n  const showcaseNodes: Node[] = [\n    {\n      id: 'start',\n      type: 'startEnd',\n      position: { x: 250, y: 0 },\n      data: { label: 'Start', variant: 'start' },\n    },\n    {\n      id: 'action-default',\n      type: 'action',\n      position: { x: 50, y: 100 },\n      data: { label: 'Default Action', description: 'No status', icon: '📋' },\n    },\n    {\n      id: 'action-success',\n      type: 'action',\n      position: { x: 300, y: 100 },\n      data: { label: 'Success Action', description: 'Status: success', icon: '✅', status: 'success' },\n    },\n    {\n      id: 'action-error',\n      type: 'action',\n      position: { x: 550, y: 100 },\n      data: { label: 'Error Action', description: 'Status: error', icon: '❌', status: 'error' },\n    },\n    {\n      id: 'action-warning',\n      type: 'action',\n      position: { x: 50, y: 230 },\n      data: { label: 'Warning Action', description: 'Status: warning', icon: '⚠️', status: 'warning' },\n    },\n    {\n      id: 'action-info',\n      type: 'action',\n      position: { x: 300, y: 230 },\n      data: { label: 'Info Action', description: 'Status: info', icon: 'ℹ️', status: 'info' },\n    },\n    {\n      id: 'condition',\n      type: 'condition',\n      position: { x: 200, y: 360 },\n      data: { label: 'Decision', description: 'Branch logic', conditions: ['Option A', 'Option B'] },\n    },\n    {\n      id: 'end',\n      type: 'startEnd',\n      position: { x: 250, y: 520 },\n      data: { label: 'End', variant: 'end' },\n    },\n  ];\n\n  const flow = useFlowBuilder({ initialNodes: showcaseNodes, initialEdges: [] });\n  return <FlowBuilder {...flow} showControls />;\n};"},{"id":"flow-builder-flowbuilder--complex-flow","name":"Complex IVR Flow","snippet":"const ComplexFlow = () => {\n  const nodes: Node[] = [\n    { id: '1', type: 'startEnd', position: { x: 300, y: 0 }, data: { label: 'Incoming Call', variant: 'start' } },\n    { id: '2', type: 'action', position: { x: 260, y: 100 }, data: { label: 'Play Welcome', description: 'IVR greeting', icon: '🔊' } },\n    { id: '3', type: 'condition', position: { x: 240, y: 220 }, data: { label: 'Language', description: 'DTMF input', conditions: ['English', 'Hindi'] } },\n    { id: '4', type: 'action', position: { x: 50, y: 380 }, data: { label: 'English Menu', icon: '🇬🇧', status: 'info' } },\n    { id: '5', type: 'action', position: { x: 450, y: 380 }, data: { label: 'Hindi Menu', icon: '🇮🇳', status: 'info' } },\n    { id: '6', type: 'condition', position: { x: 20, y: 500 }, data: { label: 'Department?', conditions: ['Sales', 'Support'] } },\n    { id: '7', type: 'action', position: { x: -120, y: 650 }, data: { label: 'Sales Queue', icon: '💰', status: 'success' } },\n    { id: '8', type: 'action', position: { x: 130, y: 650 }, data: { label: 'Support Queue', icon: '🛠️', status: 'warning' } },\n    { id: '9', type: 'action', position: { x: 420, y: 500 }, data: { label: 'Hindi Support', icon: '🛠️', status: 'warning' } },\n    { id: '10', type: 'startEnd', position: { x: 250, y: 800 }, data: { label: 'Call Ended', variant: 'end' } },\n  ];\n\n  const edges: Edge[] = [\n    { id: 'e1', source: '1', target: '2' },\n    { id: 'e2', source: '2', target: '3' },\n    { id: 'e3', source: '3', sourceHandle: 'yes', target: '4', type: 'conditional', data: { label: 'English' } },\n    { id: 'e4', source: '3', sourceHandle: 'no', target: '5', type: 'conditional', data: { label: 'Hindi' } },\n    { id: 'e5', source: '4', target: '6' },\n    { id: 'e6', source: '6', sourceHandle: 'yes', target: '7', type: 'conditional', data: { label: 'Sales' } },\n    { id: 'e7', source: '6', sourceHandle: 'no', target: '8', type: 'conditional', data: { label: 'Support' } },\n    { id: 'e8', source: '5', target: '9' },\n    { id: 'e9', source: '7', target: '10' },\n    { id: 'e10', source: '8', target: '10' },\n    { id: 'e11', source: '9', target: '10' },\n  ];\n\n  const flow = useFlowBuilder({ initialNodes: nodes, initialEdges: edges });\n  return <FlowBuilder {...flow} showMinimap showControls />;\n};"}],"import":"import { Box, FlowBuilder, FlowToolbar } from \"@exotel-npm-dev/signal-design-system\";\nimport { ReactFlowProvider } from \"@xyflow/react\";","jsDocTags":{},"description":"FlowBuilder — Exotel Design System wrapper around React Flow. Thin abstraction that: - Forwards all props to the underlying `<ReactFlow />` - Applies Exotel theme tokens via CSS variables (light/dark auto-switch) - Provides pre-built, themed node and edge types - Exposes convenience props (`showMinimap`, `showControls`, `showBackground`)","reactDocgen":{"description":"FlowBuilder — Exotel Design System wrapper around React Flow.\n\nThin abstraction that:\n- Forwards all props to the underlying `<ReactFlow />`\n- Applies Exotel theme tokens via CSS variables (light/dark auto-switch)\n- Provides pre-built, themed node and edge types\n- Exposes convenience props (`showMinimap`, `showControls`, `showBackground`)","methods":[],"displayName":"FlowBuilderComponent","definedInFile":"/Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/components/FlowBuilder/FlowBuilder.tsx","actualName":"FlowBuilderComponent","exportName":"FlowBuilder","props":{"nodes":{"required":true,"tsType":{"name":"Array","elements":[{"name":"Node"}],"raw":"Node[]"},"description":""},"edges":{"required":true,"tsType":{"name":"Array","elements":[{"name":"Edge"}],"raw":"Edge[]"},"description":""},"showMinimap":{"required":false,"tsType":{"name":"boolean"},"description":"Show the minimap panel. @default false","defaultValue":{"value":"false","computed":false}},"showControls":{"required":false,"tsType":{"name":"boolean"},"description":"Show the zoom/fit-view controls panel. @default true","defaultValue":{"value":"true","computed":false}},"showBackground":{"required":false,"tsType":{"name":"boolean"},"description":"Show the dot-grid background. @default true","defaultValue":{"value":"true","computed":false}},"colorMode":{"required":false,"tsType":{"name":"ColorMode"},"description":"Color mode override. When omitted the wrapper reads the current\nExotel theme mode automatically (light / dark)."},"className":{"required":false,"tsType":{"name":"string"},"description":"Extra CSS class on the wrapper div."},"style":{"required":false,"tsType":{"name":"CSSProperties"},"description":"Inline style on the wrapper div (height/width)."},"nodeTypes":{"required":false,"tsType":{"name":"NodeTypes"},"description":"Merge additional node types with the built-in set."},"edgeTypes":{"required":false,"tsType":{"name":"EdgeTypes"},"description":"Merge additional edge types with the built-in set."},"children":{"required":false,"tsType":{"name":"ReactNode"},"description":"Content rendered inside the ReactFlow container (panels, toolbars, etc.)."}},"composes":["Omit"]},"docs":{"flow-builder-flowbuilder--docs":{"id":"flow-builder-flowbuilder--docs","name":"Docs","path":"./src/stories/ui-components/FlowBuilder.mdx","title":"Flow Builder/FlowBuilder","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as FlowBuilderStories from './FlowBuilder.stories';\nimport { FlowBuilder } from '../../components/FlowBuilder';\n\n<Meta of={FlowBuilderStories} />\n\n# FlowBuilder\n\n## Overview\n\n`FlowBuilder` wraps **React Flow** (`@xyflow/react`) with Exotel theme tokens and built-in node/edge types.\n\n```tsx\nimport { FlowBuilder } from '@exotel-npm-dev/signal-design-system';\n```\n\nBuilt-in node types: `action`, `condition`, `startEnd`, `group`. Edge types: `default`, `conditional`.\n\n## Convenience props\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `showMinimap` | `boolean` | `false` | Show minimap |\n| `showControls` | `boolean` | `true` | Zoom/fit controls |\n| `showBackground` | `boolean` | `true` | Dot background |\n| `colorMode` | `ColorMode` | — | Override theme light/dark |\n\nForwards remaining `ReactFlowProps` (`nodes`, `edges`, `onNodesChange`, etc.).\n\n## Stories\n\n`Basic`, `WithMinimap`, `WithToolbar`, `ReadOnly`, `NodeShowcase`, `ComplexFlow`\n\n<Canvas of={FlowBuilderStories.Basic} />\n<Canvas of={FlowBuilderStories.NodeShowcase} />\n\n## Guidance for AI Agents\n\nUse built-in node types before custom nodes. Requires `ExotelThemeProvider` for CSS variable theming. **Not exported from package `index.ts`** — import from `components/FlowBuilder`. Specialized for flow/workflow UIs.\n\n## Related Components\n\n`Box`, `Icon`, `Button`, `ThemeProvider`\n"}}},"lottie-lottie":{"id":"lottie-lottie","name":"Lottie","path":"./src/stories/ui-components/Lottie.stories.tsx","stories":[{"id":"lottie-lottie--basic","name":"Basic","snippet":"const Basic = () => <Lottie\n    animationData={refreshAnimation}\n    loop\n    autoplay\n    style={{ width: 160, height: 160 }} />;"},{"id":"lottie-lottie--playback-controls","name":"Playback controls (lottieRef)","snippet":"const PlaybackControls = () => <PlaybackControlsDemo />;"},{"id":"lottie-lottie--use-lottie-hook","name":"useLottie hook","snippet":"const UseLottieHook = () => <UseLottieHookDemo />;"},{"id":"lottie-lottie--static","name":"Static (no autoplay / no loop)","snippet":"const Static = () => (\n  <Box sx={{ display: 'flex', justifyContent: 'center' }}>\n    <Lottie\n      animationData={refreshAnimation}\n      loop={false}\n      autoplay={false}\n      style={{ width: 120, height: 120 }}\n    />\n  </Box>\n);"}],"import":"import { Box, Button, Lottie, Stack, Typography } from \"@exotel-npm-dev/signal-design-system\";","jsDocTags":{},"error":{"name":"Component file in node_modules","message":"File: /Users/rudrakshula.prasanth/Main/Exotel-Design-System/src/lottie.ts\nError:\nNo suitable component definition found.\nYou can debug your component file in this playground: https://react-docgen.dev/playground\nCode:\n/**\n * @exotel-npm-dev/signal-design-system/lottie\n *\n * Separate entry point that re-exports lottie-react's component, hooks, player,\n * and types. This keeps lottie-react (and lottie-web) out of the main bundle —\n * consumers only pay the cost when they import from this path.\n *\n * Usage:\n *   import {\n *     Lottie,\n *     useLottie,\n *     useLottieInteractivity,\n *     type LottieRefCurrentProps,\n *   } from '@exotel-npm-dev/signal-design-system/lottie';\n */\nexport { default as Lottie } from 'lottie-react';\nexport * from 'lottie-react';\n\n\nFile: /Users/rudrakshula.prasanth/Main/Exotel-Design-System/node_modules/lottie-react/build/index.es.js\nError:\nComponent files in node_modules are not supported.\nThe distributed files in node_modules usually don't contain the necessary comments or types needed to analyze component information.\nConfigure TypeScript path aliases to map your package name to the source file instead.\n\nExample (tsconfig.json):\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@design-system/button\": [\"src/components/Button.tsx\"],\n      \"@design-system/*\": [\"src/components/*\"]\n    }\n  }\n}\n\nThen import using:\nimport { Button } from '@design-system/button'\n\nStorybook resolves tsconfig paths automatically.\nCode:\n/* File in node_modules */\n\nFile: /Users/rudrakshula.prasanth/Main/Exotel-Design-System/node_modules/lottie-react/build/index.es.js\nError:\nComponent files in node_modules are not supported.\nThe distributed files in node_modules usually don't contain the necessary comments or types needed to analyze component information.\nConfigure TypeScript path aliases to map your package name to the source file instead.\n\nExample (tsconfig.json):\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@design-system/button\": [\"src/components/Button.tsx\"],\n      \"@design-system/*\": [\"src/components/*\"]\n    }\n  }\n}\n\nThen import using:\nimport { Button } from '@design-system/button'\n\nStorybook resolves tsconfig paths automatically.\nCode:\n/* File in node_modules */"},"docs":{"lottie-lottie--docs":{"id":"lottie-lottie--docs","name":"Docs","path":"./src/stories/ui-components/Lottie.mdx","title":"Lottie/Lottie","content":"import { Meta, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as LottieStories from './Lottie.stories';\n\n<Meta of={LottieStories} />\n\n# Lottie\n\n## Overview\n\n`Lottie` renders [Lottie](https://airbnb.io/lottie/) (After Effects / Bodymovin) animations in React. This is a re-export of [`lottie-react`](https://lottiereact.com/) shipped as a **separate entry point** so it stays out of the main bundle — consumers only pay the cost when they explicitly import from this path.\n\n```tsx\nimport { Lottie, useLottie, useLottieInteractivity } from '@exotel-npm-dev/signal-design-system/lottie';\nimport type { LottieRefCurrentProps } from '@exotel-npm-dev/signal-design-system/lottie';\n```\n\n**Note:** `lottie-react` and `lottie-web` come bundled — no extra install needed.\n\n**When to use**\n\n- Loading / processing states with branded animations\n- Empty states with illustrative animations\n- Micro-interactions and delighters\n- Onboarding walkthroughs with animated illustrations\n\n**When not to use**\n\n- Simple spinners → use `CircularProgress` or `LinearProgress`\n- Static icons → use `Icon`\n- CSS transitions → use MUI `Grow`, `Slide`, `Fade`\n\n## Basic Usage\n\n```tsx\nimport { Lottie } from '@exotel-npm-dev/signal-design-system/lottie';\nimport animationData from './my-animation.json';\n\nfunction Loader() {\n  return (\n    <Lottie\n      animationData={animationData}\n      loop\n      autoplay\n      style={{ width: 160, height: 160 }}\n    />\n  );\n}\n```\n\n## Key Props\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `animationData` | `object` | — | Parsed Lottie JSON animation data |\n| `loop` | `boolean` | `true` | Repeat the animation when it finishes |\n| `autoplay` | `boolean` | `true` | Start playing as soon as it mounts |\n| `style` | `CSSProperties` | — | Inline styles (width, height) |\n| `lottieRef` | `Ref<LottieRefCurrentProps>` | — | Imperative control handle |\n| `onComplete` | `() => void` | — | Callback when animation finishes (non-loop) |\n| `speed` | `number` | `1` | Playback speed multiplier |\n| `direction` | `1 \\| -1` | `1` | Forward or reverse playback |\n\n## Imperative Control (lottieRef)\n\nPass a `lottieRef` to control playback programmatically:\n\n```tsx\nconst lottieRef = useRef<LottieRefCurrentProps>(null);\n\n<Lottie lottieRef={lottieRef} animationData={data} loop autoplay={false} />\n\n// Control methods:\nlottieRef.current?.play();\nlottieRef.current?.pause();\nlottieRef.current?.stop();\nlottieRef.current?.setSpeed(2);\nlottieRef.current?.setDirection(-1);\nlottieRef.current?.goToAndStop(30, true); // frame 30\n```\n\n## useLottie Hook\n\nFor full control, the `useLottie` hook returns the rendered `View` plus control methods:\n\n```tsx\nimport { useLottie } from '@exotel-npm-dev/signal-design-system/lottie';\n\nfunction AnimatedWidget() {\n  const { View, play, pause, stop, setSpeed } = useLottie(\n    { animationData: data, loop: true, autoplay: false },\n    { width: 160, height: 160 },\n  );\n\n  return (\n    <div>\n      {View}\n      <button onClick={() => play()}>Play</button>\n    </div>\n  );\n}\n```\n\n## Stories\n\n### Basic\n\nLooping, autoplaying animation rendered with default settings.\n\n<Canvas of={LottieStories.Basic} />\n\n### Playback controls (lottieRef)\n\nImperative control via `lottieRef` — play, pause, stop, speed, direction.\n\n<Canvas of={LottieStories.PlaybackControls} />\n\n### useLottie hook\n\nHook-based approach returning `View` and control methods.\n\n<Canvas of={LottieStories.UseLottieHook} />\n\n### Static (no autoplay / no loop)\n\nPaused single-frame render for thumbnail/preview usage.\n\n<Canvas of={LottieStories.Static} />\n\n## Best Practices\n\n- Import from `@exotel-npm-dev/signal-design-system/lottie` (not the main entry) to keep the main bundle lean.\n- Always set explicit `width` and `height` via `style` to prevent layout shift.\n- Use `loop={false}` for one-shot animations (e.g. success confirmations).\n- Prefer `useLottie` when you need both the View and control methods in one place.\n- Keep animation JSON files small (< 100KB) for fast loading.\n- Use `autoplay={false}` with imperative control for animations triggered by user actions.\n\n## Accessibility\n\n- Lottie animations are decorative by default. Add `aria-hidden=\"true\"` on the container if purely decorative.\n- For meaningful animations, wrap in a container with `role=\"img\"` and `aria-label` describing the animation.\n- Respect `prefers-reduced-motion` by conditionally disabling `autoplay` or showing a static fallback.\n\n## Related Components\n\n| Component | Relationship |\n|-----------|--------------|\n| `CircularProgress` | Simple spinner for loading states without custom animation |\n| `LinearProgress` | Determinate/indeterminate progress bar |\n| `Icon` | Static icons from the Phosphor icon set |\n"}}}},"meta":{"docgen":"react-docgen","durationMs":1450}}